1、FreeModbus簡介
FreeModbus是一款開源的Modbus協議棧,但是只有從機開源,主機源碼是需要收費的。同時網上也沒有發現比較好的開源的Modbus主機協議棧,所以才開發這款支持主機模式的FreeModbus協議棧。本版FreeModbus版本號更改為V1.6,特性如下:
- 新增加的主機源碼與原有從機的風格及接口保持一致;
- 支持主機與從機在同一協議棧運行;
- 支持實時操作系統及裸機移植;
- 為應用提供多種請求模式,用戶可以選擇阻塞還是非阻塞模式,自定義超時時間等,方便應用層靈活調用;
- 支持所有常用的Modbus方法。
1.1、文件結構
源文件 | 描述 |
---|---|
FreeModbus\modbus\mb.c | 給應用層提供Modbus從機設置及輪詢相關接口 |
FreeModbus\modbus\mb_m.c | 給應用層提供Modbus主機設置及輪詢相關接口 |
FreeModbus\modbus\functions\mbfunccoils.c | 從機線圈相關功能 |
FreeModbus\modbus\functions\mbfunccoils_m.c | 主機線圈相關功能 |
FreeModbus\modbus\functions\mbfuncdisc.c | 從機離散輸入相關功能 |
FreeModbus\modbus\functions\mbfuncdisc_m.c | 主機離散輸入相關功能 |
FreeModbus\modbus\functions\mbfuncholding.c | 從機保持寄存器相關功能 |
FreeModbus\modbus\functions\mbfuncholding_m.c | 主機保持寄存器相關功能 |
FreeModbus\modbus\functions\mbfuncinput.c | 從機輸入寄存器相關功能 |
FreeModbus\modbus\functions\mbfuncinput_m.c | 主機輸入寄存器相關功能 |
FreeModbus\modbus\functions\mbfuncother.c | 其余Modbus功能 |
FreeModbus\modbus\functions\mbutils.c | 一些協議棧中需要用到的小工具 |
FreeModbus\modbus\ascii\mbascii.c | ASCII模式設置及其狀態機 |
FreeModbus\modbus\rtu\mbcrc.c | CRC校驗功能 |
FreeModbus\modbus\rtu\mbrtu.c | 從機RTU模式設置及其狀態機 |
FreeModbus\modbus\rtu\mbrtu_m.c | 主機RTU模式設置及其狀態機 |
FreeModbus\modbus\tcp\mbtcp.c | TCP模式設置及其狀態機 |
FreeModbus\port\port.c | 實現硬件移植部分接口 |
FreeModbus\port\portevent.c | 實現從機事件移植接口 |
FreeModbus\port\portevent_m.c | 實現主機事件及錯誤處理移植接口 |
FreeModbus\port\portserial.c | 從機串口移植 |
FreeModbus\port\portserial_m.c | 主機串口移植 |
FreeModbus\port\porttimer.c | 從機定時器移植 |
FreeModbus\port\porttimer_m.c | 主機定時器移植 |
FreeModbus\port\user_mb_app.c | 定義從機數據緩沖區,實現從機Modbus功能的回調接口 |
FreeModbus\port\user_mb_app_m.c | 定義主機數據緩沖區,實現主機Modbus功能的回調接口 |
注:所有帶_m后綴的文件為主機模式下必須使用的文件,如使用從機模式則無需這些文件。
對於協議棧的移植主要包括兩個方面,硬件及軟件。用戶需要根據自己的需求進行自行選擇。
注:以下所有說明都主要針對Modbus主機模式進行介紹。
2.1、軟件接口(portevent)
軟件方面支持基於裸機及實時操作系統的移植;支持單個主機與單個從機同時獨立運行。另外用戶也可以修改協議棧的事件回調接口,使主機請求的接口采用阻塞及非阻塞模式;主機資源等待方面,用戶也可以設置等待超時時間等等,諸多功能將會一一介紹。
2.1.1、操作系統與裸機
對於操作系統與裸機目前協議棧都是支持的,但個人更加推薦采用實時操作系統,因為這樣會使得接口調用及接口移植變得更加簡單。目前移植完成的操作系統包括RT-Thread 、 UCOS 及 FreeRTOS等。
操作系統與裸機移植的過程中涉及的文件為FreeModbus\port\portevent_m.c
該文件主要有以下需要用戶移植的接口:
接口 | 功能描述 |
---|---|
xMBMasterPortEventInit | 主機事件初始化 |
xMBMasterPortEventPost | 主機發送事件 |
xMBMasterPortEventGet | 主機獲取事件 |
vMBMasterOsResInit | 主機操作系統資源初始化 |
xMBMasterRunResTake | 主機資源獲取 |
vMBMasterRunResRelease | 主機資源釋放 |
vMBMasterErrorCBRespondTimeout | 主機響應超時回調接口 |
vMBMasterErrorCBReceiveData | 主機接收數據出錯回調接口 |
vMBMasterErrorCBExecuteFunction | 主機執行Modbus方法出錯回調接口 |
vMBMasterCBRequestScuuess | 主機請求執行成功回調接口 |
eMBMasterWaitRequestFinish | 主機等待請求完成處理回調接口 |
在基於操作系統移植時,主要用到操作系統線程同步方面的技術,Modbus 協議棧自身需要使用操作系統自帶的事件機制來實現事件的發送通知與等待獲取,同時用戶請求 Modbus 功能的線程與 Modbus 協議棧自身線程(Modbus Poll 線程)需要通過事件機制實現兩個線程的同步;主機協議棧還需要一個主機資源占用的信號量,初始化默認為1,采用信號量保證了多線程同時發送主機請求時,只有一個線程可以使用主機。
在基於裸機移植時,需要通過軟件模擬方式實現事件通知機制,事件等待及資源等待都得采用用戶自定義延時及標志變量來實現,實現起來比操作系統模式下的線程同步機制要復雜很多。
2.1.2、數據緩沖區(user_mb_app_m)
數據緩沖區定義的位置位於 FreeModbus\port\user_mb_app_m.c
文件頂部,共計4種數據類型。 FreeModbus從機默認使用 一維數組 作為緩存區數據結構,主機可以存儲所有網內從機的數據,所以主機采用 二維數組 對所有從機節點數據進行存儲。二維數組的列號代表寄存器、線圈及離散量地址,行號代表從機節點ID,但需要做減一處理,例如usMRegHoldBuf[2][1]
代表從機ID為 3,保持寄存器地址為 1 的從機數據。
2.1.3、Modbus數據處理回調接口
Modbus 一共有4種不同的數據類型,所有的 Modbus 功能都圍繞這些數據類型進行操作。由於不同的用戶數據緩沖區結構可能有所不同,那么對應的 Modbus 數據處理方式也就存在差異,所以用戶需要把每種數據類型對應的操作,按照自己的數據緩沖區結構進行定制實現。 所有的 Modbus 數據處理回調接口如下:
接口 | 功能描述 |
---|---|
eMBMasterRegInputCB | 輸入寄存器回調接口 |
eMBMasterRegHoldingCB | 保持寄存器回調接口 |
eMBMasterRegCoilsCB | 線圈回調接口 |
eMBMasterRegDiscreteCB | 離散輸入回調接口 |
對於數組形式的數據緩沖區結構,源碼中已經做好了移植,直接使用即可。也可以使用 EasyDataManager 庫,采用鏈表作為緩沖區,該庫還支持事件驅動,做到數據變化自動通知應用層。
2.2、硬件接口(portserial、porttimer)
移植 FreeModbus 協議棧主機部分時,在硬件方面需要修改串口及定時器配置,文件位於port文件下,用戶需要根據自己的CPU進行移植修改。
注:協議棧默認自帶STM32F103X移植文件,用戶可以參考移植
這里提一下基於操作系統設備驅動框架的移植,后期協議棧會增加對 RT-Thread 自帶設備驅動框架的移植,只要是 RT-Thread 的 BSP 支持的 MCU,用戶都無需考慮底層的移植過程,減低移植成本。
2.2.1、串口
涉及到串口的移植文件位於FreeModbus\port\portserial_m.c
,在這個文件中用戶需要對以下接口方法進行修改
接口 | 功能描述 |
---|---|
vMBMasterPortSerialEnable | 使能和失能串口的發送及接收功能,如使用485總線,需要注意收發模式切換 |
vMBMasterPortClose | 關閉串口 |
xMBMasterPortSerialInit | 串口初始化,如果使用485,收發模式切換引腳也要在此初始化 |
xMBMasterPortSerialPutByte | 串口發送單字節數據 |
xMBMasterPortSerialGetByte | 串口接收單字節數據 |
prvvUARTTxReadyISR | 串口發送完成中斷服務程序接口,按照默認方式,直接引用pxMBMasterFrameCBTransmitterEmpty 方法即可 |
prvvUARTRxISR | 串口接收中斷服務程序接口,按照默認方式,直接引用pxMBMasterFrameCBByteReceived 方法即可 |
還需要在文件末尾增加 CPU 的自帶的串口服務程序,將上表中的發送及接收中斷程序接口,放到對應的中斷服務程序中去即可。
2.2.2、定時器
涉及到定時器的移植文件位於FreeModbus\port\porttimer_m.c
,在這個文件中用戶需要對以下接口方法進行修改
接口 | 功能描述 |
---|---|
xMBMasterPortTimersInit | 定時器初始化,將定時器預分頻數及T3.5時間計數值分別備份到usPrescalerValue 及usT35TimeOut50us |
vMBMasterPortTimersT35Enable | 設置定時器按照T3.5時間開始計數 |
vMBMasterPortTimersConvertDelayEnable | 設置定時器按照廣播幀的轉換延時時間開始計數 |
vMBMasterPortTimersRespondTimeoutEnable | 設置定時器按照響應超時時間開始計數 |
vMBMasterPortTimersDisable | 失能定時器,定時器將停止計數 |
prvvTIMERExpiredISR | 定時器中斷服務程序接口,按照默認方式,直接引用pxMBMasterPortCBTimerExpired 方法即可 |
注: 1、
usPrescalerValue
及usT35TimeOut50us
在文件頂部有定義2、轉換延時時間及響應超時時間在
FreeModbus\modbus\include\mbconfig.h
,用戶可以根據自己系統的特點自行設置。
除上面接口方法外,用戶需要在文件末尾增加 CPU 的自帶的定時器中斷服務程序,將上表中的定時器中斷服務程序接口放進去。
Modbus 主機使用過程中與從機有很大不同,從機是需要被動等待主機請求,而主機則是主動發出請求,並接收處理從機響應。在主機發送廣播請求的時候,從機不需要返回響應,所以廣播請求適合主機的寫從機數據命令,不適合讀從機數據命令。 主機請求API中的所有方法的返回值格式都相同,返回值意義如下。
返回值 | 描述 |
---|---|
MB_MRE_NO_ERR | 正常,沒錯誤 |
MB_MRE_NO_REG | 寄存器、線圈或離散輸入地址出錯 |
MB_MRE_ILL_ARG | 入參格式有誤 |
MB_MRE_REV_DATA | 接收數據出錯 |
MB_MRE_TIMEDOUT | 響應超時。主機在設定的時間內未收到從機響應。 |
MB_MRE_MASTER_BUSY | 主機忙。在設定的時間內,沒有請求沒有被發送。 |
MB_MRE_EXE_FUN | 主機收到響應后,執行Modbus方法(功能)出錯。 |
所有的主機請求方法都是 線程安全 的也是 阻塞模式 的。在使用過程中,只要在設定的超時時間內沒有得到主機資源,就會返回主機忙;如果在設定的超時時間內得到主機資源,那么必須等待得到請求結果后才會返回。
3.1、寫單個保持寄存器
往從機某個保持寄存器中寫入數據:
eMBMasterReqErrCode eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr,USHORT usRegData,LONG lTimeOut );
ucSndAddr:請求的從機地址,0代表廣播
usRegAddr:寫寄存器的地址
usRegData:寫寄存器的數據
lTimeOut:請求超時時間。支持永久等待,使用操作系統的永久等待參數即可。
3.2、寫多個保持寄存器
往從機多個保持寄存器中寫入數據:
eMBMasterReqErrCode eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,USHORT usRegAddr,USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut );
ucSndAddr:請求的從機地址,0代表廣播。
usRegAddr:寫寄存器的起始地址
usNRegs:寫寄存器的總數
pusDataBuffer:寫寄存器的數據
lTimeOut:請求超時時間。支持永久等待,使用操作系統的永久等待參數即可。
讀取多個保持寄存器中的數據:
eMBMasterReqErrCode eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr,USHORT usNRegs,LONG lTimeOut );
ucSndAddr:請求的從機地址,0代表廣播。
usRegAddr:讀寄存器的地址
usRegData:讀寄存器的數量
lTimeOut:請求超時時間。支持永久等待,使用操作系統的永久等待參數即可。
3.4、讀寫多個保持寄存器
先讀多個寄存器,然后再寫多個寄存器:
eMBMasterReqErrCode eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,USHORT usReadRegAddr,USHORT usNReadRegs,USHORT * pusDataBuffer,USHORT usWriteRegAddr, USHORT usNWriteRegs,LONG lTimeOut );
ucSndAddr:請求的從機地址,0代表廣播。
usReadRegAddr:讀寄存器的地址
usNReadRegs:讀寄存器的數量
pusDataBuffer:寫寄存器的數據
usWriteRegAddr:寫寄存器的地址
usNWriteRegs:寫寄存器的數量
lTimeOut:請求超時時間。支持永久等待,使用操作系統的永久等待參數即可。
3.5、讀多個輸入寄存器
讀取多個輸入寄存器中的數據:
eMBMasterReqErrCode eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr,USHORT usNRegs,LONG lTimeOut );
ucSndAddr:請求的從機地址,0代表廣播。
usRegAddr:讀寄存器的地址
usRegData:讀寄存器的數量
lTimeOut:請求超時時間。支持永久等待,使用操作系統的永久等待參數即可。
3.6、寫單個線圈
往從機某個線圈中寫入數據:
eMBMasterReqErrCode eMBMasterReqWriteCoil( UCHAR ucSndAddr,USHORT usCoilAddr,USHORT usCoilData,LONG lTimeOut );
ucSndAddr:請求的從機地址,0代表廣播。
usCoilAddr:寫線圈的地址
usCoilData:寫線圈的數量
lTimeOut:請求超時時間。支持永久等待,使用操作系統的永久等待參數即可。
3.7、寫多個線圈
往從機多個線圈中寫入數據:
eMBMasterReqErrCode eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,USHORT usCoilAddr,USHORT usNCoils,UCHAR * pucDataBuffer,LONG lTimeOut)
ucSndAddr:請求的從機地址,0代表廣播。
usCoilAddr:寫線圈的起始地址
usNCoils:寫線圈的總數
pucDataBuffer:寫線圈的數據
lTimeOut:請求超時時間。支持永久等待,使用操作系統的永久等待參數即可。
3.8、讀多個線圈
讀取多個線圈中的數據:
eMBMasterReqErrCode eMBMasterReqReadCoils( UCHAR ucSndAddr,USHORT usCoilAddr,USHORT usNCoils ,LONG lTimeOut )
ucSndAddr:請求的從機地址,0代表廣播。
usCoilAddr:讀線圈的地址
usNCoils:讀線圈的數量
lTimeOut:請求超時時間。支持永久等待,使用操作系統的永久等待參數即
3.9、讀多個離散輸入
讀取多個離散輸入中的數據:
eMBMasterReqErrCode eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr,USHORT usDiscreteAddr,USHORT usNDiscreteIn, LONG lTimeOut )
ucSndAddr:請求的從機地址,0代表廣播。
usDiscreteAddr:讀離散輸入的地址
usNDiscreteIn:讀離散輸入的數量
lTimeOut:請求超時時間。支持永久等待,使用操作系統的永久等待參數即可。
4、使用流程
4.1、初始化配置流程
本協議棧所有配置參數都位於FreeModbus\modbus\include\mbconfig.h
,目前協議棧支持主機及從機兩種模式,並且支持兩種模式同時開啟。從機支持Modbus RTU 、Modbus ASCII 及Modbus TCP 3種模式,主機現在只支持常用的Modbus RTU模式。在使用主機的過程中,用戶需要對廣播的轉換延時時間、命令響應超時時間及從機數量做以配置。需要注意的是,目前協議棧只支持從機地址連續,並且起始地址從1開始。
4.2、正常使用流程
這里只介紹主機的正常使用流程,在使用主機前,需要先把協議棧移植到自己的項目中去,包括上述的軟件及硬件部分,移植完成后的使用流程如下:
(1)調用eMBMasterInit
方法初始化Modbus主機協議棧,主機涉及到的一些硬件就在這個時候做了初始化
(2)調用eMBMasterEnable
方法啟動Modbus主機
(3)通過在線程或者定時器輪詢調用eMBMasterPoll
方法,輪詢周期決定了命令的響應時間。
(4)調用主機請求API方法,設定一定的請求超時時間,直到方法有結果后才會返回。如果方法執行成功並且命令是讀命令,可以通過查看Modbus主機的數據緩沖區,獲取最新從機數據。
4.3、異常處理流程
異常處理主要出現在主機正常使用過程中,所有的主機請求API的錯誤碼都在第三章開頭已經做以描述,針對的這些錯誤碼,用戶需要根據自己的產品特征去完成不同的動作。建議用戶自己封裝實現主機請求方法的重發機制,這樣實現方式比較靈活,一般是在接收到幀數據出錯及命令響應超時的錯誤碼時需要重發,重發次數自動加一,如果重發次數超過設定值則認為從機掉線,以后所有只要是發給這個從機命令都被提前攔截掉;如果第二次重發命令響應成功,則自動清零該從機重發次數。 上述所有功能可以利用主機請求方法或者使用FreeModbus\port\portevent_m.c
中的回調接口來實現,用戶可以根據自己的需求靈活選擇。
基於 BSD 協議,詳細內容請查看 LICENSE 文件。
轉自:https://github.com/armink/FreeModbus_Slave-Master-RTT-STM32