新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > freeModbus代碼解讀及移植筆記

freeModbus代碼解讀及移植筆記

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

  1、eMBErrorCode為枚舉類型變量,代表錯(cuò)誤碼,共有8個(gè)錯(cuò)誤代號(hào)。常用的是MB_ENOERR,即沒有錯(cuò)誤。

本文引用地址:http://m.butianyuan.cn/article/201611/323738.htm

  2、eMBMode枚舉類型變量代表設(shè)備的工作模式,分別是MB_RTU、MB_ASCII和MB_TCP。

  3、eMBEventType枚舉類型變量定義了event的類型,分別是EV_READY,代表Startup啟動(dòng)完成;EV_FRAME_RECEIVED代表接收到幀;EV_EXECUTE代表執(zhí)行功能函數(shù);EV_FRAME_SENT代表幀已發(fā)送。

  4、eMBParity枚舉類型變量代表奇偶校驗(yàn)選項(xiàng),分別是MB_PAR_NONE無(wú)校驗(yàn),MB_PAR_ODD奇校驗(yàn),和MB_PAR_EVEN偶校驗(yàn)。

  5、mb.c文件中的靜態(tài)變量ucMBAddress存儲(chǔ)設(shè)備地址,此變量在eMBInit函數(shù)中初始化。

  6、在C51Modbus中將freeModbus庫(kù)中的源碼進(jìn)行了更改,例如盡量不使用函數(shù)指針,而是直接調(diào)用相關(guān)功能函數(shù),根據(jù)eMBCurrentMode中的工作模式,來(lái)判斷調(diào)用哪個(gè)函數(shù)。在freeModbus庫(kù)中某些函數(shù)聲明前加上reentrant,這是Keil編譯器特有的關(guān)鍵詞。這樣做帶來(lái)的一個(gè)不足是:不能動(dòng)態(tài)綁定函數(shù),從而導(dǎo)致庫(kù)代碼失去可移植性。這樣做是C51編譯器與ANSI標(biāo)準(zhǔn)不兼容的特殊性導(dǎo)致的。

  7、ENTER_CRITICAL_SECTION()和EXIT_CRITICAL_SECTION()宏,實(shí)際上就是關(guān)閉和打開全局中斷。

  8、帶xMBPort前綴的函數(shù)都屬于port layer層,也就是獨(dú)立于ModBus協(xié)議棧。

  9、freeModbus庫(kù)中函數(shù)名稱的第一個(gè)字母表示返回值類型,例如e表示返回enum枚舉類型;v表示void無(wú)返回值;x表示BOOL布爾類型。注意這條規(guī)則并不是總成立,但主要函數(shù)基本上還是符合此規(guī)則的。第一個(gè)字母后的MB代表是屬于ModBus協(xié)議棧的函數(shù)。

  10、port.h文件中宏#define F_MCU 定義了單片機(jī)的工作頻率。需要用其值計(jì)算Uart0定時(shí)器和Tick定時(shí)器的重裝入值。

  11、在程序主函數(shù)main中,使用協(xié)議棧的方法是:

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

  /* Enable the Modbus Protocol Stack. */

  eStatus = eMBEnable( );

  for( ;; )

  {

  ( void )eMBPoll( );

  ……

  }

  12、在port layer層的xMBPortSerialInit函數(shù)中,需要根據(jù)傳入的波特率、奇偶校驗(yàn)、數(shù)據(jù)位長(zhǎng)度設(shè)置來(lái)配置Uart0及其使用的定時(shí)器。

  13、在port layer層的vMBPortSerialEnable函數(shù)中配置接收和發(fā)送使能,由于在單片機(jī)的寄存器SCON0中只有接收使能控制位REN0,而沒有發(fā)送使能控制位,所以在portserial.c文件中又定義了一個(gè)TxEnable變量,用來(lái)表示發(fā)送的使能狀態(tài)。若同時(shí)關(guān)閉接收和發(fā)送,則要關(guān)閉Uart0中斷,即讓ES0 = 0。

  14、eMBRTUInit函數(shù)中的變量usTimerT35_50us代表如果50us進(jìn)行一次Tick的話,T35超時(shí)的Tick次數(shù)。這個(gè)公式很重要:

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

  函數(shù)xMBPortTimersInit要以變量usTimerT35_50us為傳入?yún)?shù),對(duì)T35超時(shí)定時(shí)器進(jìn)行設(shè)置。

  15、在mbrtu.c文件中定義了兩個(gè)狀態(tài)變量,一個(gè)是接收狀態(tài)變量eRcvState,為eMBRcvState枚舉類型,有4個(gè)狀態(tài),在使能ModBus協(xié)議棧后賦予STATE_RX_INIT,即初始狀態(tài);另一個(gè)是發(fā)送狀態(tài)變量eSndState,為eMBSndState枚舉類型,有兩個(gè)狀態(tài),初始化為發(fā)送idle狀態(tài),即STATE_TX_IDLE。

  16、mb.c文件中的eMBState狀態(tài)變量為枚舉類型,代表設(shè)備的工作狀態(tài),有3種狀態(tài),分別是“未初始化”、 “使能”和“禁止”狀態(tài)。調(diào)用完eMBInit 函數(shù)后要調(diào)用eMBEnable函數(shù)來(lái)使能ModBus協(xié)議棧,在其中將eMBState狀態(tài)變量從“未初始化狀態(tài)”變?yōu)?ldquo;使能狀態(tài)”,然后使能串口和打開T35定時(shí)器。

  17、如果T35定時(shí)器超時(shí)并產(chǎn)生中斷,則要調(diào)用xMBRTUTimerT35Expired函數(shù),其內(nèi)部是一個(gè)狀態(tài)機(jī)轉(zhuǎn)換的switch,根據(jù)當(dāng)前接收狀態(tài)來(lái)通過(guò)xMBPortEventPost發(fā)送事件通知,然后關(guān)閉T35定時(shí)器,并將當(dāng)前接收狀態(tài)設(shè)置為STATE_RX_IDLE。

  18、eMBException枚舉型變量表示Exception的類型,共有10種Exception,在ModBus協(xié)議中有定義。

  19、在eMBPoll( )中,首先通過(guò)xMBPortEventGet函數(shù)取event,如果沒有則退出,若有event的話便根據(jù)event類型進(jìn)行相應(yīng)處理。EV_READY是在協(xié)議棧初始化后xMBRTUTimerT35Expired函數(shù)發(fā)出來(lái)的,表示startup完成;EV_FRAME_RECEIVED是xMBRTUTimerT35Expired函數(shù)在T35超時(shí)后發(fā)出的,表示已經(jīng)收到了一幀,需要進(jìn)行成幀處理,調(diào)用eMBRTUReceive函數(shù);EV_EXECUTE是在處理EV_FRAME_RECEIVED過(guò)程中最后一步,如果此幀的地址符合本機(jī)地址,則發(fā)出EV_EXECUTE事件,進(jìn)行應(yīng)用層的處理。

  20、在eMBRTUReceive函數(shù)中首先查看幀大小是否符合要求,然后進(jìn)行CRC校驗(yàn)。此函數(shù)的原型是:

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

  第一個(gè)參數(shù)是為了返回幀中的地址,也就是幀中第一個(gè)字節(jié);第二個(gè)傳入的參數(shù)以后要當(dāng)做數(shù)組來(lái)使用,所以用了指針的指針類型;第三個(gè)參數(shù)表示PDU的長(zhǎng)度,也就是幀中除去地址字節(jié)和CRC校驗(yàn)字節(jié)后的長(zhǎng)度。

  21、在eMBPoll( )中處理EV_EXECUTE事件,首先從PDU中提取出FunctionCode,然后根據(jù)FunctionCode找到相應(yīng)的處理函數(shù)。xMBFunctionHandler結(jié)構(gòu)體類型變量xFuncHandlers中定義了各個(gè)FunctionCode對(duì)應(yīng)的處理函數(shù)pxHandler,函數(shù)的第一個(gè)參數(shù)ucMBFrame是PDU的存儲(chǔ)地址,第二個(gè)參數(shù)usLength返回PDU的長(zhǎng)度。如果幀不是一個(gè)廣播幀,則需要設(shè)備發(fā)出一個(gè)回復(fù),如果前面有錯(cuò)誤發(fā)生,則要回復(fù)一個(gè)錯(cuò)誤報(bào)告幀。

  22、在Keil中程序需要使用大模式編譯,否則會(huì)出現(xiàn)error c249: data: segment too large的錯(cuò)誤。

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



關(guān)鍵詞: freeModbus代碼解讀移植筆

評(píng)論


技術(shù)專區(qū)

關(guān)閉