一.前面講了S7連線的握手過程讀寫DB的位元組演算法,今天我們講講如何直接寫DB區bool位
硬體環境:S71200
軟體環境:威綸通EasyBuilder、TIAV16、Wireshark抓包工具、VS2019
二.開始抓包分析吧
1.電腦IP:192.168.0.227
2.PLCIP:192.168.0.50
3.用威綸通觸控式螢幕組態軟體線上模擬監控DB2.DBx18.0用寫入資料
4.抓報文,老規矩從這麼多報文裡面找到有價值的資料,多次嘗試,分析
5.程式碼分析結合上一節內容
三.寫程式碼
public bool WriteDB(int DB, int startByte, bool b, int startbit = 0) { //固定35個位元組,加上我要寫的位元組組成報文,由於長度可變我們用list List<byte> s7Comm = new List<byte>() { 0x03,0x00,0x00,0x25,0x02,0xf0,0x80,0x32,0x01,0x00, 0x00,0xa0,0x00,0x00,0x0e,0x00,0x06,0x05,0x01,0x12, 0x0a,0x10,0x02,0x00,0x02,0x00,0x02,0x84,0x00,0x00, 0x40,0x00,0x04,0x00,0x10//...資料區 };//0x84代表DB區 byte[] writeBs = new byte[] { b ? (byte)1 : (byte)0 }; //分析報文看到規律第2(高8位)3(低8位)控制要寫的報文長度 ,獲得位元組陣列 先轉為ushort型別是為了確定輸出位元組為2個固定35個位元組 byte[] bs = BitConverter.GetBytes((ushort)(35 + writeBs.Length)); s7Comm[02] = bs[1]; s7Comm[03] = bs[0]; refercence++; //通訊參考標識每次自增 相當於給這個報文起了個名字 bs = BitConverter.GetBytes((ushort)refercence); s7Comm[11] = bs[1]; s7Comm[12] = bs[0]; bs = BitConverter.GetBytes((ushort)(writeBs.Length + 4));//data 長度 這裡指的item長度 固定長度4+可變長度資料 s7Comm[15] = bs[1]; s7Comm[16] = bs[0]; s7Comm[22] = 0x01; bs = BitConverter.GetBytes((ushort)writeBs.Length); //分析報文看到規律第23(高8位)24(低8位)控制要寫的位元組數 s7Comm[23] = bs[1]; s7Comm[24] = bs[0]; bs = BitConverter.GetBytes((ushort)DB);//分析報文看到規律第25(高8位)26(低8位)控制要寫的DB號 s7Comm[25] = bs[1]; s7Comm[26] = bs[0]; if (startbit > 7) { throw new Exception("bool位範圍0-7");//拋異常 一個位元組只有8位 允許操作的二進位制是0-7位 } //重點 分析報文看到規律第28 29 30,控制要寫的地址,高21位是控制位元組位置的,左移二進位制把低三位位置騰出來,低3位控制bit位(2^3)不能超過8 uint startByte1 = (uint)startByte << 3; startByte1 |= (uint)startbit;//與要寫的bit位或一下,生成具體地址 s7Comm[28] = (byte)((startByte1 & 0xff0000) >> 16);//獲取bit16-bit23位元組,與0xff0000獲得,再右移16位讓它可以存在位元組 大端儲存 bs = BitConverter.GetBytes((ushort)(startByte1 & 0x00ffff)); //與0xffff獲得低16位再獲取2個位元組 s7Comm[29] = bs[1]; s7Comm[30] = bs[0]; s7Comm[32] = 0x03; //分析報文看到規律第33(高8位)34(低8位)控制要寫的bit數量 s7Comm[33] = 0x00; s7Comm[34] = 0x01; s7Comm.AddRange(writeBs);//新增我們要寫的位元組陣列資料 byte[] s7Result = SendRecive(s7Comm.ToArray());//傳送s7報文並接收 if (s7Result?.Length >= 21 && s7Result[21] == 0xff && s7Result[11] == s7Comm[11] && s7Result[12] == s7Comm[12]) //0xff s7協議代表著成功 { return true; } return false; } public byte[] SendRecive(byte[] arry) { int delay = 0; try { Monitor.Enter(lockS7); int reslut = S7TcpClient.Send(arry); while (S7TcpClient.Available == 0) { Thread.Sleep(10); delay++; if (delay > MaxDelayCycle) { break; } } byte[] ResByte = new byte[S7TcpClient.Available]; reslut = S7TcpClient.Receive(ResByte); return ResByte; } catch (Exception ) { IsConnected = false; return null; } finally { Monitor.Exit(lockS7); } }
四 .測試:
五.完成