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