自定義用戶層的靈活性串口通信協議
想不到第一次接觸串口就要去寫一個自定義的靈活性串口通信協議,所以在這裏記錄一下自己的心得,有什麽不合理的地方還請大佬們指出。
先說明這裏提到的靈活性其實也是相對來說的,並不是說明數據包都可以定義。
一、用戶層串口通信協議
簡單的來說用戶層的串口通信協議就是如何定義一個數據包格式,發送端按照規定的數據包格式發送出去,接收端按照規定的數據包格式解析出正確的數據。
那為什麽又要在用戶層定義呢,其一是因為底層的通信協議不是隨隨便便就可以寫出來的,二是因為我們在市面上買到的串口模塊本身就已經有了底層通信協議,我們又何必去再自己寫呢。
二、定義數據包格式
因為是第一次接觸串口,所以肯定先上網搜了搜常見的數據包模板,發現基本上數據包格式有以下元素:
幀頭 包序號 數據長度 數據 校驗 幀尾
領導並不需要數據包定義的復雜,所以決定就從以上的元素來構思我自己的數據包格式。
首先,既然提到了靈活性,那麽上面的部分元素可以存在或者不存在,存在的話又可以更換位置,之所以說部分元素是因為考慮以下幾點:
1.幀頭位置固定存在,這個不需要解釋;
2.數據長度存在則必須放到數據的前面,這樣更方便我們解析不定長數據;
3.校驗必須存在且放在數據後面,因為校驗本身就是為了檢查數據的正確性,放到前面也不便於我們解析;
通過以上幾點對各種形式的數據包排除後還剩18種,也就是說我定義的靈活性串口通信協議一共支持18種數據包(有無幀尾對半分)。
幀頭 | 序號 | 數據長度 | 數據 | 校驗 | 幀尾 |
幀頭 | 數據長度 | 序號 | 數據 | 校驗 | 幀尾 |
幀頭 | 數據長度 | 數據 | 序號 | 校驗 | 幀尾 |
幀頭 | 數據長度 | 數據 | 校驗 | 序號 | 幀尾 |
幀頭 | 序號 | 數據 | 校驗 | 幀尾 | |
幀頭 | 數據 | 序號 | 校驗 | 幀尾 | |
幀頭 | 數據 | 校驗 | 序號 | 幀尾 | |
幀頭 | 數據長度 | 數據 | 校驗 | 幀尾 | |
幀頭 | 數據 | 校驗 | 幀尾 |
幀頭:必須存在,長度不限,但不建議太長;
序號:可定義1-4字節,若定義1字節,序號從1-255循環;
數據長度:可定義1-4字節;
數據:不定長,和數據長度匹配;
校驗:1字節,暫時只考慮累加計數,用unsigned char保存;
幀尾:可有可無,長度不限;
三、註意事項:
1.定義的數據包發送的數據只能是字符‘0‘-‘9‘,‘a‘-‘z‘,‘A‘-‘Z‘;而幀頭和幀尾的字符肯定和數據字符不同,所以不考慮數據中出現幀頭或幀尾的情況;
2.因為是系統與系統之間串口通信,所以需要考慮大小端問題,我自己定義發送為大端模式,接收端需要判斷自身系統的模式來獲取數據;
3.發送和接收的頻率,因為工作要求,我自考慮了發送頻率比接收頻率快的情況(範圍有限),並且當發送和接收的頻率不同時,數據包的序號不可以讓程序來自動改變;
4.還有一些代碼上的特殊註意,不要用strlen來獲取數據包的長度,因為會存在‘\0‘字符,比如序號大小為3字節,但序號為12,這其余兩個字節為0,0就是‘\0‘;存放數據的變量類型一定要認真選擇,如序號大小是0-4字節不固定,所以我們需要一個字節一個字節的進行存放和解析,那麽會有情況是字節大小為3,序號為1023,如果用char一個一個去獲取的話,你懂得;還有一些其他細節問題就不一一說明了。
四、API
建議將代碼封裝成庫,然後提供幾個接口供用戶使用即可,這樣也方便用戶切換其他串口通信協議。
我自己是提供了三個接口:
int GetPacketSize(stPacketFormat stPacket,int bufLen);
參數 : stPacket 是從xml解析出來的數據包格式,bufLen為要發送的數據長度。
返回值: 組裝成的數據包大小;
int CreatePacket(stPacketFormat stPacket,char **dataBuf,int bufLen);
參數 : stPacket 是從xml解析出來的數據包格式,*dataBuf為根據GetPacketSize的返回值創建的數組,用來存放組裝成的數據包,bufLen為發送的數據長度。
返回值: 成功為0,非0失敗;
int ParsePacket(stPacketFormat stPacket,char **dataBuf,int *pDataLen);
參數 : stPacket 是從xml解析出來的數據包格式,*dataBuf傳進去從串口獲取到的數據,函數調用成功後,解析出來的數據也從*dataBuf獲取,*pDataLen傳進去*dataBuf的長度,函數調用成功後,返回實際數據*dataBuf的長度。
四、收發數據包
1.先說配置數據包格式,可以采用xml文件來進行配置,程序通過解析xml來設置數據包格式;
2.發送端調用GetPacketSize獲取數據包大小,創建數組將發送的數據傳給CreatePacket封裝成數據包;
3.發送端將數據包通過串口發送出去;
4.接收端從串口接收數據,然後將數據傳給ParsePacket進行解析,獲取到實際需要的數據。
思路就記錄到這,具體實現的代碼其實不重要。
自定義用戶層的靈活性串口通信協議