zl程序教程

您现在的位置是:首页 >  工具

当前栏目

CC2530的串口通信原理与应用

2023-09-11 14:22:52 时间

1.CC2530的串口资源

CC2530有两个串行通信接口:异步UART模式: USART0和同步SPI模式: USART1

对于每个USART外设,有5个相关的寄存器(x时USART的编号,0或1)

UxCSR: USARTx 控制状态寄存器
UxUCR: USARTx UART控制寄存器
UxGCR: USARTx 通用控制寄存器
UxBUF: USARTx UART接受/发送数据缓冲区
UxBAUD: USARTx 波特率控制寄存器

1.1.CC2530的UART串口引脚的映射关系

两个USART接口具有相同的功能,通过PERCFG寄存器可以设置两个USART接口对应外部I/O引脚的映射关系
在这里插入图片描述

1.2.PERCFG外设控制寄存器

在这里插入图片描述

2.波特率的计算与设置

CC2530的波特率有BAUD_E和BAUD_M共同决定:
在这里插入图片描述
F为系统时钟频率,16MHz或32MHz

TI公司提供的数据手册中,给出了32MHz系统时钟频率下各种常用波特率的参数值
在这里插入图片描述
由计算公式可已计算出16MHz系统时钟频率下对应的参数值

  1. 16MHz下9600波特率的UxBAUD.BAUD_M:U0BAUD = 59
  2. 16MHz下9600波特率的UxGCR.BAUD_E:U0GCR = 9

3.串口0的UART初始化设置

void Init_Uart0(){

    //端口配置
    PERCFG &= ~0x01;    //将串口0的引脚映射到位置1,即P0_2和P0_3
    P0SEL = 0x0C;       //将P0_2和P0_3端口设置为外设功能
    
    /*======使用CC2530的内部16MHz晶振产生9600的波特率====*/
    
    //波特率配置
    U0BAUD = 59;
    U0GCR = 9;
    
    //流控配置
    U0UCR |= 0x80;      //禁止流控,8位数据,清楚缓冲器
    
    //串口模式配置
    U0CSR |= 0xC0;      //选择UART模式,使能接收器

    //中断配置
    UTX0IF = 0;         //清除TX发送中断标志
    URX0IF = 0;         //清除RX接收中断标志
    URX0IE = 1;         //使能URAT0的接收中断
    EA = 1;             //使能总中断
}

4.案例

4.1.串口数据发送

要求:

  1. USART0选择UART模式,波特率9600,I/O引脚映射到备用位置1
  2. 利用看门狗定时器的定时功能实现1秒定时
  3. 在看门狗中断服务模式中,由串口向上机位发送“Hello World!”,回车换行
    D5等作为数据发送指示灯,在字符串发送前点亮,字符串发送结束后熄灭
    在这里插入图片描述

代码:

#include "ioCC2530.h"

#define D5 P1_3

/*=============系统时钟切换16MHz→32MHz(32MHz更为准确)====================*/
void Set_Clock_32M(){
  CLKCONCMD &= ~0x40;        //选择系统时钟源为32MHz晶振
  while(CLKCONCMD & 0x40);   //等待晶振稳定
  CLKCONCMD &= ~0x47;        //设置系统主时钟频率为32MHz
}

/*========================端口初始化函数====================================*/
void Init_Port(){
  //初始化LED灯的I/O口
  P1SEL &= ~0x1B;            //P1_0、P1_1、P1_3和P1_4作为通用I/O口
  P1DIR |= 0x1B;             //P1_0、P1_1、P1_3和P1_4端口输出
  P1 &= ~0x1B;               //关灯D3~D6
}

/*==============================串口初始化函数==============================*/
void Init_Uart0(){
  //设置串口引脚功能,将P0_2、P0_3设置成外设功能
  PERCFG &= ~0x01;
  P0SEL |= 0x0C;             
  //设置串口波特率:32MHz——9600  中文手册P144
  U0BAUD = 59;
  U0GCR = 8;
  //设置UART控制U0UCR
  U0UCR |= 0x80;
  //设置控制与状态寄存器
  U0CSR |= 0xC0;
}

/*===============看门狗初始化函数,设置为定时器模式=========================*/
void Init_WDT(){
  WDCTL = 0x0C;
  INE2 |= 0x20;
  EA = 1;
}

/*==================看门狗定时1秒中断服务函数===============================*/
#pragma vector = WDT_VECTOR
__interrupt void Service_WDT(){
  WDTIF = 0;
  DS = 1;
  UR0_SendString("Hello World!\r\n");
  D5 = 0;
}

/*=====================串口字节发送函数=====================================*/
void UR0_SendByte(unsigned char dat){
  U0DBUF = dat;
  while(UTX0IF == 0);
  UTX0IF = 0;
}

/*=============================串口字符发送函数=============================*/
void UR0_SendString(unsigned char *str){
  while(*str != '\0'){
    UR0_SendByte(*str++);
  }
}

/*=====================================main函数=============================*/
void main(){
  Set_Clock_32M();
  Init_Port();
  Init_Uart0();
  Init_WDT();
  while(1){}
}

4.2.串口数据收发

要求:

  1. USART0选择UART模式,波特率9600,I/O引脚映射到备用位置1
  2. 串口接受到上位机的一个数据后,在原值上加1,发回上位机
  3. D3灯作为数据接受指示灯,在收到一个数据后,D3灯亮
  4. D5灯作为数据发送指示灯,在数据发送之前亮,在数据发送完成后,D3灯与D5灯同时熄灭
    在这里插入图片描述

代码:

#include "ioCC2530.h"

#define D3 P1_0
#define D5 P1_3

/*=============系统时钟切换16MHz→32MHz(32MHz更为准确)====================*/
void Set_Clock_32M(){
  CLKCONCMD &= ~0x40;        //中文手册P60
  while(CLKCONCMD & 0x40);   //中文手册P61
  CLKCONCMD &= ~0x47;        //中文手册P60
}

/*========================端口初始化函数====================================*/
void Init_Port(){
  P1SEL &= ~0x1B;            //中文手册77
  P1DIR |= 0x1B;
  P1 &= ~0x1B;               //关灯D3~D6
}

/*==============================串口初始化函数==============================*/
void Init_Uart0(){
  //设置串口引脚功能,将P0_2、P0_3设置成外设功能,中文手册P72、P77
  PERCFG &= ~0x01;
  P0SEL |= 0x0C;             
  //设置串口波特率:32MHz——9600  中文手册P144
  U0BAUD = 59;
  U0GCR = 8;
  //设置UART控制U0UCR,中文手册P146
  U0UCR |= 0x80;
  //设置控制与状态寄存器U0CSR,中文手册P145
  U0CSR |= 0xC0;              //UART模式
  //清除中断标志
  UTX0IF = 0;
  URX0IF = 0;
}

/*================================串口字节发送函数==========================*/
void UR0_SendByte(unsigned char dat){
  U0DBUF = dat;
  while(UTX0IF == 0);
  UTX0IF = 0;
}

/*=========================串口数据接受完成的中断服务函数===================*/
#pragma vector = URX0_VECTOR
__interrupt void Service_UR0Recv(){
  D3 = 1;
  unsigned char tmp;
  tmp = U0DBUF;
  tmp++;
  D5 = 1;
  UR0_SendByte(temp);
  D3 = 0;
  D5 = 0;
}

/*=====================================main函数=============================*/
void main(){
  Set_Clock_32M();
  Init_Port();
  Init_Uart0();
  while(1){}
}

4.3.串口命令控制LED灯开关

要求:

  1. USART0选择UART模式,波特率9600,I/O引脚映射到备用位置1
  2. 命令字"0xA1",点亮D4,操作完成后,返回"D4 is open!"
  3. 命令字"0xA2",关闭D4,操作完成后,返回"D4 is closed!"
  4. 命令字"0xA1",点亮D6,操作完成后,返回"D6 is open!"
  5. 命令字"0xA1",关闭D6,操作完成后,返回"D6 is closed!"
    在这里插入图片描述

代码:

#include "ioCC2530.h"

#define D3 P1_0
#define D4 P1_1
#define D5 P1_3
#define D6 P1_4

unsigned char cmd = 0;        //存放上机位PC发送过来的数据

/*=============系统时钟切换16MHz→32MHz(32MHz更为准确)====================*/
void Set_Clock_32M(){
  CLKCONCMD &= ~0x40;        //选择系统时钟源为32MHz晶振
  while(CLKCONCMD & 0x40);   //等待晶振稳定
  CLKCONCMD &= ~0x47;        //设置系统主时钟频率为32MHz
}

/*========================端口初始化函数====================================*/
void Init_Port(){
  //初始化LED灯的I/O口
  P1SEL &= ~0x1B;            //P1_0、P1_1、P1_3和P1_4作为通用I/O口
  P1DIR |= 0x1B;             //P1_0、P1_1、P1_3和P1_4端口输出
  P1 &= ~0x1B;               //关闭所有LED灯
}

/*==============================串口初始化函数==============================*/
void Init_Uart0(){
  //端口相关的配置——设置TXD和RXD引脚的外设功能
  PERCFG &= ~0x01;           //串口0的引脚映射到位置1,即P0_2和P0_3
  P0SEL |= 0x0C;             //将P0_2和P0_3端口设置成外设功能
  //波特率相关配置
  U0BAUD = 59;               //32MHz的系统时钟产生9600BPS的波特率
  U0GCR = 8;                 //16MHz——9,32MHz——8
  //串口属性相关配置——UART控制寄存器
  U0UCR |= 0x80;             //禁止流控,8位数据,清除缓冲器
  //串口属性相关配置——设置串口的工作模式:UART、使能接受
  U0CSR |= 0xC0;             //UART模式,使能接收器
  //串口中断相关配置——清除中断标志
  UTX0IF = 0;                //清除TX发送中断标志
  URX0IF = 0;                //清除RX接收中断标志
  //串口中断香瓜配置——使能串口中断接受
  URX0IF = 1;                //使能UART0的接收中断
  EA = 1;                    //使能总中断
}

/*================================串口字节发送函数==========================*/
void UR0_Send_Byte(unsigned char dat){
  U0DBUF = dat;              //将要发送的1字节数据写入U0DBUF
  while(UTX0IF == 0);        //等待TX中断标志,即数据发送完成
  UTX0IF = 0;                //清除TX中断标志,准备下一次发送
}

/*=============================串口字符发送函数=============================*/
void UR0_Send_String(unsigned char *str){
  while(*str != '\0'){       //发送一个字符串
    UR0_SendByte(*str++);    //逐个发送字符串字节
  }
}


/*=========================串口数据接受完成的中断服务函数===================*/
#pragma vector = URX0_VECTOR
__interrupt void Service_UR0Recv(){
  cmd = U0DBUF;              //将控制命令字节从缓冲区取出
  F_UR0_Recv = 1;            //标志成功接收上位机的单字节命令
}

/*=============================命令控制LED灯开关============================*/
void Control_LED(){
  switch(cmd){
    case 0xA1
      D4 = 1;
      UR0_Send_String("D4 is open!\r\n");
    break;
    case 0xA2
      D4 = 0;
      UR0_Send_String("D4 is closed!\r\n");
    break;
    case 0xB1
      D6 = 1;
      UR0_Send_String("D6 is open!\r\n");
    break;
case 0xB2
      D6 = 0;
      UR0_Send_String("D6 is closed!\r\n");
    break;
  }
}

/*=====================================main函数=============================*/
void main(){
  Init_Clock_32M();
  Init_Port();
  Init_Uart0();
  
  while (1){
    if (cmd != 0){
      control_LED();
    }
  }
}