CC2541有兩個串行通信接口,分別是USART0和USART1,它們能夠分別運行於異步UART模式或者同步SPI模式。兩個USART具體同樣的功能,可以設置在單獨的I/O引腳。
1.UART模式
UART模式提供異步串行接口,在UART模式中,有2種接口選擇方式:2線接口和4線接口。
- 2線接口,使用RXD、TXD。
- 4線接口,使用RXD、TXD、RTS和CTS。
I/O外設引腳映射如下圖所示:


根據上面的外設I/O引腳映射可知:
UART0對應的外部設置IO引腳關系為:位置1:P0_2----RX P0_3----TX 位置2:P1_4----RX P1_5----TX
UART1對應的外部設置IO引腳關系為:位置1:P0_5----RX P0_4----TX 位置2:P1_7----RX P1_6----TX
UART模式的操作有以下特點。
- 8位或者9位負載數據
- 奇校驗、偶校驗或者無奇偶校驗
- 配置起始位和停止位電平
- 配置LSB(最低有效位)或MSB(最高有效位)首先傳輸
- 獨立接收中斷
- 獨立收發DMA觸發
- 奇偶校驗和幀檢驗出錯狀態
UART模式提供全雙工傳送,也就是說可以同時收發數據,傳送一個UART字節包括1個起始位,8個數據位,1個作為可選的第9位數據或者奇偶校驗位,再加上1個或者2個停止位。
UART操作由USART控制和狀態寄存器UxCSR以及UART控制寄存器UxUCR來控制,x是USART的編號,數值為0或者1。
當UxCSR.MODE設置為1時設定為UART模式。


1)UART的發送過程
當USART收發數據緩沖器UxDBUF寫入數據時,該字節自動發送到輸出引腳TXD,UxDBUF寄存器時雙緩沖的。當字節傳送開始時,UxCSR.ACTIVE位變為高電平,而當字節傳送結束時變為低電平。當傳送結束時,UxCSR.TX_BYTE位設置為1。當USART收發數據緩沖寄存器就緒,准備接收新的發送數據時,就產生了一個中斷請求,該中斷在傳送開始后立刻發生。

2)UART的接收過程
當1寫入UxCSR.RE位時,UART開始接收數據。UART在輸入引腳RXD上尋找有效起始位,並且設置UxCSR.ACTIVE位為1,當檢測出有效起始位時,收到的字節就傳入到接收寄存器,UxCSR.RX_BYTE位設置為1,該操作完成時,產生接收中斷,同時UxCSR.ACTIVE變為0,通過寄存器UxDBUF提取收到的數據字節。當UxDBUF讀出時,UxCSR.RX_BYTE位由硬件清零。
當運行UART模式時,內部的波特率發生器設置UART波特率。當運行在SPI模式時,內部的波特率發生器設置SPI主時鍾頻率。波特率由寄存器UxBAUD.BAUD_M[7:0] 和UxGCR.BAUD_E[4:0]定義。該波特率用於UART傳送,也用於SPI傳送的串行時鍾速率。波特率定義公式:

式中:f是系統的時鍾頻率,等於16MHz或者32MHz
標准波特率所需的寄存器值如下表所示,該表適用於32MHz系統時鍾。波特率誤差,用百分數表示。



CC2530配置串口的一般步驟:
1、配置串口的備用位置,是備用位置1,還是備用位置2。配置寄存器PERCFG外設控制寄存器
2、配置端口的外設優先級。此處配置P0外設優先作為UART0。配置寄存器P2DIR
3、配置IO,使用外部設備功能。此處配置P0_2和P0_3用作串口UART0。配置寄存器P0SEL
4、配置相應串口的控制和狀態寄存器。配置寄存器U0CSR、U0UCR
5、配置串口工作的波特率。配置寄存器U0GCR、U0BAUD
6、將對應的串口接收/發送中斷標志位清0,清零:TCON.URX0IF、TCON.URX1IF、IRCON2.UTX0IF、IRCON2.UTX1IF
7、使能串口接收中斷(一般發送不用中斷),置1 IEN0.URX0IE
8、開總中斷
中斷相關的寄存器如下:
IEN0(0xA8)

TCON(0x88)

IRCON2(0xE8)

1 /***************************************************************************** 2 *函 數 名:InitUART 3 *功 能:UART0串口初始化,波特率:115200 4 *入口參數:無 5 *出口參數:無 6 ******************************************************************************/ 7 void InitUART(void) 8 { 9 PERCFG &= ~0x01; //USART0為位置1 10 P2DIR &= ~0xc0; //優先級USART0 >USART1 >定時器1 11 P0SEL |= 0x0c; //P0_2,P0_3 用作串口(外部設備功能) 12 U0CSR |= 0x80; //設置為UART 方式 13 U0CSR |= 0x40; //使能接收器 14 15 U0UCR = 0x02; //禁止流控制,8bits,無校驗位,1位停止位 16 //起始位低電平,停止位高電平 17 U0GCR |=11; //32MHz 下的BAUD_E:11, 115200 18 U0BAUD |= 216; //32MHz 下的BAUD_M:216 11520 19 UTX0IF = 0; //UART0 TX 中斷標志初始置位0 20 IEN0 |= 0x04; //使能USART0 RX中斷 21 EA = 1; //開總中斷 22 }
實例程序:串口控制LED1和LED2等的亮滅以及上位機控制串口接收,這里的通信協議比較簡單,上位機發送兩字節的數據:一個控制燈亮滅的字節,一個結束字節'#'
"1#":LED1滅
"2#":LED1亮
"3#":LED2滅
"4#":LED2亮
"5#":LED1、LED2亮
"6#":LED1、LED2滅
"7#":CC2541向上位機發送字符串”Hello Chen Zhao!“ 按一下界面上的”接收“按鈕,接收下位機發送過來的字符串。
這個程序寫的比較簡單,這里只是一個演示,很容易出現發送解碼錯誤,應該組幀,以一定的通信協議傳輸數據,包括幀頭、校驗、數據字節、幀尾,在后續串口介紹中,將專門介紹下這方面的技巧。
為了驗證程序,我做了一個上位機程序,界面如下,用labview軟件編寫的。如果需要的話,可以拿走源程序。

1 /****************************************************************************** 2 *文 件 名:main.c 3 *作 者:陳照 4 *時 間:2015-05-18 5 *版 本:1.0 6 *描 述:UART串口發送與接收 7 ******************************************************************************/ 8 #include <iocc2541.h> 9 #include <string.h> 10 11 typedef unsigned char uchar; 12 typedef unsigned int uint; 13 14 #define LED1 P1_0 15 #define LED2 P1_1 16 17 char Rxdata[2] = " " ; //串口接收字符串 18 char Txdata[] = "Hello Chen Zhao!" ; //串口接收字符串 19 int txnum = sizeof(Txdata); 20 21 char temp; //串口接收字符 22 uchar datanum = 0; //串口接收字符串長度 23 uchar RXflag = 1; 24 uchar TXflag = 0; 25 26 /**************************************************************** 27 *函 數 名:InitClock 28 *功 能:系統時鍾初始化 29 *入口參數:無 30 *出口參數:無 31 *****************************************************************/ 32 void InitClock(void) 33 { 34 CLKCONCMD &= ~0x40; // 設置系統時鍾源為 32MHZ晶振 35 while(CLKCONSTA & 0x40); // 等待晶振穩定 36 CLKCONCMD &= ~0x47; // 設置系統主時鍾頻率為 32MHZ 37 } 38 39 /****************************************************************************** 40 *函 數 名:InitLED 41 *功 能:LED口功能初始化 42 *入口參數:無 43 *出口參數:無 44 ******************************************************************************/ 45 void InitLED(uchar On_Off) 46 { 47 P1SEL &= ~0x03; //P1.0、P1.1設置為通用I/O口 48 P1DIR |= 0x03; ///P1.0、P1.1設置為輸出 49 LED1 = On_Off; ///P1.0、P1.1亮滅初始化 50 LED2 = On_Off; 51 } 52 53 /****************************************************************************** 54 *函 數 名:InitUART 55 *功 能:UART0串口初始化,波特率:115200 56 *入口參數:無 57 *出口參數:無 58 ******************************************************************************/ 59 void InitUART(void) 60 { 61 PERCFG &= ~0x01; //USART0為位置1 62 P2DIR &= ~0xc0; //優先級USART0 >USART1 >定時器1 63 P0SEL |= 0x0c; //P0_2,P0_3 用作串口(外部設備功能) 64 U0CSR |= 0x80; //設置為UART 方式 65 U0CSR |= 0x40; //使能接收器 66 67 U0UCR = 0x02; //禁止流控制,8bits,無校驗位,1位停止位 68 //起始位低電平,停止位高電平 69 U0GCR |=11; //32MHz 下的BAUD_E:11, 115200 70 U0BAUD |= 216; //32MHz 下的BAUD_M:216 11520 71 UTX0IF = 0; //UART0 TX 中斷標志初始置位0 72 IEN0 |= 0x04; //使能USART0 RX中斷 73 //IEN2 |= 0x04; //使能USART0 TX中斷 74 EA = 1; //開總中斷 75 } 76 77 /**************************************************************************** 78 * 名 稱: UartSendString() 79 * 功 能: 串口發送函數 80 * 入口參數: Data:發送緩沖區 len:發送長度 81 * 出口參數: 無 82 ****************************************************************************/ 83 void UartSendString(char *Data, int len) 84 { 85 uint i; 86 U0CSR &= ~0x40; 87 88 for(i=0; i<len; i++) 89 { 90 U0DBUF = *Data++; 91 while(UTX0IF == 0); 92 UTX0IF = 0; 93 } 94 TXflag = 0; 95 U0CSR |= 0x40; //使能接收器 96 } 97 98 /****************************************************************************** 99 *函 數 名:UART0_ISR 100 *功 能:串口0中斷服務程序 101 *入口參數:無 102 *出口參數:無 103 ******************************************************************************/ 104 #pragma vector = URX0_VECTOR 105 __interrupt void UART0_ISR(void) 106 { 107 URX0IF = 0; //UART0 RX中斷標志位清0 108 temp = U0DBUF; //讀取U0DBUF的值 109 } 110 111 /****************************************************************************** 112 *程序入口函數 113 ******************************************************************************/ 114 int main(void) 115 { 116 InitClock(); 117 InitLED(0); //LED初始化,熄滅LED1、LED2 118 InitUART(); //UART0串口初始化 119 120 UartSendString(Txdata,txnum); 121 while(1) 122 { 123 if(RXflag == 1) 124 { 125 if(temp !=0) 126 { 127 if((temp != '#') && (datanum < 2)) 128 { 129 Rxdata[datanum++] = temp; 130 } 131 else 132 { 133 RXflag = 2; 134 } 135 136 temp = 0; 137 } 138 } 139 if(RXflag == 2) 140 { 141 switch(Rxdata[0]) 142 { 143 case '1':LED1 = 0;break; 144 case '2':LED1 = 1;break; 145 case '3':LED2 = 0;break; 146 case '4':LED2 = 1;break; 147 case '5': 148 { 149 LED1 = 1; 150 LED2 = 1; 151 break; 152 } 153 case '6': 154 { 155 LED1 = 0; 156 LED2 = 0; 157 break; 158 } 159 case '7': 160 { 161 TXflag = 1; 162 break; 163 164 } 165 default: 166 {//LED1 = 0; 167 //LED2 = 0; 168 } 169 } 170 RXflag = 1; 171 memset(Rxdata, 0, 2); 172 datanum = 0; 173 } 174 if(TXflag == 1) 175 { 176 UartSendString(Txdata,txnum); 177 178 } 179 } 180 }
