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 }