利用軟件編程方式,可以更加靈活實(shí)現(xiàn)各種非常規(guī)的通訊。
由于自行編寫的程序在工程師站/操作員站運(yùn)行,需要占用一定的cup時(shí)間及內(nèi)存,因此在通訊數(shù)據(jù)量較大,同時(shí)要求通訊速度較快時(shí),由于沒有專業(yè)通訊軟件的“例外報(bào)告”機(jī)制,建議不要采用自行開發(fā)程序的辦法。
由于自行編寫的程序通常沒有“數(shù)據(jù)緩存”機(jī)制,在傳送非常重要的數(shù)據(jù)時(shí)應(yīng)該謹(jǐn)慎使用。
自行編程主要工作為了兩方面,一為i/a數(shù)據(jù)的讀寫及處理,一為通訊的實(shí)現(xiàn)。
通常自行開發(fā)通訊軟件包括:串口通訊(如智能前端)、tcp/ip通訊(如實(shí)時(shí)數(shù)據(jù)傳送)、ftp通訊(如定期傳送報(bào)表文本)、基于tcp/ip的modbus協(xié)議通訊。
以上幾種通訊方式在通訊的實(shí)現(xiàn)方式上不同,但在i/a’s內(nèi)數(shù)據(jù)的讀寫操作是一樣的,接下來將闡述軟件編程時(shí)的主要函數(shù)及方式:
1.i/a’s數(shù)據(jù)的讀寫及處理
foxboro公司i/a’s系統(tǒng)提供強(qiáng)大的內(nèi)部編程函數(shù)(c函數(shù)、fortran),主要包括有:
lomcall函數(shù)–實(shí)現(xiàn)i/a’s系統(tǒng)內(nèi)部數(shù)據(jù)的讀寫操作。
主要函數(shù)有:
2intgetval(char*name,intobj_type,intimport,char*value,unsignedint*status,intdata_len)
此函數(shù)實(shí)現(xiàn)單個(gè)數(shù)據(jù)的讀操作。
2intom_getval(char*name,intobj_type,intimport,charvalue,unsignedint*status,intdata_len,psap_addr*psap_ptr)
此函數(shù)實(shí)現(xiàn)單個(gè)數(shù)據(jù)的讀操作,它使用psap指針。
2intsetval(char*name,intobj_type,intimport,char*value,unsigned*status,intdata_len)
此函數(shù)實(shí)現(xiàn)單個(gè)數(shù)據(jù)的寫操作。
2intom_setval(char*name,intobj_type,intimport,char*value,unsigned*status,intdata_len,pasp_addr*psap_ptr);
此函數(shù)實(shí)現(xiàn)單個(gè)數(shù)據(jù)的寫操作,它使用psap指針。
2intomopen(structom_header_node*om_descriptor,intopen_id)
此函數(shù)實(shí)現(xiàn)打開一個(gè)list,為數(shù)據(jù)的讀寫操作做準(zhǔn)備。
2intomread(intomopen_id,intsize_list,structvalue*var_list)
此函數(shù)實(shí)現(xiàn)從打開的list中讀取數(shù)據(jù)。
2intomwrite(intomopen_id,intsize_list,structvalue*var_list);
此函數(shù)實(shí)現(xiàn)向打開的list中寫數(shù)據(jù)。
2intomclose(intopen_id,structom_header_node*header,structopen_var*var_list,structnet_addr*addr_tbl)
此函數(shù)實(shí)現(xiàn)關(guān)閉一個(gè)已經(jīng)打開的list。
2頭部文件、om結(jié)構(gòu)及例程
#include
#include
#include
#include
#include
main()
{
structopen_varin_var_list[8];
structheader_nodein_om_desc;
structnet_adrin_net_adr_tbl[2];
intin_open_id;
intrtn;
floatdelta_temp,delta_fc,delta_df;
structvalue*in_data_list,*temp;
inti;
delta_temp=5.0;
delta_fc=1.0;
delta_df=0.5;
in_om_desc.task_status=om_r_access;
in_om_desc.net_adr_tbl_ptr=in_net_adr_tbl;
in_om_desc.size_net_adr_tbl=2;
in_om_desc.open_list_ptr=in_var_list;
in_om_desc.size_open_list=8;
……
}
2特點(diǎn)
使用getval、setval、om_getval、om_setval函數(shù)進(jìn)行編程比較簡單,但效率較差;用omopen、omread、omwrite、omclose編程需要復(fù)雜的聲明,編程比較復(fù)雜,但程序通用性好(不要foxapi的支持)、效率高。
lfoxapi函數(shù)–實(shí)現(xiàn)i/a’s系統(tǒng)內(nèi)部數(shù)據(jù)的讀寫操作及強(qiáng)大的c/s結(jié)構(gòu)編程。
主要函數(shù)有:
2intsbopen(int*gw_array,intnument,char*name_array,int*valtyp_array,intacctyp,float*delta_array,intclexit,intrsr,intwsr,float*wdelta_array,int*dset,int*index_array,int*error_array,int*reterr)
此函數(shù)實(shí)現(xiàn)以連續(xù)更新的方式打開一個(gè)讀寫set。
2intbread(intdset,long*value_array,int*status_array,int*reterr)
此函數(shù)實(shí)現(xiàn)從一個(gè)已經(jīng)打開set中讀取數(shù)據(jù)。
2intbwrite(intdset,long*value_array,int*error_array,int*reterr)
此函數(shù)實(shí)現(xiàn)向一個(gè)已經(jīng)打開set中寫數(shù)據(jù)。
2intclsset(intdset,int*reterr)
此函數(shù)實(shí)現(xiàn)關(guān)閉一個(gè)已經(jīng)打開set,釋放程序所使用的內(nèi)存空間,釋放對(duì)cp中數(shù)據(jù)的控制權(quán)。
2頭部函數(shù),foxapi結(jié)構(gòu)定義及例程
#include
#include
#include
#include
#include
#include
#include
#defineobjnum100
#definesetnum20
typedefunion
{
longlval;
shortival;
floatfval;
charbval;
}iaxval;
/*predefinedparameterofi/avalue*/
staticintgw[setnum][objnum];/*gatewayarray*/
charname[setnum][objnum][32];/*objectnamearray*/
chardesc[setnum][objnum][15];/*objectdescriptionarray*/
staticintvaltype[setnum][objnum];/*objectvaluetypearray*/
staticintacctype=1;/*read-onlyarray*/
staticfloatrdelta[setnum][objnum];/*objectsreaddeltaarray*/
staticfloatwdelta[setnum][objnum];/*objectswritedeltaarray*/
interror[setnum][objnum];/*objectserrorarray*/
intindex[setnum][objnum];/*objectsindexesarray*/
intstatus[setnum][objnum];/*objectsstatusarray*/
iaxvalvalue[setnum][objnum];/*objectsvaluearray*/
staticintrsr=4;/*readscanrate*/
staticintwsr=4;/*writescanrate*/
staticintclexit=1;/*ignoredinunix*/
intreterr[setnum];/*opensetreturnerrorcode*/
/*predefineparameterofutility*/
intset[setnum];/*opensetnumber*/
inttotal_set;/*totalsetnumber*/
intlast_set_num;/*lastsetvaluenuber*/
inttotal_num;/*totalnumberofobjects*/
inttotal_file;/*totaloutputfilesnumber*/
intinterval;/*communicateinterval*/
intcol_num;/*valuenumberperline*/
main()
{
……scopen(gw[i],k,name[i],valtype[i],acctype,rdelta[i],clexit,rsr,\
wsr,wdelta[i],&set[i],index[i],error[i],&reterr[i]);
printf(“returnerrorcode=%-d\n”,reterr[i]);
printf(“returndataset=%-d\n”,set[i]);
……rtn=bread(set[i],value[i],status[i],&reterr[i]);
if(reterr[i]!=0)
{
printf(“bufferedreadobjectserror%d,%d,%d\n”,rtn,\
reterr[i],set[i]);
}
……for(i=0;i
{
clsset(set[i],&reterr[i]);
}
……
}
2特點(diǎn)
使用foxapi編程比較簡單,程序效率也很高,但程序的執(zhí)行需要foxapi的支持,編譯好的程序只能在裝有foxapi的aw、ap機(jī)器中運(yùn)行。pi實(shí)時(shí)數(shù)據(jù)庫實(shí)際上便是利用foxapi函數(shù)編寫的應(yīng)用程序。
lhicall函數(shù)–實(shí)現(xiàn)具有i/a’s風(fēng)格的人機(jī)界面(humaninterface)編程,包括顯示元素,如:矩形、圓弧、填充色;對(duì)話框、菜單結(jié)構(gòu)、鼠標(biāo)鍵盤驅(qū)動(dòng)、查詢、文件驅(qū)動(dòng)等,事實(shí)上,整個(gè)i/a’s的人機(jī)界面編寫既是通過這些函數(shù)完成。
lipcall函數(shù)–實(shí)現(xiàn)i/a’s系統(tǒng)內(nèi)部通訊編程,如:soe軟件等。
liccapi函數(shù)–實(shí)現(xiàn)i/a’s控制處理器cp中cio的相關(guān)操作。
l數(shù)學(xué)庫–提供各種經(jīng)典數(shù)值計(jì)算的調(diào)用函數(shù)。
l物理特性庫–提供各種物理特性計(jì)算的調(diào)用函數(shù),包括水、蒸汽的焓、熵等計(jì)算。
2intvpt(floatp,floatt,float*v)
此函數(shù)根據(jù)蒸汽的壓力及溫度計(jì)算蒸汽的容積。
2inthpt_stm(floatp,floatt,float*h)
此函數(shù)根據(jù)蒸汽的壓力及溫度計(jì)算蒸汽的焓。
2intspt_stm(floatp,floatt,float*s)
此函數(shù)根據(jù)蒸汽的壓力及溫度計(jì)算蒸汽的熵。
2inthpt_wtr(floatp,floatt,float*h)
此函數(shù)根據(jù)水的壓力及溫度計(jì)算水的焓。
2intspt_wtr(floatp,floatt,float*s)
此函數(shù)根據(jù)水的壓力及溫度計(jì)算水的熵。
2inthpt_air(floatp,floatt,float*h)
此函數(shù)根據(jù)空氣的壓力及溫度計(jì)算空氣的焓。
2intspt_air(floatp,floatt,float*s)
此函數(shù)根據(jù)空氣的壓力及溫度計(jì)算空氣的熵。
linformix編程。
在某些需要對(duì)歷史數(shù)據(jù)進(jìn)行操作的場合,可以利用informix及e-sql進(jìn)行編程。
2.通訊的實(shí)現(xiàn)
在用軟件編程實(shí)現(xiàn)通訊時(shí)所采用的具體的通訊硬件上,既可以通過串口實(shí)現(xiàn)rs-232通訊,也可以通過aui網(wǎng)卡、bnc網(wǎng)卡、rj-45網(wǎng)卡實(shí)現(xiàn)ftp通訊、tcp/ip通訊。
當(dāng)與i/a’s通訊的其它設(shè)備(如智能數(shù)據(jù)采集前端、gps、自動(dòng)同期裝置等非通用設(shè)備)可以提供串口通訊,且通訊點(diǎn)數(shù)量不多時(shí),采用專門的硬件實(shí)現(xiàn)通訊硬件不是一個(gè)非常經(jīng)濟(jì)的方案,此時(shí)可以采用rs-232實(shí)現(xiàn)通訊。
用rs-232實(shí)現(xiàn)通訊時(shí),首先應(yīng)初始化通訊端口,然后可以按rs-232通訊規(guī)程(rxd,txd,rts,cts,dsr,dtr,dcd信號(hào)),發(fā)送指令并接受數(shù)據(jù)。
以下是初始化端口的一段例程:
intinit_port(intk,int*fd,char*comport)
{
intsavef;
if((*fd=open(comport,o_rdwr|o_ndelay|o_nonblock))《0)
return(1);
fflush(stdout);
fflush(stdin);
if(savef=fcntl(*fd,f_getfl,0)《0)
return(2);
if(fcntl(*fd,f_setfl,savef|o_ndelay)《0)
return(3);
if(ioctl(*fd,tcgets,&termio)《0)
return(4);
/*settheportparameteras9600baudrate,8databits,1siopbit,
enablereceiver,evenparityenable*/
termio.c_cflag=b9600|cs8|cread|parenb|clocal;
termio.c_cflag&=~cstopb;
termio.c_cflag&=~parodd;
termio.c_iflag=inpck;
termio.c_iflag&=~istrip;
termio.c_lflag=0;
termio.c_oflag=0;
termio.c_cc[vmin]=1;
termio.c_cc[vtime]=0;
if(ioctl(*fd,tcsets,&termio)《0)
return(5);
sleep(1);
return(0);
}
以下是讀寫端口的一段例程:
intcomm(unsignedcharnum,intfd)
{
inti,rtn,tioc;
unsignedchart[200];
unsignedcharbuff[200];
……ioctl(fd,tiocmget,&tioc);
tioc=tioc|tiocm_rts;
ioctl(fd,tiocmset,&tioc);
……write(fd,t,200);
rtn=ioctl(fd,tcsbrk,1);
strcpy(buf,”“,200);
read(fd,buf,200);
}
如果與i/a’s進(jìn)行通訊的是pc機(jī)或其它dcs,比較好的通訊辦法是利用rj-45等通訊口,按ftp協(xié)議或tcp/ip協(xié)議進(jìn)行通訊。其中,ftp通訊的效率較低,且一直有讀盤/寫盤動(dòng)作,對(duì)機(jī)器的影響較大,但此方法比較簡單,容易實(shí)現(xiàn),因此,在通訊不頻繁的時(shí)候(建議大于一小時(shí)),也可以采用這個(gè)辦法。在更多的時(shí)候,則建議使用tcp/ip協(xié)議進(jìn)行通訊。
利用tcp/ip進(jìn)行通訊時(shí),有兩個(gè)協(xié)議可以選擇:tcp及udp,其中tcp(transportcontrolprotocol,傳輸控制協(xié)議)是面向聯(lián)接的,它提供高可靠性服務(wù),尤其適用于傳輸大量報(bào)文信息。udp(userdatagramprotocol,用戶數(shù)據(jù)報(bào)協(xié)議)是無聯(lián)接的,它提供高效率的服務(wù),適用于一次傳輸少量報(bào)文信息的場合。
udp通訊的程序的編寫也比較容易,只需指定客戶機(jī)的ip地址(或主機(jī)名)及傳送端口號(hào)即可,下面是一段利用udp初始化例程:
#include
#include
#include
#include
#include
#include
intsock,length;
structsockaddr_in,sockname;
charbuff[1024];
intinit_socket()
{
char*clientname=“aw5101”;
intportnum=10002;
structhostent*hp,*gethostbyname();
/*creatsocketonwhichtosend.*/
sock=socket(af_inet,sock_dgram,0);
if(sock==-1)
{
perror(“opendatagramsocketerr0r”);
exit(1);
}
hp=gethostbyname(clientname);
if(hp==(structhostent*)0)
{
printf(“unkownhost:%s\n”,clientname);
exit(2);
}
memcpy((char*)&sockname.sin_addr,(char*)hp-》h_addr,hp-》h_length);
sockname.sin_family=af_inet;
sockname.sin_port=htons(atoi(portnum);
return(0);
}……