4.6串口数据收发实验
1.了解串口通信的相关知识;
2.学习CC2530单片机串口相关寄存器配置,实现串口通信功能;
CC2530芯片有两个串行接口UART0和UART1:
UART0对应RXD(P02)、TXD(P03);
UART1对应RXD(P04)、TXD(P05);
在开发板中只接出了串口0(UART0),从串口原理图就可以看出,CC2530的串口信号与P02、P03复用,由于USB接口的众多优势,越来越普遍的被应用到计算机以及工业现场,而RS232接口的市场地位也逐渐淡漠,如图4-6所示,我们的开发板将RS232 信号通过PL2303转换为USB信号与电脑或者工业设备进行串口通信。
图4-6 开发板串口TTL与USB转换电路原理图
要实现CC2530的串口通信除了掌握硬件电路原理,还有一个关键的环节就是有关串口通信寄存器软件配置U0CSR、U0GCR、U0BAUD、U0DBUF、UTX0IF,串口相关寄存器功能描述如表4-4所示:
表4-4相关寄存器功能描述
U0CSR(UART0 控 制和状态寄存器) |
Bit7:MODE |
0:SPI 模式 |
1:UART 模式 |
||
Bit6:RE |
0:接收器禁止 |
|
1:接收器使能 |
||
Bit5:SLAVE |
0:SPI 主模式 |
|
1:SPI 从模式 |
||
Bit4:FE |
0:没有检测出帧错误 |
|
1:收到字节停止位电平出错 |
||
Bit3:ERR |
0:没有检测出奇偶检验出错 |
|
1:收到字节奇偶检验出错 |
||
Bit2:RX_BYTE |
0:没有收到字节 |
|
1:收到字节就绪 |
||
Bit1:TX_BYTE |
0:没有发送字节 |
|
1:写到数据缓冲区寄存器的最后字节已 经发送 |
||
Bit0:ACTIVE |
0:USART空闲 |
|
1:USART忙 |
||
U0GCR(UART0 通 用控制寄存器) |
Bit7:CPOL |
0:SPI 负时钟极性 |
1:SPI 正时钟极性 |
||
Bit6:CPHA |
0:当来自 CPOL 的 SCK 反相之后又返回CPOL 时,数据输出到 MOSI;当来自 CPOL的 SCK 返回 CPOL 反相时,输入数据采样到MISO |
|
1:当来自 CPOL 的 SCK 返回 CPOL 反相时,数据输出到 M OSI ;当来自 CPOL 的 SCK 反相之后又返回 CPOL 时,输入数据采样到 MISO |
||
Bit5:ORDER |
0:LSB 先传送 |
|
1:MSB 先传送 |
||
Bit[4:0]:BAUD_E |
波特率指数值 BAUD_E 连同 BAUD_M 一起决定了 UART 的波特率 |
|
U0BAUD(UART0 波特率控制寄存器) |
Bit[7:0]:BAUD_M |
波特率尾数值 BAUD_M 连同 BAUD_E 一起决定了 UART 的波特率 |
U0DBUF ( UART0 收发数据缓冲区) |
串口发送/接收数据缓冲区 |
|
UTX0IF(发送中断 标志) |
中断标志5 IRCON2 的Bit1 |
0:中断未挂起 |
1:中断挂起 |
在本实验中我们采用USART0接口,具体的软件操作以及串口寄存器配置步骤如下:
1、硬件接口配置,配置P02和P03用作串口 UART0。
2、配置相应串口的控制和状态寄存器。
3、配置串口工作的波特率。CC2530单片机的串口数据传输的波特率决定于通用控制寄存器U0GCR的Bit[4:0]——BAUD_E和波特率控制寄存器U0BAUD——BAUD_M,具体的计算公式如式4-1
波特率
在32MHz的系统时钟下常用的波特率所对应的BAUD_M和BAUD_E的值如下表4-5。
表4-5在32MHz的系统时钟下常用的波特率所对应的BAUD_M和BAUD_E的值
常用的波特率 |
BAUD_M |
BAUD_E |
误差 |
2400 |
59 |
6 |
0.14 |
4800 |
59 |
7 |
0.14 |
9600 |
59 |
8 |
0.14 |
14400 |
216 |
9 |
0.03 |
19200 |
59 |
10 |
0.14 |
28800 |
216 |
11 |
0.03 |
38400 |
59 |
12 |
0.14 |
57600 |
216 |
13 |
0.03 |
76800 |
59 |
14 |
0.14 |
115200 |
216 |
15 |
0.03 |
230400 |
216 |
16 |
0.03 |
串口寄存器配置程序如下
CLKCONCMD &= ~0x40; //设置系统时钟源为 32MHZ 晶振
while(CLKCONSTA & 0x40); //等待晶振稳定
CLKCONCMD &= ~0x47; //设置系统主时钟频率为 32MHZ
PERCFG = 0x00; //位置 1 P0 口
P0SEL = 0x3c; //P0_2,P0_3,P0_4,P0_5 用作串口,第二功能
P2DIR &= ~0XC0; //P0 优先作为 UART0 ,优先级
U0CSR |= 0x80; //UART 方式
U0GCR |= 11; //U0GCR 与 U0BAUD 配合
U0BAUD |= 216; // 波特率设为 9600
UTX0IF = 0; //UART0 TX 中断标志初始置位 1 (收发时候)
U0CSR |= 0X40; //允许接收
IEN0 |= 0x84; // 开总中断,接收中断
具体程序如下:
#include <ioCC2530.h>
#include <string.h>
#define uint unsigned int
#define uchar unsigned char
//定义控制LED灯的端口
#define LED1 P1_0 //定义LED1为P10口控制
#define LED2 P1_1 //定义LED1为P11口控制
//函数声明
void Delayms(uint xms); //延时函数
void InitLed(void); //初始化P1口
void InitUart(); //初始化串口
void Uart_Send_String(char *Data,int len);
char Rxdata[50];
uchar RXTXflag = 1;
char temp;
uchar datanumber = 0;
/****************************
延时函数
*****************************/
void Delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=587;j>0;j--);
}
/****************************
//初始化程序
*****************************/
void InitLed(void)
{
P1DIR |= 0x03; //P10、P11定义为输出
LED1 = 0;
LED2 = 0;
}
/****************************************************************
串口初始化函数
***********************************************************/
void InitUart()
{
CLKCONCMD &= ~0x40; // 设置系统时钟源为 32MHZ晶振
while(CLKCONSTA & 0x40); // 等待晶振稳定
CLKCONCMD &= ~0x47; // 设置系统主时钟频率为 32MHZ
PERCFG = 0x00; //位置1 P0口
P0SEL = 0x3c; //P0_2,P0_3,P0_4,P0_5用作串口,第二功能
P2DIR &= ~0XC0; //P0优先作为UART0 ,优先级
U0CSR |= 0x80; //UART 方式
U0GCR |= 8; //U0GCR与U0BAUD配合
U0BAUD |= 59; //波特率设为9600
UTX0IF = 0; //UART0 TX 中断标志初始置位1 (收发时候)
U0CSR |= 0X40; //允许接收
IEN0 |= 0x84; //开总中断,接收中断
}
/****************************************************************
串口发送字符串函数
****************************************************************/
void Uart_Send_String(char *Data,int len)
{
int j;
for(j=0;j<len;j++)
{
U0DBUF = *Data++;
while(UTX0IF == 0); //发送完成标志位
UTX0IF = 0;
}
}
/***************************
//主函数
***************************/
void main(void)
{
InitLed(); //调用初始化函数
InitUart();
while(1)
{
if(RXTXflag == 1) //接收状态
{
LED1=1; //接收状态指示
if( temp != 0)
{
//'#'被定义为结束字符,最多能接收50个字符
if((temp!='#')&&(datanumber<50))
{
Rxdata[datanumber++] = temp;
}
else
{
RXTXflag = 3; //进入发送状态
LED1=0; //关指示灯
}
temp = 0;
}
}
if(RXTXflag == 3) //发送状态
{
LED2= 1;
U0CSR &= ~0x40; //禁止接收
Uart_Send_String(Rxdata,datanumber); //发送已记录的字符串。
U0CSR |= 0x40; //允许接收
RXTXflag = 1; //恢复到接收状态
datanumber = 0; //指针归0
LED2 = 0; //关发送指示
}
}
}
/****************************************************************
串口接收一个字符: 一旦有数据从串口传至CC2530, 则进入中断,
将接收到的数据赋值给全局变量temp.
****************************************************************/
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISR(void)
{
URX0IF = 0; //清中断标志
temp = U0DBUF;
}
实验时,下载程序到开发板后,插上USB线,然后将S1开关拨到ON,即可进行串口实验,实验效果如图4-7所示
图4-7 实验效果图
扩展知识——串口通信基础
在串行通信中,数据在1位宽的单条线路上进行传输,一个字节的数据要分为8次,由低位到高位按顺序一位一位的进行传送。
串行通信的数据是逐位传输的,发送方发送的每一位都具有固定的时间间隔,这就要求接收方也要按照发送方同样的时间间隔来接收每一位。不仅如此,接收方还必须能够确定一个信息组的开始和结束。
常用的两种基本串行通信方式包括同步通信和异步通信。
异步通信规定传输的数据格式由起始位(start bit)、数据位(data bit)、奇偶校验位(parity bit)和停止位(stop bit)组成,如图4-8所示(该图中未画出奇偶校验位,因为奇偶检验位不是必须有的,如果有奇偶检验位,则奇偶检验位应该在数据位之后,停止位之前)。
图4-8 异步通信数据格式
(1)起始位:起始位必须是持续一个比特时间的逻辑0电平,标志传输一个字符的开始,接收方可用起始位使自己的接收时钟与发送方的数据同步。
(2)数据位:数据位紧跟在起始位之后,是通信中的真正有效信息。数据位的位数可以由通信双方共同约定,一般可以是5位、7位或8位,标准的ASCII码是0~127(7位),扩展的ASCII码是0~255(8位)。传输数据时先传送字符的低位,后传送字符的高位。
(3)奇偶校验位:奇偶校验位仅占一位,用于进行奇校验或偶校验,奇偶检验位不是必须有的。如果是奇校验,需要保证传输的数据总共有奇数个逻辑高位;如果是偶校验,需要保证传输的数据总共有偶数个逻辑高位。
举例来说,假设传输的数据位为01001100,如果是奇校验,则奇校验位为0(要确保总共有奇数个1),如果是偶校验,则偶校验位为1(要确保总共有偶数个1)。
由此可见,奇偶校验位仅是对数据进行简单的置逻辑高位或逻辑低位,不会对数据进行实质的判断,这样做的好处是接收设备能够知道一个位的状态,有可能判断是否有噪声干扰了通信以及传输的数据是否同步。
(4)停止位:停止位可以是是1位、1.5位或2位,可以由软件设定。它一定是逻辑1电平,标志着传输一个字符的结束。
(5)空闲位:空闲位是指从一个字符的停止位结束到下一个字符的起始位开始,表示线路处于空闲状态,必须由高电平来填充。