"); //-->
不管是线程间、还是设备间通信,都需制定一个通信协议,规定数据的格式、内容等。
线程间通信因为在芯片内部传输,基本可以排除数据干扰导致的异常,所以通常会设计的比较简单,但是设备间的通信(不管是无线还是有线)就会复杂一些,一般都包含帧头、校验位之类的,因此鱼鹰在一篇文章中介绍了一个基本的串口协议框架《如何写一个健壮且高效的串口接收程序?》。
因为当时刚毕业没多久,所以虽然从大的方向介绍了基本协议内容,但在细节处理上还不够好,比如可维护性、可读性等方面。
后来,鱼鹰在学习开源的飞控源码时,发现里面使用了联合体+结构体的方式,大大提高了程序的可维护性和可读性。
比如,我们的协议中有这样三条命令,心跳包、获取固件版本号、获取序列号。
初级版本:
直接使用基本的类型声明所需要的数据结构。
uint8_t heartbeat;char version[6]; // "2.0.4" char sn[7]; // "654321"
一般这样写的,大概率是工作一两年,当然也不排除工作好多年的也可能这样写。看似简单,但可维护性、可读性都非常差。
中级版本:
使用结构体的形式声明各种消息内容。
typedef struct { uint8_t heart_nbr;}msg_heartbeat_def;
typedef struct { char version[sizeof("2.0.4") + 1];}msg_version_def;
typedef struct { char sn[sizeof("123456") + 1]; }msg_serial_number_def;
这种方式,一般是工作两三年以上的,开始使用结构体容纳数据内容,可扩展性比较强,可维护性、可读性也不错。比如假设后面版本号这个消息里面希望同时获取编译时间,那直接在里面增加即可。
typedef struct { char version[sizeof("2.0.4") + 1];
char compile_time[sizeof("2022-12-12, 12:00:00") + 1];
}msg_version_def;如果其它代码写的比较好,甚至不需要多大改动,即可完成一次扩展。
高级版本:
在中级版本的基础上,使用联合体容纳前面的所有消息类型。
typedef union { msg_heartbeat_def heartbeat; // 心跳包 msg_version_def version_nbr; // 版本号 msg_serial_number_def serial_number; // 产品序列号}msg_data_def;当你需要发送消息的时候,可以这样发送:
typedef enum { MSG_ID_HEARTBEAT, MSG_ID_VERSION, MSG_ID_SN,}msg_id_def;
void msg_uart_send(msg_id_def id, msg_data_def *msg_data, uint32_t size){// 这里加入帧头、消息ID、校验之类的再发送出去#define FRAME_FIX_SIZE_MIN 10 // 组成一帧数据的最小空间,包含帧头之类的 uint8_t send_buff[sizeof(msg_data_def) + FRAME_FIX_SIZE_MIN]; }void msg_send_vesion(void){ msg_data_def data; strcpy(data.version_nbr, "1.0.1"); msg_uart_send(MSG_ID_VERSION, &data, sizeof(data.version_nbr));}
因为现在大部分 IDE 都有代码提示功能,所以当你需要发送数据的时候,可以根据提示选择你需要的消息进行发送,相当方便快捷,也不容易出错。
接收消息时,可以使用 switch(id) 之类的解析对应数据。
在这个例子中,我们利用联合体的特性,将所有消息类型集成在一起,这样当你需要发送一条消息时,很容易就能找到想要的数据类型。并且在空间占用上也是非常合理的。当需要开辟缓存容纳数据帧格式,利用了联合体空间占用特性(找最大),这样你开辟的空间一定是刚刚好,不多也不少,节省了空间使用。
所以,当我们需要传输一类消息,但这些消息不会同时存在时,不如使用联合体吧。
专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们
相关推荐
用单片机制作的纯正弦波逆变电源电路
Microchip发布PIC16F17576单片机(MCU)系列,简化模拟传感器设计
AVR 单片机专栏,资料下载!
MSP430单片机TIMER_A在产品设计中的应用
单片机语言C51应用实战集锦
倾情奉献:MSP430汇编指令集(中文),详解带实例!
创维数码5000系列彩电开关电源(AN单片机)电路
GD32E230F6V6实用指南:为下一个项目选择合适单片机
AVR 单片机专栏,资料下载!之二
介绍采用 nanoWatt XLP技术的超低功耗系列单片机
双芯智控革命:IGBT与单片机如何重塑智能微波炉
《ATmega8原理及应用手册》
MSP430x2xx4xx系列
用AT89C2051单片机实验合弦乐
车规级MCU介绍
瑞萨单片机技术概述
《AVR单片机C语言库》
利用PIC12C508单片机来实现加密狗技术[转帖]
新手必看的单片机知识
瑞萨RA0单片机连载——PWM实现呼吸灯
16位语言函数工具库
5V 单片机与5V 耐压单片机有何区别,为什么至关重要
瑞萨RA0单片机连载——面向对象编程之SHT31温度计
超低功率高性能新一代产品MSP430F5xx
MSP430 电表解决方案
[转帖]从Cygnal C8051F看8位单片机发展之路
功率监测与控制系统DIY——搭建环境,定时器翻转LED
Microchip推出集成高性能模拟外设的32位PIC32A单片机
语音合成芯片T6668和单片机8031的接口电路图
长虹R2118A型彩电开关电源(LA单片机)电路