首页 > 代码库 > 「ZigBee模块」基础实验(5)串口通讯

「ZigBee模块」基础实验(5)串口通讯

一、补充基础知识

  在CC2530 中,USART0 USART1 是串行通信接口,它们能够分别运行于异步USART 模式或者同步SPI 模式。两个USART 的功能是一样的,并且各自有单独的IO 引脚。USART里面的A指的就是asynchronous(异步),S指的是synchronous(同步)。这里我们使用异步通信方式。

  UART模式特征:

  ·一次传89个比特的数据

  ·奇校验、偶校验或者无校验位

  ·配置起始位和停止位点平

  ·配置LSB或者MSB首先传送

  ·独立收发中断

  ·独立收发DMA触发

  UART模式下可以进行全双工异步通信,UART发送的一个字节由一个起始位,8个数据位,第9个数据位或者奇偶校验位,一或二个结束位组成。

1

2

3

4

5

6

7

8

9

10

12

13

起始位

数据位

数据位或奇偶校验位

结束位

  UART的控制和状态寄存器:U0CSRU1CSR

  UART的控制寄存器:U0UCRU1UCR

  (01分别对应UART0UART1

  把UxCSR.MODE1即选中UART模式

  UART0  P0_2——RX

          P0_3——TX

  UART1  P0_5——RX

          P0_4——TX

 

二、实验目的和步骤

1. 实验目的:实现串口发送、接收、控制LED

2. 实验步骤

 我把实验分成三个小实验,逐步实现

   ①实现串口发送数据

 ②实现串口发送和接收数据

   ③实现控制LED功能

 

三、USB转串口部分原理图

 

 

四、实验1——串口发送数据

1. 寄存器及波特率计算

  本次实验串口相关的寄存器和标志位有:U0CSRU0GCRU0BAUDU0DBUFUTX0IF、PERCFG、P2DIR

  相关功能见下表

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:UART空闲

1:UART

U0GCR

UART0通用控制寄存器)

Bit7:CPOL

0:SPI负时钟极性

1:SPI正时钟极性

Bit6:CPHA

0:当来自CPOLSCK反相之后又返回CPOL时,数据输出到MOSI;当来自CPOLSCK返回CPOL反相时,输入数据采样到MISO

1:当来自CPOLSCK返回CPOL反相时,数据输出到MISO;当来自CPOLSCK反相之后又返回CPOL时,输入数据采样到MOSI

Bit5:ORDER

0:LSB先传送

1:MSB先传送

Bit[4-0]

BAUD_E

波特率指数值 BAUD_EBAUD_M一起决定了UART的波特率

U0BAUD

UART0波特率控制寄存器)

Bit[7-0]

BAUD_M

 

波特率尾数值 BAUD_EBAUD_M一起决定了UART的波特率

U0DBUFUART0收发数据缓冲区)

 

串口发送/接收数据缓冲区

UTX0IF

中断标志

IRCON2Bit1

(UART0字节发送完成标志位)

0:中断未挂起

未发送完

1:中断挂起

发送完毕

 

串口波特率公式:

 

32Mhz系统时钟的常用波特率设置

波特率(bps)

UxBaud.BAUD_M

UxGCR.BAUD_E

误差(%)

2400

59

6

0.14

4800

59

7

0.14

9600

59

8

0.14

14400

216

8

0.03

19200

59

9

0.14

28800

216

9

0.03

38400

59

10

0.14

57600

216

10

0.03

76800

59

11

0.14

115200

216

11

0.03

230400

216

12

0.03

   端口

Bit位

名称

初始化

读/写

描述

PERCFG

外设控制寄存器

7

---

0

R0

未使用

6

T1CFG

0

R/W

计时器1的I/O位置:

0:选择到位置1(Alt.1)

1:选择到位置2(Alt.2)

5

T3CFG

0

R/W

计时器3的I/O位置:

0:选择到位置1(Alt.1)

1:选择到位置2(Alt.2)

4

T4CFG

0

R/W

计时器4的I/O位置:

0:选择到位置1(Alt.1)

1:选择到位置2(Alt.2)

3:2

---

00

R/W

未使用

1

U1CFG

0

R/W

USART 1的I/O位置:

0:选择到位置1(P0_4、P0_5)

1:选择到位置2(P1_6、P1_7)

0

U0CFG

0

R/W

USART 0的I/O位置:

0:选择到位置1(P0_2、P0_3)

1:选择到位置2(P1_4、P1_5)

P2DIR

7:6

PRIP0[1:0]

00

R/W

端口0外设优先级控制,当PERCFG分配给一些外设相同引脚的时候,这些位将确定优先级。优先级从前到后如下:

00:USART 0,USART 1,Timer 1

01:USART 1,USART 0,Timer 1

10:Timer 1 channels 0-1,USART 1,USART 0,Timer 1 channels 2-3

11:Timer 1 channels 2-3,

USART 0,USART 1,Timer 1 channels 0-1

 

5

---

0

R0

未使用

 

4:0

DIRP2_[4:0]

00000

R/W

P2.4—P2.0的方向

(0:输入 1:输出)

 

2.串口初始化代码

void uartInit(){  //先设置晶振  CLKCONCMD &= ~0x40;           //设置系统时钟源为32MHz晶振  while(CLKCONSTA & 0x40);      //等待晶振稳定为32M  CLKCONCMD &= ~0x47;           //设置系统主时钟频率为32MHz    //先把串口通信相应引脚初始化下  PERCFG &= ~0x01;              //位置1,即P0口  P0SEL  |=  0x0c;              //P0_2、P0_3用作串口  P2DIR  &= ~0xc0;              //P0优先作为UART0    //再配置串口  U0CSR  |= 0x80;               //设置为UART方式  U0GCR  |= 11;                 //设置波特率115200  U0BAUD |= 216;                //|  UTX0IF  = 0;                  //UART0 TX中断标志初始位  }

3. 串口发送代码

void uartSend(char *Data, int len){  int j;  for(j=0; j<len; j++)         //发送设定长度个字节  {    U0DBUF = *Data++;          //当前字节放入缓存并指向下一个字节    while(UTX0IF == 0);        //等待标志位置1,表示当前字节发送完了    UTX0IF = 0;                //手动置0,准备发送下一个字节  }}

4. 完整代码

#include <ioCC2530.h>#include <string.h> #define uchar unsigned char#define uint  unsigned int//引脚定义#define led1 P1_0//函数声明void delayms(uint ms);              //延时函数void ledInit();                     //led初始化void uartInit();                    //串口初始化void uartSend(char *Data, int len); //串口发送//变量声明char Txdata[14];                  /*************************************延时函数*************************************/void delayms(uint ms){  uint i, j;  for(i=ms; i>0; i--)    for(j=1774; j>0; j--);}/*************************************led初始化*************************************/void ledInit(){  P1SEL &= ~0x01;  P1DIR |= 0x01;  P1INP &= ~0x01;    led1 = 1;}/*************************************串口初始化*************************************/void uartInit(){  //先设置晶振  CLKCONCMD &= ~0x40;           //设置系统时钟源为32MHz晶振  while(CLKCONSTA & 0x40);      //等待晶振稳定为32M  CLKCONCMD &= ~0x47;           //设置系统主时钟频率为32MHz    //先把串口通信相应引脚初始化下  PERCFG &= ~0x01;              //位置1,即P0口  P0SEL  |=  0x0c;              //P0_2、P0_3用作串口  P2DIR  &= ~0xc0;              //P0优先作为UART0    //再配置串口  U0CSR  |= 0x80;               //设置为UART方式  U0GCR  |= 11;                 //设置波特率115200  U0BAUD |= 216;                //|  UTX0IF  = 0;                  //UART0 TX中断标志初始位  }/*************************************串口发送*************************************/void uartSend(char *Data, int len){  int j;  for(j=0; j<len; j++)         //发送设定长度个字节  {    U0DBUF = *Data++;          //当前字节放入缓存并指向下一个字节    while(UTX0IF == 0);        //等待标志位置1,表示当前字节发送完了    UTX0IF = 0;                //手动置0,准备发送下一个字节  }}/*************************************主函数*************************************/void main(){  ledInit();  uartInit();  strcpy(Txdata, "I‘m Donut!    ");             //将发送内容复制到Txdata  while(1)  {    uartSend(Txdata, sizeof("I‘m Donut!    ")); //串口发送数据    delayms(1000);                              //延时    led1 = ~led1;  }}

5. 实验结果

 

注意波特率、数据位之类的不要设置错!不然会出现乱码!

五、实验二——串口收发数据

1. 实验目的

PC端通过串口发送数据给硬件端(数据长度不超过50,终止符为#),硬件端收到数据后发送回PC

 

2. 再多学一个寄存器和标志位IEN0URX0IF

IEN0(置1为中断)

 

 位名

 复位值

 操作性

 功能描述

 7

 EA

 0

 /

 中断总开关

 6

 

 0

 /

 未用

 5

 STIE

 0

 /

 睡眠定时器中断使能

 4

 ENCIE

 0

 /

 AES/解密,完成中断使能

 3

 URX1IE/I2SRXIE

 0

 /

 USART1/I^2S接受中断

 2

 URX0IE

 0

 /

 USART0接受中断

 1

 ADCIE

 0

 /

 A/D转换完成中断

 0

 RFTXRXIE

 0

 /

 RF收发完成中断

 

URX0IF

中断标志

TCONBit3

0USART0接受中断使能

1:保留,但必须置1

这个URX0IF我的理解就是有数据传送过来就自动置1,产生中断,然后需要手动清0

 

3. 程序流程

①初始化(LED、串口)

②接收状态(没有收到数据则一直等待、收到数据放到指定数组里、数组放满或收到终止符转到发送状态)

③发送状态(关闭数据接收中断、发送数据直至发完、打开中断、转到接收状态)

④接收状态里面的数据是怎么收到的?用串口中断!接收到的数据会放到缓冲区,中断程序的任务就是把缓冲区的数据读出来!

 

4. 完整代码

#include <ioCC2530.h>#include <string.h>#define uchar unsigned char#define uint  unsigned int//引脚定义#define led1 P1_0#define led2 P1_1//函数声明void delayms(uint ms);               //延时函数void ledInit();                      //led初始化void uartInit();                     //串口初始化void uartSend(char *Data, int len);  //串口发送函数//变量声明uchar RXTXflag = 1;                  //选择标志位,决定接收数据还是发送数据char  temp;                          //存放接收到的数据 uchar datanumber = 0;                //累计一次接收的数据个数char  Rxdata[50];                    //一次最多接收50个字符/***********************************延时函数***********************************/void delayms(uint ms){  int i, j;  for(i=ms; i>0; i--)    for(j=1156; j>0; j--);}/***********************************led初始化***********************************/void ledInit(){  P1SEL &= ~0x03;  P1DIR |= 0x03;  P1INP &= ~0x03;     led1 = 0;  led2 = 0;}/***********************************串口初始化***********************************/void uartInit(){  //设置晶振  CLKCONCMD &= ~0x40;           //设置系统时钟源为32MHz晶振  while(CLKCONSTA & 0x40);      //等待晶振稳定为32M  CLKCONCMD &= ~0x47;           //设置系统主时钟频率为32MHz    //串口引脚初始化  PERCFG &= ~0x01;            //位置1,即P0口  P0SEL  |=  0x0c;            //P0_2、P0_3用作串口  P2DIR  &= ~0xc0;            //P0优先作为UART0    //设置串口寄存器  U0CSR  |= 0x80;              //设置为UART方式  U0GCR  |= 11;                //设置波特率115200  U0BAUD |= 216;               //|  UTX0IF  = 0;                 //UART0 TX中断标志初始位  U0CSR  |= 0x40;              //设置UART0允许接收数据  IEN0   |= 0x84;              //开总中断、UART0接收中断  }/***********************************串口发送函数***********************************/void uartSend(char *Data, int len){  int j;  for(j=0; j<len; j++)         //发送设定长度个字节  {    U0DBUF = *Data++;          //当前字节放入缓存并指向下一个字节    while(UTX0IF == 0);        //等待标志位置1,表示当前字节发送完了    UTX0IF = 0;                //手动置0,准备发送下一个字节  }}/***********************************主函数***********************************/void main(){  //初始化  ledInit();  uartInit();    //循环  while(1)  {    if(RXTXflag == 1)          //接收状态    {      led1 = 1;      if(temp != 0)      {        if((temp!=#)&&(datanumber<50)) //如果没有收到终止符且字符数小于50          Rxdata[datanumber++] = temp;   //把收到的字符存入数组        else                             //否则进入发送状态        {          RXTXflag = 3;          led1 = 0;        }        temp = 0;      }     }    if(RXTXflag == 3)          //发送状态    {      led2 = 1;      U0CSR &= ~0x40;          //禁止接收      uartSend(Rxdata, datanumber); //发送已记录的字符串      RXTXflag = 1;            //恢复到接收状态      datanumber = 0;          //长度重新置0      led2 = 0;                      U0CSR |= 0x40;           //允许接收    }  }}/***********************************UART0接收中断***********************************/#pragma vector = URX0_VECTOR__interrupt void UART0_ISR(void){  URX0IF = 0;    //清中断标志  temp = U0DBUF; //读取缓冲中的数据}

六、实验三——串口控制LED

1. 实验目的

发送“L1#”,灯L1改变状态

发送“L2#”,灯L2改变状态

 2. 实验代码

其实主要思想和实验二是一样的,只是对收到的数据进行处理的方式不同

实验二是把数据发送出去,该实验则是分析数据并作出响应

#include <ioCC2530.h>#include <string.h>#define uchar unsigned char#define uint  unsigned int//引脚定义#define led1 P1_0#define led2 P1_1//函数声明void delayms(uint ms);               //延时函数void ledInit();                      //led初始化void uartInit();                     //串口初始化void uartSend(char *Data, int len);  //串口发送函数//变量声明uchar RXTXflag = 1;                  //选择标志位,决定接收数据还是发送数据char  temp;                          //存放接收到的数据 uchar datanumber = 0;                //累计一次接收的数据个数char  Rxdata[50];                    //一次最多接收50个字符/***********************************延时函数***********************************/void delayms(uint ms){  int i, j;  for(i=ms; i>0; i--)    for(j=1156; j>0; j--);}/***********************************led初始化***********************************/void ledInit(){  P1SEL &= ~0x03;  P1DIR |= 0x03;  P1INP &= ~0x03;     led1 = 1;  led2 = 1;}/***********************************串口初始化***********************************/void uartInit(){  //设置晶振  CLKCONCMD &= ~0x40;           //设置系统时钟源为32MHz晶振  while(CLKCONSTA & 0x40);      //等待晶振稳定为32M  CLKCONCMD &= ~0x47;           //设置系统主时钟频率为32MHz    //串口引脚初始化  PERCFG &= ~0x01;            //位置1,即P0口  P0SEL  |=  0x0c;            //P0_2、P0_3用作串口  P2DIR  &= ~0xc0;            //P0优先作为UART0    //设置串口寄存器  U0CSR  |= 0x80;              //设置为UART方式  U0GCR  |= 11;                //设置波特率115200  U0BAUD |= 216;               //|  UTX0IF  = 0;                 //UART0 TX中断标志初始位  U0CSR  |= 0x40;              //设置UART0允许接收数据  IEN0   |= 0x84;              //开总中断、UART0接收中断  }/***********************************串口发送函数***********************************/void uartSend(char *Data, int len){  int j;  for(j=0; j<len; j++)         //发送设定长度个字节  {    U0DBUF = *Data++;          //当前字节放入缓存并指向下一个字节    while(UTX0IF == 0);        //等待标志位置1,表示当前字节发送完了    UTX0IF = 0;                //手动置0,准备发送下一个字节  }}/***********************************主函数***********************************/void main(){  //初始化  ledInit();  uartInit();    //循环  while(1)  {    if(RXTXflag == 1)          //接收状态    {      if(temp != 0)      {        if((temp!=#)&&(datanumber<50)) //如果没有收到终止符且字符数小于50          Rxdata[datanumber++] = temp;   //把收到的字符存入数组        else                             //否则进入发送状态          RXTXflag = 3;               temp = 0;      }     }    if(RXTXflag == 3)          //发送状态    {      U0CSR &= ~0x40;          //禁止接收            if(Rxdata[0] == L)      {        if(Rxdata[1] == 1)          led1 = ~led1;        else if(Rxdata[1] == 2)          led2 = ~led2;      }            RXTXflag = 1;            //恢复到接收状态      datanumber = 0;          //长度重新置0      U0CSR |= 0x40;           //允许接收    }  }}/***********************************UART0接收中断***********************************/#pragma vector = URX0_VECTOR__interrupt void UART0_ISR(void){  URX0IF = 0;    //清中断标志  temp = U0DBUF; //读取缓冲中的数据}

 

「ZigBee模块」基础实验(5)串口通讯