姚海濤 吳永剛
【摘要】本文介紹了串口通訊數據接收處理的一般方法。該方法利用循環FIFO緩沖區,獲取串口數據,并根據狀態轉移法對通訊報文進行分析,從而獲得符合協議要求的有效報文。文章通過實例驗證了狀態轉移法分析串口通訊數據的有效性,為實際的工程應用提供了一定的指導。
【關鍵詞】循環緩沖區;串口通訊數據處理;狀態轉移法
1.應用背景
在目前很多的工程化控制應用中,大部分采用了PC機和多臺單片機構成的主從系統。單片機主要進行數據采集,處理現場信號,驅動執行機構;PC機則通過對單片機進行集中管理,完成信息顯示,數據運算并做出決策以分配任務。PC機與單片機之間則需通過通訊方式完成數據交互,在眾多通訊接口中,串口通訊應用比較普遍。
串口通訊方式有三種:RS232、RS422和RS485;RS-232是串行數據接口標準,最初都是由電子工業協會(EIA)制訂并發布的,RS-232在1962年發布,命名為EIA-232-E,作為工業標準,以保證不同廠家產品之間的兼容。RS-422由RS-232發展而來,它是為彌補RS-232的不足而提出的。為改進RS-232通信距離短、速率低的缺點,RS-422定義了一種平衡通信接口,將傳輸速率提高到10Mb/s,傳輸距離延長到4000英尺(速率低于100kb/s時),并允許在一條平衡總線上連接最多10個接收器。RS-422是一種單機發送、多機接收的單向、平衡傳輸規范,被命名為TIA/EIA-422-A標準。為擴展應用范圍,EIA又于1983年在RS-422基礎上制定了RS-485標準,增加了多點、雙向通信能力,即允許多個發送器連接到同一條總線上,同時增加了發送器的驅動能力和沖突保護特性,擴展了總線共模范圍,后命名為TIA/EIA-485-A標準。由于EIA提出的建議標準都是以“RS”作為前綴,所以在通訊工業領域,仍然習慣將上述標準以RS作前綴稱謂。
串口通訊是按照字節流的方式來進行的,即每中斷一次,表明成功傳送或者接收一個字節。
2.通訊協議
要進行數據通訊,那么通訊雙方必須遵循一定格式的協議,這樣,通訊雙方才能夠相互理解從對方所接收過來的數據。
串口通訊協議一般包含這樣幾個域:幀頭、用戶數據和幀尾。為保證數據的有效性,一般加強了幀頭和幀尾,幀頭包含前導碼、幀長度和幀號,有的增加了發方地址和收方地址,有的通訊協議將幀長度放在幀號的后面;幀尾主要是整個數據域與幀頭校驗的結果,類型有CRC檢驗、奇偶檢驗或異或偶校驗等。有的協議幀尾也采用了固定的數據,甚至沒有幀尾。
表1 串口通訊協議一般格式
前導碼 幀長度 幀號 數據域 校驗
幀頭 用戶數據 幀尾
同時通訊協議還需定義各個域的長度和每一個bit的確切的含義。
3.循環FIFO緩沖區
在通信程序中,經常使用環形緩沖區作為數據結構來存放通信中發送和接收的數據。環形緩沖區是一個先進先出(FIFO)的循環緩沖區,可以向通信程序提供對緩沖區的互斥訪問。環形緩沖區通常有一個讀指針和一個寫指針。讀指針指向環形緩沖區中可讀的數據,寫指針指向環形緩沖區中可寫的緩沖區。通過移動讀指針和寫指針就可以實現緩沖區的數據讀取和寫入。在通常情況下,環形緩沖區的讀數據僅僅會影響讀指針,而寫數據僅僅會影響寫指針。
進行串口數據接收和發送一般也采用具有先進先出功能的FIFO循環緩沖區,如圖1所示:
Tail
0 1 2 3 4 5 6 7 …… SIZE-1
Head
圖1 FIFO循環緩沖區示意圖
從圖中可以看出,先進先出功能的FIFO緩沖區須定義一個大小為SIZE的緩沖區,存放數據,Tail指針表示該緩沖區中接收到的有效數據位置,表示寫入的數據位置;Head指針表示該緩沖區中已經處理的有效數據位置,表示讀出的數據位置;初始化時,Head指針和Tail指針都指到0的位置;當串口接收到數據存放到緩沖區后,Tail就加1,當Tail大于SIZE-1時,將Tail等于0,數據接收時,線性緩沖區變成一個回環;當系統從緩沖區取出一個數據進行分析,Head就加1,當Head大于SIZE-1時,將Head等于0,數據分析時,線性緩沖區也變成一個回環;依據這種方法,可以看出,數據先到的,數據先分析,建立了先進先出功能的FIFO循環緩沖區。
根據上述說明,可以使用如下結構體來定義FIFO緩沖區:
Typedef Struct Buffer_t{
IntHead;
IntTail;
Char data[SIZE];
}Buffer;
這個結構體很簡單,Tail表示寫入的數據位置,Head表示讀出的數據位置,data用來存放數據。在對Head和Tail修改時,需要對SIZE取模,防止溢出。SIZE一般根據串口采用的波特率,數據流量和計算機的處理速度來決定大小。
4.緩沖區數據的操作
根據FIFO的方式實現緩沖區的初始化、寫入和讀出的操作時,需要注意以下幾點:
1)緩沖區的有效數據長度
緩沖區的有效數據長度表示在緩沖區中存在的沒有及時處理的數據長度;可以這樣計算:(Tail +SIZE- Head)%SIZE。
2)緩沖區的可以寫入數據長度
緩沖區的可以寫入數據長度表示在當前緩沖區中還能寫入的數據長度;可以這樣計算:SIZE-(Tail +SIZE- Head)%SIZE。
3)緩沖區空和滿的判斷條件
當Head和Tail相等的時候,緩沖區空,而當緩沖區中已經寫入了SIZE-1個有效數據時,緩沖區滿。
4)寫入和讀出的策略
當讀取或者寫入緩沖區時,需要檢查緩沖區中的數據或者空間是否足夠。在讀取時,如果沒有足夠的數據,是讀取已有的數據還是不讀取任何數據,而在寫入時,如果空間不夠,是部分寫入還是不寫入任何數據,這取決于軟件開發人員的應用程序采用的策略。一般情況下,在空間不夠時,可以不做任何操作。當出現上述情況,留給上層的程序去處理。在實際應用中,如果讀取和寫入的程序設計的合理,緩沖區的大小合適,一般是不會出現寫入失敗的情況的。
5.串口數據的分析
使用循環緩沖區,可以非常方便的實現對串口數據的分析,而要完成協議的各個域的嚴格檢查,實現對部分含有錯誤域的包和不完整的包的完美過濾,以及對混亂數據中正確包準確無誤的抽取,還須對FIFO緩沖區重新定義,具體情況如下:
Typedef Struct Buffer_t{
IntHead;
IntTail;
IntHeadBak;
Char data[SIZE];
}Buffer;
增加的HeadBak為Head的備份,當幀頭分析結束后,記錄下Head的位置,以防后續數據不符合協議要求后,根據HeadBak重新恢復Head的位置。
依據前面制定的協議,需依次完成前導碼的搜索,數據長度的檢查、校驗和的檢查以及錯誤包的處理。利用狀態轉移法,程序循環一次,從數據緩沖區讀出一個字節,改變狀態,每次分析結束后,Head++;在進行串口數據分析之前,必須判斷緩沖區不空或緩沖區的有效數據長度不為零時,才讀取數據進行分析。分析具體流程如下:
1)判斷前導碼:如果成功,轉到2。
2)幀長度的檢查:對照協議中對長度域可能出現的最大和最小包長檢查,如果正常,則轉到3,否則若不是前導碼,轉到1。
3)幀號的檢查:檢查幀號是否為有效的幀號,有效,則轉到4,HeadBak等于Head,否則若不是前導碼,轉到1,若是前導碼,轉到2。
4)數據域的接收:根據幀長度判斷包是否完整,若完整,轉5。
5)校驗和的檢查:根據協議算出校驗和,檢查校驗和是否正確,錯誤則Head=HeadBak,轉到1。如果正確,則讀取(Head-HeadBak+SIZE)%SIZE的長度數據,根據幀號,執行相應的操作。
根據上述的處理流程,完成了協議的各個域的嚴格檢查,實現了對部分含有錯誤域的包和不完整的包的完美過濾,以及對混亂數據中正確包準確無誤的抽取。
6.實例驗證
假如一幀正確數據如表2所示:
表2 一幀正確數據格式
前導碼 幀長度 幀號 數據域 校驗
0x55 0x01 0x02 0x03 0x50
幀長度表示數據域的長度,數據長度在0~32之間,幀號在0x00~0x0F之間,校驗采用異或檢驗。
為驗證上述流程的正確性,我們采取了各種案例進行驗證,具體情況如下:
表3 串口數據處理流程正確性案例驗證結果
通過表3中各種案例進行驗證,都可以得到正確結果,每次取出的數據都符合協議,證明串口數據分析的狀態轉移法流程滿足要求。
7.結束語
以上給出的是根據一個簡單的協議,構造了一個串口接收數據緩沖區,根據緩沖區如何得到正確包的基本思路。我們根據這個思路,在多個產品上已經得到了成功的運用。但實際的通信系統中協議遠比這個要復雜,而且涉及到數據包響應、命令錯誤、延時等等一系列的問題,不過有了這樣的一個基礎,通過克服這些困難我們就可以實現較為穩定可靠的系統。
參考文獻
[1]李現勇.Visual C++串口通信技術與工程實踐(第二版)[M].人民郵電出版社,2004.
[2]周立功,張華等.深入淺出ARM7-LPC213x/214x(上冊) [M].北京航空航天大學出版社,2005.
作者簡介:姚海濤(1979—),女,碩士,現供職于宜昌測試技術研究所,主要從事電子對抗技術研究。