一.前面講了S7連線的握手過程,及讀取DB的演算法,今天我們講講如何寫DB區
今天手裡有1200,那就繼續用實體PLC測試,再嘗試用威綸通觸控式螢幕連線PLC進行抓包解析,首先環境準備。
硬體環境:S71200
軟體環境:威綸通EasyBuilder、TIAV16、Wireshark抓包工具、VS2019
二.開始抓包分析吧
1.電腦IP:192.168.0.227
2.PLCIP:192.168.0.50
3.用威綸通觸控式螢幕組態軟體線上模擬監控DB2.DBW2用寫入資料8
4.抓報文,老規矩從這麼多報文裡面找到有價值的資料,多次嘗試,分析
5.報文分析,由於我們操作DB區有可能操作其bool位,所以是有必要把bit位的操作考慮進去。
6.如圖分析,控制寫地址有三個位元組,多分析幾個報文看到規律第28 29 30,控制要寫的地址
高21位是控制DB號的,左移二進位制把低三位位置騰出來,或者乘以8,低3位控制bit位(2^3)不能超過8.
由於3個位元組中,前面21位是控制位元組位置的,我們獲取bit16-bit23位元組,與0xff0000獲得,再右移16位讓它可以存在高8位位元組,大端儲存方式。
整個報文位元組數
7.分析報文發現第2(高8位)、3(低8位)位元組是控制整個報文位元組數
DBW2bit 2*8=16#0010
8.分析報文看到規律第33(高8位)34(低8位)控制要寫的bit數量,一個位元組8個bit位,乘以8就是最終二進位制位。
9.我們分析多次報文,發現第11(高8位)12(低8位)位元組控制通訊參考標識,怎麼理解?透過悟性可以悟到,這東西就相當於給通訊的每一筆資料起個名字,用來區分不同筆報文。
10.其他報文前面幾講,有講了。
三.我們開始擼程式碼吧
1.接著前面程式碼寫,寫DB的演算法程式碼
2.原始碼我也貼了上來
int refercence = 888;//通訊參考標識 /// <summary> /// 寫DB的方法位元組排序大端 參考1413筆資料 /// </summary> /// <param name="DB">DB號</param> /// <param name="startByte">起始位元組數</param> /// <param name="writeBs">寫多少個位元組</param> /// <returns></returns> public bool WriteDB(int DB,int startByte, byte[] writeBs) { //固定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區 //分析報文看到規律第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]; 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]; //重點 分析報文看到規律第28 29 30,控制要寫的地址,高21位是控制位元組位置的,左移二進位制把低三位位置騰出來,低3位控制bit位(2^3)不能超過8 uint startByte1 = (uint)startByte << 3; 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]; bs = BitConverter.GetBytes((ushort)(writeBs.Length * 8)); //分析報文看到規律第33(高8位)34(低8位)控制要寫的bit數量 s7Comm[33] = bs[1]; s7Comm[34] = bs[0]; s7Comm.AddRange(writeBs);//新增我們要寫的位元組陣列資料 S7TcpClient.Send(s7Comm.ToArray());//傳送s7報文 Thread.Sleep(100);//等待10ms給1500CPU反應時間 實際時間根據效能自己寫 或者寫智慧接收..我這裡只提供思路 byte[] s7Result = new byte[S7TcpClient.Available];//接收了多少個位元組 我們new相應的長度 S7TcpClient.Receive(s7Result);//接收位元組 if (s7Result?.Length>=21&& s7Result[21]==0xff) //0xff s7協議代表著成功,咱們也加上這個判斷 { return true; } return false; }
三.是騾子是馬測一測
1.給DB2.DBW寫個666試試
2.可以看到博圖軟體監控顯示已寫入成功
3.好了,S7協議寫程式碼已經成功了。這裡封裝的是位元組寫包括 PLC的 8位16位32位整形和32位單精度浮點等等的寫入,只不過區別是我們在上位機計算位元組陣列的方法不一樣。
四.其實S7協議的強大之處,還可以直接操作bool。我們傳統的做法是把對應的位元組,字讀上來,再進行與或運算再寫入,這樣從嚴謹角度上來說是不靠譜的,如modbus 40001區的操作。下期我們講bool量怎麼直接操作。