我有一只S7-200 226PLC及三根不同的连接线,以前用PC ACCESS的OPC方式可以实现用电脑,访问它,总觉得太烦,很想试试电脑直接用对话协议访问。
非广告!
西门子的原配连接线,串口,价贵500元,是我去南京的西门子代理那里买的,可以以极高的速度通迅。由于本子上并没有串口,只在台式上用。
这是串口简易线,扬州可以买到,100元,但只能以普通速度通迅,本子上也不好用。
这是国内生产的仿制连接线,一头是USB口,可以用在本子上,这是我常用的一根线了,
需要安装驱动程序,因为它以USB仿真串口的方式,本子上插上线后,就可在硬件管理器
上找到所仿真的串口号,可以修改对应串口号。这要查一下,不知串口号是无法通迅的。
PPI对话协议前几年网上就有文章,但说的很含糊没法用高级语言实施,这几年文章多了,百度上可以搜到,
已说的很清楚了,我总结了一下,对每一个字节进行分析,几乎差不多明白了:
S7-200 PPI通讯协议
一、读PLC的报文 【一次一组最多读222字节的数据】
一般33字节,编号从0到32,由三部分组成:头块、命令块、尾块
(1) 头块 【4B】
0. SD 头标志68H
1. LE 命令块字节数 读为1B,即27字节;
2. LER 同上, 冗余的
3. SD 头标志68H
(2) 命令块 【27B】
4. DA 目的地址: PLC地址【默认2】
5. SA 源地址: PC地址 00
6. FC 命令码 读
7-12.DSAP 目的存取点 32,01,00,00,00,00
13.SSAP 源存取点 00
14.SSAP 数据块长 0E, 公式: 4+块数*10 (一组)
15-18. SSAP 00,00,04,01
19-21. BK 命令头 12,
22. 单元类型 1:1位/2:字节/4:字/6:双字
23. 保留 00
24. 单元数 位:1, N:N个单元
25. 保留 00
26. 是否V区 1:V区/0:非V区
27. 单元类型 04:S/05:SM/06:AI/07:AQ/1E:C/
81:I/82:Q/83:M/84:V/T:
28-30. 单元按位编址 地址*8+位址, 28/29/30由高位到低位
(3) 尾块 【2B】
31. FCS 命令块字节和 27字节的和为校验码
32. ED 尾标志 16H
注:PC发送后,PLC将返回E5,等待几个毫秒后电脑再发送10 2 0
PLC读取后的返回块格式:
00 – 20 不要关心
21 FF
22 位03/非位04
23 读取的总位数【高位】
24 读取的总位数【低位】 位:1,字节:8,字:10H,双字:20H
25 读到的数据开始, N为1到4个字节
25+N 命令块的校验和(不包括头块与尾块)
26+N 尾标志16H
二、写PLC的报文 【每次只能写1个单元,不超过4字节】
由三部分组成:头块、命令块、尾块 总长度与写入数据的字节数有关,写1字节为20H,二字节为21H,双字为23H
(1) 头块 【4B】
0. SD 头标志68H
1. LE 命令块字节数 20H到23H
2. LER 同上, 冗余的
3. SD 头标志68H
(2) 命令块 【20H-23H】
4. DA 目的地址: PLC地址【默认2】
5. SA 源地址: PC地址 00
6. FC 命令码 写
7-12.DSAP 目的存取点 32,01,00,00,00,00
13.SSAP 源存取点 00
14.SSAP 数据块长 0E,
15 00
16 GU4 位5/字节5/字6/双字 8
17-18 05,01
19-21. BK 命令头 12,
22. 单元类型 1:1位/2:字节/4:字/6:双字
23. 保留 00
24. 写字节数 位:1/ N:N个单元
25. 保留 00
26. 是否V区 1:V区/0:非V区
27. 单元类型 04:S/05:SM/06:AI/07:AQ/1E:C/
81:I/82:Q/83:M/84:V/T:
28-30. 单元按位编址 地址*8, 28/29/30由高到低
31 保留 00
32 是否位 03:位/04: 非位
33 总位数【高】 读取的总位数【高位】
34 总位数【低】 位:1/字节:8/字:10H/双字:20H
35 写入的数据 字节为N =1
(3) 尾块 【2B】
35+N. FCS 命令块字节和做校验码
36+N. ED 尾标志 16H
注:PC发送后,PLC将返回E5,等待几个毫秒后电脑再发送10 2 0
写入PLC后的返回块格式,可以不关心。
工控人一般用VB工具编程较多,少数高校的“高手”喜欢用VC,我认为:
1.VB编程简单,易入门,但是解释执行,运行速度并不快,但它是可视化编程工具,多数人很喜欢它;
2. DELPHI与C++BUILDER 是姐妹语言工具,编译执行,比VB执行快多了,也是可视化的,我认为这是
最佳的编程工具,DELPHI学生用的多,C++BUILDER用的人不太多,但我喜欢用,是C++是可视化最
好的编程工具,数据库支持的非常好;
3. 微软的VC++可视化程度低,编程太烦,开发效率太低,比C++BUILDER的技术要低一代,但高校人
认为VC++是时髦高档工具,很少知道C++BUILDER更方便。
所以,我认为 C++BUILDER/DELPHI是首选语言,其次是VB很方便;最后VC++是最差的。
90后女友
因为用的是串行通迅,需要有现成的模块,
最方便的还是微软的串口控件 MSCOMM32.ocx, 有一部分人认为它有问题,其实是因为没掌握它的方法,
多数人认为它不方便发布,需要注册,不便于做绿色EXE程序, 其实MSCOMM32.ocx 可以资源方式绑入
EXE, 执行时释放到windows 系统目录中,再用动态DLL的方式自注册(mscomm32.ocx自带有注册子程序):
delphi 中tmscomm控件使用指南
Delphi 中TMsComm控件使用指南
l 注册TMsComm控件
1.将Mscomm.srg, Mscomm32.ocx,Mscomm32.dep三个文件复制到系统文件夹中C:\winnt\system32\。
2.用Windows下的注册工具regsvr32注册该OCX控件,点击“开始”->"运行",再在中填入(假设操作安装在C盘,WIN2000):
Regsvr32 C:\winnt\system32\Mscomm32.ocx
3.在注册表中手工新建一个主键项:先在点击“开始”->"运行",再在中填入regedit命令打开注册表,找到HKEY_CLASSES_ROOT\Licenses,在其中添加主键
4250E830-6AC2-11cf-8ADB-00AA00C00905 并将内容设置为:
kjljvjjjoquqmjjjvpqqkqmqykypoqjquoun
l 引入TMSComm控件
(1)进入Delphi 编程环境下,在菜单项中选中Component/Import ActiveX选项,出现ActiveX控件导入窗口;
(2)在其中选中Microsoft Comm Control 6.0(Version 1.1),并按需要选定Palette pages、unit dir name、Search path值(一般取默认值),最后选择Install按钮进行安装。即可将MSComm控件引入到Delphi 中。
(3)在编程使用中,直接打开ActiveX控件,选取TMSComm控件,放在窗体上,设置其属性即可。其使用方法与Delphi其它控件相同.
l TMSComm控件的主要属性及事件
MSComm控件有27个属性,其中一部分可缺省设置为不用,常用的属性如下:
(1) CommPort:设置串行口选择。缺省值为1,选择为COM1;若赋值为2,则选择COM2。
(2) PortOpen:设置通信端的状态。设置为True时,打开端口;设置为False时,关闭端口并清除接受和发送缓冲区。
(3) Settings:设置通信时的波特率、奇偶校验、停止位参数。
(4) Inputlen:设置每次从接受缓冲区读却的字符个数。缺省值为0,表示将读取接受缓冲区中全部内容;若设置值为n,表示每次将读取接受缓冲区中的n个字符。
(5) InputMode:设置接收数据的类型。
(6) InBufferCount:设置返回接受缓冲区中等待被读取的字符个数。初始化程序时,InBufferCount设置值为0,表示清除接受缓冲区。
(7) OutBufferCount:设置返回发送缓冲区中等待发送的字符个数。设置值为0时,表示清除发送缓冲区。
(8) InBufferSize:设置接受缓冲区中的长度,缺省值为1024字节。
(9) OutBufferSize:设置发送缓冲区中的长度,缺省值为512字节。
(10) Rthreshold:设置表示在触发OnComm事件之前接收缓冲区允许有的字符数。缺省值为0,表示即使接收缓冲区有字符时,也不会触发OnComm事件;设置值为n时,表示接收缓冲区每有n个字符时,就会触发一次OnComm事件。
(11) Sthreshold:设置表示在触发OnComm事件之前发送缓冲区允许有的字符数。缺省值为0,表示不触发OnComm事件;设置值为n时,表示发送缓冲区每有n个字符时,就会触发一次OnComm事件。
(12) DTREnable:设置DTR的有效性。
(13) RTSEnable:设置RTS的有效性。
(14) Input:从串口读取数据。
(15) Output:向串口写入数据。
使用MSCOMM32.ocx 多数人使用它的异步方式,就是事件方式,但我认为与PLC通迅还是用同步方式方便,
就是说发送命令串后,立即用读取语句读取到应答串,程序更简单。
你只要编两个子程序就完全可以了:
1 。发送子程序 void PPI::SendBuf(BYTE buf【】,int size) // 向串口发送size字节
2. 读取子程序 int PPI::ReadBuf(BYTE *buf,int &size,int tk)
// 从串口读size个字节,size=0表示读所有字节,超时值 tk 毫秒
// 返回出错状态
有了这两个子程序,一切就简单了,VB同样可以编出这两个子程序:
//---------------TMSCOMM---------------------------------
int PPI::ReadBuf(BYTE *buf,int &size,int tk)
{ // 从串口读size个字节,size=0表示读所有字节,超时值tk
int err=0; // 0:正常,1:端口关,2:超时, 3:字符满
int count=0;
OleVariant vbuf;
int tk0=GetTickcount();
while (err==0)
{
if (!MSComm->PortOpen)
{ err=1;
break;
}
if ((int)GetTickcount()-tk0>=tk)
{ err=2;
break;
}
MSComm->InputLen=size>0?(size-count):0;
vbuf=MSComm->Input;
int cn=vbuf.ArrayHighBound()+1;
if (cn>0)
{
tk0=GetTickcount();
for (int i=0;i<cn;i++)
{
buf【count++】=(BYTE)vbuf.GetElement(i);
if (size>0 && count>=size)
{ err=3;
break;
}
}
}
}
size=count;
return(err);
}
void PPI::SendBuf(BYTE buf【】,int size) // 向串口发送size字节
{
OleVariant vbuf=VarArrayCreate(OPENARRAY(int,(0,(size-1))),varByte);
for (int i=0;i<size;i++)
{
BYTE b=(BYTE)buf【i】;
vbuf.PutElement(b,i);
}
MSComm->Output=vbuf;
}
void PPI::InitMSComm() // 初始串口关键参数
{
// Settings: 9600,e,8,1 // S7-200的缺省通迅参数
MSComm->InputMode=1; // 发送格式 0:文本 1:二进
MSComm->RThreshold=0; // 让COM1产生接收事件 0/1
MSComm->InputLen=0; // 每次接收的字符数
}
//-----------------------------------------------------------------------
在东南亚感受阳光和海滩,还有那浓浓的异国风情,让人心醉
一个多星期的试验没有白费,用C++BUILDER6编程,为了调用方式,对子程序进行了对象封装,
调用方式:
PPI *ppi=new PPI();
ppi->MSComm=MSComm1; // 串口控件
ppi->timeout=50; // 50ms超时
ppi->InitMSComm(); // 初始串口参数
MSComm1->PortOpen=true; // 打开串口
charbuf【1024】;
ppi->ReadPPI(_V_,_B_,100,0,20,buf); // 读 VB100开始20个字节到buf 中
ppi->ReadNB(_M_,100,10,buf); // 从MB100开始读10个字节到buf
ppi->ReadB(_M_,100,buf); // 读MB00 一字节
bool b=ppi->ReadBit(_Q_,1,0); // 读Q1.0 一位
............................................. // 写PLC
MSCOmm1->PortOpen=false; // 关闭串口
delete ppi; // 释放对象
就 拍 张 照,全 都 肿 了!