1、CC2530的IO口概述
CC2530芯片有21 個數字輸入/輸出引腳,可以配置為通用數字I/O 或外設I/O 信號,配置為連接到ADC、定時器或USART外設。這些I/O 口的用途可以通過一系列寄存器配置,由用戶軟件加以實現。
I/O 端口具備如下重要特性:
21 個數字I/O 引腳
可以配置為通用I/O 或外部設備I/O
輸入口具備上拉或下拉能力
具有外部中斷能力。
21 個I/O 引腳都可以用作於外部中斷源輸入口。因此如果需要外部設備可以產生中斷。外部中斷功能也可以從睡眠模式喚醒設備。
2、未使用的I/O 引腳處理
未使用的I/O 引腳電平是確定的,不能懸空。一個方法是使引腳不連接,配置引腳為具有上拉電阻的通用I/O輸入。這也是所有引腳復位后的狀態(除了P1.0 和P1.1 沒有上拉/下拉功能)。或者引腳可以配置為通用I/O輸出。這兩種情況下引腳都不能直接連接到VDD 或GND,以避免過多的功耗。
3、低I/O 電壓
在數字I/O 電壓引腳DVDD1 和DVDD2 低於2.6V 的應用中,寄存器位PICTL.PADSC 應設置為1,以獲得DC 特性表中所述的輸出DC 特性。
4、通用I/O
用作通用I/O 時,引腳可以組成3 個8 位端口,端口0、端口1 和端口2,表示為P0、P1 和P2。其中,P0和P1 是完全的8 位端口,而P2 僅有5 位可用。所有的端口均可以通過SFR 寄存器P0、P1 和P2 位尋址和字節尋址。每個端口引腳都可以單獨設置為通用I/O 或外部設備I/O。
(驅動電流很重要,有時候和MOS管電路、上拉電阻的選擇等密切相關)除了兩個高驅動輸出口P1.0 和P1.1 各具備20 mA 的輸出驅動能力之外,所有的輸出均具備4 mA 的驅動能力。
寄存器PxSEL(選擇為通用IO模式還是外設IO信號),其中x 為端口的標號0~2,用來設置端口的每個引腳為通用I/O 或者是外部設備I/O 信號。作為缺省的情況,每當復位之后,所有的數字輸入/輸出引腳都設置為通用輸入引腳。在任何時候,要改變一個端口引腳的方向,就使用寄存器PxDIR(選擇輸入或輸出)來設置每個端口引腳為輸入或輸出。因此只要設置PxDIR 中的指定位為1,其對應的引腳口就被設置為輸出了。當讀取端口寄存器P0、P1 和P2 的值,不管引腳配置如何,輸入引腳上的邏輯值都被返回。這在執行讀-修改-寫指令期間不適用。讀-修改-寫指令是:ANL,ORL,XRL,JBC,CPL,INC,DEC,DJNZ,MOV,CLR和SETB。在一個端口寄存器上操作,以下是正確的:當目標是端口寄存器P0、P1 或P2 中一個獨立的位,寄存器的值,而不是引腳上的值,被讀取、修改並寫回端口寄存器。
用作輸入時,通用I/O 端口引腳可以設置為上拉、下拉或三態操作模式。作為缺省的情況,復位之后,所有的端口均設置為帶上拉的輸入。要取消輸入的上拉或下拉功能,就要將PxINP(輸入上拉、下拉、三態模式選擇)中的對應位設置為1。I/O 端口引腳P1.0 和P1.1 沒有上拉/下拉功能。注意配置為外設I/O 信號的引腳沒有上拉/下拉功能,即使外設功能是一個輸入。
在電源模式PM1、PM2 和PM3 下I/O 引腳保留當進入PM1/PM2/PM3 時設置的I/O 模式和輸出值(如果可用的話)。
5、通用I/O 中斷
通用I/O 引腳設置為輸入后,可以用於產生中斷。中斷可以設置在外部信號的上升或下降沿觸發。P0、P1或P2 端口都有中斷使能位,對位於IENl(端口中斷使能寄存器)寄存器內的端口所有的位都是公共的,如下:
IENI.P0 IE:P0 中斷使能
IEN2.PI IE:P1 中斷使能
IEN2.P2IE:P2 中斷使能
除了這些公共中斷使能之外,每個端口的位都有位於SFR 寄存器P0IEN、P1IEN 和P2IEN(單獨引腳中斷使能寄存器)的單獨的中斷使能。即使配置為外設I/O 或通用輸出的I/O 引腳使能時都有中斷產生。
當中斷條件發生在I/O 引腳之一上面,P0-P2 中斷標志寄存器P0IFG、P1IFG 或P2IFG(中斷標志寄存器)中相應的中斷狀態標志將設置為1。不管引腳是否設置了它的中斷使能位,中斷狀態標志都被設置。當中斷已經執行,中斷狀態標志被清除,該標志寫入0。這個標志必須在清除CPU 端口中斷標志(PxIF)之前被清除。用於中斷的SFR 寄存器描述在下一節。寄存器總結如下:
P0IEN: P0 中斷使能
P1IEN: P1 中斷使能
P2IEN: P2 中斷使能
PICTL: P0、P1 和P2 觸發沿設置
P0FG: P0 中斷標志
P1IFG: P1 中斷標志
P2IFG: P2 中斷標志
6、通用I/O DMA
當用作通用I/O 引腳時,每個P0 和P2 端口都關聯一個DMA 觸發。這些DMA 觸發對於P0 為IOC_0,對於P1 為IOC_1。當一個中斷發生在P0 引腳時IOC_0 觸發是被激活的。當一個中斷發生在P1 引腳時IOC_1 觸發是被激活的。
7、外設I/O
本節描述了數字I/O 引腳是如何配置為外設I/O 的。對於可以通過數字輸入/輸出引腳和外部系統接口的每個外設單元,如何配置外設I/O 的描述給定在以下小節中。
對於USART 和定時器I/O,在一個數字I/O 引腳上選擇外設I/O 功能,需要設置對應的PxSEL 位為1。
注意,該外部單元具有兩個可以選擇的位置對應它們的I/O 引腳,參見下表。如果有關於I/O 映射的沖突設置,可以在這些之間設置優先級(使用P2SEL.PRIxP1 和P2DIR.PRIP0 位)。所有不會導致沖突的組合都可以使用。
注意即使沒有使用,外設一般也會出現在選定的位置,使用引腳的其他外設必須給予較高的優先級。例外情況是流量控制禁用時UART 模式下USART 的RTS 和CTS 引腳, 以及SPI 主模式下USART 配置的SSN 引腳。
還要注意不管PxINP 的設置,有輸入引腳的外設單元是從引腳接收輸入,這可能會影響外設單元的狀態。例如如果RX 引腳在用作一個UART 引腳之前,可能已經有活動, UART 在使用之前必須被清除。
7.1、定時器1
PERCFG.T1CFG 選擇是否使用備用位置1 或備用位置2。
在上表中,定時器1 的信號顯示如下:
● 0:通道0 捕獲/比較引腳
● 1:通道1 捕獲/比較引腳
● 2:通道2 捕獲/比較引腳
● 3:通道3 捕獲/比較引腳
● 4:通道4 捕獲/比較引腳
P2DIR.PRIP0(指派端口0一些外設的優先順序)選擇為端口0 指派一些外設的優先順序。當設置為10,定時器通道0-1 優先,當設置為11,定時器通道2-3 優先。要所有定時器1 通道在備用位置1 上可見,移動USART 0 和USART 1 到備用位置2。P2SEL.PRI1P1 和P2SEL.PRI0P1(外設優先級設置)選擇為端口1 指派一些外設的優先順序。當前者設置為低電平而后者設置為高電平時,定時器1 通道優先。
7.2、定時器3
PERCFG.T3CFG 選擇是否使用備用位置1 或備用位置2。
在表中,定時器3 的信號顯示如下:
● 0:通道0 比較引腳
● 1:通道1 比較引腳
P2SEL.PRI2P1 和P2SEL.PRI3P1 選擇為端口1 指派一些外設的優先順序。當這兩個位都設置為高電平時,定時器3 通道優先。如果P2SEL.PRI2P1 設置為高電平且P2SEL.PRI3P1 設置為低電平時,定時器3 通道優先於USART 1,但是USART 0 優先於定時器3 通道以及USART 1。
7.3、定時器4
PERCFG.T4CFG 選擇是否使用備用位置1 或備用位置2。
在表中,定時器4 的信號顯示如下:
● 0:通道0 比較引腳
● 1:通道1 比較引腳
P2SEL.PRI1P1 選擇為端口1 指派一些外設的優先順序。當這個位設置時,定時器4 通道優先。
7.4、USART 0
SFR 寄存器位PERCFG.U0CFG 選擇是否使用備用位置1 或備用位置2。
在表中,USART 0 信號顯示如下:
UART:
● RX:RXDATA
● TX:TXDATA
● RT:RTS
● CT:CTS
SPI:
● MI:MISO
● MO:MOSI
● C:SCK
● SS:SSN
P2DIR.PRIP0 選擇為端口0 指派一些外設的優先順序。當設置為00 時,USART 0 優先。注意如果選擇了UART 模式,且硬件流量控制禁用,UART 1 或定時器1 將優先使用端口P0.4 和P0.5。P2SEL.PRI3P1 和P2SEL.PRI0P1 選擇為端口1 指派一些外設的優先順序。當它們兩個都設置為0 時,USART0 優先。注意如果選擇了UART 模式,且硬件流量控制禁用,定時器1 或定時器3 將優先使用端口P1.2 和P1.3。
7.5、USART 1
SFR 寄存器位PERCFG.U1CFG 選擇是否使用備用位置1 或備用位置2。
在表中,USART 1 信號顯示如下:
UART:
● RX:RXDATA
● TX:TXDATA
● RT:RTS
● CT:CTS
SPI:
● MI:MISO
● MO:MOSI
● C:SCK
● SS: SSN
P2DIR.PRIP0 選擇為端口0 指派一些外設時的優先順序。當設置為01,USART 1 優先。注意如果選擇了UART 模式,且硬件流量控制禁用,USART 0 或定時器1 將優先使用P0.2 和P0.3。P2SEL.PRI3P1 和P2SEL.PRI2P1 選擇為端口1 指派一些外設的優先順序。當前者設置為1 而后者設置為0時,USART 1 優先。注意如果選擇了UART 模式,且硬件流量控制禁用,USART 0 或定時器3 將優先使用P1.4和P1.5。
7.6、ADC
當使用ADC 時,端口0 引腳必須配置為ADC 輸入。可以使用多達八個ADC 輸入引腳。要配置一個端口0引腳為一個ADC 輸入,APCFG 寄存器中相應的位必須設置為1。這個寄存器的默認值選擇端口0 引腳為非ADC輸入,即數字輸入/輸出。
APCFG 寄存器的設置將覆蓋P0SEL的設置。
ADC 可以配置為使用通用I/O 引腳P2.0 作為內部觸發器來啟動轉換。當用作ADC 內部觸發器時,P2.0 必須在輸入模式下配置為通用I/O。
7.7、調試接口
端口P2.1 和P2.2 分別用於調試數據和時鍾信號。這些顯示為表中的DD(調試數據)和DC(調試時鍾)。當處於調試模式,調試接口控制這些引腳的方向。當處於調試模式在這些引腳上禁用上拉/下拉。
7.8、32 kHz XOSC 輸入
端口P2.3 和P2.4 用於連接一個外部32 kHz 晶振。當CLKCONCMD.OSC32K 是低電平時,不管寄存器設置如何,這些端口引腳由32 kHz XOSC 使用。當CLKCONCMD.OSC32K 是低電平,這些端口引腳將設置在模擬模式。
7.9 無線測試輸出信號
通過使用OBSSELx 寄存器(OBSSEL0-OBSSEL5),用戶可以從RF 內核輸出不同的信號到GPIO 引腳。這些信號可以用於調試低級別的協議或控制外部PA、LNA 或交換機。控制寄存器OBSSEL0-OBSSEL5 可以用於覆蓋標准的GPIO 行為,以及在引腳P1[0:5]上輸出RF 內核信號(rfc_obs_sig0、rfc_obs_sig1 和rfc_obs_sig2)。可用信號的列表見第19 章。
7.10、掉電信號MUX (PMUX)
PMUX 寄存器可以用於輸出32 kHz 時鍾和/或數字穩壓器的狀態。所選的32 kHz 時鍾源可以輸出在P0 其中的一個引腳上。使能位CKOEN 使得輸出在P0 上,使用CKOPIN(詳細信息見PMUX 寄存器描述)選擇P0 的引腳。當CKOEN 被設置,所選引腳的所有其他配置都被覆蓋。時鍾在所有供電模式下都輸出;但是,在PM3 下時鍾停止(見第4 章的PM3)。而且,數字穩壓器的狀態可以輸出在P1 其中的一個引腳上。當DREGSTA 位被設置,數字穩壓器的狀態就被輸出。DREGSTAPIN 選擇P1 引腳(詳細信息見PMUX 寄存器描述)。當DREGSTA 被設置,所選引腳的所有其他配置都被覆蓋。當1.8V 片上數字穩壓器上電(芯片有調整過的電壓),所選的引腳輸出1。當1.8V片上數字穩壓器掉電,即在PM2 和PM3 下,所選的引腳輸出0。
7.11 I/O 引腳
I/O 端口的寄存器描述在本節中。寄存器如下:
● P0 :端口0
● P1 :端口1
● P2 :端口2
● PERCFG :外設控制寄存器
● APCFG :模擬外設I/O 配置
● P0SEL :端口0 功能選擇寄存器
● P1SEL :端口1 功能選擇寄存器
● P2SEL :端口2 功能選擇寄存器
● P0DIR :端口0 方向寄存器
● P1DIR :端口1 方向寄存器
● P2DIR :端口2 方向寄存器
● P0INP :端口0 輸入模式寄存器
● P1INP :端口1 輸入模式寄存器
● P2INP :端口2 輸入模式寄存器
● P0IFG :端口0 中斷狀態標志寄存器
● P1IFG :端口1 中斷狀態標志寄存器
● P2IFG :端口2 中斷狀態標志寄存器
● PICTL :中斷邊緣寄存器
● P0IEN :端口0 中斷掩碼寄存器
● P1IEN :端口1 中斷掩碼寄存器
● P2IEN :端口2 中斷掩碼寄存器
● PMUX :掉電信號Mux 寄存器
● OBSSEL0 :觀察輸出控制寄存器0
● OBSSEL1 :觀察輸出控制寄存器1
● OBSSEL2 :觀察輸出控制寄存器2
● OBSSEL3 :觀察輸出控制寄存器3
● OBSSEL4 :觀察輸出控制寄存器4
● OBSSEL5 :觀察輸出控制寄存器5
8、隔一秒閃爍例程(引腳輸出控制)
下面代碼是控制P1_0引腳上的LED每隔1s閃爍一次的實驗。黃色部分P1DIR用來設置P1的8個端口的每個的輸入輸出方向。
1 /**************************************************************************** 2 * 文 件 名: main.c 3 * 作 者: Andy 4 * 修 訂: 2013-01-08 5 * 版 本: 1.0 6 * 描 述: GPIO輸出控制實驗1 操作IO口控制LED燈的亮和滅 7 ****************************************************************************/ 8 #include <ioCC2530.h> 9 10 typedef unsigned char uchar; 11 typedef unsigned int uint; 12 13 #define LED1 P1_0 //定義P1.0口為LED1控制端 14 15 16 /**************************************************************************** 17 * 名 稱: DelayMS() 18 * 功 能: 以毫秒為單位延時,系統時鍾不配置時默認為16M(用示波器測量相當精確) 19 * 入口參數: msec 延時參數,值越大,延時越久 20 * 出口參數: 無 21 ****************************************************************************/ 22 void DelayMS(uint msec) 23 { 24 uint i,j; 25 26 for (i=0; i<msec; i++) 27 for (j=0; j<535; j++); 28 } 29 30 /**************************************************************************** 31 * 名 稱: InitLed() 32 * 功 能: 設置LED燈相應的IO口 33 * 入口參數: 無 34 * 出口參數: 無 35 ****************************************************************************/ 36 void InitLed(void) 37 { 38 P1DIR |= 0x01; //P1.0定義為輸出口 39 } 40 41 /**************************************************************************** 42 * 程序入口函數 43 ****************************************************************************/ 44 void main(void) 45 { 46 InitLed(); //設置LED燈相應的IO口 47 48 while(1) //死循環 49 { 50 LED1 = 0; //點亮LED1 51 DelayMS(1000); //延時1秒 52 53 LED1 = 1; //LED1熄滅 54 DelayMS(1000); //延時1秒 55 } 56 }
上面的例子是控制1個引腳,下面的流水燈例子展示了同時控制3個引腳,其實大同小異:

1 /**************************************************************************** 2 * 文 件 名: main.c 3 * 作 者: Andy 4 * 修 訂: 2013-01-08 5 * 版 本: 1.0 6 * 描 述: 操作IO口控制3盞LED燈的全亮和全滅、閃爍、流水燈 7 ****************************************************************************/ 8 #include <ioCC2530.h> 9 10 typedef unsigned char uchar; 11 typedef unsigned int uint; 12 13 #define LED1 P1_0 //定義P1.0口為LED1控制端 14 #define LED2 P1_1 //定義P1.1口為LED2控制端 15 #define LED3 P1_4 //定義P1.4口為LED3控制端 16 17 18 /**************************************************************************** 19 * 名 稱: DelayMS() 20 * 功 能: 以毫秒為單位延時,系統時鍾不配置時默認為16M(用示波器測量相當精確) 21 * 入口參數: msec 延時參數,值越大,延時越久 22 * 出口參數: 無 23 ****************************************************************************/ 24 void DelayMS(uint msec) 25 { 26 uint i,j; 27 28 for (i=0; i<msec; i++) 29 for (j=0; j<535; j++); 30 } 31 32 /**************************************************************************** 33 * 名 稱: LedOnOrOff() 34 * 功 能: 點亮或熄滅所有LED燈 35 * 入口參數: mode為0時LED燈亮 mode為1時LED燈滅 36 * 出口參數: 無 37 ****************************************************************************/ 38 void LedOnOrOff(uchar mode) 39 { 40 LED1 = mode; 41 LED2 = mode; 42 LED3 = mode; //由於P1.4與仿真器共用,必須拔掉仿真器的插頭才能看到LED3的變化 43 } 44 45 /**************************************************************************** 46 * 名 稱: InitLed() 47 * 功 能: 設置LED燈相應的IO口 48 * 入口參數: 無 49 * 出口參數: 無 50 ****************************************************************************/ 51 void InitLed(void) 52 { 53 P1DIR |= 0x13; //P1.0、P1.1、P1.4定義為輸出 54 LedOnOrOff(1); //使所有LED燈默認為熄滅狀態 55 } 56 57 /**************************************************************************** 58 * 程序入口函數 59 ****************************************************************************/ 60 void main(void) 61 { 62 uchar i; 63 64 InitLed(); //設置LED燈相關IO口 65 66 while(1) //死循環 67 { 68 LED1 = !LED1; //流水燈,初始化時LED為熄滅執行后則點亮 69 DelayMS(200); 70 LED2 = !LED2; 71 DelayMS(200); 72 LED3 = !LED3; 73 DelayMS(200); 74 75 for (i=0; i<2; i++) //所有燈閃爍2次 76 { 77 LedOnOrOff(1); //關閉所有LED燈 78 DelayMS(200); 79 LedOnOrOff(0); //打開所有LED燈 80 DelayMS(200); 81 } 82 83 LedOnOrOff(1); //使所有LED燈熄滅狀態 84 DelayMS(500); 85 } 86 }
9、按鍵控制LED亮滅(外部信號輸入讀取)
外設電路圖如下,P10低電平時LED亮,按鍵沒有按下P01為高電平,按下為低電平:
這里重點講P01按鍵信號讀取的設置:黃色部分P0SEL將P01設置為通用IO:
P0DIR將P01設置為輸入模式:
P0INP打開P01上的上拉電阻:
這里讀取一個引腳的狀態,和讀取51單片機一個引腳狀態一樣,比較簡單~
1 /**************************************************************************** 2 * 文 件 名: main.c 3 * 作 者: Andy 4 * 修 訂: 2013-01-08 5 * 版 本: 1.0 6 * 描 述: 按下按鍵S1控制LED1燈亮和滅 7 ****************************************************************************/ 8 #include <ioCC2530.h> 9 10 typedef unsigned char uchar; 11 typedef unsigned int uint; 12 13 #define LED1 P1_0 // P1.0口控制LED1 14 #define KEY1 P0_1 // P0.1口控制S1 15 16 /**************************************************************************** 17 * 名 稱: DelayMS() 18 * 功 能: 以毫秒為單位延時,系統時鍾不配置時默認為16M(用示波器測量相當精確) 19 * 入口參數: msec 延時參數,值越大,延時越久 20 * 出口參數: 無 21 ****************************************************************************/ 22 void DelayMS(uint msec) 23 { 24 uint i,j; 25 26 for (i=0; i<msec; i++) 27 for (j=0; j<535; j++); 28 } 29 30 /**************************************************************************** 31 * 名 稱: InitLed() 32 * 功 能: 設置LED相應的IO口 33 * 入口參數: 無 34 * 出口參數: 無 35 ****************************************************************************/ 36 void InitLed(void) 37 { 38 P1DIR |= 0x01; // P1.0定義為輸出 39 LED1 = 1; // LED1燈熄滅 40 } 41 42 /**************************************************************************** 43 * 名 稱: InitKey() 44 * 功 能: 設置按鍵相應的IO口 45 * 入口參數: 無 46 * 出口參數: 無 47 ****************************************************************************/ 48 void InitKey(void) 49 { 50 P0SEL &= ~0x02; //設置P0.1為普通IO口 51 P0DIR &= ~0x02; //按鍵接在P0.1口上,設P0.1為輸入模式 52 P0INP &= ~0x02; //打開P0.1上拉電阻 53 } 54 55 /**************************************************************************** 56 * 名 稱: KeyScan() 57 * 功 能: 讀取按鍵狀態 58 * 入口參數: 無 59 * 出口參數: 0為抬起 1為按鍵按下 60 ****************************************************************************/ 61 uchar KeyScan(void) 62 { 63 if (KEY1 == 0) 64 { 65 DelayMS(10); 66 if (KEY1 == 0) 67 { 68 while(!KEY1); //松手檢測 69 return 1; //有按鍵按下 70 } 71 } 72 73 return 0; //無按鍵按下 74 } 75 76 /**************************************************************************** 77 * 程序入口函數 78 ****************************************************************************/ 79 void main(void) 80 { 81 InitLed(); //設置LED1相應的IO口 82 InitKey(); //設置S1相應的IO口 83 84 while(1) 85 { 86 if (KeyScan()) //按鍵按下則改變LED狀態 87 LED1 = ~LED1; 88 } 89 }
小結
本篇幾乎把和IO相關的寄存器全部介紹完了,最后又介紹了簡單的IO輸入輸出的控制,一個是流水燈,一個是按鍵讀取,接下來會介紹IO的更多功能~
系列:
PS:如果您覺得還不錯,點個贊,讓更多人受益~
@beautifulzzzz 2016-07-10 continue~
e-mail:beautifulzzzz@qq.com
sina:http://weibo.com/beautifulzzzz?is_all=1