【轉】西門子PLC以太網 通訊協議 解析


一直想把三菱和西門子這兩個使用頻率最高的PLC上位通訊,融合到WCS系統的框架里;
現在三菱主流使用Q系列,使用的是MC協議, 前一段時間也寫過一個入門介紹:
三菱Q系列通訊方式設計說明
去年8月份,無意中發現用網絡抓包工具可以一點不漏的抓取通訊包,簡單摸索一下,也把規律摸索的七七八八了,
也寫了一個簡單的說明:
終於破解了西門子通訊協議
但是真正用於項目,就需要100%的摸索出來;
一直都想早點弄出來,代替OPC, 但是拖延症太厲害,一直拖了半年,都沒有進一步去完善;
這兩天過年期間,難得心里靜下來,不去考慮老項目維護,也暫時把手頭上新項目先放下,腦子可以放空,把這個拖延了10幾年的問題先處理掉;
這么多年來,做項目一直計較框架的設計; 每次新項目下來,都有些新的個性化的東西, 這時都會就會發現之前的框架里又有些不滿足的地方;
這時候就會糾結; 到底是沿用老框架,迅速做項目;還是先把老框架升級好,再做項目;
如果不革新,項目就壓的你就沒機會升級;小米的MIUI基本每周升級一次;我們這點升級其實算不了什么;
這么大歲數了,能干活也沒幾年了,在避免不了的被淘汰之前, 還是咬牙升級框架升級好;不要被甩的太遠;
想想白居易的<琵芭行>, 印象最深的幾句:門前冷落鞍馬稀,老大嫁作商人婦,商人重利輕別離 ;一直靠拼體力生存,歲月最終會讓你體會到門可羅雀的凄涼;
再看看最馮小剛主演的<老炮兒>; 也許未曾擁有,就被時代的洪流給淹沒了;如今互諒網時代,苟延殘喘的混着吧。
言歸正傳,先說說
1.西門子和三菱的幾個區別(上位只關心的通訊層面):

  1. 西門子PLC通訊端口固定102,但是可以連接多個PC端(客戶端),三菱PLC通訊端口可以自定義,最多好像8個,但是每個端口只能連接一個客戶端;
  2. 兩者的讀寫指令類似,但是西門子在端口連接的時候,要做兩個初始化指令交互后,才能正常讀寫處理; 如果中途有錯誤格式的指令,可能導致端口連接斷開;
  3. 三菱PLC主要是以字為單位讀寫的;西門子主要是以字節為單位讀寫; 所以三菱相鄰兩個地址相差16bit,西門子相鄰兩個地址相差8bit;
    4.三菱PLC的數據塊,一般最小處理單位就是字,很少拆成bit處理(或者把整個字當作0,1布爾類型處理,但是這樣有點太浪費了),
    而且上位PC端只能用字去讀寫,無法按位讀寫,如果真的要用bit處理,一般就用M點;
    西門子這塊比較靈活,可以按bit或byte去讀寫;如果按byte,標識的樣子是:DB10.B99 ;如果是bit,標識的樣子是:DB10.X99.0~DB10.X99.7
    5.三菱PLC的數據塊是固定的,比如D0~D6000; 西門子的數據塊是通過西門子的編程工具初始化的,也就是說,你可以把一片地址定義成DB10,也可以定義成DB50;
    通俗的說:三菱PLC的數據庫偏硬; 西門子的偏軟,它的地址是映射的虛擬地址;
  4. 三菱的數據位是從小到大的,比如某個雙字,低位在前,高位在后;這是針對數字類型,但是如果是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 C1 02
    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的報文后,就通過一個布爾變量通知整個系統可以正常讀寫;
    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=198=讀取偏移量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=請求數據長度(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=198=讀取偏移量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=188=讀取偏移量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
    =40008=讀取偏移量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=請求數據長度(bit為單位), B[26]~B[45]=數據值)
    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發出報文:
    (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=28=讀取偏移量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 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發出報文:
    (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=讀取的數據類型為Input,A[29]~A[31]=0x000000=0=08=讀取偏移量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=08=讀取偏移量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 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=請求數據長度(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
    根據以上8個報文的demo,摸索出大致規律如下(未必完全正確,但是應付項目可以了);
    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個字節;
    A[12]~A[13]: 兩個字節,標識序列號,回復報文相同位置和這個完全一樣;范圍是0~65535;
    A[14]~A[23]:00 0E 00 00 04 01 12 0A 10 02 固定10個字節
    A[24]~A[25]:兩個字節,訪問數據的個數,以byte為單位;
    A[26]~A[27]: DB塊的編號,比如DB50, 就是0x32=50, 兩個字節,范圍是0~65535(也許是一個1個字節,因為沒有設置估DB255以上的數據塊,所以不知道到底是幾個字節,姑且認為是2個字節);
    A[28] : 訪問數據塊的類型:0x81-input ,0x82-output ,0x83-flag , 0x84-DB(這個最常見);
    A[29]~A[31]: 訪問DB塊的偏移量offset (地址+1以byte為單位); 3個字節,范圍是0~16777216(一般 用不到這么大)
    程序設計的時候,其實主要關注最后4個信息,即:
  5. A[24]~A[25]: 訪問byte個數
  6. A[26]~A[27]: DB塊編號
  7. A[28] : 數據塊類型
    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個字節,和讀取請求相同的位置幾乎一樣,就 B[9]=0x03 ;A[9]=0x01;
    B[12]~B[13]: 兩個字節,標識序列號,回復報文相同位置和這個完全一樣;范圍是0~65535;
    B[14]~B[15]: 兩個字節,固定為00 02;對應讀取位置是 00 0E;正好 02+0E=10 ;有點補碼的感覺,其實不需要關注規律,反正是固定的;
    B[16]~B[17]:兩個字節,=請求讀取的字節數+4;
    B[18]~B[23]:6個字節,固定為:00 00 04 01 FF 04 ;
    B[24]~B[25]:兩個字節, 請求訪問的byte個數*8 ;其實就是以二進制為單位的個數;由此可以看出,一口氣最多訪問的地址個數是8192;
    B[26]~ 最后一個 :以offset作為首地址,所對應的各個byte的值;
    程序設計的時候,其實只要關注兩個信息:
    1.校驗B[3]~B[4]:校驗長度正確;
    2.B[26]~最后一個 :獲取對應的值;
    到這里讀的處理就算結束了;幾個小注意點:
  8. 對於不同信號的PLC,除了初始化的CPUSolt不同;正常讀/寫指令是一樣的;
    2.讀的時候,都是以byte為單位的,如果程序只需要bit,那么還是以Byte為單位去讀,將讀出的部分按bit再去分解;
    3.flag類型到底是什么,不是很清楚,有點類似三菱里的M點;這個也不需要去深究,一般項目里主要就是用DB塊;
    4.讀取的長度如果是N(以byte為單位),那么返回的長度就是N8(以bit為單位);怎么判斷長度是否要8;主要看后面是不是緊挨着數據,
    如果是數據,就需要8;offset都是以bit為單位的;
    5.正常讀的操作都是DB塊,所以在A[26]~A[27]這個字節寫入DB塊的編號,但是對於input,output,flags這三個類型,是不需要數據塊編號的,
    不過我們可以隨便寫一個DB編號;
    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=28=寫入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 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發出報文:
    (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 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發出報文:
    (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
    根據以上4個報文的demo,摸索出大致規律如下(未必完全正確,但是應付項目可以了);
    A[1]~A[2]: 03 00 固定報文頭;
    A[3]~A[4]: 整個報文長度:35+寫入長度;
    A[5]~A[11]: 02 F0 80 32 01 00 00 固定6個字節(和讀取的完全一樣)
    A[12]~A[13]: 兩個字節,標識序列號,回復報文相同位置和這個完全一樣;范圍是0~65535;
    A[14]~A[15]:00 0E 固定2個字節;
    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]:兩個字節,寫入數據的個數(可能是byte或bit, 按A[23]來區分)
    A[26]~A[27]: DB塊的編號
    A[28] : 寫入數據塊的類型:0x81-input ,0x82-output ,0x83-flag , 0x84-DB(這個最常見);
    A[29]~A[31]: 寫入DB塊的偏移量offset (地址+1以byte為單位); 3個字節,范圍是0~16777216(一般 用不到這么大)A[32]~A[33]:寫入方式為: 03-按bit寫入; 04-按byte寫入;
    A[34]~A[35]:寫入bit的個數(bit為單位)
    A[36]~最后 : 連續的寫入值;
    B[1]~B[2]: 03 00 固定報文頭;
    B[14]: FF 標識寫入正常;
    到這里,初始化,讀,寫 這3種方式都摸索完了,未必都正確,應付開發應該綽綽余裕了;
    在接下來的時間里,就需要把這些規律變成相應的程序;
    注意點:
    1.寫入可以按byte和bit兩種方法去操作;
    2.對於byte,可以一口氣寫連續多個byte, 理論上一條指令連續寫bit也可以,但是實踐下來,發現有問題,所以對於bit操作,我們就一個一個寫吧;

原文鏈接:https://m.baidu.com/mip/c/www.360doc.cn/mip/763580999.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM