西门子TCP协议解析

Posted 自动化电气系统

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了西门子TCP协议解析相关的知识,希望对你有一定的参考价值。

1.西门子和三菱的几个区别(上位只关心的通讯层面)

1. 西门子PLC通讯端口固定102,但是可以连接多个PC(客户端),三菱PLC通讯端口可以自定义,最多好像8个,但是每个端口只能连接一个客户端;

2. 两者的读写指令类似,但是西门子在端口连接的时候,要做两个初始化指令交互后,才能正常读写处理;如果中途有错误格式的指令,可能导致端口连接断开;

4.三菱PLC的数据块,一般最小处理单位就是字,很少拆成bit处理(或者把整个字当作0,1布尔类型处理,但是这样有点太浪费了)   而且上位PC端只能用字去读写,无法按位读写,如果真的要用bit处理,一般就用M点;   西门子这块比较灵活,可以按bitbyte去读写;如果按byte,标识的样子是DB10.B99;如果是bit,标识的样子是 DB10.X99.0~DB10.X99.7

6.  三菱的数据位是从小到大的,比如某个双字,低位在前,高位在后;这是针对数字类型,但是如果是ascii码,因为一个字有两个字节,这时候却又是反的;    所以在三菱里面对数字和字符类型,要分两种顺序处理;    西门子是从大到小的;这两种方法有什么区别呢;简单来说:从小到大主要是计算机思考的方式;从大到小是人的思考方式;    比如655539,它等于65536+3,转换成16进制是0x00010003 需要两个字  , 如果在三菱里存储的顺序就是先低位3,再高位1,也就是 03 00 01 00;    在西门子里存储的顺序从高到低,也就是00 01 00 03    就像oracle在的数据在windows系统里的数据存储顺序是从小到大,在liunx系统里又是从大到小;


2.报文的基本格式:   

 

2.1  1和第2个字节是:固定报文头03 00,这里我们就用到三种报文: a.初始化 b. c.,都是这种格式;    

2.2  3和第4个字节是:整个报文的长度;    

其它部分就是各种报文的个性化处理了;下面分析大量报文的案例进行规律分析,为了便于对照,每种都用1200 300 两种对照demo显示:


3.初始化报文;

初始化报文分两个交互;

3.1 交互一 西门子1200: 

PC发出报文 ( [A18]=0x01 =CPUSlot)                 

03 00  00 16 11 E0 00 00         00 01  00 C1 02 01 00 C2

02 01  01 C0 01 09            

 PLC回复报文

( B[10]=0x06 可能 是西门子的小型号  

B[22]=0x01=CPUSlot)             

 03 00 00 16 11 D0 00 01        00 06 00 C0 01 09 C102              01 00 C2 02 01 01              

  西门子300:            

 PC发出报文 (A[18]=0x02 =CPUSlot)                

 03 00  00 16 11 E0 00 00        00 01  00 C1 02 01 00 C2               

 02 02 01 C0 01 09           

  PLC回复报文

 (B[10]=0x04 可能 是西门子的小型号 

 B[22]=0x0=CPUSlot)                

03 00 00 16 11 D0 00 01       00 04 00 C0 01 09 C1 02                  

01 00 C2 02 01 02       

 opc 对 1200 和 300 不用配置的不同点,就一个地方:前者 CPUSlot = 1 ,后者CPUSlot = 2;      

所以可以摸索规律是:             

 a.pc发起第一个初始化报文的时候,第18个字节标识了CPUSlot ;              

b.plc回复报文和读取报文长度一样都是22个字节长度;              

c.plc回复报文的最后一个字节也是CPUSlot,这个可以用来校验;             

d. plc回复的第10个字节一个是06,一个是04,这个好像是小型号的区别;                 细节摸索下来:1200该字节是06,314是04,315是03;咱写程序的时候,就不要考虑这个来校验了;       


3.2交互二        

PC发出报文           

  03 00 00 19 02 F0 80 32       01 00 00 FF FF 00 08 00              

  00 F0 00 00 01 00 01 07      80             

  PLC回复报文            

03 00 00 1B 02 F0 80 32     03 00 00 FF FF 00 08 00             

00 00 00 F0 00 00 01 00     01 00 F0           

第二个初始化报文交互,通过1200 和314,315的对比,发现居然完全没有任何区别;     

所以我们可以把这个交互完全固话;  

到此,整个初始化处理就算结束了,正常在设计架构的时候,可以这么实现:     

在ClentSocket的onConnect(即正常连接上)的瞬间,pc给plc发起第一个初始请求,得到回复后(为了简单,就仅仅判断长度为22即可);       

立刻发起第二个固定的初始话请求,得到长度为24的报文后,就通过一个布尔变量通知整个系统可以正常读写;

 

到这里,初始化,读,写3种方式都摸索完了,未必都正确,应付开发应该绰绰余裕了;在接下来的时间里,就需要把这些规律变成相应的程序;

 

4.读操作  

读demo1:         

西门子1200:  读取DB10,count=17 ,offset=19  

PC发出报文

(A[3]~A[4]=0x001F=31=读取报文总长度, A[12]~A[13]=0x001C=序列号,A[24]~A[25]=0x0011=17=读取请求count;  

A[26]~A[27]=0x000A=10=DB10,A[28]=0x84=读取的数据类型为DB块,A[29]~A[31]=0x000098=152=19*8=读取偏移量offset(bit为单位) )
03 00 00 1F 02 F0 80 32     01 00 00 00 1C 00 0E00  
00 04 01 12 0A 10 02
 00    11 00 0A 84 00 00 98     

PLC回复报文:
(B[3]~B[4]=0x002A=42=回复报文总长度, B[12]~B[13]=0x001C=序列号,B[16]~B[17]=0x0015=21=读取请求count(17)+4
B[24]~B[25]=0x0088=17*8=请求数据长度(bit为单位), B[26]~最后=数据值)

03 00 
00 2A 02 F0 80 32     03 00 00 00 1C 00 02 00    
15 00 00 04 01 FF 04 00     88 13 14 15 16 17 00 00   
00 00 00 00 00 00 00 00     00 00                   

读demo2:  
西门子1200:   读取DB11,count=17 ,offset=19
  PC发出报文:
(A[3]~A[4]=0x001F=31=读取报文总长度, A[12]~A[13]=0x008E=序列号,A[24]~A[25]=0x0011=17=读取请求count; 
A[26]~A[27]=0x000B=11=DB11, A[28]=0x84=读取的数据类型为DB块,A[29]~A[31]=0x000098=152=19*8=读取偏移量offset(bit为单位) )

03 00 00 1F 02 F0 80 32    01 00 00 00 8E 00 0E 00
00 04 01 12 0A 10 02 
00   11 00 0B 84 00 00 98

PLC
回复报文:
(B[3]~B[4]=0x002A=42=
回复报文总长度, B[12]~B[13]=0x001C=序列号,

B[16]~B[17]=0x0015=21=读取请求count(17)+4
B[24]~B[25]=0x0088=17*8=
请求数据长度(bit为单位), B[26]~B[42]=数据值)


03 00 
00 2A 02 F0 80 32    03 00 00 00 8E 00 02 00

15 00 00 04 01 FF 04 00    88 13 14 15 16 17 18 00
00 00 00 00 00 00 00 21    22 23

demo3   

西门子1200:读取DB11, count=16 ,offset=18

PC发出报文:

(A[3]~A[4]=0x001F=31=读取报文总长度, A[12]~A[13]=0x0013=序列号,

A[24]~A[25]=0x0010=16=读取请求count; 
A[26]~A[27]=0x000B=11=DB11, 

A[28]=0x84=读取的数据类型为DB块,A[29]~A[31]=0x000090=146=18*8=读取偏移量offset(bit为单位) )
03 00 00 1F 02 F0 80 32    01 00 00 00 13 00 0E 00
00 04 01 12 0A 10 02 00   10 
00 0B 84 00 00 90

PLC回复报文:
(B[3]~B[4]=0x0029=41=
回复报文总长度, B[12]~B[13]=0x0013=序列号,

B[16]~B[17]=0x0014=20=读取请求count(16)+4
B[24]~B[25]=0x0080=16*8=
请求数据长度(bit为单位), B[26]~B[41]=数据值)

03 00 
00 29 02 F0 80 32    03 00 00 00 13 00 02 00 

14 00 00 04 01 FF 04 00    80 00 13 14 15 16 17 18
00 00 00 00 00 00 00 00    21 
demo4     

西门子300 (314)  读取D50, count=20 ,offset=4000 

PC发出报文:
(A[3]~A[4]=0x001F=31=读取报文总长度, A[12]~A[13]=0x0028=序列号,

A[24]~A[25]=0x0014=20=读取请求count; 
A[26]~A[27]=0x0032=50=DB50, A[28]=0x84=读取的数据类型为DB块A[29]~A[31]=0x007D00=32000

=4000*8=读取偏移量offset(bit为单位) )

03 00 00 1F02 F0 80 32       01 00 00 00 28 00 0E 00  
00 04 01 12 0A 10 02 
00     14 00 32 84 00 7D 00    

PLC回复报文:

(B[3]~B[4]=0x002D=45=回复报文总长度, B[12]~B[13]=0x0028=序列号,

B[16]~B[17]=0x0018=24=读取请求count(20)+4
B[24]~B[25]=0x00A0=20*8=请求数据长度(bit为单位), B[26]~B[45]=数据值)
03 00 
00 2D02 F0 80 32        03 00 00 00 28 00 02 00 


18 00 00 04 01 FF 04 00        A0 00 04 0E AB 00 00 00   
00 00 00 03 00 00 00 00        00 00 00 00 00         

 

读demo5:  
    西门子300 (315)  读取D10, count=100 ,offset=2

PC发出报文:
(A[3]~A[4]=0x001F=31=读取报文总长度, A[12]~A[13]=0x0003=序列号,

A[24]~A[25]=0x0064=100=读取请求count; 
A[26]~A[27]=0x000A=10=DB10, A[28]=0x84=读取的数据类型为DB块,

A[29]~A[31]=0x000010=16=2*8=读取偏移量offset(bit为单位) )

03 00 00 1F 02 F0 80 32     01 00 00 00 03 00 0E 00
00 04 01 12 0A 10 02 00    64 00 0A 84 00 00 10


PLC回复报文:
(B[3]~B[4]=0x007D=125=回复报文总长度, B[12]~B[13]=0x0003=序列号,

B[16]~B[17]=0x0068=104=读取请求count(100)+4

B[24]~B[25]=0x0320=100*8=请求数据长度(bit为单位), B[26]~B[125]=数据值)

03 00 00 7D 02 F0 80 32    03 00 00 00 03 00 02 00

68 00 00 04 01 FF 04 03    20 00 00 00 01 00 00 00

00 00 00 00 00 00 0000     00 00 00 00 00 00 00 00

00 00 00 00 00 00 0000     00 00 00 00 00 00 00 00

00 00 00 00 00 00 0000     00 00 00 00 00 00 00 00

00 00 00 00 00 00 0000     00 00 00 00 00 00 00 00

00 00 00 00 00 00 0000     00 00 00 00 00 00 00 00

00 00 00 00 00 00 0000     00 00 00 00 00


读demo6:  
西门子1200 读取X输入(input)两个byte:

PC发出报文:

(A[3]~A[4]=0x001F=31=读取报文总长度, A[12]~A[13]=0x0002=序列号,

A[24]~A[25]=0x0002=2=读取请求count; 
A[26]~A[27]=0x000A=10=DB10[其实这里写什么都可以,因为input不属于DB块],
A[28]=0x81=读取的数据类型为InputA[29]~A[31]=0x000000=0=0*8=读取偏移量offset(bit为单位) )

03 00 
00 1F 02 F0 80 32     01 00 00 00 02 00 0E 00
00 04 01 12 0A 10 02
 00    02 00 0A 81 00 00 00

PLC回复报文:
(B[3]~B[4]=0x001B=27=回复报文总长度, B[12]~B[13]=0x0002=序列号,

B[16]~B[17]=0x0068=104=读取请求count(100)+4
B[24]~B[25]=0x0320=100*8=请求数据长度(bit为单位), B[26]~B[27]=数据值)
03 00 
00 1B 02 F0 80 32      03 00 00 00 02 00 02 00

06 00 00 04 01 FF 04 00      10 08 00


读demo7:  

西门子1200 读取Y输出(output)两个byte:PC发出报文:
(A[3]~A[4]=0x001F=31=读取报文总长度, A[12]~A[13]=0x0001=序列号,

A[24]~A[25]=0x0002=2=读取请求count; 
A[26]~A[27]=0x000A=10=DB10[其实这里写什么都可以,因为input不属于DB块],
A[28]=0x82=读取的数据类型为Output,A[29]~A[31]=0x000000=0=0*8=读取偏移量offset(bit为单位) )

03 00 
00 1F 02 F0 80 32    01 00 00 00 01 00 0E 00
00 04 01 12 0A 10 02 
00   02 00 0A 82 00 00 00

PLC
回复报文:
(B[3]~B[4]=0x001B=27=回复报文总长度, B[12]~B[13]=0x0002=序列号,

B[16]~B[17]=0x0068=104=读取请求count(100)+4
B[24]~B[25]=0x0320=100*8=请求数据长度(bit为单位), B[26]~B[27]=数据值)

03 00
 
00 1B 02 F0 80 32   03 00 00 00 01 00 02 00

06 00 00 04 01 FF 04 00   10 05 00                                                                                                  

读demo8:

西门子1200读取flag两个byte:
PC发出报文:
03 00 00 1F 02 F0 80 32   01 00 00 05 65 00 0E 00

00 04 01 12 0A 1002 00   02 00 09 83 00 00 00


PLC回复报文:
(B[3]~B[4]=0x001B=27=回复报文总长度, B[12]~B[13]=0x0565=序列号,

B[16]~B[17]=0x0006=6=读取请求count(2)+4

B[24]~B[25]=0x0010=2*8=请求数据长度(bit为单位), B[26]~B[27]=数据值)

03 00 00 1B 02 F0 80 32     03 00 00 05 65 00 02 00

06 00 00 04 01 FF 04 00     10 FF 17

 


程序设计的时候,其实主要关注最后4个信息,

 

4.写操作

写demo1: 

西门子1200 写  db10.WORD18=0xFFFE=65534; 也就是:DB10.b18=0xFF; DB10.B19=0xFE;


PC发出报文:
(A[3]~A[4]=0x0025=37=读取报文总长度, A[12]~A[13]=0x0005=序列号,A[16]~A[17]=0x06=写入byte个数(2)+4 , A[23]=0x02=写入方式为byte,A[24]~A[25]=0x0002=2=写入个数count; 
A[26]~A[27]=0x000A=10=DB10,A[28]=0x84=写入的数据类型为DB块,A[29]~A[31]=0x000090=144=18
*8=读取偏移量offset(bit为单位)
A[32]~A[33]=0x0004=写入方式为Byte ,  A[34]~A[35]=0x0010=2*8=写入byte的个数(bit为单位) ,A[36]~A[37]= 写入数据)

03 00 00 25 02 F0 80 32         01 00 00 00 05 00 0E 00 

06 05 01 12 0A 10 02 00            02  00 0A 84 00 00 90 00

04 00 10  FF FE                   

PLC回复报文:
( B[12]~B[13]=0x0565=
序列号,最后一个B[14]=0xFF表示写入)

03 00 00 16 02 F0 80 32    03 00 00 00 05 00 02 00   01 00 00 05 01 FF                         

 写demo2:  

1200 写入 DB10. X2.6=1 (这里是按bit写入)

PC发出报文:

(A[3]~A[4]=0x0024=36=读取报文总长度, A[12]~A[13]=0x0008=序列号,A[16]~A[17]=0x05=写入bit个数(1)+4  A[26]~A[27]=0x000A=10=DB10,A[28]=0x84=写入的数据类型为DB块,A[29]~A[31]=0x000016=22=2*8+6=读取偏移量offset( bit为单位)A[32]~A[33]=0x0003=写入方式为bit ,  A[34]~A[35]=0x0001=写入bit的个数(bit为单位) ,A[36]= 写入数据[0或1])

03 00 00 24 02 F0 80 32    01 00 000 08 00 0E 00

05 05 01 12 0A 10 01 00    01 00 0A 84 00 00 16 00

03 00 01 01

PLC回复报文:
( B[12]~B[13]=0x0565=
序列号,最后一个B[14]=0xFF表示写入)
03 00 00 16 02 F0 80 32    03 00 00 00 08 00 02 00

01 00 00 05 01 FF  


写demo3:    

1200 写 入:output0=4

PC发出报文:
(A[3]~A[4]=0x0024=36=读取报文总长度, A[12]~A[13]=0x0008=序列号,A[16]~A[17]=0x05=写入byte个数(1)+4 ,

A[23]=0x02=写入方式为byte,A[24]~A[25]=0x0001=1=写入个数count; 

A[26]~A[27]=0x0001=DB1(因为是output,所以DB块编号无所谓),A[28]=0x82=写入的数据类型为output,A[29]~A[31]=0x000000=读取偏移量offset( bit为单位)
A[32]~A[33]=0x0004=写入方式为byte,  A[34]~A[35]=0x0008=1*8=写入byte的个数 ,A[36]= 写入数据)

03 00 00 24 02 F0 80 32     01 00 00 00 08 00 0E 00

05 05 01 12 0A 10 02 00    01 00 01 82 00 00 00 00
04 00 08 04


PLC回复报文:
( B[12]~B[13]=0x0565=
序列号,最后一个B[14]=0xFF表示写入)
03 00 00 16 02 F0 80 32     03 00 00 00 08 00 02 00

01 00 00 05 01 FF  


写demo4:
1200
写 输入:output 0.3=1
PC发出报文:
(A[3]~A[4]=0x0024=36=写入报文总长度, A[12]~A[13]=0x0003=序列号,A[16]~A[17]=0x05=写入bit个数(1)+4A[23]=0x01=写入方式为bit,A

[24]~A[25]=0x0001=1=写入个数count;   

A[26]~A[27]=0x000A=10=DB10(因为是output,所以DB块编号无所谓),A[28]=0x82=写入的数据类型为output,

A[29]~A[31]=0x000003=读取偏移量offset( bit为单位)
 A[32]~A[33]=0x0003=写入方式为bit ,  

A[34]~A[35]=0x0001=写入bit的个数(bit为单位) ,

A[36]= 写入数据[0或1])
03 00 00 24 02 F0 80 32    01 00 00 00 03 00 0E 00

05 05 01 12 0A 10 01 00    01 00 01 82 00 00 03 00

03 00 01 01


PLC回复报文:

( B[12]~B[13]=0x0565=
序列号,最后一个B[14]=0xFF表示写入)

03 00 00 16 02 F0 80 32   03 00 00 00 03 00 02 00

01 00 00 05 01 FF


关注订阅本公众号,学习机器人、PLC、触摸屏、组态、变频器、伺服控制、传感器、气动等自动化技术,轻松成为优秀的自动化工程师。
自动化电气系统,QQ群  60886850






















以上是关于西门子TCP协议解析的主要内容,如果未能解决你的问题,请参考以下文章

2021-12-03 WPF上位机 104-西门子S7协议之写数据方法流程解析

2021-12-03 WPF上位机 106-西门子S7协议之读写PLC时间方法流程解析

2021-12-03 WPF上位机 105-西门子S7协议之启动,停止方法流程解析

2021-12-03 WPF上位机 103-西门子S7协议之V区,DB区读数据方法流程解析

西门子S7comm协议解析 —— 利用Wireshark对报文逐字节进行解析详细解析S7comm所含功能码以及UserData功能(path3)

西门子S7comm协议解析 —— 利用Wireshark对报文逐字节进行解析详细解析S7comm所含功能码以及UserData功能(path1)