1. 程式人生 > 實用技巧 >關於freemodbus協議中eMBFuncReadHoldingRegister()函式的所謂錯誤

關於freemodbus協議中eMBFuncReadHoldingRegister()函式的所謂錯誤

摘要:網上看到有好心的網友提示,freemodbus協議中的mbfuncholding.c 檔案中eMBFuncReadHoldingRegister()函式,有一處錯誤,即:第185行的“usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );”應為“usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );”,我認為這不能算是一個錯誤,且聽我的分析。

關鍵詞:freemodbus Modbus 保持暫存器 eMBFuncReadHoldingRegister

1.關於freemodbus協議棧的一點粗淺體會

Modbus通訊協議,搞過工業控制的人,多多少少應該瞭解一點。其結構簡單,應用廣泛。幾乎是很多PLC的標配介面。但其通訊規約也有幾十頁之多,要在微控制器上實現,如果自己寫原始碼,估計還是需要一些時間的,因為不光要實現常用的功能,還要保持協議的完整性和錯誤處理機制。

freemodbus是一個比較完整的協議棧,有機構在維護,並且開源。有點微控制器基礎得朋友,1個小時應該可以移植好(前提能參考一個不錯的教程)。比自己擼程式碼快N倍。個人感覺這個協議棧還是很好用的,但免費的只支援從站,需要做主站就要自己再想辦法了。

2.為什麼說這不算個錯誤

首先要看這句程式碼是幹什麼用的?上下文如下:

usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );

usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );

usRegAddress++;

usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );

usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );

pucFrame[MB_PDU_FUNC_READ_ADDR_OFF]儲存的是Modbus資料幀中暫存器起始地址的高位元組,pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] 儲存的是Modbus資料幀中暫存器起始地址的低位元組,pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] 儲存的是Modbus資料幀中暫存器個數的高位元組,pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] 儲存的是Modbus資料幀中暫存器個數的低位元組。

下面給一個例項,能更好理解,如圖1。此幀資料是讀取地址為1的從站的保持暫存器,暫存器起始地址為:18430(0x47FE),讀取暫存器的個數為:101(0x0065),在這裡:

pucFrame[MB_PDU_FUNC_READ_ADDR_OFF]的值為:0x47;

pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] 的值為:0xFE;

pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] 的值為:0x00;

pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] 的值為:0x65。

從這裡也可以看出,Modbus在傳送一個word(16bit)資料的時候,是高位元組在前,低位元組在後。

圖1

既然pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] 表示的是暫存器個數的高位元組,那麼我們來檢視一下Modbus協議,看一下這個引數的範圍,如圖2、圖3所示。此兩圖是從Modbus協議文字中截出來的,0x03功能碼是讀保持暫存器,0x10功能碼是寫多個保持暫存器,這兩個功能碼會涉及到保持暫存器數量的問題,暫存器數量的範圍一個是0x7D,一個是0x78,都在一個位元組的範圍內,因此,暫存器數量這個引數的高位元組始終為0,也就是說pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF]是等於0的,可以不處理。

圖2

圖3

3.總結及討論

綜上,我認為這個不能算是個錯誤,不影響程式的正常結果,只是寫法不夠嚴謹。但有一個極端情況,是有影響的,Modbus主站讀寫暫存器的數量超過協議規定的數量的時候,本應該返回錯誤碼,但這種寫法由於只處理了低位元組,就有可能認為沒有錯誤,而對資料進行處理。為了安全起見,大家還是把這句程式碼改掉吧,改為“usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );”,以防止極端情況的發生。

還有一個問題,Modbus協議規定的讀寫保持暫存器的數量都在一個位元組的範圍內,傳送資料的時候為什麼要用2個位元組來表示暫存器數量,這個還沒有做深入研究,可能是考慮協議的整體相容性吧,有興趣的朋友可以一起討論。

文章在微信公眾號同步推出,微信公眾號:孔丙火,關注欣賞更多文章。