基于狀態(tài)機的串口通信協(xié)議的研究設計
1 定義數據包格式
串口通信中最小的的信息單元是數據幀。一個(gè)數據幀通常包括起始位、數據位、結束位,另外還可以包含用于檢測傳輸錯誤的“奇偶校驗位”,每個(gè)數據幀中傳輸的數據位可以有5、6、7、8或9個(gè)。
實(shí)際通信過(guò)程中,數據的發(fā)送是一幀一幀地進(jìn)行,當被傳輸的數據超過(guò)一幀時(shí)(例如浮點(diǎn)型數據),如果沒(méi)有對數據幀進(jìn)行必要的打包,發(fā)送出去的數據將會(huì )很難被數據接收方解釋與分析,進(jìn)而造成數據傳輸混亂與錯誤。因此,在一般應用中有必要將數據幀組裝成數據包再發(fā)送。為了保證數據傳輸的正確性,將數據包定義為如圖1所示。
1)起始標志表示開(kāi)始接收一個(gè)新的數據包,本協(xié)議中規定為0x55。
2)數據長(cháng)度命令和附加數據共占的字節數。設置此字段,可方便接收方識別數據包的長(cháng)度并能夠準確地接收數據包。
3)命令用來(lái)說(shuō)明數據包的用途。
4)附加數據 當命令不同時(shí),含義不同。例如,當命令表示數據包的用途為質(zhì)量時(shí),附加數據用來(lái)保存質(zhì)量數據。
5)校驗是對命令字段與附加數據字段的所有字節數據的異或校驗。
6)結束標志表示該數據包結束,本協(xié)議中規定為0x56。
另外,在多機通信中,數據包中還應增加源地址與設備地址等字段。這里主要介紹上位機與下位機之間的通信,因此無(wú)需設置源地址與設備地址等字段。
2 通信狀態(tài)機
2.1 狀態(tài)機簡(jiǎn)介
狀態(tài)機由事物所處的狀態(tài)及引發(fā)狀態(tài)變化的外部事件兩部分組成。在軟件編程中,事物所處的狀態(tài)可以描述為某個(gè)程序片斷或函數,而引發(fā)狀態(tài)變化的處部條件可以理解為條件判斷語(yǔ)句,當條件為真時(shí),事物的狀態(tài)發(fā)生變化。事物發(fā)生變化前的狀態(tài)稱(chēng)為現態(tài),變化后的狀態(tài)稱(chēng)為次態(tài),程序中可以通過(guò)不同的數字對不同的狀態(tài)進(jìn)行編號?,F態(tài)到次態(tài)的變化可以通過(guò)狀態(tài)變量值的改變來(lái)描述。
本協(xié)議中需要傳輸的基本信息單元是數據包,數據包一般包含多個(gè)數據幀。實(shí)際傳輸過(guò)程中,數據的傳輸通常是一幀一幀地進(jìn)行,數據包是被拆分成若干幀數據后再進(jìn)行傳輸,數據接受方也是分幀接受一個(gè)數據包。數據接受方在解釋與分析數據包時(shí)可能存在兩個(gè)問(wèn)題:
1)識別并接收完整的數據包
對于數據接收方,一個(gè)數據包是分若干批到來(lái),在識別包頭與包尾時(shí),也就是幀同步問(wèn)題,具體編程時(shí)存在難度,特別對于已接收部分與未接收部分以及數據接收的進(jìn)度及狀態(tài)的處理。
2)數據傳輸時(shí)的容錯能力
數據傳輸過(guò)程中已經(jīng)出現錯誤時(shí),系統應該具有擺脫錯誤狀態(tài),恢復到正常狀態(tài)的能力。例如,當一個(gè)數據包只傳輸完一部分時(shí),因為未知故障,下一個(gè)數據包就開(kāi)始傳輸,系統應該能識別出傳輸錯誤,拋棄前一個(gè)出錯的數據包,并且能正確接收下一個(gè)數據包。實(shí)際編程時(shí)處理這種問(wèn)題難度較大,結果很可能會(huì )出現將第一個(gè)數據包的前一部分與第二個(gè)數據包的前一部分拼裝成一個(gè)新的數據包的情況,這就損失了兩個(gè)數據包,最嚴重的結果可能是系統無(wú)法從錯誤中恢復,這就嚴重降低了系統的安全性與可靠性。
為解決上面提出的兩個(gè)問(wèn)題,本協(xié)議引入了狀態(tài)機。在狀態(tài)機中,狀態(tài)的變化依賴(lài)于外部觸發(fā)條件,當條件滿(mǎn)足時(shí),狀態(tài)將發(fā)生變化。本協(xié)議中將數據包接收的各個(gè)階段定義為不同的狀態(tài),將接收一幀新的數據或數據處理的結果作為外部觸發(fā)條件,從而達到狀態(tài)改變的目的,最終完成一個(gè)數據包的接收與校驗。
2.2 串口通信狀態(tài)圖
串口通信協(xié)議中,發(fā)送數據包時(shí)一般不需引入狀態(tài)機,這主要是為提高發(fā)送速率和簡(jiǎn)化編程模型而考慮的。本協(xié)議中主要針對數據接收過(guò)程建立狀態(tài)機。數據接收狀態(tài)圖如圖2所示。
串口通信的數據接收過(guò)程如下:當未開(kāi)始接收數據包或發(fā)現數據傳輸出錯時(shí),系統進(jìn)入空閑狀態(tài);當數接收到數據包0x55(起始標志)時(shí),變?yōu)槭盏狡鹗紭酥緺顟B(tài),如果收到的數據不為0x55,系統繼續保持空閑狀態(tài);進(jìn)入收到起始標志狀態(tài)后,新接收到的任何數據將被當作數據包中命令與附加數據的總字節數(記為L(cháng)EN),系統進(jìn)入收到數據長(cháng)度狀態(tài);繼續接收新的數據,直至接到新收到的數據總字節數達到LEN +2,進(jìn)入檢驗結束標志狀態(tài);這時(shí)可以檢驗結束標志是否為0x56,如果是,說(shuō)明傳輸正確,否則傳輸出錯,出錯后應查找接收緩沖區中本數據包的起始標志后有無(wú)其它起始標志,如果沒(méi)有發(fā)現起始標志,系統應進(jìn)入空閑狀態(tài),否則應直接進(jìn)入接收到起始標志狀態(tài),這樣可提高系統容錯能力,方便系統從錯誤中恢復。檢驗結柬標志正確后,進(jìn)入數據校驗狀態(tài);校驗結果如果正確,數據包接收完成,否則說(shuō)明傳輸出錯,系統進(jìn)入空閑狀態(tài)。
3 協(xié)議實(shí)現
下位機采用ATMEL公司的AVR系列單片機ATmega168作為其核心控制單元;上位機軟件采用Delphi 7.0編寫(xiě),Delphi 7.0是Borland公司開(kāi)發(fā)的基于Windows平臺的面向對象的快速應用程序開(kāi)發(fā)工具。本協(xié)議上位機程序采用Delphi開(kāi)發(fā),主要考慮到Delphi易于實(shí)現多線(xiàn)程編程。另外,Delphi開(kāi)發(fā)程序的簡(jiǎn)單、高效,也是上位機軟件選擇其作為開(kāi)發(fā)工具的重要原因。
串口通信協(xié)議包括發(fā)送與接收兩部分。在本系統中,下位機負責發(fā)送數據,上位機負責接收數據,而另一種情況:下位機接收、上位機發(fā)送,其處理方法與前面一種相似。因此,這里僅介紹下位機發(fā)送數據、上位機負責接收數據的實(shí)現。
下位機串口通信發(fā)送程序由于不考慮狀態(tài)機,實(shí)現較為簡(jiǎn)單,其示例代碼如下:
上位機軟件中,當接收到數據時(shí),串口控件會(huì )觸發(fā)一個(gè)事件,在事件處理代碼中應及時(shí)將收到的數據存入接收沖區,同時(shí)不應該把串口通信協(xié)議接收部分的代碼放置在此事件中,否則后面到來(lái)的數據可能因為前面先到的數據沒(méi)有及時(shí)處理完畢而被沖掉,導致數據丟失。因此,在上位機軟件運行時(shí),應該啟動(dòng)一個(gè)Windows線(xiàn)程,用于不斷檢測接收緩沖區是否為空,不為空時(shí)則對緩沖中的數據進(jìn)行處理,創(chuàng )建一個(gè)名為T(mén)BufferThread的線(xiàn)程類(lèi):
評論