Modbus協(xié)議是一種已廣泛應(yīng)用于當(dāng)今工業(yè)控制領(lǐng)域的通用通訊協(xié)議。通過此協(xié)議,控制器相互之間、或控制器經(jīng)由網(wǎng)絡(luò)(如以太網(wǎng))可以和其它設(shè)備之間進(jìn)行通信。Modbus 協(xié)議使用的是主從通訊技術(shù),即由主設(shè)備主動查詢和操作從設(shè)備。一般將主控設(shè)備方所使用的協(xié)議稱為Modbus Master,從設(shè)備方使用的服務(wù)器協(xié)議稱為Modbus Slave。典型的主設(shè)備包括工控機(jī)和工業(yè)控制器等;典型的從設(shè)備如PLC可編程控制器等。Modbus通訊物理接口可以選用串口(包括RS232和RS485),也可以選擇以太網(wǎng)口。其通信遵循以下的過程:
·主設(shè)備向從設(shè)備發(fā)送請求;
·從設(shè)備分析并處理主設(shè)備的請求,然后向主設(shè)備發(fā)送結(jié)果;
·如果出現(xiàn)任何差錯,從設(shè)備將返回一個異常功能碼。
英創(chuàng)公司提供的ARM9嵌入式主板系列產(chǎn)品,均帶有豐富的串口、網(wǎng)絡(luò)資源、通用GPIO接口等,同時具有強大的處理能力,除了適用于作為Modbus 主設(shè)備的開發(fā)應(yīng)用,還可以作為ModBus從設(shè)備的開發(fā)應(yīng)用。主控協(xié)議軟件在英創(chuàng)的《WinCE下的ModBus主控協(xié)議軟件》一文已有介紹, 在本文中主要介紹基于實現(xiàn)ModBus設(shè)備方協(xié)議的軟件包“WinCE下的ModBus設(shè)備方協(xié)議軟件”(以下簡稱modbusSlave軟件包)。該軟件的是以C函數(shù)加靜態(tài)LIB庫的形式提供給客戶。主要特征如下:
·非常適用于實時的工業(yè)應(yīng)用。
·可以支持基于串口的Modbus協(xié)議應(yīng)用或者基于TCP的Modbus協(xié)議應(yīng)用。
·支持RTU傳輸模式。
·支持大多數(shù)的Modbus功能碼操作,包括對線圈、離散開關(guān)輸入的位操作,以及對寄存器的字節(jié)操作。
·可以獲取通訊中傳輸協(xié)議的錯誤代碼的詳細(xì)信息。
作為ModBus服務(wù)器,無論是基于串口還是基于TCP,在英創(chuàng)提供的modbusSlave軟件包中,實現(xiàn)了對于ModBus應(yīng)用報文的分析與響應(yīng),這只是ModBus通訊的一部分。另一部分是還需要有對應(yīng)用數(shù)據(jù)的訪問,這部分的內(nèi)容則需要用戶自己來進(jìn)行定義,為了方便客戶的使用,在modbusSlave軟件包中通過函數(shù)指針的形式,實現(xiàn)了這些用戶接口函數(shù)的自動加載,將用戶應(yīng)用數(shù)據(jù)處理和ModBus應(yīng)用報文響應(yīng)關(guān)聯(lián)起來。用戶只需根據(jù)需求定義這些接口函數(shù)來實現(xiàn)相應(yīng)的功能,各個函數(shù)具體的定義是通過專門的一個CPP文件:DataProvider.cpp來實現(xiàn)。所以在使用英創(chuàng)的modbusSlave軟件包時,有兩個部分組成,一部分是 modbus_slave.h/ modbus_slave.lib定義的API函數(shù);另一部分是DataProvider.h /DataProvider.cpp定義的用戶數(shù)據(jù)接口函數(shù),其中接口函數(shù)需要用戶在DataProvider.cpp中具體實現(xiàn)。
1、modbusSlave軟件包API函數(shù)
為了方便應(yīng)用程序的使用,對不同的通訊介質(zhì)保持一致的代碼形式,英創(chuàng)所提供的modbusSlave軟件包的API函數(shù)可以同時支持基于串口和TCP的Modbus協(xié)議,應(yīng)用程序只需要在調(diào)用初始化函數(shù)時,用不同參數(shù)區(qū)分即可。以下介紹英創(chuàng)modbusSlave軟件包的相關(guān)API函數(shù),各個函數(shù)的定義如下:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述:通過串口或者網(wǎng)絡(luò)TCP打開ModBus協(xié)議,連接到ModBus設(shè)備。對于串口方式,通過該函數(shù)打開串口,并設(shè)置相應(yīng)串口的通訊參數(shù),以滿足數(shù)據(jù)和控制命令的通訊;對于TCP方式,通過該函數(shù)和ModBus設(shè)備建立基于Socket方式的TCP連接,利用該連接進(jìn)行數(shù)據(jù)和控制命令的通訊。
輸入?yún)?shù) lpPortName:
該參數(shù)為TCHAR類型的字符串,該字符串中包含了啟動ModBus協(xié)議的需要設(shè)置的通訊參數(shù)信息。對于串口模式和TCP兩種模式分別采用不同的格式的字符串。
(1) 串口模式:
字符串必須以COM作為開頭,后面再帶上需要設(shè)置的串口通訊參數(shù)。格式為:
COMIdx:baudRate-dataBits-opBits-parity
其中Idx為串口序號,‘:’ 后為串口通訊參數(shù),各個通訊參數(shù)均用整型數(shù)據(jù)來表示,依次為波特率、數(shù)據(jù)位、停止位、校驗位,校驗位 0-無校驗 1-奇校驗 2-偶校驗。
如COM3作為通訊的協(xié)議口,波特率:9600bps、8為數(shù)據(jù)位、1個停止位、無校驗。其格式如下:
_T( ‘COM3:9600-8-1-0’ );
也可以直接就用 _T( ‘COM3’ )來表示,表明串口所用的為缺省參數(shù):
波特率 9600bps 數(shù)據(jù)位 8 停止位 1 無奇偶校驗。
(2) TCP模式:
字符串以IP地址或者”*”作為開頭,‘:’后為指定TCP連接的特殊端口號,ModBus協(xié)議中缺省端口為502。如果不需要指定特殊端口,可以不帶此參數(shù)。格式如:
_T( ‘192.168.201.178’ )或者_(dá)T(“*”),使用端口號為502;
slaveAddr:
ModBus Slave設(shè)備地址。
timeout:
設(shè)置ModBus協(xié)議通訊響應(yīng)的超時時間,單位為毫秒ms
mbusSlave_Interface:
數(shù)據(jù)處理函數(shù)指針結(jié)構(gòu),即需要加載ModBus Slave設(shè)備響應(yīng)各個功能的用戶數(shù)據(jù)處理接口函數(shù)。這些用戶接口函數(shù)是由用戶自己提供,用戶可以根據(jù)選擇的功能來實現(xiàn)。這些函數(shù)的名稱和定義是固定的。分別為:
(1) 功能:讀保持寄存器/讀寫寄存器,實現(xiàn)功能碼3、23
int ReadHoldingRegistersTable( int startRef, short regArr[], int refCnt );
(2) 功能:寫寄存器,實現(xiàn)功能碼6、16、22、23
int WriteHoldingRegistersTable( int startRef, const short regArr[], int refCnt );
(3) 功能:讀輸入寄存器,實現(xiàn)功能碼4
int ReadInputRegistersTable( int startRef, short regArr[], int refCnt );
(4) 功能:讀線圈,實現(xiàn)功能碼1
int ReadCoilsTable( int startRef, char bitArr[], int refCnt );
(5) 功能:寫線圈,實現(xiàn)功能碼5、15
int WriteCoilsTable( int startRef, const char bitArr[], int refCnt );
(6) 功能:讀離散量,實現(xiàn)功能碼 2
int ReadInputDiscretesTable( int startRef, char bitArr[], int refCnt );
返回值 = NULL: 啟動ModBus設(shè)備失敗。
!= NULL: 啟動ModBus設(shè)備成功,并返回相應(yīng)的操作句柄。
/////////////////////////////////////////////////////////////////////////////////////////////////////////
(1) HANDLE mbusSlave_StartupServer( LPCTSTR lpPortName, int slaveAddr,int timeout, ModBusSlave_Interface mbusSlave_Interface );
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述: ModBus 服務(wù)器執(zhí)行函數(shù),用于對ModBus報文的分析和響應(yīng)。
該函數(shù)為阻塞模式,阻塞的時間為函數(shù)mbusSlave_StartupServer (…)中設(shè)置的ModBus協(xié)議通訊響應(yīng)的超時時間 timeout,也相當(dāng)于等待請求響應(yīng)的超時時間。實際應(yīng)用中需要在線程中不斷地調(diào)用該函數(shù)。
輸入?yún)?shù)
hPort: 啟動ModBus設(shè)備后獲取的操作句柄
返回值 0: 相應(yīng)操作成功
!=0: 錯誤代碼,可調(diào)用函數(shù)mbusSlave_GetErrorText(…)獲取錯誤的文本信息
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(2) int mbusSlave_ServerLoop( HANDLE hPort );
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述: 關(guān)閉ModBus服務(wù)器應(yīng)用。
輸入?yún)?shù)
hPort: 啟動ModBus設(shè)備后獲取的操作句柄
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(3) void mbusSlave_ShutdownServer( HANDLE hPort );
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述: 獲取ModBus軟件包的版本信息。
返回值 : TCHAR類型的字符串,為ModBus軟件包的版本信息。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(4) TCHAR * mbusSlave_GetPackageVersion( );
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述: 根據(jù)錯誤代碼獲取錯誤文本信息。
返回值 : TCHAR類型的字符串,為錯誤文本信息。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(5) TCHAR * mbusSlave_GetErrorText( int errCode );
modbus_Slave API調(diào)用的使用范例:
1、啟動modbus設(shè)備方協(xié)議
TCP方式:
hPort = mbusSlave_StartupServer( _T(‘*’), 1, 10000, mbusSlave_Interface );
串口方式:
hPort=mbusSlave_StartupServer( _T(‘COM3:9600-8-1-0’),1,10000,
mbusSlave_Interface );
2、線程中調(diào)用Serverloop 響應(yīng)請求
while( 1 )
{
result = mbusSlave_ServerLoop( hPort );
if( result!=0 ) // 檢查是否返回錯誤
{
// 出錯處理:本例為獲取并打印錯誤代碼的文本信息
wcscpy( szText, mbusSlave_GetErrorText( result ) );
i1 = wcslen( szText );
if( i1》0 )
{
wcstombs( strText, szText, i1 );
printf( ‘ error code: %s!\n’, strText );
}
}
}
2、modbusSlave軟件包用戶接口函數(shù)
在DataProvider.h中共定義了6個用戶數(shù)據(jù)接口函數(shù)定義如下:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述: 讀保持寄存器/讀寫寄存器,實現(xiàn)功能碼3、23
輸入?yún)?shù)
startRef: 寄存器的起始地址,范圍:1-0x10000
regArr: 讀取寄存器的值
refCnt: 需要讀取的寄存器數(shù)目,范圍:1-125
返回值
=1:操作成功
=0:不支持該項操作
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(1) int ReadHoldingRegistersTable( int startRef, short regArr[], int refCnt );
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述: 寫寄存器,實現(xiàn)功能碼6、16、22、23
輸入?yún)?shù)
startRef: 寄存器的起始地址,范圍:1-0x10000
regArr: 寫寄存器的值
refCnt: 需要操作的寄存器數(shù)目,范圍:1-125
返回值
=1:操作成功
=0:不支持該項操作
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(2) int WriteHoldingRegistersTable( int startRef, const short regArr[], int refCnt );
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述: 讀輸入寄存器,實現(xiàn)功能碼4
輸入?yún)?shù)
startRef: 寄存器的起始地址,范圍:1-0x10000
regArr: 讀取寄存器的值
refCnt: 需要讀取的寄存器數(shù)目,范圍:1-125
返回值
=1:操作成功
=0:不支持該項操作
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(3) int ReadInputRegistersTable ( int startRef, short regArr[], int refCnt );
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述: 讀線圈,實現(xiàn)功能碼1
輸入?yún)?shù)
startRef: 寄存器的起始地址,范圍:1-0x10000
bitArr: 讀取線圈的值
refCnt: 需要讀取的線圈數(shù)目,范圍:1-2000
返回值
=1:操作成功
=0:不支持該項操作
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(4) int ReadCoilsTable( int startRef, char bitArr[], int refCnt );
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述: 寫線圈,實現(xiàn)功能碼5、15
輸入?yún)?shù)
startRef: 寄存器的起始地址,范圍:1-0x10000
bitArr: 寫線圈的值
refCnt: 需要操作的線圈數(shù)目,范圍:1-2000
返回值
=1:操作成功
=0:不支持該項操作
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(5) int WriteCoilsTable( int startRef, const char bitArr[], int refCnt );
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
功能描述: 讀離散量,實現(xiàn)功能碼 2
輸入?yún)?shù)
startRef: 寄存器的起始地址,范圍:1-0x10000
bitArr: 讀取離散量的值
refCnt: 需要讀取的離散量數(shù)目,范圍:1-2000
返回值
=1:操作成功
=0:不支持該項操作
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(6) int ReadInputDiscretesTable( int startRef, char bitArr[], int refCnt );
-
嵌入式主板
+關(guān)注
關(guān)注
7文章
6083瀏覽量
35099
發(fā)布評論請先 登錄
相關(guān)推薦
評論