用户自主开发特别是想用VB、VC等语言自行开发,根本没办法接入PLC,要么你大把掏钱给他们。洋为中用,最近在国外网站得到一个串口监视软件,带协议分析的相当不错,通过此软件的数据监视、分析方法,找出了PPI协议的关键报文格式所在。
其实西门子S7-200PLC之间或者PLC与PC之间通信有很多种方式:自由口,PPI方式,MPI方式,Profibus方式。使用自由口方式进行编程时,在上位机和PLC中都要编写数据通信程序。使用PPI协议进行通信时,PLC可以不用编程,而且可读写所有数据区,快捷方便。这也是我们之所以要研究、找出PPI协议的源动力!
下面我们就要说说分析的方法了!
西门子的STEP7MicroWIN是用于S7-200系列PLC的开发工具,它使用PC机上的COM口通过一条PC/PPI编程电缆连到PLC的编程口上。这说明,PC实际上是可以通过串口同S7-200CPU通讯。只是我们不知道通讯协议而已。通过截获PC机串口上的收发数据,对照Step7软件发出的指令,我们就有可能分析出有关指令的报文和通讯方式;然后,直接通过串口向PLC发送报文,以验证这些指令报文是否正确。本着这一思想,我们采用以下步骤获得这些报文。
首先你用串口监控软件,新建、选择端口COM1,然后再将PC/PPI编程电缆接在COM1上,这样,Step7Micro/Win发给PLC的报文就可以在监视软件上完全裸露的展现在你的面前了。我们按S7-200系统手册设置好串口参数:9600,8,E偶校验,1位停止位。然后设置好Step7软件,使之能与S7-200CPU正常通讯。从Step7软件中发出一个明确指令,监视软件就能显示这条报文了(用16进制显示,ASCII码的只能看到几个版本号之类的,其他都没有意义)。
我们的破解策略就是通过软件监视的方法,分析PLC内部固有的PPI通讯协议,然后上位机采用VB编程,遵循PPI通讯协议,读写PLC数据,实现人机操作任务。这种通讯方法,与一般的自由通讯协议相比,省略了PLC的通讯程序编写,只需编写上位机的通讯程序资源。S7-200的编程口物理层为RS-485结构,SIEMENS提供MicroWin软件,采用的是PPI(PointtoPoint)协议。
下面我们就说说西门子PLC到底是怎么通讯的。
说了这么多乱不乱呐!目的就是要理清上下级关系、主从关系,指令的顺序,用一个好的记忆方法记住枯燥无味的机器码。
读命令分析:一次读一条数据SDLELERSDDASAFCDASPSSAPDUFCSEDSD:(StartDelimiter)开始定界符(68H)LE:(Length)报文数据长度LER:(RepeatedLength)重复数据长度SD:(StartDelimiter)开始定界符(68H)SA:(SourceAddress)目标地址,指该地址的值,就是PLC的地址DA:(DestinationAddress)本地地址,指该地址的指针,就是上位机自己的地址FC:(FunctionCode)功能码,5CH为交替周期触发,6CH为首次信息周期触发,7CH为交替周期触发。DSAP:(DestinationServiceAccessPoint)目的服务存取点SSAP:(SourceServiceAccessPoint)源服务存取点DU:(DataUnit)数据单元FCS:(FrameCheckSequence)校验码ED:(EndDelimiter)结束分界符(16H)报文数据长度和重复数据长度为自DA至DU的数据长度,校验码为DA至DU数据的和校验,只取其中的末字节值关于这个校验码的计算方法同上面说明。在读写PLC的变量数据中,读数据的功能码为6CH,写数据的功能码为7CH。对于一次读取一个数据,读命令都是33个字节。前面的0—21字节是相同的,为
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SD
LE
LER
DA
SA
FC
开始符
长度
站号
源地址
功能码
协议识别
远程控制
冗余识别
协议数据
单元参考
参数长度
数据长度
04读05写
变量地址数
68
1B
02
00
6C
32
01
0E
04
0A
下面我们列表分析读取PLC密码的指令:681B1B6802006C320100000000000E00000401120A100200080000030005E0D216
22
23
24
25
26
27
28
29
30
31
DU
FCS
DE
读取长度
数据个数
存储器类型
偏移量
校验码
结束符
08
03
05
E0
D2
因为是PC上发的读PLC数据的命令,SA=00,DA=02,如果有多个站,DA要改成相应的站号。读命令中从DA到DU的长度为1B即27个字节。从22字节开始根据读取数据的类型、位置不同而不同。上表是读不同存储器命令的Byte22—32。
字节
功能
读Q0.1
82
64
读M0.0
83
65
读M0.1
66
读SMB34
F9
读VB100
84
8B
读VW100
8D
读VD100
06
8F
读I0.5
81
读I0.7
07
6A
上表读命令的Byte22-32从表中我们可以得出以下结果:Byte22读取数据的长度01:1Bit02:1Byte04:1Word06:DoubleWordByte24数据个数,这里是01,一次读多个数据时见下面的说明。Byte26存储器类型,01:V存储器00:其它Byte27存储器类型04:S05:SM06:AI07:AQ1E:C81:I82:Q83:M84:V1F:TByte28,29,30存储器偏移量指针(存储器地址*8),如:VB100,存储器地址为100,偏移量指针为800,转换成16进制就是320H,则Byte28—29这三个字节就是:000320。Byte31校验和,前面已说到这是从(DA+SA+DSAP+SSAP+DU)Mod256。一次读多条数据对于一次读多个数据的情况,前21Byte与上面相似只是长度LD,LDr及Byte14不同:Byte14数据块占位字节,它指明数据块占用的字节数。与数据块数量有关,长度=4+数据块数*10,如:一条数据时为4+10=0E(H);同时读M,V,Q三个不同的数据块时为4+3*10=22(H)。Byte22总是02即以Byte为单位。Byte24以字节为单位,连续读取的字节数。如读2个VD则Byte24=8Byte19---30按上述一次读一个数据的格式依次列出,Byte31---42另一类型的数据,也是按上述格式给出。以此类推,一次最多读取222个字节的数据。
写命令分析:一次写一个DoubleWord类型的数据,写命令是40个字节,其余为38个字节。写一个DoubleWord类型的数据,前面的0—21字节为:
7C
6823236802006C320100000000000E00000401120A10写一个其它类型的数据,前面的0—21字节为:(与上面比较,只是长度字节发生变化)6821216802006C320100000000000E00000401120A10
33
34
35
36
37
存储类型
数据形式
数据位数
写入值
终止符
79
从22字节开始根据写入数据的值和位置不同而变化。上表是几个写命令的Byte22—40。字节22232425262728293031323334353637383940写入位置及值长度个数类型偏移量位数值、校验码、结束符M0.0=10100010000830000000003000101007116M0.0=00100010000830000000003000100007016M0.1=10100010000830000010003000101007216vb100=10020001000184000320000400081000AE16vb100=FF02000100018400032000040008FF009D16VW100=FFFF04000100018400032000040010FFFFA616VD100=FFFFFFFF06000100018400032000040020FFFFFFFFB816
写命令的Byte22—最后,经分析我们可以得出以下结果:Byte22--Byte30写入数据的长度、存储器类型、存储器偏移量与读命令相同。T,C等不能用写命令写入。Byte32如果写入的是位数据这一字节为03,其它则为04Byte34写入数据的位数01:1Bit08:1Byte10H:1Word20H:1DoubleWordByte35--40值、校验码、结束符如果写入的是位、字节数据,Byte35就是写入的值,Byte36=00,Byte37=检验码,Byte38=16H,结束。如果写个的是字数据(双字节),Byte35,Byte36就是写入的值,Byte37=检验码,Byte38=16H,结束。如果写个的是双字数据(四字节),Byte35—38就是写入的值,Byte39=检验码,Byte40=16H,结束。
写指令:先发1002005C5E16后发写指令
1、写一位M区(例子M0.0)
先发1002005C5E16收到E5后
发6820206802007C320100000000000E00050501120A1001000100008300000000030001018016
收到E5说明写入完成(只要报文长度,跟校验码对了,就会回复E5)
报文长度
目标
地址(PLC
)
源站地址(上位机)
写
报文长度为:目标地址到倒数第二位的校验位前面的字节长度(根据写入值不通报文长度不同)
功能码:7C表示写入;6C表示读取。
17位:05表示写入;04表示读取。
16位:16位的05表示写入的是位或者字节(即用一个字节存储)
06表示字;08表示双字(4个字节);0C表示8个字节
数据长度(22位):01位;02字节;04字;06双字。
数据个数:0100表示一个;0200表示连续的两个;0400连续的4个。
存储类型:26位:01V区;00其他。
27位:04S区;05SM区;06AI;07AQ;1EC;
81I;82Q;83M;84V;1FT
偏移量:000000000000000000000XXX(XXX表示位)
例如:10.3=1010.011即000053
数据形式:03表示位;04表示其他。
数据位数:即写入数据多少位。01一位;08八位;10十六位;20三十二位。
写入值:写入位,字节均用一个字节存储;写入双字得用四个字节。
校验码:即报文的偶校验(所有之和Mod100H)
终止符:16H
若M10.3=1写入,00005301D3(校验码D3是从开头第五个02到倒数第三个01的所有数字的偶校验(算术和))
因为01010.011(10.3)为000053
即:6820206802007C320100000000000E00050501120A100100010000830000530003000101D316
M10.3=0
即:6820206802007C320100000000000E00050501120A100100010000830000530003000100D216
2、写V区一个字节(例子VB100=10H)
发:6820206802007C320100000000000E00050501120A100200010001840003200004000810bd16
3、写V区一个字(双字)
发:6821216802007C320100000000000E00060501120A1004000100018400032000040010abcd3016
发:6823236802007C320100000000000E00080501120A1006000100018400032000040020abcdeffe3116
读指令:先发读指令,后发1002005C5E16
1、读取数据(例子读取VW10的值,值为FFFF)
先发读取命令:
681B1B6802006C320100000000000E00000401120A10020002000184000050B916(红色或者改为04000100校验也得改)
回复E5
然后发送1002005C5E16
收到数据:
681717680002083203000000000002000600000401FF040010FFFF5D16
读指令的前21位都是相同的。读取长度,数据个数,存储类型,偏移量都与写指令里面的定义一样。
收到数据中的
16位:05表示收到数据用一个字节存储,可能是PLC位,也可能是一个字节;06表示用两个字节存储,即一个字;08双字;0C表示8个字节。
21位:FF
24位:表示读取数值的位数。01表示一位;08八位;10十六位;20三十二位。
25位开始之后几位:要读取的数值。
若回复F9(会产生不同结果,但接受值不变)
收到数据:(关闭串口再打开的不同结果)
DAA1211B9032616640408000000002000600000401FF040010FFFF5D16
B4A1211B1030616640808000000002000600000401FF040010FFFF5D16
4、读取VB10
681B1B6802006C320100000000000E00000401120A10020001000184000050B816
681616680002083203000000000002000500000401FF040008FF5516
5、读取VD10
681B1B6802006C320100000000000E00000401120A10060001000184000050BC16
681919680002083203000000000002000800000401FF040020FFFF00006F16
6、读取VB10后面的8个字节
681B1B6802006C320100000000000E00000401120A10020008000184000050Bf16
681D1D680002083203000000000002000C00000401FF040040FFFF0000000000009316
7、读取V10.0
681B1B6802006C320100000000000E00000401120A10010001000184000050B716
681616680002083203000000000002000500000401FF030001014F16
4、读取Q0.1
发送:681B1B6802006C320100000000000E00000401120A100100010000820000016516
回复:E5
681616680002083203000000000002000500000401FF030001004E16Q0.1为0时
681616680002083203000000000002000500000401FF030001014F16Q0.1为1时
5、读取Q1.3
发送:681B1B6802006C320100000000000E00000401120A1001000100008200000B6516
681616680002083203000000000002000500000401FF030001004E16
6、读取M0.0
发送:681B1B6802006C320100000000000E00000401120A100100010000830000006516