博客專欄

        EEPW首頁 > 博客 > 聯合體原來是這么用的!

        聯合體原來是這么用的!

        發布人:魚鷹談單片機 時間:2022-06-22 來源:工程師 發布文章

        不管是線程間、還是設備間通信,都需制定一個通信協議,規定數據的格式、內容等。

        線程間通信因為在芯片內部傳輸,基本可以排除數據干擾導致的異常,所以通常會設計的比較簡單,但是設備間的通信(不管是無線還是有線)就會復雜一些,一般都包含幀頭、校驗位之類的,因此魚鷹在一篇文章中介紹了一個基本的串口協議框架《如何寫一個健壯且高效的串口接收程序?》。

        因為當時剛畢業沒多久,所以雖然從大的方向介紹了基本協議內容,但在細節處理上還不夠好,比如可維護性、可讀性等方面。

        后來,魚鷹在學習開源的飛控源碼時,發現里面使用了聯合體+結構體的方式,大大提高了程序的可維護性和可讀性。

        比如,我們的協議中有這樣三條命令,心跳包、獲取固件版本號、獲取序列號。

        初級版本:

        直接使用基本的類型聲明所需要的數據結構。

        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) 之類的解析對應數據。


        在這個例子中,我們利用聯合體的特性,將所有消息類型集成在一起,這樣當你需要發送一條消息時,很容易就能找到想要的數據類型。并且在空間占用上也是非常合理的。當需要開辟緩存容納數據幀格式,利用了聯合體空間占用特性(找最大),這樣你開辟的空間一定是剛剛好,不多也不少,節省了空間使用。


        所以,當我們需要傳輸一類消息,但這些消息不會同時存在時,不如使用聯合體吧。


        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



        關鍵詞: 單片機

        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 昭觉县| 胶南市| 西青区| 柳江县| 惠来县| 保德县| 三台县| 瑞金市| 田林县| 安阳县| 湟中县| 新和县| 吐鲁番市| 武安市| 富平县| 玛沁县| 道真| 金塔县| 开平市| 玉山县| 巴彦县| 石嘴山市| 罗平县| 宝清县| 高碑店市| 措美县| 浏阳市| 元江| 崇明县| 左云县| 临澧县| 安塞县| 金坛市| 荆门市| 策勒县| 桃园县| 保德县| 凤城市| 磐石市| 太仆寺旗| 郓城县|