一、cc2530串口基础
1、串口资源
CC2530有两个串行通信接口USART0和USART1,它们能够分别运行于异步UART模式或者同步SPI模式。其外设引脚,如下图所示。
由图可知,串行通信接口USART0和USART1的外设引脚有两个备用位置,如USART0可以通过SFR 寄存器位 PERCFG.U0CFG 选择是否使用备用位置 1 或备用位置 2。
2、UART模式通讯
(1) CC530的UART 模式提供全双工传送,接收器中的位同步不影响发送功能。传送一个 UART 字节包含 1 个起始位、8个数据位、1 个作为可选项的第 9 位数据或者奇偶校验位再加上 1 个或 2 个停止位。注意,虽然真实的数据包含 8 位或者 9 位,但是,数据传送只涉及一个字节。
(2)使用串口通讯时,需要配置系统时钟为32M;
二、uart开发流程
uart开发流程一般步骤如下:
(1)配置系统时钟为32M;
(2)指定串口的IO位置;
(3)相应IO配置成偏上外设功能;
(4)8个数据位、1个停止位、无流控、无校验确立;
(5)波特率;
(6)开CPU中断、对应串口接收中断;
下面结合寄存器介绍一一讲解
1、配置系统时钟为32M
使用串口通讯时,需要配置系统时钟为32M,配置流程请参考前期文章:
zigbee笔记:三、zigbee高频时钟源切换-CSDN博客
2、选择指定的串口的IO位置
CC2530有两个串行通信接口USART0和USART1,每个对应的外设引脚备用位置为两个,如下图
(1)备用位置的选择
寄存器PERCFG的第0和第1位分别控制串行通信接口USART0和USART1的外设引脚有两个备用位置的选择,通过设置相应的值即可。例如我们选择使用串行通信接口USART0,使用UART的模式,外设引脚使用备用位置1。
PERCFG &= 0xfe; // USART_0 , 用备用位置1
3、引脚配置成外设模式
我们选择使用串行通信接口USART0,使用UART的模式,外设引脚使用备用位置1。则P2_2和P2_3口需要配置成偏上外设模式。
P0SEL |= 0x0c; //P0_2,P0_3 设为偏上外设 ,作为Tx和Rx
4、8个数据位、1个停止位、无流控、无校验确立;
USART0的设置主要通一下几个寄存器设置(x 是 USART 的编号,为 0 或者1)
UxCSR:USARTx 控制和状态;
UxUCR:USARTx UART 控制;
UxGCR:USARTx 通用控制
UxBUF:USART x 接收/发送数据缓冲
UxBAUD:USART x 波特率控制
(1)U0CSR寄存器
该寄存器最重要的是第7与第6位,决定了USART的工作模式和是否能够接收数据。
U0CSR |= 0x80; // USART模式选择为UART
U0CSR |= 0x40; //使能UART0接收器,使之能接收数据
//或者直接 U0CSR |= 0xC0;
(2)U0UCR寄存器
常用的可能就是是否设置奇偶校验。可以直接默认不使用奇偶校验,该寄存器不进行设置
5、波特率
由寄存器 UxBAUD.BAUD_M[7:0]和 UxGCR.BAUD_E[4:0]定义波特率。该波特率用于 UART 传送,也用于 SPI 传送的串行时钟速率。公示如下
式中:f 是系统时钟频率,对于典型的 32 MHz 系统时钟,标准波特率所需的寄存器值如下表
注意:波特率必须通过 UxBAUD 和寄存器 UxGCR 在任何其他 UART 和 SPI 操作发生之前设置
(1)U0GCR和U0BAUD寄存器
//设置波特率115200
U0BAUD = 216 ; //设置波特率小数部分的值
U0GCR |= 0x0b ; //设置波特率指数值
(2)U0BUF寄存器
该寄存器是发送和接收数据的缓存,当写这个寄存器的时候数据被写到内部,传送数据寄存器。当读取该寄存器的时候,数据来自内部读取的数据寄存器。通过这个寄存器数据获取和对外发送。
6、串口中断
(1)首先开启总中断,EA=1;
(2)串口中断
每个 USART 都有两个中断:RX 完成中断(URXx)和 TX 完成中断(UTXx)。当传输开始触发 TX 中断,且数据缓冲区被卸载。
串口中断没有三级,只有两级,并且接收中断与发送中断是分开的。中断详解可参考:
zigbee笔记:特别篇1 zigbee中断总结-CSDN博客
USART 的中断使能位在寄存器 IEN0 和寄存器 IEN2 中,中断标志位在寄存器 TCON 和寄存器 IRCON2 中。总结如下:
EA = 1; //总中断
IEN0 |= 0x04; //USART 0 Rx中断使能
三、案例
CC2530通过串口0在UART模式与上位机通信(串口调试工具发送,下位机返回回显)
#include <iocc2530.h>
void Delayms( unsigned int a ) //@16MHz
{
unsigned char i, j;
for( int s = 0; s < a; s++ )
{
i = 3;
j = 148;
do
{
while( --j );
}
while( --i );
}
}
//32M高频时钟切换函数
void CLOCK_SET32M()
{
SLEEPCMD &= 0xFB; // 让2个时钟源都起振
while( 0 == ( SLEEPSTA & 0x40 ) ); //等待32M 晶振供电且稳定
Delayms( 20 ); //延时约10ms,大于64us即可
CLKCONCMD &= 0xF8; //1111 1000 不分频输出
CLKCONCMD &= 0xBF; //1011 1111 让32M作为系统主时钟供给CPU
while( 1 == ( CLKCONSTA & 0x40 ) ); //确保32M确实供给CPU在工作
SLEEPCMD |= 0x40; // 0000 0100 ;//关闭不提供给CPU的时钟源,节能
}
void Uart_Config()
{
//串口0的备用位置1配置为波特率9600
PERCFG &= 0xFE;//1111 1110 选中串口0的备用位置1
P0SEL |= 0x0C; //0000 1100 配置P0_2 P0_3为偏上外设功能
U0CSR |= 0xC0;
U0BAUD = 216 ; //设置波特率小数部分的值
U0GCR |= 0x0b ; //设置波特率指数值 1152000
EA=1;
URX0IE=1;//开启串口接收中断
}
void main()
{
Init32M();
Uart_Config();
while(1)
{
}
}
#pragma vector=URX0_VECTOR
__interrupt void UART0_IRQ(void)
{
char ch;
URX0IF = 0;//串口0接收标志位,硬件会自动置1,需要软件清0
ch = U0DBUF;//从接收寄存器取字节存入ch
U0DBUF = ch;//把变量ch的值传给串口发送寄存器
while(UTX0IF == 0);//等待发送标志硬件置1
UTX0IF = 0;
}