1. 程式人生 > >freeModbus程式碼解讀及移植筆記

freeModbus程式碼解讀及移植筆記

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

                freeModbus的程式碼庫還是很好用的,本人在wince和C8051F410下均移植成功(只用到RTU模式)。但freeModbus提供的文件比較少,只能對照著Modbus協議一點點試著讀懂原始碼。下面是閱讀程式碼期間的跟蹤筆記:

  1、eMBErrorCode為列舉型別變數,代表錯誤碼,共有8個錯誤代號。常用的是MB_ENOERR,即沒有錯誤。

  2、eMBMode列舉型別變數代表裝置的工作模式,分別是MB_RTU、MB_ASCII和MB_TCP。

  3、eMBEventType列舉型別變數定義了event的型別,分別是EV_READY,代表Startup啟動完成;EV_FRAME_RECEIVED代表接收到幀;EV_EXECUTE代表執行功能函式;EV_FRAME_SENT代表幀已傳送。

  4、eMBParity列舉型別變數代表奇偶校驗選項,分別是MB_PAR_NONE無校驗,MB_PAR_ODD奇校驗,和MB_PAR_EVEN偶校驗。

  5、mb.c檔案中的靜態變數ucMBAddress儲存裝置地址,此變數在eMBInit函式中初始化。

  6、在C51Modbus中將freeModbus庫中的 原始碼
進行了更改,例如儘量不使用函式指標,而是直接呼叫相關功能函式,根據eMBCurrentMode中的工作模式,來判斷呼叫哪個函式。在freeModbus庫中某些函式宣告前加上reentrant,這是Keil編譯器特有的關鍵詞。這樣做帶來的一個不足是:不能動態繫結函式,從而導致庫程式碼失去可移植性。這樣做是C51編譯器與ANSI標準不相容的特殊性導致的。

  7、ENTER_CRITICAL_SECTION()和EXIT_CRITICAL_SECTION()巨集,實際上就是關閉和開啟全域性中斷。

  8、帶xMBPort字首的函式都屬於port layer層,也就是獨立於ModBus協議棧。

  9、freeModbus庫中函式名稱的第一個字母表示返回值型別,例如e表示返回enum列舉型別;v表示void無返回值;x表示BOOL布林型別。注意這條規則並不是總成立,但主要函式基本上還是符合此規則的。第一個字母后的MB代表是屬於ModBus協議棧的函式。

  10、port.h檔案中巨集#define F_MCU 定義了微控制器的工作頻率。需要用其值計算Uart0定時器和Tick定時器的重灌入值。

  11、在程式主函式main中,使用協議棧的方法是:

  eStatus = eMBInit( MB_RTU, 0x0A, 0, 9600, MB_PAR_EVEN );

  /* Enable the Modbus Protocol Stack. */

  eStatus = eMBEnable( );

  for( ;; )

  {

  ( void )eMBPoll( );

  ……

  }

  12、在port layer層的xMBPortSerialInit函式中,需要根據傳入的波特率、奇偶校驗、資料位長度設定來配置Uart0及其使用的定時器。

  13、在port layer層的vMBPortSerialEnable函式中配置接收和傳送使能,由於在微控制器的暫存器SCON0中只有接收使能控制位REN0,而沒有傳送使能控制位,所以在portserial.c檔案中又定義了一個TxEnable變數,用來表示傳送的使能狀態。若同時關閉接收和傳送,則要關閉Uart0中斷,即讓ES0 = 0。

  14、eMBRTUInit函式中的變數usTimerT35_50us代表如果50us進行一次Tick的話,T35超時的Tick次數。這個公式很重要:

  usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );

  函式xMBPortTimersInit要以變數usTimerT35_50us為傳入引數,對T35超時定時器進行設定。

  15、在mbrtu.c檔案中定義了兩個狀態變數,一個是接收狀態變數eRcvState,為eMBRcvState列舉型別,有4個狀態,在使能ModBus協議棧後賦予STATE_RX_INIT,即初始狀態;另一個是傳送狀態變數eSndState,為eMBSndState列舉型別,有兩個狀態,初始化為傳送idle狀態,即STATE_TX_IDLE。

  16、mb.c檔案中的eMBState狀態變數為列舉型別,代表裝置的工作狀態,有3種狀態,分別是“未初始化”、 “使能”和“禁止”狀態。呼叫完eMBInit 函式後要呼叫eMBEnable函式來使能ModBus協議棧,在其中將eMBState狀態變數從“未初始化狀態”變為“使能狀態”,然後使能串列埠和開啟T35定時器。

  17、如果T35定時器超時併產生中斷,則要呼叫xMBRTUTimerT35Expired函式,其內部是一個狀態機轉換的switch,根據當前接收狀態來通過xMBPortEventPost傳送事件通知,然後關閉T35定時器,並將當前接收狀態設定為STATE_RX_IDLE。

  18、eMBException列舉型變量表示Exception的型別,共有10種Exception,在ModBus協議中有定義。

  19、在eMBPoll( )中,首先通過xMBPortEventGet函式取event,如果沒有則退出,若有event的話便根據event型別進行相應處理。EV_READY是在協議棧初始化後xMBRTUTimerT35Expired函式發出來的,表示startup完成;EV_FRAME_RECEIVED是xMBRTUTimerT35Expired函式在T35超時後發出的,表示已經收到了一幀,需要進行成幀處理,呼叫eMBRTUReceive函式;EV_EXECUTE是在處理EV_FRAME_RECEIVED過程中最後一步,如果此幀的地址符合本機地址,則發出EV_EXECUTE事件,進行應用層的處理。

  20、在eMBRTUReceive函式中首先檢視幀大小是否符合要求,然後進行CRC校驗。此函式的原型是:

  eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )

  第一個引數是為了返回幀中的地址,也就是幀中第一個位元組;第二個傳入的引數以後要當做陣列來使用,所以用了指標的指標型別;第三個引數表示PDU的長度,也就是幀中除去地址位元組和CRC校驗位元組後的長度。

  21、在eMBPoll( )中處理EV_EXECUTE事件,首先從PDU中提取出FunctionCode,然後根據FunctionCode找到相應的處理函式。xMBFunctionHandler結構體型別變數xFuncHandlers中定義了各個FunctionCode對應的處理函式pxHandler,函式的第一個引數ucMBFrame是PDU的儲存地址,第二個引數usLength返回PDU的長度。如果幀不是一個廣播幀,則需要裝置發出一個回覆,如果前面有錯誤發生,則要回復一個錯誤報告幀。

  22、在Keil中程式需要使用大模式編譯,否則會出現error c249: 'data': segment too large的錯誤。

  23、若使用波特率為9600,則 t3.5= ( 11 * 3.5 ) / 9600 = 4.01 ms。 不能使用8位模式的Timer,因為11.0590MHz主頻在最大48分頻後,最長的超時時間為1.11ms,不能滿足T35的超時要求。


24、freeModbus 1.5庫,在使用過程中發現了一個bug,即如果在PDU中傳送的暫存器資料長度與要讀寫的暫存器的數量不符,只要CRC校驗正確,freeModbus便不會檢測出來。例如寫多個暫存器命令中,標明寫暫存器的數量為2,也就是後面接的資料長度為4,但隨後的資料只為2個位元組,即一個暫存器的資料,freeModbus不會發現此錯誤,同時會將後面的CRC校驗值認作是寫第二個暫存器的資料。這個bug實際上是通過Modbus除錯精靈1.024的一個寫多暫存器bug發現的。

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述