需求功能
- 使用串口助手,发送一帧数据给设备。
- 设备解析某一位,如果为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语句,否则输出“数据校验失败!”。