自己編寫MODBUS協議代碼所踩過的坑

早在2008年左右,我就在設計的產品中使用Modbus協議與其它設備進行通信。

記得第一款是智能馬達保護器,其作為Modbus從,與Modbus主設備進行通信。

這麼多年來,一直都沒有使用開源的Modbus協議代碼,

而在在不斷在自己編寫的Modbus協議代碼上進行優化,發現問題並解決。

自己寫的代碼用起來比較得心應用可以針對不同的平臺進行優化,將處理器的性能發揮到極致。

在此期間,也踩過一些坑,現在做一些總結:

串口數據接收完之後,到通過IO口重新使用接收的時間間隔。


自己編寫MODBUS協議代碼所踩過的坑

發送完成之後切換接收的延時時間


如上圖所示的Td,按照Modbus協議的規定,接收完數據之後,必須要間隔3.5個字符對應的時間才能發送。

如果是9600bps的波特率,8位數據位,1位起始位,1位停止位,無奇偶校驗位,則1個字符為10個 bit,對應1.04ms,3.5個字符對應3.5ms。

考慮到總線上的電容對傳輸延時的影響,建議在發送完數據1.7個字符的時間之後再使能接收。

對於這個時間,可能會犯一些錯誤,比如:

  • 在發送完最後一個字節的發送完成中斷中,直接將控制IO口使能485芯片的接收。殊不知,由於電容導致的信號延時,串口數據還沒有完全發送到總線,485芯片就被置為接收狀態,導致最後幾個bit的數據誤碼;
  • 沒有正確理解發送完成中斷以及發送緩存器空中斷之間的差別;
  • 發送完成中斷一般是指串口數據已經從移位寄存器從端口送出。但是並不說明已經被送到RS485總線。從MCU的IO口到RS485總線還需要考慮隔離光耦、電容、RS485芯片的延時;
  • 發送緩存器空中斷是指騰出了緩存的位置,可以緩存數據。此時,上一個數據可能還在移位寄存器中被緊張有序地按位移出到IO口,此時把RS485芯片置為接收。還正在移位的數據就嗝屁了。

因此,

  1. 一定要搞清楚選用的中斷是發送完成中斷還是緩存器空的中斷;
  2. 在發送中斷中,不能立即切為接收,應當延時一段時間,我現在的做法是不管三七二十一,在發送中斷中,如果判斷為最後一個byte,則延時1.7ms將RS485設置為接收;
  3. 不應該啟動定時器進行延時,定時器資源很寶貴,應該在100us左右的定時器中斷中,通過變量計數來進行1.7ms左右的延時;

MODBUS從設備多少時間會應答

Modbus是問答式的通信,主設備發送完數據之後,從設備會做出響應。

按照Modbus協議規定,從設備3.5個字符時間之後做出響應都是合法的。

不同的傳感器應答響應時間各不相同。

有些差的傳感器可能到幾十ms才響應,有些3.5ms左右就立即響應了。

有些甚至沒有按照Modbus的協議出牌,還沒有到3.5ms左右的時間就響應了。

這就要求主設備在將RS485接收使能之後,立即進行接收狀態。

如果是用串口中斷進行接收,則應該注意在主程序中是否有關中斷的操作,關中斷的操作是否影響接收。

每一個串口數據之間的時間間隔

Modbus根據數據之間的時間間隔來判斷一楨消息的結束,需要保證一楨消息內的前後數據之間的間隔不超過3.5個字符。

而數據一般在發送中斷中發送,有些人為了保證數據完整性,保證數據訪問的互斥,很喜歡關中斷來保護現場。

這種做法一不小心就會使發送兩個數據的間隔超過3.5個字符。

特別是當波特率比較高時,更容易出現這種情況。

比如,當波特率為38400時,3.5 個字符僅為850us左右,在發送串口數據的時間內,中斷關閉850us,Modbus通信就嗝屁了。

如果MCU支持DMA,建議使用DMA+定時器進行數據收發。

作為Modbus從設備時,收到數據之後,多少時間應答

按照Modbus協議要求,3.5個字符之後就可以應答。

有些Modbus主設備可以是為了保證實時性,對這個應答時間要求比較苛刻。

比如我們前一段時間跟西門子的工控屏對接時,就碰到過這樣的問題,

總線的波特率為19200bps,我們的設備在收到西門子的命令之後大概在5ms左右做出了應答。

但是西門子工控屏卻判為錯誤。

之後,我們將應答時間縮短到2ms左右,與西門子的通信才變得正常(這個問題接下來還會再深入研究,可能還有其它原因)。

建議在3.5個字符之後,立即應答。


分享到:


相關文章: