| 注冊| 產(chǎn)品展廳| 收藏該商鋪

行業(yè)產(chǎn)品

當前位置:
上海邑斯自動化科技有限公司>>技術(shù)文章>>西門子S7報文解析

西門子S7報文解析

閱讀:780        發(fā)布時間:2022-12-1

1.報文的基本格式

1.1 第1和第2個字節(jié)是:固定報文頭03 00,這里我們就用到三種報文:a.初始化 b. 讀 c.寫,都是這種格式;

1.2 第3和第4個字節(jié)是:整個報文的長度;

       其它部分就是各種報文的個性化處理了;

       下面分析大量報文的案例進行規(guī)律分析,為了便于對照,每種都用1200 和300 兩種對照demo顯示:

 

2.初始化報文

初始化報文分兩個交互:

2.1 交互一
西門子1200:
PC發(fā)出報文 ( [A18]=0x01 =CPUSlot)
03 00 00 16 11 E0 00 00 00 01 00 C1 02 01 00 C2 02 01 01(cpuslot) 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 C1 02  01 00 C2 02 01 01 (cpuslot)

 

 

西門子300:
PC發(fā)出報文 ( A[18]=0x02 =CPUSlot)
03 00 00 16 11 E0 00 00 00 01 00 C1 02 01 00 C2 02 01 02(cpuslot) 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;
所以可以摸索規(guī)律是:
a.pc發(fā)起第一個初始化報文的時候,第18個字節(jié)標識了CPUSlot ;
b.plc回復報文和讀取報文長度一樣都是22個字節(jié)長度;
c.plc回復報文的最后一個字節(jié)也是CPUSlot ,這個可以用來校驗;
d. plc回復的第10個字節(jié)一個是06,一個是04,這個好像是小型號的區(qū)別;
細節(jié)摸索下來:1200該字節(jié)是06,314是04,315是03;咱寫程序的時候,就不要考慮這個來校驗了;

 

2.2交互二
PC發(fā)出報文
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的對比,發(fā)現(xiàn)居然全沒有任何區(qū)別;
所以我們可以把這個交互完**話;
到此,整個初始化處理就算結(jié)束了,正常在設(shè)計架構(gòu)的時候,可以這么實現(xiàn):
在ClentSocket的onConnect(即正常連接上)的瞬間,pc給plc發(fā)起第一個初始請求,得到回復后(為了簡單,就僅僅判斷長度為22即可);
立刻發(fā)起第二個固定的初始話請求,得到長度為24的報文后,就通過一個布爾變量通知整個系統(tǒng)可以正常讀寫;

 

3.讀操作

 

讀demo1:

西門子1200: 讀取DB10, count=17 ,offset=19

PC發(fā)出報文

(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=讀取的數(shù)據(jù)類型為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 0E 00 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=請求數(shù)據(jù)長度(bit為單位), B[26]~最后=數(shù)據(jù)值)

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發(fā)出報文:

(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=讀取的數(shù)據(jù)類型為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=請求數(shù)據(jù)長度(bit為單位), B[26]~B[42]=數(shù)據(jù)值)

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發(fā)出報文:

(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=讀取的數(shù)據(jù)類型為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=請求數(shù)據(jù)長度(bit為單位), B[26]~B[41]=數(shù)據(jù)值)

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發(fā)出報文:

(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=讀取的數(shù)據(jù)類型為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 8400 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=請求數(shù)據(jù)長度(bit為單位), B[26]~B[45]=數(shù)據(jù)值)

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發(fā)出報文:
(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=讀取的數(shù)據(jù)類型為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=請求數(shù)據(jù)長度(bit為單位), B[26]~B[125]=數(shù)據(jù)值)

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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


讀demo6:

西門子1200 讀取X輸入(input)兩個byte:

PC發(fā)出報文:

(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=讀取的數(shù)據(jù)類型為Input,A[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=請求數(shù)據(jù)長度(bit為單位), B[26]~B[27]=數(shù)據(jù)值)

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發(fā)出報文:

(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=讀取的數(shù)據(jù)類型為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=請求數(shù)據(jù)長度(bit為單位), B[26]~B[27]=數(shù)據(jù)值)

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發(fā)出報文:
03 00 00 1F 02 F0 80 32 01 00 00 05 65 00 0E 00 00 04 01 12 0A 10 02 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=請求數(shù)據(jù)長度(bit為單位), B[26]~B[27]=數(shù)據(jù)值)

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

根據(jù)以上8個報文的demo,摸索出大致規(guī)律如下(未必全正確,但是應付項目可以了);
A[1]~A[2]: 03 00 固定報文頭;
A[3]~A[4]: 00 1F 整個讀取請求長度為0x1F= 31 ;
A[5]~A[11]: 02 F0 80 32 01 00 00 固定6個字節(jié);
A[12]~A[13]: 兩個字節(jié),標識序列號,回復報文相同位置和這個全一樣;范圍是0~65535;
A[14]~A[23]:00 0E 00 00 04 01 12 0A 10 02 固定10個字節(jié)
A[24]~A[25]:兩個字節(jié),訪問數(shù)據(jù)的個數(shù),以byte為單位;
A[26]~A[27]: DB塊的編號,比如DB50, 就是0x32=50, 兩個字節(jié),范圍是0~65535(也許是一個1個字節(jié),因為沒有設(shè)置估DB255以上的數(shù)據(jù)塊,所以不知道到底是幾個字節(jié),姑且認為是2個字節(jié));
A[28] : 訪問數(shù)據(jù)塊的類型:0x81-input ,0x82-output ,0x83-flag , 0x84-DB(這個最常見);
A[29]~A[31]: 訪問DB塊的偏移量offset (地址+1以byte為單位); 3個字節(jié),范圍是0~16777216(一般 用不到這么大)


程序設(shè)計的時候,其實主要關(guān)注最后4個信息,即:
1. A[24]~A[25]: 訪問byte個數(shù)
2. A[26]~A[27]: DB塊編號
3. A[28] : 數(shù)據(jù)塊類型
4.A[29]~A[31] :訪問地址偏移量;相當于首地址編號
B[1]~B[2]: 03 00 固定報文頭
B[3]~B[4]: 整個讀取回復報文長度:25+讀取長度;
B[5]~B[11]: 02 F0 80 32 03 00 00 固定6個字節(jié),和讀取請求相同的位置幾乎一樣,就 B[9]=0x03 ;A[9]=0x01;
B[12]~B[13]: 兩個字節(jié),標識序列號,回復報文相同位置和這個全一樣;范圍是0~65535;

B[14]~B[15]: 兩個字節(jié),固定為00 02;對應讀取位置是 00 0E;正好 02+0E=10 ;有點補碼的感覺,其實不需要關(guān)注規(guī)律,反正是固定的;
B[16]~B[17]:兩個字節(jié),=請求讀取的字節(jié)數(shù)+4;
B[18]~B[23]:6個字節(jié),固定為:00 00 04 01 FF 04 ;
B[24]~B[25]:兩個字節(jié), 請求訪問的byte個數(shù)*8 ;其實就是以二進制為單位的個數(shù);由此可以看出,一口氣最多訪問的地址個數(shù)是8192;
B[26]~ 最后一個 :以offset作為首地址,所對應的各個byte的值;


程序設(shè)計的時候,其實只要關(guān)注兩個信息
1.校驗B[3]~B[4]:校驗長度正確;
2.B[26]~最后一個 :獲取對應的值;
到這里讀的處理就算結(jié)束了;幾個小注意點:
1. 對于不同信號的PLC,除了初始化的CPUSolt不同;正常讀/寫指令是一樣的;
2.讀的時候,都是以byte為單位的,如果程序只需要bit,那么還是以Byte為單位去讀,將讀出的部分按bit再去分解;
3.flag類型到底是什么,不是很清楚,有點類似三菱里的M點;這個也不需要去深究,一般項目里主要就是用DB塊;
4.讀取的長度如果是N(以byte為單位),那么返回的長度就是N*8(以bit為單位);怎么判斷長度是否要*8;主要看后面是不是緊挨著數(shù)據(jù),
如果是數(shù)據(jù),就需要*8;offset都是以bit為單位的;
5.正常讀的操作都是DB塊,所以在A[26]~A[27]這個字節(jié)寫入DB塊的編號,但是對于input,output,flags這三個類型,是不需要數(shù)據(jù)塊編號的,
不過我們可以隨便寫一個DB編號;


4.寫操作

寫demo1: 
西門子1200 寫 db10.WORD18=0xFFFE=65534; 也就是:DB10.b18=0xFF; DB10.B19=0xFE;
PC發(fā)出報文:
(A[3]~A[4]=0x0025=37=讀取報文總長度, A[12]~A[13]=0x0005=序列號,A[16]~A[17]=0x06=寫入byte個數(shù)(2)+4 , A[23]=0x02=寫入方式為byte, A[24]~A[25]=0x0002=2=寫入個數(shù)count; A[26]~A[27]=0x000A=10=DB10,A[28]=0x84=寫入的數(shù)據(jù)類型為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的個數(shù)(bit為單位) ,A[36]~A[37]= 寫入數(shù)據(jù))

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發(fā)出報文:
(A[3]~A[4]=0x0024=36=讀取報文總長度, A[12]~A[13]=0x0008=序列號,A[16]~A[17]=0x05=寫入bit個數(shù)(1)+4 A[26]~A[27]=0x000A=10=DB10,A[28]=0x84=寫入的數(shù)據(jù)類型為DB

塊,A[29]~A[31]=0x000016=22=2*8+6=讀取偏移量offset( bit為單位)

A[32]~A[33]=0x0003=寫入方式為bit , A[34]~A[35]=0x0001=寫入bit的個數(shù)(bit為單位) ,A[36]= 寫入數(shù)據(jù)[0或1])

03 00 00 24 02 F0 80 32 01 00 00 00 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發(fā)出報文:(A[3]~A[4]=0x0024=36=讀取報文總長度, A[12]~A[13]=0x0008=序列號,A[16]~A[17]=0x05=寫入byte個數(shù)(1)+4 ,A[23]=0x02=寫入方式為byte,A[24]~A[25]=0x0001=1=寫入個數(shù)count; A[26]~A[27]=0x0001=DB1(因為是output,所以DB塊編號無所謂),A[28]=0x82=寫入的數(shù)據(jù)類型為output,A[29]~A[31]=0x000000=讀取偏移量offset( bit為單位)A[32]~A[33]=0x0004=寫入方式為byte , A[34]~A[35]=0x0008=1*8=寫入byte的個數(shù) ,A[36]= 寫入數(shù)據(jù))

03 0000 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發(fā)出報文:(A[3]~A[4]=0x0024=36=寫入報文總長度, A[12]~A[13]=0x0003=序列號,A[16]~A[17]=0x05=寫入bit個數(shù)(1)+4A[23]=0x01=寫入方式為bit,A[24]~A[25]=0x0001=1=寫入個數(shù)count; A[26]~A[27]=0x000A=10=DB10(因為是output,所以DB塊編號無所謂),A[28]=0x82=寫入的數(shù)據(jù)類型為output,A[29]~A[31]=0x000003=讀取偏移量offset( bit為單位)
A[32]~A[33]=0x0003=寫入方式為bit , A[34]~A[35]=0x0001=寫入bit的個數(shù)(bit為單位) ,A[36]= 寫入數(shù)據(jù)[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

根據(jù)以上4個報文的demo,摸索出大致規(guī)律如下(未必全正確,但是應付項目可以了);
A[1]~A[2]: 03 00 固定報文頭;
A[3]~A[4]: 整個報文長度:35+寫入長度;
A[5]~A[11]: 02 F0 80 32 01 00 00 固定6個字節(jié)(和讀取的全一樣)
A[12]~A[13]: 兩個字節(jié),標識序列號,回復報文相同位置和這個全一樣;范圍是0~65535;
A[14]~A[15]:00 0E 固定2個字節(jié);
A[16]~A[17]:寫入長度+4;
A[18]~A[22]: 05 01 12 0A 10 固定5個自己
A[23] : 寫入方式:01-按bit寫入;02-按byte寫入;
A[24]~A[25]:兩個字節(jié),寫入數(shù)據(jù)的個數(shù)(可能是byte或bit, 按A[23]來區(qū)分)
A[26]~A[27]: DB塊的編號
A[28] : 寫入數(shù)據(jù)塊的類型:0x81-input ,0x82-output ,0x83-flag , 0x84-DB(這個最常見);
A[29]~A[31]: 寫入DB塊的偏移量offset (地址+1以byte為單位); 3個字節(jié),范圍是0~16777216(一般 用不到這么大)A[32]~A[33]:寫入方式為:03-按bit寫入; 04-按byte寫入; 
A[34]~A[35]:寫入bit的個數(shù)(bit為單位) 
A[36]~最后 :連續(xù)的寫入值;

 

B[1]~B[2]: 03 00 固定報文頭;

B[14]: FF 標識寫入正常;

到這里,初始化,讀,寫 這3種方式都摸索完了,未必都正確,應付開發(fā)應該綽綽有余;
在接下來的時間里,就需要把這些規(guī)律變成相應的程序


收藏該商鋪

登錄 后再收藏

提示

您的留言已提交成功!我們將在第一時間回復您~
二維碼