[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] 1、 ZigBee简介

[ZigBee] 2、 ZigBee开发环境搭建

[ZigBee] 3、ZigBee基础实验——GPIO输出控制实验-控制Led亮灭

[ZigBee] 4、ZigBee基础实验——中断

[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

 

 

posted @ 2016-07-16 03:13  beautifulzzzz  阅读(6258)  评论(10编辑  收藏  举报