基于UART的自定义通信协议

688 阅读2分钟

需求功能

  1. 使用串口助手,发送一帧数据给设备。
  2. 设备解析某一位,如果为1,则点亮LED2,如果为0,则熄灭LED1。

协议标准

示例:AA 01 01 02 BB
AA——帧头
01——地址
01——控制字
02——校验和(地址+控制字)
BB——帧尾

main函数

判断传输是否完成rx_stack.finish_flag == 1,使用switch-case判断rx_stack.recevie_data[1]内容,并控制led灯的亮灭。在switch语句完成后,使用rx_stack_init()清空rx_stack的内容。
初始化LED,初始化UART。

自定义协议的结构体

结构体的特点,在于能直接指定成员的类型,并且在赋值时更直观,可读性更强。

struct receive_stack
{
      u8 head;//帧头
      u8 addr;//从机地址
      u8 recevie_data[10];//数据
      u8 check;//校验
      u8 tail;//帧尾
      u8 head_flag;//接收到帧头标志
      u8 tail_flag;//接收到帧尾标志位
      u8 finish_flag;//接收完成标志位
      u8 data_pt;//已接收的字节数
      u8 commPack_OK_flag;//数据解包完成标志
}rx_stack

协议栈的初始化与归零

rx_stack_init(),初始化结构体变量,将结构体变量中对应成员填入相应的内容,并将各个标志位与recevie_data归零。
CommClr(),清零函数,将结构体变量的内容全部归零。

中断服务函数

使用中断的最大好处,在于同一时间只有中断服务函数运行,不会有其他程序产生干扰。如果不使用中断,数据会被存储到DR寄存器,如果没有及时取出,可能会被其他程序写入的数据覆盖。
首先使用USART_GetITStatus()判断接收中断的状态是否不等于reset,然后使用一个临时变量保存读取接收的数据,并使用Usart_SendByte()发送至上位机界面; 然后判断rx_stack.head_flag是否为1,是说明收到了。。,否则没有。
接收到帧头后,检查rx_stack.tail,查看当前是否为帧尾,是则置1帧尾标志位与接收完成标志位,置0帧头标志位;否则将临时变量赋值给rx_stack.recevie_data,由data_pt作为索引,因此data_pt要同时+1。如果data_pt大于9,则重置为0。
如果没有接收到帧头,说明数据帧没有被读取,检查临时变量是否等于帧头,是则将帧头标志位置1,否则说明传输出错,使用CommClr()函数将数据帧全部清零。
最后,使用USART_ClearITPendingBit()函数清除接收中断标志。

实验现象

串口助手发送AA  01  01  02  BB到目标开发板,正确原样返回数据,LED灯被正确点亮。

Bug

从机地址和校验和未起实际作用。可以在main函数中,在数据接收完成后进行判断,成功则开始switch语句,否则输出“数据校验失败!”。