在實際自動化工作中,我們發現西門子PLC與上位機觸控式螢幕很方便的,PLC端不用寫程式碼。用的是什麼協議呢?
一.今天我們就來解析S7協議。
1.硬體環境:S71215DCDCDC
2.軟體環境:Kepserver、VS2019、Wireshark(網路抓包工具)、TIA V16
3.說S7協議之前我們首先說說tcp協議。為什麼要說tcp協議呢?因為s7協議是在tcp協議基礎上封 裝的一層應用協議,與之對應還有,modbustcp,其底層都是tcp。
4.為什麼要用tcp協議呢?因為它是一個可靠的連線。我們知道tcp協議都有三次握手?
5.有沒有想過為什麼是三次握手?兩次四次行不行?
6.兩次模擬:
客戶端:服務端你能聽到我說話嗎?
服務端:我能聽到客戶端說話。你能聽到我說話嗎?
如果兩次,服務端無法確定客戶端收到它的訊息,如果服務端先說話,可能客戶端收不到他的話
7.四次:模擬
客戶端:服務端你能聽到我說話嗎?
服務端:我能聽到客戶端說話。你能聽到我說話嗎?
客戶端:我可以聽到服務端說話。你能聽到我說話嗎?
服務端:靠,不想跟傻子說話...
8.三次:模擬
客戶端:服務端你能聽到我說話嗎?
服務端:我能聽到客戶端說話。你能聽到我說話嗎?
客戶端:我可以聽到服務端說話,今晚去喝酒
連線OK
以上,通俗理解,如果想更深入瞭解,可以檢視TCP通訊原理.這裡先重點分析S7協議
二.S7協議分析
當我們用kepserver連線PLC時,出現以下報文資訊。S7連線過程
2.如果看到當我們用S7協議連線PLC時,首先進行的是3次TCP握手,再分別有兩次往返握手COTP,S7COM確認。
CTOP傳送報文
3.從TKPT開始是我們需要封裝的報文,如紅色區域,前面是IP報文頭,我們不用管,底層會幫我們處理。
TKPT返回報文
4.TKPT返回報文紅色區域是有效資料。
5.然後就是S7COMM握手如圖:
S7COMM傳送報文
6.S7的返回報文其中有一項是PDU length,什麼意思呢?這個就是我們一次允許通訊的報文位元組數,我這裡是240;如博圖F1幫助,S7通訊1200對應的位元組是240.
保守最大通訊位元組數
三.擼程式碼實現
1.我們建立S7-1200.cs類,程式碼如下。
S7協議連線
public class S71200 { Socket S7TcpClient; public int PDU { get;private set; }//對外開放PDU只讀屬性 /// <summary> /// 連線S71200 /// </summary> /// <param name="ip">PLC的IP地址</param> /// <returns>是否連線成功</returns> public bool Connect(string ip) { S7TcpClient = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//建立sokcet tcp連線物件 IAsyncResult asyncResult=S7TcpClient.BeginConnect( new IPEndPoint(IPAddress.Parse(ip),102 ),null,null);//非同步連線 asyncResult.AsyncWaitHandle.WaitOne(3000,true);//阻塞等待3秒 if (!asyncResult.IsCompleted)//非同步操作沒完成 就關掉tcp連線 返回失敗 { S7TcpClient.Close(); return false; } //上面的socket連線相當於執行了tcp的三次握手 byte[] cotp = new byte[] //cotp報文封裝 { 0x03,0x00,0x00,0x16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC0,0x01,0x0A,0xC1, 0x02,0x01,0x02,0xC2,0x02,0x01,0x00 }; byte[] s7comm = new byte[]//s7comm報文封裝 { 0x03, 0x00, 0x00,0x19, 0x02, 0xf0,0x80,0x32,0x01,0x00,0x00,0xff,0xff,0x00, 0x08,0x00, 0x00, 0xf0, 0x0, 0x0, 0x3, 0x0, 0x3, 0x7, 0x80 }; try { //第一次握手 S7TcpClient.Send(cotp, SocketFlags.None); byte[] buffer = new byte[S7TcpClient.Available]; S7TcpClient.Receive(buffer,buffer.Length,SocketFlags.None); //第二次握手 S7TcpClient.Send(s7comm, SocketFlags.None); buffer = new byte[S7TcpClient.Available]; S7TcpClient.Receive(buffer, buffer.Length, SocketFlags.None); if (buffer.Length == 27) { PDU = (short)(buffer[25] * 256 + buffer[26]);//因為佔了兩個位元組 高8位位權256 } return true; } catch (Exception) { return false; } } }
2.以上僅給大家學習除錯使用.
#上位機# #PLC# #觸控式螢幕# #電工交流圈# #電氣自動化#