1、引言
modbus plus(以下簡(jiǎn)稱(chēng)mb+)是一種針對(duì)工業(yè)控制應(yīng)用的本地局域網(wǎng)系統(tǒng)。以太網(wǎng)是當(dāng)今現(xiàn)有局域網(wǎng)采用的最通用的通信協(xié)議標(biāo)準(zhǔn)。其具有低成本、高可靠性、高速率、開(kāi)放性好等特點(diǎn),在工控領(lǐng)域得到了廣泛的應(yīng)用。
動(dòng)態(tài)數(shù)據(jù)交換(dde)是windows操作系統(tǒng)一直保持兼容的一種應(yīng)用程序間的數(shù)據(jù)通信方式。對(duì)于很多直接和硬件打交道的應(yīng)用程序,尤其是plc編程軟件,是一種較為可靠的通信方式。
本文通過(guò)某鋼廠單機(jī)架平整機(jī)板型改造過(guò)程中的實(shí)際應(yīng)用,介紹使用vc2005在windows下實(shí)現(xiàn)pc與mb+網(wǎng)的dde通信并通過(guò)以太網(wǎng)實(shí)現(xiàn)與板型儀plc的數(shù)據(jù)交換。
2、系統(tǒng)簡(jiǎn)要說(shuō)明
本系統(tǒng)如圖1所示,包括生產(chǎn)控制plc組,mb+網(wǎng),pc服務(wù)器,100m以太網(wǎng),板型控制系統(tǒng)。通過(guò)pc服務(wù)器實(shí)現(xiàn)互聯(lián)。
圖1 單機(jī)架平整機(jī)板型控制系統(tǒng)
生產(chǎn)控制plc組由mb+網(wǎng)來(lái)連接,pc機(jī)上使用一塊sa-85的pci卡來(lái)連接到mb+,用于訪問(wèn)各節(jié)點(diǎn)上的plc。pc機(jī)上另外使用一塊pci接口的以太網(wǎng)卡連接到以太網(wǎng)。板型儀提供了以太網(wǎng)接口,與pc機(jī)接入同一個(gè)局域網(wǎng)。
pc機(jī)上安裝mb+網(wǎng)的dde服務(wù)程序,以及本文介紹的自編程序。dde服務(wù)程序通過(guò)mb+網(wǎng)獲取plc上的數(shù)據(jù),自編程序使用dde技術(shù)獲得數(shù)據(jù),打包后使用tcp協(xié)議發(fā)送給板型儀。板型儀通過(guò)tcp協(xié)議將各種測(cè)量數(shù)據(jù)和狀態(tài)信號(hào)發(fā)給pc服務(wù)器,相關(guān)數(shù)據(jù)再通過(guò)dde協(xié)議送dde服務(wù)程序,最后通過(guò)mb+網(wǎng)送到相應(yīng)的plc。
3、系統(tǒng)的具體實(shí)現(xiàn)
3.1 dde server軟硬件安裝方法
dde基于用戶(hù)/服務(wù)器原則,通過(guò)建立應(yīng)用程序間的對(duì)話連接,根據(jù)不同的主題和項(xiàng)目進(jìn)行數(shù)據(jù)通信。為了從服務(wù)器獲取數(shù)據(jù),用戶(hù)使用一種固定的3級(jí)特殊訪問(wèn)方式,這3級(jí)訪問(wèn)分別為:服務(wù)(service)、主題(topic)和數(shù)據(jù)項(xiàng)(item)。
不同的硬件平臺(tái)所使用的dde數(shù)據(jù)通信硬件設(shè)備也不同,本文介紹的數(shù)據(jù)通信方法是針對(duì)mb+網(wǎng)而言的。pc平臺(tái)上使用sa-85的pci卡來(lái)連接mb+網(wǎng)。使用前需要配置好sa-85的網(wǎng)絡(luò)連接。
軟件上,使用wonderware公司提供的io server組件中的modicon modbus
plus(以下簡(jiǎn)稱(chēng)mbplus)來(lái)連接mb+并提供dde的方式來(lái)訪問(wèn)數(shù)據(jù)的接口。此工具運(yùn)行后如圖2所示。
圖2 mbplus連接
要使用此工具,還需要對(duì)它進(jìn)行一些配置。從configure菜單中選擇adapter card setting,設(shè)置需要連接的適配器,因?yàn)槲覀冎话惭b了一個(gè)mb+的適配器,所以使用默認(rèn)配置。之后就可以開(kāi)始配置dde服務(wù)了。我們需要給每一個(gè)需要訪問(wèn)的mb+網(wǎng)上的設(shè)備按照dde協(xié)議定義一個(gè)topic。選擇configure菜單下的topic definition,進(jìn)行topic的配置,如圖3。
圖3、topic配置
這里的topic name 就是之后訪問(wèn)dde服務(wù)的topic需要使用的名稱(chēng),每個(gè)topic需要定義不同的名稱(chēng),本系統(tǒng)共連接5個(gè)mb+網(wǎng)上的plc,分別定義為plc1、plc2、plc3、plc4、plc5。slave path 處定義的是不同設(shè)備的節(jié)點(diǎn)地址。配置好以后就可以使用dde協(xié)議來(lái)訪問(wèn)mb+網(wǎng)上的數(shù)據(jù)了。
3.2 編程實(shí)現(xiàn)
在完成了mb+的dde數(shù)據(jù)通信安裝與設(shè)置后,就要在用戶(hù)程序中進(jìn)行編程,建立dde對(duì)話,控制數(shù)據(jù)通信流程。本文介紹vc2005的dde通信方式。事實(shí)上,vc2005并不直接與dde server進(jìn)行dde對(duì)話,它是通過(guò)windows操作系統(tǒng)提供的ddeml(dde通信管理庫(kù))來(lái)管理dde通信具體工作的。該管理庫(kù)的使用方法如下:
(1) ddeml的初始化工作
加載頭文件,.#include “ddeml.h” //在工程中引用ddeml庫(kù)然后按照dde server提供的3級(jí)訪問(wèn)方式建立vc與ddeserver的對(duì)話。此時(shí)service為mbplus,topic為plc4。通過(guò)選擇不同的item及相應(yīng)dde函數(shù)可以完成接收過(guò)程數(shù)據(jù)、發(fā)送控制命令、獲取系統(tǒng)狀態(tài)等工作。
使用ddeml后,實(shí)際上客戶(hù)和服務(wù)器之間的多數(shù)會(huì)話并不是直達(dá)對(duì)方的,而是經(jīng)由ddeml中轉(zhuǎn),即用回調(diào)函數(shù)處理dde交易(transaction)。在調(diào)用其他ddeml函數(shù)前,必須調(diào)用ddeinitialize()函數(shù),以獲取實(shí)例標(biāo)識(shí)符,注冊(cè)dde 回調(diào)函數(shù)。通過(guò)回調(diào)函數(shù)來(lái)處理dde的事務(wù)。
本例中使用如下方法來(lái)初始化dde連接,dword idinst = 0; //定義dde實(shí)例標(biāo)識(shí)的變量ddeinitialize(&idinst,(pfncallback)ddecallback,appclass_standard | appcmd_clientonly,0);這里將ddecallback函數(shù)指定為dde的回調(diào)函數(shù)。實(shí)例初始化后得到實(shí)例的標(biāo)識(shí)idinst,之后的操作都要使用這個(gè)標(biāo)識(shí)。
(2) 通過(guò)dde協(xié)議的服務(wù)名,主題名和項(xiàng)目名來(lái)訪問(wèn)具體某個(gè)項(xiàng)目的數(shù)據(jù)
先定義dde的服務(wù)名和主題名
tchar szapp[] = text(“mbplus”); //服務(wù)名
tchar sztopic4[]=text(“plc4”); //主題名
tchar szwidth[]=text(“400401”); //項(xiàng)目名
tchar vlwidth[16]; //儲(chǔ)存從dde服務(wù)器返回的數(shù)據(jù)
hsz hszwidth; //項(xiàng)目的dde標(biāo)識(shí)
//項(xiàng)目名的命名規(guī)則具體可以查看mbplus程序的說(shuō)明,這里400401表示的是項(xiàng)目在plc中的地址,這是一個(gè)//16位的整形數(shù)
hconv4=ddeconnecttotopic(idinst,szapp,sztopic4,&hsztopic4);
if( hconv4 != null )
{
ddeautorequest(idinst,hconv4,szwidth,&hszwidth);
}
此處的ddeconnecttotopic和ddeautorequest為自定義的函數(shù)
hconv ddeconnecttotopic(dword idddeinst, lpctstr szapp, lpctstr
sztopic, hsz * hsztopic)
{
hsz
hszapp=ddecreatestringhandle(idddeinst,szapp,cp_winunicode);
*
hsztopic=ddecreatestringhandlew(idddeinst,sztopic,cp_winunicode);
return ddeconnect(idddeinst,hszapp,*hsztopic,null);
}
使用ddecreatestringhandle來(lái)獲取服務(wù)器和主題名的字符句柄,使用ddeconnect來(lái)建立指定服務(wù)下的指定的主題的連接。之后使用ddeautorequest函數(shù)來(lái)向dde服務(wù)器請(qǐng)求置頂項(xiàng)目名的數(shù)據(jù),在數(shù)據(jù)發(fā)生變化后dde服務(wù)器會(huì)自動(dòng)將新的數(shù)據(jù)發(fā)送給客戶(hù)端,客戶(hù)端在回調(diào)函數(shù)中就可以獲取到新的數(shù)據(jù),具體方法見(jiàn)下文。如果某個(gè)主題下有多個(gè)項(xiàng)目需要處理,都用ddeautorequest來(lái)處理即可,此函數(shù)的實(shí)現(xiàn)如下:
void ddeautorequest(dword idddeinst, hconv hconv, lpctstr
szitem, hsz * hszitem)
{
*hszitem=ddecreatestringhandle(idddeinst,szitem,cp_winunicode);
hddedata hdata=ddeclienttransaction
(null,0,hconv,*hszitem,cf_text,xtyp_advstart| xtypf_ackreq,5000,
null);
}
接下來(lái)就可以通過(guò)dde的回調(diào)函數(shù)來(lái)獲取數(shù)據(jù)了。
hddedata callback ddecallback(uint utype,uint ufmt,hconv
hconv,hsz hsz1,hsz hsz2,hddedata hdata,
dword dwdata1,dword dwdata2)
{
switch( utype )
{
case xtyp_advdata: //處理dde數(shù)據(jù)
if( ufmt != cf_text )
return dde_fnotprocessed;
memset(szbuffer,0,64); //初始化緩沖區(qū)
datalen=ddegetdata(hdata,null,64,0);//獲取數(shù)據(jù)的長(zhǎng)度
ddegetdata(hdata,(unsigned char* )szbuffer,datalen,0);//獲取數(shù)據(jù)
if( hsz1==hsztopic4 && hsz2 == hszwidth ) //判斷數(shù)據(jù)對(duì)應(yīng)于那個(gè)數(shù)據(jù)項(xiàng),并作出具體處理
{
_atoflt(&fltval,szbuffer); //dde的數(shù)據(jù)以字符串形式創(chuàng)送過(guò)來(lái)的,這里將它轉(zhuǎn)換成數(shù)值
ptele1101-》msgblock1.stripwidth=fltval.f; //將數(shù)字存入緩沖區(qū)
}
return ( hddedata )dde_fack;
}
return 0;
}
本例中dde回調(diào)函數(shù)要處理的dde項(xiàng)目不止一個(gè),任意一個(gè)dde項(xiàng)目的值發(fā)生變化時(shí),回調(diào)函數(shù)都會(huì)被自動(dòng)調(diào)用一次,具體實(shí)現(xiàn)時(shí)只需要用if語(yǔ)句對(duì)hsz1和hsz2進(jìn)行逐一比較即可處理所有的項(xiàng)目。緩沖區(qū)ptele1101用于存儲(chǔ)通過(guò)以太網(wǎng)發(fā)送到板型儀的數(shù)據(jù),下文中將詳細(xì)介紹。
上面介紹的方法用于從dde服務(wù)器中獲取mb+網(wǎng)上的數(shù)據(jù),那么如何將數(shù)據(jù)寫(xiě)入到mb+網(wǎng)呢,同樣還是使用ddeml庫(kù)中提供的方法,具體如下:
ddepoke(idinst,hconv4,szwidth,text(“1020”));
//寫(xiě)數(shù)據(jù)到mb+,設(shè)置寬度為1020mm
ddepoke為自定義函數(shù),具體實(shí)現(xiàn)為:
void ddepoke(dword idinst, hconv hconv, tchar* szitem, tchar*
szdata)
{
hsz hszitem=ddecreatestringhandlew(idinst,szitem,cp_winunicode);
ddeclienttransaction((lpbyte)unicodetoansi(szdata),(dword)(lstrlenw(szdata)+1),hconv,
hszitem,cf_text,xtyp_poke,3000,null);
ddefreestringhandle(idinst,hszitem);
}
(3) 與以太網(wǎng)交換數(shù)據(jù),這里使用的是socket協(xié)議。前面提到了緩沖區(qū)ptele1101,這里存儲(chǔ)的是要傳送到板型儀的數(shù)據(jù)。這是一個(gè)結(jié)構(gòu)指針,定義如下:
typedef struct
{
teleheader msgheader; //消息頭
tele1101block1 msgblock1; //消息第一部分
tele1101block2 msgblock2; //消息第二部分
tele1101block3 msgblock3; //消息第三部分
} tele1101, *ptele1101;
ptele1101 ptele1101;
這其中teleheader、tele1101block1、tele1101block2和tele1101block3也分別是一個(gè)結(jié)構(gòu),這里就不詳述了。
本實(shí)例中使用另外一個(gè)線程來(lái)處理以太網(wǎng)的數(shù)據(jù)交換,這樣不會(huì)中斷處理dde數(shù)據(jù)的過(guò)程。
dword dwthreadid;
thread=createthread(null,0,(lpthread_start_routine )
sockthread,null,0,&dwthreadid);
sockthread為線程的過(guò)程函數(shù),具體實(shí)現(xiàn)如下:
void sockthread()
{
int i=0;
tchar buf[256];
initwinsock();//初始化socket
//創(chuàng)建并設(shè)置協(xié)議類(lèi)型,地址和端口
socket socksrv=socket(af_inet,sock_stream,0);
sockaddr_in addrsrv;
addrsrv.sin_addr.s_un.s_addr=htonl(inaddr_any);
addrsrv.sin_family=af_inet;
addrsrv.sin_port=htons(5001);
//綁定并監(jiān)聽(tīng)端口
bind(socksrv,(sockaddr*)&addrsrv,sizeof(sockaddr));
listen(socksrv,5);
sockaddr_in addrclient;
int len=sizeof(sockaddr);
while (1) //程序正常運(yùn)行時(shí),始終接收連接請(qǐng)求
{
sockconn=accept(socksrv,(sockaddr*)&addrclient,&len);
zeromemory(buf,sizeof(buf));
__try
{
while (1) //連接建立后每50秒交換一次數(shù)據(jù)
{
len=send(sockconn,(char *)ptele1101,sizeof(tele1101),0);
len=recv(sockconn,(char *)ptele1102,sizeof(tele1102),0);
if (0==len || socket_error==len)
{
len=wsagetlasterror();
raiseexception(1,0,0,null);
}
sleep(50);
}
}
__except(exception_execute_handler)
{
closesocket(sockconn);
}
}
closesocket(socksrv);
wsacleanup();
}
這里ptele1102為接收數(shù)據(jù)的緩沖區(qū),也是一個(gè)結(jié)構(gòu),定義與ptele1101類(lèi)似,此處不詳述。
從mb+網(wǎng)來(lái)的數(shù)據(jù)在使用dde協(xié)議獲取后存入緩沖區(qū)ptele1101,發(fā)送到板型儀,從板型儀來(lái)的數(shù)據(jù)存入緩沖區(qū)ptele1102,相關(guān)數(shù)據(jù)再使用dde協(xié)議寫(xiě)回到mb+網(wǎng),這樣就實(shí)現(xiàn)了mb+網(wǎng)和以太網(wǎng)的數(shù)據(jù)交換。
4、結(jié)束語(yǔ)
本文介紹的數(shù)據(jù)交換的方法編程實(shí)現(xiàn)起來(lái)比較容易,代碼量較少,能很好的解決異種網(wǎng)絡(luò)間的數(shù)據(jù)交換的需求,并在單機(jī)架平整機(jī)板型控制系統(tǒng)中得到了成功的應(yīng)用,取得了滿(mǎn)意的效果。文中介紹的使用dde協(xié)議和socket協(xié)議處理數(shù)據(jù)的方式有較好的通用性,經(jīng)過(guò)簡(jiǎn)單修改既可以用于其他的系統(tǒng)。另外通過(guò)簡(jiǎn)單的擴(kuò)展,即可實(shí)現(xiàn)數(shù)據(jù)采集和分析的功能??梢詮V泛應(yīng)用于工業(yè)控制的各個(gè)領(lǐng)域。
責(zé)任編輯:gt
評(píng)論
查看更多