趙艷明 曾培峰



文章編號: 2095-2163(2018)03-0050-05中圖分類號: 文獻標志碼: A
摘要: 關鍵詞: (School of Computer Science and Technology, Donghua University, Shanghai 201620, China)
Abstract: Based on STM32 chip, a Modbus-RS485 communication method is proposed. The method uses the object-oriented technology to manage Modbus calls and serial ports is universal, which can be easily portable to other systems with the same characteristics. After that, the paper elaborates using a state machine to manage Modbus communication combined with logs, so that the communication network has self-diagnosis and adaptive function. In combination with the characteristics of STM32 chip and Modbus protocol, a DMA receiving data method is proposed which is independent of the Modbus command length. This method can be used as a reference scheme to solve the low communication efficiency and slow data transmission of Modbus-RS485.
Key words:
引言
Modbus-RS485是一種在工業現場廣泛使用的布網方法\[1\]。RS485總線上最多支持255個從站,然而在實際應用場景中從站的數量遠遠大于這個數量??刹捎脭U展Modbus地址域,或者數據域中添入物理地址來增加從站的數量\[2\]。
常見的Modbus通信方法有2種。一種是主站根據要請求的數據信息,封裝相應的請求幀,并生成對應的定時器,通信程序通過定時器來執行Modbus通話\[3\]。這種方法存在明顯的缺點,如果定時器時間設置過短容易發生數據碰撞,過長則導致通信效率低。另外一種是主站一次只允許發起一個通話,當從站回復數據或者從站在規定時間內不回復數據,主站才可以發起下一次通話\[4\],這種方法和第一種沒有本質上的區別。
STM32芯片常見的數據接收方法有串口中斷\[5\]和DMA中斷 \[6-7\]。使用串口中斷接收數據存在2個缺點。其一是接收效率太低,其二是通信雙方要設置既定的結束符。使用DMA中斷能夠提高數據接收效率,前提條件是接收的長度固定。然而掛載在同一根RS485總線上的從站回復的數據幀長度是不固定的,此時無法使用DMA接收中斷。
本文采用面向對象的思想將Modbus通話封裝成任務,任務中增加了通話對應的端口地址,使用這種方式使得主站可以訪問從站的數量超過255個。將實現數據收發的串口封裝成端口,一個端口對應一個對象,任務對象和端口對象通過消息建立聯系。通信程序使用狀態機管理Modbus通信,并將通信過程中的異常狀況以日志的形式記錄下來。通過對日志提取分析當前網絡狀態,動態調整任務調度。此外,本文基于STM32芯片,未配置DMA接收中斷實現一種DMA接收長度不固定的Modbus數據幀的方法。
1系統介紹
使用STM32芯片的串口實現RS485通信需結合RS485收發器。系統結構如圖1所示,圖中每個I/O端口連接一條RS485總線。
在系統中,主站和從站的串口設置,包括:波特率、停止位、奇偶校驗等重要匹配。RS485總線上的Modbus協議使用半雙工主從方式通信,主站發起Modbus通話向從站發出請求,從站則處于接收狀態,一直等待主站發送的數據。
2系統中的對象
在RS485總線下主站通過Modbus請求數據幀訪問從站,通信程序中如果直接為每個功能設計寫定一段請求幀,雖然程序看起來比較直觀,但是這種方式喪失了通用性,且可維護性差。在系統移植時,需要變更程序內請求幀。因此要將運算時的變量和實際操作變量的函數分離。在系統中的Modbus通話是有限的,可將通話封裝成任務。將通信系統中的所有任務的描述,以XML配置文件的方式得到保存。XML文件可用一個專門的上位機生成,當需要增加、刪除、修改功能時,就可通過上位機來重新生成配置文件,并將配置文件導入到單片機中,單片機通過文件解析程序構建任務對象。任務對象定義可見表1。
屬性名稱描述屬性名稱描述Index任務的編號cmd數組,存放請求數據幀PortIndex任務對應的端口號Cmdlen數據幀長度DeviceAddr設備地址rcvCmd指針,指向接收數組Function功能碼RcvLen接收數據長度RegAddr寄存器地址TErrorCount超時錯誤計數Interval任務的掃描周期SErrorCount發送錯誤計數Timeout任務超時時間RErrorCount接收錯誤計數Timer任務的執行時間Traffic任務執行次數計數status枚舉,任務狀態Enable任務使能開關同理,將每個物理串口映射到唯一的邏輯端口,每個端口都是一個對象。端口對象的定義則可見表2。
任務的調度借助一個循環鏈表,任務可以加入到鏈表的前提是任務使能開關被打開。系統經過初始化后,開始依次執行鏈表中的任務。周期性的任務常存在鏈表中;非周期任務,則在每次任務輪詢前插入到鏈表,或者從鏈表中刪除。當串口連接了RS485總線,并且總線上掛載了從站時,將打開串口對應的邏輯端口的使能開關,從而激活端口對象。
屬性名稱描述屬性名稱描述TaskAddr指針,指向任務Sendlen發送長度status枚舉,端口狀態RcvBuf數組,接收數據Timer端口工作時間Rcvlen接收長度Timeout端口超時時間Enable端口使能開關SendBuf指針,指向發送數組通信網絡需具備自診斷與自適應的功能,實現這一功能借助于系統日志,通過日志及時發現并處理通信異常狀況。通信雙方的串口設置不匹配或者從站出現異常的現象是:從站對應任務的Traffic統計中,RErrorCount數值偏高,而與該任務使用同一端口的其它任務RErrorCount數值正常。此時可以減少對該任務的輪詢。當物理鏈路發生損壞時,會導致端口發送出錯誤的請求命令,可設計硬件回送功能再次檢查發送的數據。鏈路損壞的現象是:當前任務和該任務使用同一個端口的其它任務的Traffic統計中SErrorCount都偏高,此時停止執行該端口對應下的所有任務。
3DMA數據收發
如果單純使用串口接收中斷的方式實現數據接收,頻繁地觸發串口接收中斷將會嚴重影響CPU的執行效率。STM32芯片提供了將串口復用成DMA的功能。DMA發送數據時,發送數據的長度是已知的,可配置DMA發送完成中斷來告知數據發送完成。但是在接收數據時,數據的長度是未知的。因此使用DMA接收數據需要解決2個問題,分別是:
(1)如何判斷有數據接收。
(2)如何從接收的數據中解析出一條完整的指令。
首先定義4個標志位,也就是:curPos、lastPos、startPos、 prev。定義一個和時間相關的變量LastRcvTime。其中,curPos指向當前接收數據位置;lastPos指向上次數據接收的位置;startPos指向開始接收數據的位置;prev指向數據接收完畢的位置;LastRcvTime記錄最近一次接收數據的時間。數據接收狀態如圖2所示。圖2數據接收狀態
Fig. 2Data receiving state
將DMA配置成循環模式,并設置隊列長度RXLen。DMA中的CNDTR寄存器會記錄數據的接收位置(curPos)。使用STM32芯片提供的SysTick_Handler滴答計時器定時查看curPos是否發生變化,結合Modbus協議特點,如果3.5個字節(記為frameTime)內curPos一直不發生變化,認為DMA接收數據完畢。具體流程如下。
(1)當準備接收數據前、系統新近開始接收數據或者上一次命令接收結束后。置4個標志位為同一位置(RXLen-CNDTR)。
(2)通過SysTick_Handler函數定時查看curPos是否發生改變。如果發生改變,則將LastRcvTime賦值為當前系統時間,并且將lastPos賦值為curPos。
(3)當curPos數值和lastPos數值相等時,可認為當前數據可能接收完畢。
(4)frameTime內curPos不發生改變,即系統當前時間systemTime和LastRcvTime的差值超過frameTime,認為當前數據接收完畢,將prev賦值為curPos。此時認為startPos和prev之間接收為一條待驗證的Modbus命令。
4狀態機模型建立
4.1端口狀態機
在端口對象定義中,status是一個枚舉類型,包含了端口7個狀態,端口的狀態轉換如圖3所示。
圖3中,CRC(Sending(msg))表示對回送的數據做CRC校驗,檢驗結果正確時值為0,否則值不為0。任務與端口的關系是多對一的,并且主站可以訪問同一從站的不同寄存器。因此Prase(Receiving(msg))不僅對接收的數據啟用CRC校驗,也會對設備地址和功能碼進行檢查。端口狀態機的處理流程描述如下。
(1)當端口對象處于Port_Idle狀態,并且端口的TaskAddr指針指向為空時,此時端口可被占用。
(2)當端口對象被占用之后,端口對象將指針變量TaskAddr指向當前任務。通過端口,該指針可獲得任務對象存儲發送的命令的數組的地址和命令的長度。端口開始發送數據,跳轉到Port_Sending狀態。
(3)對回送數據進行CRC校驗。如果檢驗失敗,跳轉到Port_SendError狀態;如果校驗正確,跳轉到Port_Wait狀態。
(4)如果沒有數據接收,則繼續等待,并開始計時,等待超時則跳轉到Port_Timeout狀態。如果發現有數據接收,跳轉到Port_ Receiving狀態。
(5)判斷當前數據是否接收完畢。數據接收完畢后對數據進行解析。解析包括CRC校驗、設備地址的檢查。如果解析失敗,則跳轉到Port_ReceiveError;如果解析成功,則將數據的接收地址和接收的長度通過任務指針告知給任務對象。
(6)當端口處于Port_SendError、Port_Timeout、Port_ReceiveError異常狀態時,會將狀態反饋給任務。
4.2任務狀態機
任務對象定義中,status是一個枚舉類型,任務包含了10個狀態,任務狀態轉換如圖4所示。
設計任務狀態機時有一個前提條件:正確的命令可能會收到正確的回復數據,不正確的命令一定收不到正確的回復數據。因此在任務狀態機中增加Task_Retry狀態,盡可能保證發出的請求命令是正確的。圖4中,rescheduleTime表示任務再次發起的時間,該值為任務開始進入Task_Retry的系統時間systemTime加掃描周期Interval。任務狀態機的處理流程可分述如下。
(1)開始任務對象處于Task_Idle狀態。當有任務執行時,跳轉到Task_Check狀態,檢查要綁定的是否被占用。
(2)如果端口被占用,放棄當前任務,跳轉到Task_Idle狀態。如果沒有被占用,則跳轉到Task_Bind狀態。
(3)任務會把命令數組的地址和長度告知給端口,跳轉到Task_Schedule狀態。
(4)當任務對象接收到端口Port_Timeout、Port_ReceiveError異常狀況反饋時,相應跳轉到Task_Timeout狀態、Task_ReceiveError狀態,同時TErrorCount、SErrorCount的數值加1,將異常狀況保存到日志當中,并跳轉到Task_Unbind狀態。
(5)任務得到接收的地址和長度,跳轉到Task_Receive狀態。將得到的數據返回給Modbus主站后,跳轉到Task_Unbind狀態。
(6)當任務接收到端口Port_SendError反饋,首先跳轉到Task_SendError狀態,RErrorCount數值加1,把異常狀況保存到日志當中。然后判斷任務的執行時間是否已經結束。如果已經結束,跳轉到Task_Unbind狀態。如果還未結束,則跳轉到Task_Retry狀態。
(7)任務處于Task_Retry狀態,需要等到掃描周期才能再次發起任務。在掃描周期內,任務一直處于該狀態。一旦等到掃描周期,則跳轉到Task_Schedule狀態。
(8)任務處于Task_Unbind狀態時,無論任務執行成功,或是失敗,都會解除對端口的占用。
5結束語
實現面向對象方法既可避免重復性代碼的編寫,又容易維護。作為一種思想,這是不受編程語言限制的,本文利用面向對象和狀態機設計研發的RS485-Modbus通信方法具備通用性。同時,將通信異常狀況以日志的形式記錄下來,通信網絡借助日志使得自身具備自診斷性和自適應性。文中提出的DMA接收數據方法亦可使用于同特點的其它系統中。
參考文獻
[1] 顏河恒, 王曉華, 佟為明. Modbus關鍵技術分析及節點開發\[J\]. 自動化技術與應用, 2006, 25(5):49-51.
[2] 周海洋. 大規??刂乒濣c群管理系統設計\[D\]. 天津:天津大學, 2015.
[3] 李年鎖, 顏罡, 郭彥每. 基于Modbus協議的RS485總線通信在內電混合工程車中的設計及實現\[J\]. 電力機車與城軌車輛, 2017,40(3):44-47.
[4] 陳科, 蔣軍. 基于STM32的MODBUS協議的實現與應用\[J\]. 視聽, 2013(4):9-10.
[5] 張永偉, 康興無. 基于STM32和Modbus的串口服務器系統\[J\]. 電子設計工程, 2017, 25(16):108-111,116.
[6] 魏琳, 田波. 基于STM32F4系列的串口DMA數據處理傳輸研究\[J\]. 自動化應用, 2016(8):92-93.
[7] 孫景龍, 王業成, 陳銳. STM32F4xx利用DMA實現異步多串口高速通信設計\[J\]. 黑龍江科技信息, 2013(27):36.