串口通信用戶層協(xié)議編制技巧與實現(xiàn)
掃描二維碼
隨時隨地手機看文章
前言
協(xié)議就是約束雙方通信的一種規(guī)范,只有嚴格遵守這種協(xié)議的設備才能進行相互的通信。比如串口通信協(xié)議,必須包含起始位、主體數(shù)據(jù)、校驗位及停止位,雙方需要約定一致的數(shù)據(jù)包格式才能正常收發(fā)數(shù)據(jù)的有關規(guī)范。在串口通信中,常用的協(xié)議包括RS-232、RS-422和RS-485等。與此類似還有I2C通信協(xié)議。但是往往這些只是底層的通信協(xié)議,很多外設都已經集成好了,只需配置相關的寄存器就能夠得到數(shù)據(jù)主體了。根本不需要用戶去關注協(xié)議的組成,而我這篇文章主要講的是用戶層協(xié)議的編制原理和實現(xiàn)手段。
什么是用戶層協(xié)議?簡單的說就是用戶自定義的某種數(shù)據(jù)格式,有包頭,心跳幀,命令字,數(shù)據(jù)幀,校驗幀,結尾幀等。當需要接受數(shù)據(jù)幀的設備收到一幀數(shù)據(jù)后,進行解包,并且校驗,將有用的數(shù)據(jù)幀提取出來,然后根據(jù)具體的數(shù)據(jù)幀執(zhí)行相應的動作。這就是用戶協(xié)議編制的基本原理。下面來具體講一下這個過程。
什么情況下會用到用戶層協(xié)議
做嵌入式肯定會遇到兩個模塊進行通信的情景,比如兩個mcu或者兩個mpu,mcu與mpu之間的交互,往往涉及到多種邏輯。不像單功能模塊一樣只做一件事,可能涉及到許多的交互,比如狀態(tài)上傳,控制邏輯等等。舉個例子來說,mcu要和智能電表進行交互。此時mcu不僅可以讀取到電表電能,電量等信息,也可以控制空開的開合閘。同時,電表也可能主動向mcu上傳一些報警信息。針對這樣的情況,就需要制定電表協(xié)議,電表按照這樣的協(xié)議進行數(shù)據(jù)收發(fā),mcu也需要有發(fā)出或者解析這樣格式的能力。
從modbus協(xié)議開始分析
首先Modbus是一種工業(yè)上常用的通信協(xié)議,其中包含RTU,ASCII,TCP等等,其中MODBUS-RTU比較容易實現(xiàn)。一般的文檔寫的都比較復雜,將用最簡單的方式講述一下這個過程。我們不分析協(xié)議內容,只講協(xié)議的實現(xiàn)。
假如我們從串口收到了一條報文:01 06 00 01 00 17 98 04。這一串16進制的數(shù)據(jù)被存放在一個buf數(shù)組中,首先編程人員要理解這一串數(shù)據(jù)的含義,所以先進行拆包。
01 | 06 | 00 ?01 | 00 ?17 | 98 ?04 |
---|---|---|---|---|
從機地址 | 功能號 | 數(shù)據(jù)地址 | 數(shù)據(jù) | CRC校驗 |
從機地址:
一條總線上可能掛載多個設備(對于串口一般是RS-485)。所以需要廣播這個消息是發(fā)送給哪個設備的,01表示告訴的是地址編號為01的設備。
功能號:
顧名思義,功能號就是通知該設備執(zhí)行什么動作,比如控制LED燈,或者打開某個寄存器等等。每一項動作都是有特定的功能號。
數(shù)據(jù)地址:
數(shù)據(jù)地址就是操作的設備的寄存器,這個在modbus協(xié)議特有,暫時不做分析。自定義協(xié)議時也很少用到。
數(shù)據(jù):
這部分就是將特定的數(shù)據(jù)交給設備,比如可以自定義開燈動作為數(shù)據(jù)”1“,關燈動作為數(shù)據(jù)"0"。設備接收到特定的功能號,然后解析這個數(shù)據(jù),就能夠執(zhí)行具體的動作了。
CRC校驗:
校驗的目的就是為了保證這一包數(shù)據(jù)的完整性,發(fā)送過來的數(shù)據(jù)是主機已經算好了CRC校驗碼,然后設備收到數(shù)據(jù)后,再次將前面的數(shù)據(jù)算一遍,然后與接收到的CRC校驗碼進行對比,如果數(shù)據(jù)是準確的,就證明數(shù)據(jù)完整且傳輸過程中沒有出現(xiàn)錯誤數(shù)據(jù)。然后才能開始執(zhí)行動作。如果校驗有誤,應該丟棄該包數(shù)據(jù),請求重傳,以免造成不可預知的后果。
主機發(fā)送完這串字符串后,可以看到編號為01的從機開始執(zhí)行動作了。這只是一個最簡單的例子,但是也能說明白用戶層協(xié)議是怎么一回事。
開始一個簡單的應用
協(xié)議制定
在做項目之前,先設計需求,假如我們有這樣一個需求:現(xiàn)在做了一個從機的板子,上邊只有一個按鍵和一個led。這塊板子和另一塊主機通過串口方式進行連接。當主機發(fā)送數(shù)據(jù)包:命令碼0x01,控制碼0x01的數(shù)據(jù)過來時,點亮模塊板上的LED,當主機發(fā)送數(shù)據(jù)包:命令碼0x01,控制碼0x00的數(shù)據(jù)過來時,熄滅板子上的LED。當按鍵按下時,板子主動上傳:命令碼0x02,控制碼0x00的數(shù)據(jù)。
功能已經明確,接著就開始寫協(xié)議文檔。
協(xié)議文檔就是約束通信雙方的通信格式,一般用word文檔比較正式也比較好交接。首先可以規(guī)定串口波特率,有無校驗位,停止位。然后開始規(guī)范包格式。根據(jù)這個簡單的應用需求,我可以先制定包格式如下
包頭 | 命令碼 | 控制碼 | CRC校驗 |
---|---|---|---|
2字節(jié) | 1字節(jié) | 1字節(jié) | 2字節(jié) |
制定完基本格式,然后一條一條的完善這個協(xié)議
LED控制(0x01)
數(shù)據(jù)格式
包頭 | 命令碼 | 控制碼 | CRC校驗 |
---|---|---|---|
0xAA 0xBB | 0x01 | 0x00(關燈) ?0x01(熄燈) | -- |
說明:
當收到命令為0x01的命令碼時,需要判斷控制碼執(zhí)行的動作,然后進行關燈和開燈的操作。
按鍵狀態(tài)上傳(0x02)
數(shù)據(jù)格式
包頭 | 命令碼 | 控制碼 | CRC校驗 |
---|---|---|---|
0xAA 0xBB | 0x02 | 0x00 | -- |
說明:
當按鍵按下時,模塊主動向主機發(fā)送命令碼為0x02的數(shù)據(jù)包,其他情況下不會發(fā)送。
程序分析
可以用在stm32f103cbt6上進行實驗,在寫代碼時,先設計程序的框架。用到的資源:
1.串口
2.rt-thread操作系統(tǒng)
3.按鍵中斷
4.led
如果用到了rt-thread系統(tǒng),就不用從頭開始,我們只專注于協(xié)議部分的實現(xiàn)就好。點燈操作可以采用pin驅動模型。程序部分的設計我將在下一篇文章中詳細介紹。
總結
用戶協(xié)議的制定是非常重要,也是非常的關鍵的,前面很多人都不理解協(xié)議,這篇文章寫得很基礎,也非常容易理解,希望能夠給大家一點幫助。下一篇文章將從協(xié)議的去耦合性以及可擴展性上詳細設計一下代碼。