二、通讯软件的设计
在本项目中,上位机选用计算机, 下位机选用日本omron公司的cp1h系列xa40dr-a可编程序控制器。在计算机外设中,rs-232串口因为其组成方式简单,编程控制方便而成为应用最为广泛的i/o通道之一。32 位下串口通信程序通常采用两种方法实现:一是利用activex控件; 二是使用api通信函数。使用activex控件, 程序实现非常简单, 结构清晰,缺点是欠灵活; 使用api通信函数的优缺点则基本上相反。vc++6.0的mscomm是microsoft 公司提供的简化windows 下串行通信编程的activex控件,它为应用程序提供了通过串行接口收发数据的简便方法,笔者采用了这种方法。其端口接线见附图。
2.1 上位机与plc的通讯协议
host link系统使用host link 通信协议进行通信,上位机具有传送优先权,总是首先发出命令并启动通信,host link 通信单元收到命令交由plc执行,然后将执行结果返回上位机,两者以帧为单位轮流交换数据。
2.2 上位机的plc链接通讯
通信时一组传送的数据称为块,它是命令或响应的单位,从上位机发送到hostlink 单元的数据称为命令块,相应的,从hostlink单元发送到上位机的数据称为响应块。多点通信时,单帧发送的最大数据块为131 个字符,因此当一个数据块含有132 个或更多字符时,要分成两帧或多帧进行发送。多帧发送时中间帧的格式为:正文、fcs、分界符。起始帧、中间帧的长度为131 ,结束帧的长度最多为131 个字符。
omron系列的plc 通过rs232 口与主机通信有两种方式,第一种是由上位机向plc 发送初始命令,第二种是由plc 向上位机发送初始命令[3]。在监测系统中一般采用第一种方式。有关通信协议如下所述:
2.2.1上位机→plc 的命令格式
其中:
(1)@为起始标志符;
(2)n2 、n1 为plc 节点标志码,由两位十进制数表示,它们用来指定与上位机通信的plc。而plc 自己的通信节点码可由它的dm6648 和dm6653 来设置;
(3)cmd2 、cmd1 为两字节命令码;
(4)mt 为命令内容,用来设置具体的命令参数;
(5)v2、v1 为两字节的帧校验码,它是从开始符“@”到mt码结束的所有字符的ascii 码按位异或的结果; 帧校验和是一个转换成2 个ascii 字符的8 位数据。它把帧中每一个字符顺序地进行异或操作而得到的结果,即把帧的第一个字符到正文结束的所有字符转换成二进制形式的ascii 码后,逐个异或而得到的[4]。当发送命令时,将其加在命令格式中,作为帧的一部分发送到接收端。当接收数据时,按上述步骤重新计算fcs ,当计算结果与数据块中所带的fcs 相同时,说明传输无误,否则,说明接收到的数据不正确。
(6)“*”和“cr”两字符表示命令结束。
例如,@00wd00060500表示写一个数500到节点为0的plc的dm0006中。
2.2.2 plc→上位机的响应格式
其中s2 、s1 为命令结束状态码,如00 表示正常结束,01 表示run 模态下plc 无法完成上位机命令,其余符号代码意义同上。实现上位机与host link 通信单元的通信只需编写上位机程序,因为host link 通信单元自身带有通信程序,上位机下发命令,地址相符的plc 自动上传响应帧,所以这一部分程序不需要客户编写,但是,编写上位机的通信程序时,通信参数的设置必须保证与plc 的通信参数一致性。nextpage
三、用vc++6.0编写串行通信程序
首先建立一个基于对话框的mfc应用程序scommtest,支持activex控件,电话形状的控件是在系统中注册过的microsoftcommunications control, version 6.0,接受缺省的选项。
1.打开串口设置串口参数
在主对话框cscommtestdlg::oninitdialog()中打开串口,加入如下代码:
if(m_ctrlcomm.getportopen())
m_ctrlcomm.setportopen(false);
m_ctrlcomm.setcommport(1); //选择com1
i f ( ! m _ c t r l c o m m . g e t p o r t o p e n ( ) ) m _ c t r l c o m m .
setportopen(true);//打开串口
else
afxmessagebox("cannot open serial port");
m_ctrlcomm.setsettings("9600,e,7,2"); //波特率9600,偶校验,7个数据位,2个停止位m_ctrlcomm.setinputmodel(1); //1:表示以二进制方式检取数据m_ctrlcomm.setrthreshold(1);
//参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的oncomm事件
m_ctrlcomm.setinputlen(0); //设置当前接收区数据长度为0
m_ctrlcomm.getinput();//先预读缓冲区以清除残留数据
2.发送数据
为发送按钮添加一个单击消息bn_clicked处理函数,选择idc_button_manualsend,添加onbuttonmanualsend()函数,并在函数中添加如下代码:
updatedata(true); //读取编辑框内容
senddata(m_strtxdata1,6);
// m_strtxdata1表示发送速度命令的具体数值,6表示写数
据的地址dm0006
sleep(100);
senddata(m_strtxdata2,12); //m_strtxdata1表示发送时间命令的具体数值,12表示写数据的地址dm0012
3.发送命令
按照命令格式,本课题主要发送两个wd命令:
(1)数据采用十进制发送,向dm0006中写入速度指令;
(2)数据采用十进制发送,向dm0012中写入时间指令。部分程序如下:
void cscommtestdlg::senddata(int m_tobesend,intm_address)
{ cbytearray array;
unsigned char auchmsg[45]={0}
auchmsg[0]=64; // 起始标志符
auchmsg[1]=0x0; //节点号
auchmsg[2]=0x0; auchmsg[3]=‘w‘; //命令符
auchmsg[4]=‘d‘;
auchmsg[5]=m_address/1000;
auchmsg[6]=(m_address%1000)/100;
auchmsg[7]=(m_address%100)/10;
auchmsg[8]=m_address%10;
auchmsg[9]=m_tobesend/1000;
auchmsg[10]=(m_tobesend%1000)/10;
auchmsg[11]=(m_tobesend%100)/10;
auchmsg[12]=m_tobesend%10;
lrc(auchmsg,13);
//auchmsg[13] ,auchmsg[14] ,保存fcs值
auchmsg[15]=‘*‘; //命令结束符
auchmsg[16]=13;
array.removeall();
for (count=0;count<17;count++)
array.add(auchmsg[count]);
m _ c t r l c o m m . s e t o u t p u t ( c o l e va r i a n t ( a r r a y ) ) ;
4.计算校验码函数
unsigned char uchlrc = 0 ; 初始值设定
while (usdatalen——)
{uchlrc ︿= *auchmsg++; }
unsigned char high=0xf0;
//high为校验码的高位
unsigned char low=0x0f;
//low为校验码的低位
high&=uchlrc;
low&=uchlrc;
high>>=4;右移四位
if(high<=9)
high=high+48;
else
high=high+55;
if(low<=9)
low=low+48;
else
low=low+55;
*auchmsg++=high;
*auchmsg++=low;
该系统采用omron xa40dr-a plc与上位机连接组成控制系统,上位机通过串行口向plc发出写命令及数据,plc接受数据后,通过d/a转换模块,将模拟量发给变频器,从而实现了变频器速度和时间的控制。