新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > freeModbus代碼解讀及移植筆記

        freeModbus代碼解讀及移植筆記

        作者: 時間:2016-11-30 來源:網絡 收藏
        freeModbus的代碼庫還是很好用的,本人在wince和C8051F410下均移植成功(只用到RTU模式)。但freeModbus提供的文檔比較少,只能對照著Modbus協議一點點試著讀懂源代碼。下面是閱讀代碼期間的跟蹤筆記:

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

        本文引用地址:http://www.104case.com/article/201611/323738.htm

          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的超時要求。



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 连云港市| 青铜峡市| 江山市| 灌阳县| 海南省| 潍坊市| 江北区| 嘉禾县| 怀宁县| 子长县| 浦县| 岑巩县| 开化县| 新野县| 南召县| 桦川县| 镇雄县| 景洪市| 临西县| 鸡泽县| 奉贤区| 莱西市| 上蔡县| 许昌县| 于都县| 望江县| 大名县| 彭阳县| 武胜县| 天全县| 西峡县| 马公市| 柳州市| 宁都县| 南投县| 光山县| 石河子市| 许昌市| 绿春县| 图们市| 南澳县|