二、通讯软件的设计
在本项目中,上位机选用计算机, 下位机选用日本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转换模块,将模拟量发给变频器,从而实现了变频器速度和时间的控制。

 
 
 
 扫码加我微信
扫码加我微信


