CC2530基础实验三:Uart

距离上一次发,五个月了……
贴代码了,Uart是最常用的串行通信方式了,每个单片机一定都会自带至少一个uart用于通信,CC2530也不例外。当然CC2530的是Usart,即通用同步异步串行接收发送器,即可以使用异步Uart模式,也可以使用同步SPI模式。

代码及解析

#include <ioCC2530.h>
#include "string.h"

/****************************
该示例简单的使用了CC2530的Usart模块。
上电后会自动的通过Uart发送一段文字。
在按下KET1时会发送出数字“1”。
在串口助手中给CC2530发送数字“0”,板载的LED1会改变状态。
****************************/

#define LED1 P1_0   //定义LED1为P10口控制
#define KEY1 P0_1   //定义KEY1为P01口控制

#define uchar unsigned char 
#define uint unsigned int 

/*本地函数*/
void initUART(void);
void initLED(void);
void sendmsg(char *);
void delay(int n);

char temp=0;

int main(void)
{
  /*初始化LED*/
  initLED();
  /*初始化Uart*/
  initUART();
  
  sendmsg("新冠新冠快离开!\r\n\r\n");
  
  while(1)
  {
    /*Uart发送相关代码段*/
    if(KEY1 == 0)   //如果有按键按下
    {
      delay(40);    //延时以消抖
      if(KEY1 == 0)
      {
        sendmsg("1\r\n");   //检测到按键1按下后发送数字1
      }
    }
    
    /*Uart接受相关代码段*/
    if(0 != temp)   //如果Uart接收到数据
    {
      if(temp == 0x30)    //如果接受到数字0
      {
        LED1 = !LED1;   //改变LED1状态
      }
      temp = 0;   //清除temp
    }
  }
}
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISR(void) 
{ 
    URX0IF = 0;   //清除中断标志位
    temp = U0DBUF;    //将接收缓冲区的8位数据存入temp中
}

void initLED(void)
{
  P1DIR |= 0x03;    //P1_0/P1_1定义为输出
  LED1 = 1;   //LED1灯初始化为关
}

void initUART(void)
{
  P0SEL |= 0x0C;    //将端口0_4/0_5设置为外设功能
  U0GCR |= 11;
  U0BAUD |= 216;    //设置波特率为57600
  U0CSR |= 0XC0;    //将USART设置为Uart功能,并使能Usart接收器
 			
  URX0IF = 0;   //清除接收中断标志位
  EA = 1;   //开启总中断开关,以能够使用系统的中断功能
  URX0IE = 1;   //Usart0中断功能使能
}

/*延时函数*/
void delay(int n)
{
  int i,j;
  for(i=0;i<n;i++)
    for(j=0;j<1000;j++);
}

/*Uart发送函数*/
void sendmsg(char *data)
{
  while(1)
  {
    if('\0' == *data)   //一旦检测到字符串结束,就退出,一个字符串总是以'\0'作为结尾
    {
      break;
    }
    
    U0DBUF = *data++;   //否则就将当前字符传入发送缓冲区中
    while(UTX0IF == 0);   //等待发送完成,发送完成后UTX0IF会被系统自动置1
    UTX0IF = 0;   //清除发送完成状态
  }
}

另一个版本

当然还有一个代码比较多的版本,也是我当时实验的时候检查的版本。用了DMA和FSM,记录一下😑,注释我懒得打了😬。

#include <ioCC2530.h>
#include "string.h"

/****************************
该示例使用了Usart、DMA,通过DMA将Uart接收到的数据直接放入数组中,不需要CPU的干预。
在上电后会发送一段文字。
定义了一个数据包结构,一共五位,帧头为0x0F,0x0D,然后是包长度0x34,然后是数据位,
0x30关灯,0x31开灯,0x37切换灯状态,最后为校验位,前四个字节的异或和。
以16进制不换行发送该五位数据后,CC2530会使用根据校验和的结果继续判断或输出校验出错,
校验通过后FSM校验前三个字节,成功后会对灯状态进行切换,否则输出错误信息。
****************************/

#define LED1 P1_0
#define LED2 P1_1
#define KEY1 P0_1

#define uchar unsigned char 
#define uint unsigned int 

#pragma bitfields=reversed    //转换为小端模式
typedef struct 
{
  uchar SRCADDRH;        // 源地址高8位
  uchar SRCADDRL;        // 源地址低8位
  uchar DESTADDRH;       // 目标地址高8位
  uchar DESTADDRL;       // 目标地址低8位
  uchar VLEN          :3;// 长度域模式选择
  uchar LENH          :5;// 传输长度高字节
  uchar LENL          :8;// 传输长度低字节
  uchar WORDSIZE      :1;// 字节或字传输
  uchar TMODE         :2;// 传输模式选择
  uchar TRIG          :5;// 触发事件选择
  uchar SRCINC        :2;// 源地址增量   :-1/0/1/2
  uchar DESTINC       :2;// 目的地址增量 :-1/0/1/2
  uchar IRQMASK       :1;// 中断屏蔽
  uchar M8            :1;// 7或8bit传输长度,仅在字节传输模式下适用 
  uchar PRIORITY      :2;// 优先级
}DMA_DESC;
#pragma bitfields = default   //转回大端模式

DMA_DESC uartdma;      //DMA配置参数 结构体变量

void initUART(void);
void initLED(void);
void sendmsg(char *);
void receivemsg(void);
void delay(int n);
uint FSM(uchar *buff);
void changeled(uchar data);
uint xor(uchar *data);
void init_DMA();



uint count = 0;
char temp=0;
uchar buff[6];		//	需添加多一个字节作为结束符 否则出错
//起始字段定义为0x0F 0x0D 包长度为4个字节 命令码:1代表开灯 0代表关灯 7代表切换灯状态 FCS为前四个字节异或和
#define  STATE1  0x00
#define  STATE2  0x02
#define  STATE3  0x04
#define  STATE4  0x06
#define  STATE5  0x08

int main(void)
{
  
  initLED();
  init_DMA();
  initUART();
  
  sendmsg("新冠新冠快离开!\r\n\r\n");
  
  while(1)
  {
    DMAARM |= 0x01;   //令DMA通道0进入工作状态
    DMAIRQ |= 0x00;   //清除DMA传送完成标志
    delay(500);   
    if(buff[4] != 0)    //如果buff中已经有五位数据
    {  
       buff[5]='\0';
	sendmsg("接收数据包如下:");
	sendmsg(buff);
	sendmsg("\r\n");
	if(xor(buff) == 1)
	{
	  if(FSM(buff) == 1)
	  {
	    sendmsg("接收数据包有效\r\n");
	  }
	  else
	  {
	    sendmsg("接收数据包无效\r\n");
	  }
	}
	else
	{
	  sendmsg("FCS出错");
	}
	memset(buff,0,6);
    }
  }
}
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISR(void) 
{ 
    URX0IF = 0;
    temp = U0DBUF;
}

void initLED(void)
{
  P1DIR |= 0x03;
  LED1 = 1;
  LED2 = 1;
}

void initUART(void)//9600
{
  P0SEL |= 0x0C;
  U0GCR |= 11;
  U0BAUD |= 216;
  U0CSR |= 0XC0;
 			
  UTX0IF = 0;
  URX0IF = 0;
  EA = 1;
  URX0IE = 1;
}

void delay(int n)//11us
{
  int i,j;
  for(i=0;i<n;i++)
    for(j=0;j<1000;j++);
}
void sendmsg(char *data)
{
  while(1)
  {
    if(*data=='\0')
      break;
    U0DBUF = *data++;
    while(UTX0IF == 0);
    UTX0IF = 0;
  }
}
 
uint FSM(uchar *buff)
{
	uchar state = STATE1;
	uchar data;
	uint flag = 0;
	
	while(1)
	{
		data = *buff++;
		switch(state)
		{
			case STATE1:
				if(data == 0x0F)
				{
					state = STATE2;
				}
				else
				  flag = 1;
				break;
			case STATE2:
				if(data == 0x0D)
				{
					state = STATE3;
				}
				else
				  flag = 1;
				break;
			case STATE3:
				if(data == 0x34)
				{
					state = STATE4;
				}
				else
				  flag = 1;
				break;
			case STATE4:	
				changeled(data);
				state = STATE5;
				break;
			default:
				break;
		}
		if(state == STATE5)
		{
			return 1;
		}
		if(flag == 1)
		{
			break;
		}
	}
	
	return 0;
}
void changeled(uchar data)
{
	if(data == 0x30)
		LED1 = 1;
	if(data == 0x31)
		LED1 = 0;
	if(data == 0x37)
		LED1 = !LED1;
}

/*校验*/
uint xor(uchar *data)
{
  uchar temp = 0;
  
  /*取异或和*/
  for(int i=0;i<4;i++)
  {
    temp ^= *data++;
  }

  sendmsg("FCS:");   //打印异或和查看
  sendmsg(&temp);
  sendmsg("\r\n");
//  sendmsg(&(*data));
  if(temp == *data)
    return 1;
  else
    return 0;
}

void init_DMA()
{
  /*配置源地址*/    
  uartdma.SRCADDRH=(uchar)((uint)&X_U0DBUF>>8);    
  uartdma.SRCADDRL=(uchar)((uint)&X_U0DBUF&0x00ff);

  /*配置目的地址*/      
  uartdma.DESTADDRH=(uchar)((uint)&buff >> 8);    
  uartdma.DESTADDRL=(uchar)((uint)&buff&0x00FF);  
  
  /*选择LEN作为传送长度*/
  uartdma.VLEN=0x00;         //选择LEN作为传送长度
  
  /*设置传输长度*/
  uartdma.LENH=0;  
  uartdma.LENL=5;
  
  uartdma.WORDSIZE=0x00;     //选择字节(byte)传送
  
  uartdma.TMODE=0x00;        //字节模式
  
  uartdma.TRIG=14;           //串口接收中断触发
  
  uartdma.SRCINC=0x00;       //源地址增量为0
  
  uartdma.DESTINC=0x01;      //目的地址增量为1
  
  uartdma.IRQMASK=0;         //清除DMA中断
    
  uartdma.M8=0x00;           //选择8位长的字节来传送数据
  
  uartdma.PRIORITY=0x02;     //传输优先级为高
  
  /*将配置结构体的首地址赋予相关SFR*/
  DMA0CFGH=(uchar)((uint)&uartdma >> 8);   
  DMA0CFGL=(uchar)((uint)&uartdma & 0x00ff);
  
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
}
  • 了解一下CC2530的Usart。
    在这里插入图片描述
    在这里插入图片描述
  • 72行,首先将Usart0对应的端口设置成外设端口,Usart即是一个外设,设置成外设端口Usart才能够通过Uart将数据发送和接受;
  • 73-74行,设置Uart的波特率,只要将下图中的数据一一对应写进寄存器里就行,非常简单。但是要注意,我手里的CC2530默认的系统时钟是16M的,下图是32M的波特率寄存器对应值,这里记得要小心,如果你的单片机系统时钟是32M,那么就可以直接对着表里写寄存器,如果是16M的,像我的一样,那么下图中波特率所对应的寄存器的值写进去了,实际的波特率会减半。比如选择115200波特率,对应U0GCR为11,U0BAUD为216,这样写进去之后,16M系统时钟下,实际上的波特率为57600,设置错误就会导致乱码,务必小心。
  • 75行,将Usart设置为Uart模式,且使能接收。
  • 77-79行,把中断相关的寄存器打开,包括总中断和Uart0的接受中断。78-79行当然也可以直接IEN0 |= 0x84;

    其他没啥好说的了,大概效果就是这样,上电发送一次,按键会发送1,回复0会让LED取反状态。

小结

Uart是真的很常用了,这段时间一直在实习,其实在公司虽然也会用到CAN、SPI、IIC这种协议,但是Uart依旧是最常用,最方便,最简单的一个。了解好Uart还是很重要的。上面那个复杂点的用到的DMA,放下次单独说吧,DMA还是很牛的。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值