[ZigBee] 7、ZigBee之UART剖析(ONLY串口发送)
综述:USART0和USART1是串行通信接口,它们能够分别运行于异步UART模式或者同步SPI 模式。两个USART具有同样的功能,可以设置在单独的I/O 引脚。
1、UART 模式
UART 模式提供异步串行接口。在UART 模式中,接口使用2 线或者含有引脚RXD、TXD、可选RTS 和CTS 的4 线。
UART 模式的操作具有下列特点:
● 8 位或者9 位负载数据
● 奇校验、偶校验或者无奇偶校验
● 配置起始位和停止位电平
● 配置LSB 或者MSB 首先传送
● 独立收发中断
● 独立收发DMA 触发
● 奇偶校验和帧校验出错状态
UART 模式提供全双工传送,接收器中的位同步不影响发送功能。传送一个UART 字节包含1 个起始位、8个数据位、1 个作为可选项的第9 位数据或者奇偶校验位再加上1 个或2 个停止位。注意,虽然真实的数据包含8 位或者9 位,但是,数据传送只涉及一个字节。
UART操作由USART控制寄存器UxUCR和状态寄存器UxCSR来控制。这里的x 是USART的编号,其数值为0 或者1。
当UxCSR.MODE 设置为1 时,就选择了UART 模式。
1.1、UART 发送
当USART 收/发数据缓冲器、寄存器UxBUF 写入数据时,该字节发送到输出引脚TXDx。UxBUF 寄存器是双缓冲的。
当字节传送开始时, UxCSR.ACTIVE 位变为高电平,而当字节传送结束时为低。当传送结束时,UxCSR.TX_BYTE 位设置为1。当USART 收/发数据缓冲寄存器就绪,准备接收新的发送数据时,就产生了一个中断请求。该中断在传送开始之后立刻发生,因此,当字节正在发送时,新的字节能够装入数据缓冲器。
1.2、UART 接收
当1 写入UxCSR.RE 位时,在UART 上数据接收就开始了。然后UART 会在输入引脚RXDx 中寻找有效起始位,并且设置UxCSR.ACTIVE 位为1。当检测出有效起始位时,收到的字节就传入到接收寄存器,UxCSR.RX_BYTE 位设置为1。该操作完成时,产生接收中断。同时UxCSR.ACTIVE 变为低电平。
通过寄存器UxBUF 提供收到的数据字节。当UxBUF 读出时,UxCSR.RX_BYTE 位由硬件清0。
注意:当应用程序读UxDBUF,很重要的一点是不清除UxCSR.RX_BYTE。
1.3、UART 硬件流控制
当UxUCR.FLOW 位设置为1,硬件流控制使能。然后,当接收寄存器为空而且接收使能时,RTS 输出变低。在CTS 输入变低之前,不会发生字节传送。
1.4、UART 特征格式
如果寄存器UxUCR 中的BIT9 和奇偶校验位设置为1,那么奇偶校验产生而且检测使能。奇偶校验计算出来,作为第9 位来传送。在接收期间,奇偶校验位计算出来而且与收到的第9 位进行比较。如果奇偶校验出错,则UxCSR.ERR 位设置为高电平。当读取UxCSR 时,UxC-SR.ERR 位清除。
要传送的停止位的数量设置为1 或者2,这取决于寄存器位UxUCR. SPB。接收器总是要核对一个停止位。如果在接收期间收到的第一个停止位不是期望的停止位电平,就通过设置寄存器位UxCSR.FE 为高电平,发出帧出错信号。当读取UxCSR 时,UxCSR.FE 位清除,当UxCSR.SPB 设置为1 时,接收器将核对两个停止位。
注意:当检测到第一个停止位正确时,将设置RX 中断。如果第二个停止位不正确,设置帧误码时将有一个延迟。这个延迟与波特率有关(位持续时间)。
2、SPI 模式
本节描述了同步通信的SPI 模式。在SPI 模式中,USART 通过3 线接口或者4 线接口与外部系统通信。接口包含引脚MOSI、MISO、SCK 和SS_N。参见GPIO节中有关如何将USART 引脚指派到I/O 引脚的描述。
SPI 模式包含下列特征:
3 线(主要)或者4 线SPI 接口
主和从模式
可配置的SCK 极性和相位
可配置的LSB 或MSB 传送
当UxCSR.MODE 设置为0 时,选中SPI 模式。在SPI 模式中,USART 可以通过写UxCSR.SLAVE 位来配置SPI 为主模式或者从模式。
2.1、SPI 主模式操作
当寄存器UxBUF 写入字节后,SPI 主模式字节传送就开始了。USART 使用波特率发生器生成SCK 串行时钟,而且传送发送寄存器提供的字节到输出引脚MOSI。与此同时,接收寄存器从输入引脚MISO获取收到的字节。
当传送开始UxCSR.ACTIVE 位变高,而当传送结束后, UxCSR.ACTIVE 位变低。当传送结束时,UxCSR.TX_BYTE 位设置为1。
串行时钟SCK 的极性由UxGCR.CPOL 位选择,其相位由UxCSR.CPHA 位选择。字节传送的顺序由UxCSR.ORDER 位选择。
传送结束时,收到的数据字节由UxBUF 提供读取。当这个新的数据在UxDBUF USART 接收/发送数据寄存器中准备好,就产生一个接收中断。当单元就绪接收另一个字节用来发送时,发送中断产生。由于UxBUF 是双缓冲,这个操作刚好在发送开始时就发生了。注意数据不应写入UxDBUF,直到UxCSR.TX_BYTE 是1。对于DMA 传输这是自动处理的。
对于使用DMA 的背对背传输,如果传输字节不能被损坏,UxGDR.CPHA 位必须设置为0。对于需要设置UxGDR.CPHA 的系统,需要轮询UxCSR.TX_BYTE。还要注意发送中断和接收中断的区别,因为前者比后者大约提前8 位周期到达。
如上所述的SPI 主模式操作是一个3 线接口。不选择输入用于使能主模式。如果外部从模式需要一个从模式选择信号,这可以使用一个通用I/O 引脚通过软件实现。
2.2、SPI 从模式操作
SPI 从模式字节传送由外部系统控制。输入引脚MISO 上的数据传送到接收寄存器,该寄存器由串行时钟SCK 控制。SCK 为从模式输入。与此同时,发送寄存器中的字节传送到输出引脚MOSI。
当传送开始时UxCSR.ACTIVE 位变高,而当传送结束后,UxCSR.ACTIVE 位变低。当传送结束时,UxCSR.RX_BYTE 位设置为1,接收中断产生。
串行时钟SCK 的极性由UxCSR.CPOL 位选择,其相位由UxGCR.CPHA 位选择。字节传送的顺序由UxGCR.ORDER 位选择。
传送结束时,收到的数据字节由UxBUF 提供读取。当SPI 从模式操作开始时,发送中断。
2.3、SSN 从模式选择引脚
当USART 运行在SPI 模式,配置为SPI 从模式,从模式选择(SSN)引脚使用一个4 线接口来作为SPI的输入(边沿控制)。SSN 的下降沿,SPI 从模式活跃,在MOSI 输入上接收数据,在MOSI 输出上输出数据。SSN 的上升沿,SPI 从模式不活跃,不接收数据。还要注意SSN 上升沿之后MISO 输出不是三态。还要注意释放SSN(SSN 变为高电平)必须在字节接收或发送结束。如果在字节中间释放,下一个要接收的字节将不能正确接收,因为关于之前字节的信息在SPI 系统中。USART 清除能用于删除这个信息。在SPI 主模式中,不使用SSN 引脚。当USART 运行在SPI 主模式,外部SPI 从模式设备需要提供一个从模式选择信号,然后一个通用I/O 引脚应在软件方面作为从模式选择信号功能。
2.4、波特率的产生
当运行在UART 模式时,内部的波特率发生器设置UART 波特率。当运行在SPI 模式时,内部的波特率发生器设置SPI 主时钟频率。
由寄存器UxBAUD.BAUD_M[7:0]和UxGCR.BAUD_E[4:0]定义波特率。该波特率用于UART 传送,也用于SPI 传送的串行时钟速率。波特率由下式给出:
式中:f 是系统时钟频率,等于16 MHz RCOSC 或者32 MHz XOSC。
标准波特率所需的寄存器值如表16-1 所列。该表适用于典型的32 MHz 系统时钟。真实波特率与标准波特率之间的误差,用百分数表示。
当BAUD_E 等于16 且BAUD_M 等于0 时,UART 模式的最大波特率是f/16 且f 是系统时钟频率。SPI 模式下的最大波特率见设备数据手册。
注意:波特率必须通过UxBAUD 和寄存器UxGCR 在任何其他UART 和SPI 操作发生之前设置。这意味着使用这个信息的定时器不会更新,直到它完成它的起始条件,因此改变波特率是需要时间的。
2.5、清除USART
通过设置寄存器位UxUCR.FLUSH 可以取消当前的操作。这一事件会立即停止当前操作并且清除全部数据缓冲器。应注意在TX/RX 位中间设置清除位,清除将不会发生,直到这个位结束(缓冲将被立即清除但是知道位持续时间的定时器不会被清除)。因此使用清除位应符合USART 中断,或在USART 可以接收更新的数据或配置之前,使用当前波特率的等待时间位。
2.6 USART 中断
每个USART 都有两个中断:RX 完成中断(URXx)和TX 完成中断(UTXx)。当传输开始触发TX 中断,且数据缓冲区被卸载。
USART 的中断使能位在寄存器IEN0 和寄存器IEN2 中,中断标志位在寄存器TCON 和寄存器IRCON2 中,中断使能和标志总结如下。
中断使能:
● USART0 RX:IEN0.URX0IE
● USARTl RX:IEN0.URXlIE
● USART0 TX:IEN2.UTX0IE
● USARTl TX:IEN2.UTXlIE
中断标志:
● USART0 RX:TCON.URX0IF
● USARTl RX:TCON.URXlIF
● USART0 TX:IRCON2.UTX0IF
● USARTl TX:IRCON2.UTX1IF
2.7、USART DMA 触发
有两个DMA 触发与每个USART 相关。DMA 触发由事件RX 或者TX 完成激活,也就是说,该事件作为DMA 中断请求。可以配置DMA 通道使用USART 收/发缓冲器(即UxBUF)作为它的源地址或者目标地址。
2.8、USART 寄存器
本节描述了USART 的寄存器。对于每个USART,有5 个如下的寄存器(x 是USART 的编号,为0 或者1):
● UxCSR:USARTx 控制和状态;
● UxUCR:USARTx UART 控制;
● UxGCR:USARTx 通用控制
● UxBUF:USART x 接收/发送数据缓冲
● UxBAUD:USART x 波特率控制
3、代码分析
3.1、发送代码分析
1 /**************************************************************************** 2 * 文 件 名: main.c 3 * 描 述: 设置串口调试助手波特率:115200bps 8N1 4 * 会收到CC2530发过来的:Hello Zigbee 5 ****************************************************************************/ 6 #include <ioCC2530.h> 7 #include <string.h> 8 9 typedef unsigned char uchar; 10 typedef unsigned int uint; 11 #define TX_SIZE 20 12 13 #define TX_STRING "Hello Zigbee " 14 15 char TxData[TX_SIZE]; //存储发送字符串 16 17 /**************************************************************************** 18 * 名 称: DelayMS() 19 * 功 能: 以毫秒为单位延时 16M时约为535,32M时要调整,系统时钟不修改默认为16M 20 * 入口参数: msec 延时参数,值越大延时越久 21 * 出口参数: 无 22 ****************************************************************************/ 23 void DelayMS(uint msec) 24 { 25 uint i,j; 26 27 for (i=0; i<msec; i++) 28 for (j=0; j<1070; j++); 29 } 30 31 /**************************************************************************** 32 * 名 称: InitUart() 33 * 功 能: 串口初始化函数 34 * 入口参数: 无 35 * 出口参数: 无 36 ****************************************************************************/ 37 void InitUart(void) 38 { 39 PERCFG = 0x00; //外设控制寄存器 USART 0的IO位置:0为P0口位置1 40 P0SEL = 0x0c; //P0_2,P0_3用作串口(外设功能) 41 P2DIR &= ~0XC0; //P0优先作为UART0 42 43 U0CSR |= 0x80; //设置为UART方式 44 U0GCR |= 11; 45 U0BAUD |= 216; //波特率设为115200 46 UTX0IF = 0; //UART0 TX中断标志初始置位0 47 } 48 49 /**************************************************************************** 50 * 名 称: UartSendString() 51 * 功 能: 串口发送函数 52 * 入口参数: Data:发送缓冲区 len:发送长度 53 * 出口参数: 无 54 ****************************************************************************/ 55 void UartSendString(char *Data, int len) 56 { 57 uint i; 58 59 for(i=0; i<len; i++) 60 { 61 U0DBUF = *Data++; 62 while(UTX0IF == 0); 63 UTX0IF = 0; 64 } 65 } 66 67 /**************************************************************************** 68 * 程序入口函数 69 ****************************************************************************/ 70 void main(void) 71 { 72 CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振 73 while(CLKCONSTA & 0x40); //等待晶振稳定为32M 74 CLKCONCMD &= ~0x47; //设置系统主时钟频率为32MHZ 75 76 InitUart(); //调置串口相关寄存器 77 memset(TxData, 0, TX_SIZE); //数据清0 78 memcpy(TxData, TX_STRING, sizeof(TX_STRING)); //复制发送字符串到TxData 79 80 while(1) 81 { 82 UartSendString(TxData, sizeof(TX_STRING)); //串口发送数据 83 DelayMS(1000); //延时 84 } 85 }
第39~41行是串口的IO设置相关,这个要回到IO节进行了解。
首先我们先看下面外设IO映射表:发现USART0和USART1都各自对应着两种端口映射关系:
以USART0为例,第一种映射关系是RT-P05\CT-P04\TX-P03\RX-P02;另一种映射关系是TX-P15\RX-P14\RT-P13\CT-P12。
那么在使用过程中,一种模式对应两种映射肯定会出现矛盾!因此代码中第39行:
PERCFG = 0x00;
就是实现选中USART0和USART1的各自的第一种映射!(这样我们就能找到对应的引脚了!)这里的SFR 寄存器位PERCFG.U0CFG的功能就是选择是否使用备用位置1 或备用位置2。
对于USART 和定时器I/O,在一个数字I/O 引脚上选择外设I/O 功能,需要设置对应的PxSEL 位为1。因此,代码中第40行0x0c=1100
P0SEL = 0x0c;
是设置P02、P03用在串口外设IO
以上两个设置导致USART0的4个串口IO和USART1的四个IO冲突了,如果同时发生USART事件就会导致问题。因此可以通过指派这些冲突外设的优先级:
P2DIR &= ~0XC0;
P2DIR.PRIP0 选择为端口0 指派一些外设的优先顺序。当设置为00 时,USART 0 优先。注意如果选择了UART 模式,且硬件流量控制禁用,UART 1 或定时器1 将优先使用端口P0.4 和P0.5。2SEL.PRI3P1 和P2SEL.PRI0P1 选择为端口1 指派一些外设的优先顺序。当它们两个都设置为0 时,USART0 优先。注意如果选择了UART 模式,且硬件流量控制禁用,定时器1 或定时器3 将优先使用端口P1.2 和P1.3。这里设置的是00,因此UART0优先于UART1!
上面这么长的分析我们才知道39~41行是设置UART1和UART0对应的引脚及他们的优先级关系!
接下来的几行代码主要和串口设置有关,比如波特率、奇偶校验等...
其中第43行:
U0CSR |= 0x80;
用来设置UART0模式:UART模式,不接收数据(仅仅发送)等
其中第44行:
U0GCR |= 11;
设置USART0:MSB first及波特率其中一个影响因素BAUD_E(和45行U0BAUD设置BAUD_M一起根据上面讲的公式能够计算波特率)
其中第45行:
U0BAUD |= 216;
用来设置BAUD_M
其中第46行用来初始化UART0 TX中断标志为0:
UTX0IF = 0;
在串口发送函数中将数据写入BUF,然后等待UART0 TX为1,表示发送出去了,然后清除中断标志,等待下一次发送。这个类似51单片机中的串口发送,不多讲!
今天太晚了,此外这篇文章写的太长了!就不准备把串口收发等剖析放在这里讲了~晚安,各位!
Zigbee系列文章:
[ZigBee] 3、ZigBee基础实验——GPIO输出控制实验-控制Led亮灭
[ZigBee] 5、ZigBee基础实验——图文与代码详解定时器1(16位定时器)(长文)
[ZigBee] 6、ZigBee基础实验——定时器3和定时器4(8 位定时器)
PS:如果您觉得还不错,点个赞,让更多人受益~
@beautifulzzzz 2016-07-15 continue~
e-mail:beautifulzzzz@qq.com
sina:http://weibo.com/beautifulzzzz?is_all=1