logo资料库

C++实现的西门子S7-200 PPI通讯.doc

第1页 / 共4页
第2页 / 共4页
第3页 / 共4页
第4页 / 共4页
资料共4页,全文预览结束
使用 c++(Qt)实现 PPI 协议 西门子的 S7-200 小型 PLC 确实很经典,要不然也不会出现在 gemfield 的办公桌上。使用该 PLC 进行通讯的方式有多种选择,其中自由口协议需要耗费 PLC 自身的软硬件资源,又闲置了它对通 讯口的扫描。而该 PLC 自身的 PPI 协议就巧妙的化解了这一不足,然而不足就是没有可以自由定制的 软硬件,或者说它的协议是不公开的。 gemfield 本文阐述一个方案来解决上面提到的 PPI 协议不足——使用 c++(Qt)实现 PPI 协议。 宏观情况就是:s7-200提供了一个 RS485标准的通讯口,pc 拥有 RS232接口。两者的物理连接是通 过 PPI 线缆来实现的。你在电脑上可以使用自己的软件来监控 PLC 的运行。 阅读本文前,你要注意一点:本文代码的实现环境是诺基亚的 Qt,完全基于 c++语言。但是由 于 Qt 没有直接提供串口读写控件,因此 gemfield 选用了目前自己拥有的两种环境之一:SYSZUX OS 的 SYSZUXqt(另一种是 UP-TECH 公司的 HMI Developer)。需要说明的是,你不必为没有这两种环 境而沮丧,你只需要拥有 c++基础及一个可以读写 pc 串口的类即可。据 gemfield 所知,Qt 圈内就有 这么一个现成的类,在可以预见的一个月左右,gemfield 将在本博客公布该串口类的源代码以及其详 细讲解。 首先说 PPI 线缆,这个可以通过 RS232转 RS485来替代。硬件的连接如下图所示: 需要提醒的是,有的 pc 的串口直接在内部电路交叉过了,所以选用线缆的时候交叉线和平行线 都有可能。 物理连接好了之后,就是软件的实现。软件运行的截图如下:
gemfield 本博文的主要内容是用自己的软件来读写 S7-200 CPU224的 V、M、Q、I 区。而软件 的实现就得先要破解 PPI 协议的帧格式了。幸运的是,青岛之光社区站点(www.civilnet.cn/bbs)上提 供了大量的这方面的资料和实验数据,你可以结合这些资料来研究,本博文就不过多阐释这一块了。 要实现读写 V、M、Q、I 区我们最好封装4x2个函数,以下是 gemfield 封装的8个方法: void gemfieldReadVB(int addr); void gemfieldWriteVB(int addr,int value); void gemfieldReadMB(int addr); void gemfieldWriteMB(int addr,int value); void gemfieldReadQB(int addr); void gemfieldWriteQB(int addr,int value); void gemfieldReadIB(int addr); void gemfieldWriteIB(int addr,int value); gemfield 就以读写 V 区来阐述一下。先强调一下,不管是读还是写,都是两个过程的,也即 PC COM 先发送一个读(或者写)的指令给 PLC,然后会从 PLC 返回一个"E5"(表明 PLC 响应了),然 后 PC COM 再发送一个确认指令,PLC 再会返回一串数据,而我们要读的变量就存储在这里面。 先说读 V 区的 void gemfieldReadVB(int addr),读 V 区的帧数据根据以下内容会有所区别:读 取的变量是一位还是一个字节还是二字节还是四字节、读取的数据个数是多少、读取的位置是哪里(也 就是偏移)等等。gemfield 就以读取 V 存储区上第99个字节处的一个字节长度的数据为例: //按钮按下,调用读函数,读 VB 存储区
void Mainframe::on_pushButton_readvb_clicked() { bool ok; QString string=lineEdit_vb->text();//获取地址,此处得到的就是99 int temp=string.toInt(&ok, 10);//转换成 int gemfieldReadVB(temp);//调用 gemfieldReadVB 方法来读取 V 存储区上的变量,VB 是一个字节,同 理 VW 是一个字。 } 那么 gemfieldReadVB()方法又是如何实现的呢?参见下面代码: void Mainframe::gemfieldReadVB(int addr) { QByteArray gemfield_temp(gemfield_read_vb);// 定 义 一 个 QByteArray 类 型 的 临 时 变 量 gemfield_temp,用参数 gemfield_read_vb 来初始化,可见 gemfield_read_vb 也是 QByteArray 类型 的了。那 gemfield_read_vb 里放的是什么内容呢?为什么要用 QByteArray 类型呢?下面会知晓的。 int temp= addr*8;//addr 是99,乘以8表明的是要读取的变量的地址相对于0的位偏移,会影响帧数据 的内容。 gemfield_temp[29]=temp/256; gemfield_temp[30]=temp%256;//这两步就是将位偏移转换成帧数据中对应的字节。 gemfield_temp[31]=(104+gemfield_temp[29]+gemfield_temp[30])%256;//校验位的值 serialport->write(gemfield_temp);//串口写 } 通过上面的代码,我们知道了,要根据变量的地址计算出位偏移。因为对于 gemfieldReadVB(int addr)来说,我读取的都是 V 存储区,也都是一个字节长,所以唯一的变量就是地址了,也就是你读的 是第99字节的还是第100字节的。代码中的“串口写”是 SYSZUX OS 的 SYSZUXqt 环境中的串口类中 的方法,你也可以用第三方的串口类。串口的初始化是:9600 e 8 1 。 然后我们也得知了,gemfield_read_vb 这个变量存放的是读指令的固定格式,而根据地址参数 和校验值演变而成的 gemfield_temp 临时变量则是读特定地址的指令,本例中读的是 VB99。下面是 gemfield_read_vb 的内容,在构造函数中实现: gemfield_read_vb[0] = 0x68; gemfield_read_vb[1] = 0x1B; gemfield_read_vb[2] = 0x1B; gemfield_read_vb[3] = 0x68; gemfield_read_vb[4] = 0x02; ... ... ... ... ... ... ... ... ... ... ... ... gemfield_read_vb[31] =0x00; gemfield_read_vb[32] =0x16; 这个时候就完成了一次读指令的发送,然后侦听串口数据,如果是“e5”,则再发送确认指令: serialport->write(gemfield_ok);
gemfield_ok 的内容是: //////////////////////////确认指令的初始化 gemfield_ok[0] = 0x10; gemfield_ok[1] = 0x02; gemfield_ok[2] = 0x00; gemfield_ok[3] = 0x5C; gemfield_ok[4] = 0x5E; gemfield_ok[5] = 0x16; 然后返回的数据中,判断指定字节上的值,即是你要读取的变量的值。读 VB 是这样,写 VB 同 理;读写 VB 这样,读写 QB、IB、QB 同样道理。如果你继续深入的话,写 IB 还是有点曲折的,呵呵。 有了一个字节的值,两个字节就不是问题,三四个字节也不是问题,每一位(bit)的值也不是问题, 问题是本文内容有限,不能囊括所有。但阐述的思想相信能帮你一把。 最后分享一个有趣的故事,gemfield 在 pc 上使用此软件没有任何问题。但移植到 SYSZUX PAD 上时,只能收到 PLC 返回的前8个字节,后面的接受不到。郁闷了一段时间之后,牛人说你用 pc 的串 口侦听一下,没想到侦听线做好接上之后,SYSZUX PAD 也能接收完整了。原来是侦听线从 PC 的 com 口上取到了能源,看来是电平的问题,用一个有源的 RS232~RS485转换器解决了问题。
分享到:
收藏