一直想把三菱和西門子這兩個使用頻率最高的PLC上位通訊,融合到WCS系統(tǒng)的框架里;
現(xiàn)在三菱主流使用Q系列,使用的是MC協(xié)議, 前一段時間也寫過一個入門介紹:
三菱Q系列通訊方式設(shè)計說明
去年8月份,無意中發(fā)現(xiàn)用網(wǎng)絡(luò)抓包工具可以一點不漏的抓取通訊包,簡單摸索一下,也把規(guī)律摸索的七七八八了,
也寫了一個簡單的說明:
終于破解了西門子通訊協(xié)議
但是真正用于項目,就需要100%的摸索出來;
一直都想早點弄出來,代替OPC, 但是拖延癥太厲害,一直拖了半年,都沒有進一步去完善;
這兩天過年期間,難得心里靜下來,不去考慮老項目維護,也暫時把手頭上新項目先放下,腦子可以放空,把這個拖延了10幾年的問題先處理掉;
這么多年來,做項目一直計較框架的設(shè)計; 每次新項目下來,都有些新的個性化的東西, 這時都會就會發(fā)現(xiàn)之前的框架里又有些不滿足的地方;
這時候就會糾結(jié); 到底是沿用老框架,迅速做項目;還是先把老框架升級好,再做項目;
如果不革新,項目就壓的你就沒機會升級;小米的MIUI基本每周升級一次;我們這點升級其實算不了什么;
這么大歲數(shù)了,能干活也沒幾年了,在避免不了的被淘汰之前, 還是咬牙升級框架升級好;不要被甩的太遠;
想想白居易的<琵芭行>, 印象最深的幾句:門前冷落鞍馬稀,老大嫁作商人婦,商人重利輕別離 ;一直靠拼體力生存,歲月最終會讓你體會到門可羅雀的凄涼;
再看看最馮小剛主演的<老炮兒>; 也許未曾擁有,就被時代的洪流給淹沒了;如今互諒網(wǎng)時代,茍延殘喘的混著吧。
言歸正傳,先說說
1.西門子和三菱的幾個區(qū)別(上位只關(guān)心的通訊層面):
1. 西門子PLC通訊端口固定102,但是可以連接多個PC端(客戶端),三菱PLC通訊端口可以自定義,最多好像8個,但是每個端口只能連接一個客戶端;
2. 兩者的讀寫指令類似,但是西門子在端口連接的時候,要做兩個初始化指令交互后,才能正常讀寫處理; 如果中途有錯誤格式的指令,可能導(dǎo)致端口連接斷開;
3. 三菱PLC主要是以字為單位讀寫的;西門子主要是以字節(jié)為單位讀寫; 所以三菱相鄰兩個地址相差16bit,西門子相鄰兩個地址相差8bit;
4.三菱PLC的數(shù)據(jù)塊,一般最小處理單位就是字,很少拆成bit處理(或者把整個字當(dāng)作0,1布爾類型處理,但是這樣有點太浪費了),
而且上位PC端只能用字去讀寫,無法按位讀寫,如果真的要用bit處理,一般就用M點;
西門子這塊比較靈活,可以按bit或byte去讀寫;如果按byte,標(biāo)識的樣子是:DB10.B99 ;如果是bit,標(biāo)識的樣子是:DB10.X99.0~DB10.X99.7
5.三菱PLC的數(shù)據(jù)塊是固定的,比如D0~D6000; 西門子的數(shù)據(jù)塊是通過西門子的編程工具初始化的,也就是說,你可以把一片地址定義成DB10,也可以定義成DB50;
通俗的說:三菱PLC的數(shù)據(jù)庫偏硬; 西門子的偏軟,它的地址是映射的虛擬地址;
6. 三菱的數(shù)據(jù)位是從小到大的,比如某個雙字,低位在前,高位在后;這是針對數(shù)字類型,但是如果是ascii碼,因為一個字有兩個字節(jié),這時候卻又是反的;
所以在三菱里面對數(shù)字和字符類型,要分兩種順序處理;
西門子是從大到小的;這兩種方法有什么區(qū)別呢; 簡單來說:從小到大主要是計算機思考的方式; 從大到小是人的思考方式;
比如655539,它等于65536+3,轉(zhuǎn)換成16進制是0x00010003 需要兩個字 , 如果在三菱里存儲的順序就是先低位3,再高位1,也就是 03 00 01 00;
在西門子里存儲的順序從高到低,也就是00 01 00 03;
就像oracle在的數(shù)據(jù)在windows系統(tǒng)里的數(shù)據(jù)存儲順序是從小到大,在liunx系統(tǒng)里又是從大到小;
2.報文的基本格式:
2.1 第1和第2個字節(jié)是:固定報文頭03 00,這里我們就用到三種報文: a.初始化 b. 讀 c.寫,都是這種格式;
2.2 第3和第4個字節(jié)是:整個報文的長度;
其它部分就是各種報文的個性化處理了;
下面分析大量報文的案例進行規(guī)律分析,為了便于對照,每種都用1200 和300 兩種對照demo顯示:
3.初始化報文
初始化報文分兩個交互;
3.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 C0 01 09
PLC回復(fù)報文( 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
西門子300:
PC發(fā)出報文 ( 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回復(fù)報文 (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é)標(biāo)識了CPUSlot ;
b.plc回復(fù)報文和讀取報文長度一樣都是22個字節(jié)長度;
c.plc回復(fù)報文的最后一個字節(jié)也是CPUSlot ,這個可以用來校驗;
d. plc回復(fù)的第10個字節(jié)一個是06,一個是04,這個好像是小型號的區(qū)別;
細節(jié)摸索下來:1200該字節(jié)是06,314是04,315是03;咱寫程序的時候,就不要考慮這個來校驗了;
3.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回復(fù)報文
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ā)起第一個初始請求,得到回復(fù)后(為了簡單,就僅僅判斷長度為22即可);
立刻發(fā)起第二個固定的初始話請求,得到長度為24的報文后,就通過一個布爾變量通知整個系統(tǒng)可以正常讀寫;
4.讀操作
讀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回復(fù)報文:
(B[3]~B[4]=0x002A=42=回復(fù)報文總長度, 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回復(fù)報文:
(B[3]~B[4]=0x002A=42=回復(fù)報文總長度, 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回復(fù)報文:
(B[3]~B[4]=0x0029=41=回復(fù)報文總長度, 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回復(fù)報文:
(B[3]~B[4]=0x002D=45=回復(fù)報文總長度, 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
1800 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回復(fù)報文:
(B[3]~B[4]=0x007D=125=回復(fù)報文總長度, 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回復(fù)報文:
(B[3]~B[4]=0x001B=27=回復(fù)報文總長度, 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回復(fù)報文:
(B[3]~B[4]=0x001B=27=回復(fù)報文總長度, 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回復(fù)報文:
(B[3]~B[4]=0x001B=27=回復(fù)報文總長度, 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ī)律如下(未必完全正確,但是應(yīng)付項目可以了);
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é),標(biāo)識序列號,回復(fù)報文相同位置和這個完全一樣;范圍是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] :訪問地址偏移量;相當(dāng)于首地址編號
B[1]~B[2]: 03 00 固定報文頭
B[3]~B[4]: 整個讀取回復(fù)報文長度: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é),標(biāo)識序列號,回復(fù)報文相同位置和這個完全一樣;范圍是0~65535;
B[14]~B[15]: 兩個字節(jié),固定為00 02;對應(yīng)讀取位置是 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作為首地址,所對應(yīng)的各個byte的值;
程序設(shè)計的時候,其實只要關(guān)注兩個信息:
1.校驗B[3]~B[4]:校驗長度正確;
2.B[26]~最后一個 :獲取對應(yīng)的值;
到這里讀的處理就算結(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回復(fù)報文:
( 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回復(fù)報文:
( 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回復(fù)報文:
( 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回復(fù)報文:
( 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ī)律如下(未必完全正確,但是應(yīng)付項目可以了);
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é),標(biāo)識序列號,回復(fù)報文相同位置和這個完全一樣;范圍是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 標(biāo)識寫入正常;
到這里,初始化,讀,寫 這3種方式都摸索完了,未必都正確,應(yīng)付開發(fā)應(yīng)該綽綽余裕了;
在接下來的時間里,就需要把這些規(guī)律變成相應(yīng)的程序;
注意點:
1.寫入可以按byte和bit兩種方法去操作;
2.對于byte,可以一口氣寫連續(xù)多個byte, 理論上一條指令連續(xù)寫bit也可以,但是實踐下來,發(fā)現(xiàn)有問題,所以對于bit操作,我們就一個一個寫吧;
聯(lián)系客服