西門子S7協議是用來和PLC進行通訊的一個協議,默認端口是102,數據會保存在一個個DB塊中,比較經典的用法是一個DB塊專門用來讀取,一個用來寫入。
DB(數據塊)+ {塊號}.DBX/DBD/DBW+{字節地址}.{位偏移}
1、數據塊是存放全局變量的內存區域,類似數據庫的表.
2、三種類型的字節地址是共用的,所以要特別注意不同數據類型占用的長度是不同的,否則會出現異常數據的情形。
提到字節排列就得提到不同的通信設備的排列方式是有區別的,像是C#,三菱PLC就是小端排列類似于ABCD,4個字母表示4個字節;西門子PLC是大端排列,順序是DCBA,modbus等協議是不規則排列,順序有BADC,CDAB。
DBX(data block bit) 按位訪問,用于訪問數據塊中的單個位即Bool類型,例如: DB1.DBX0.1 表示數據塊1的第0字節的第0位。
每個字節有8位,所以偏移量的范圍是0~7.
DBW(Data Block Word)數據塊字,用于訪問16位的數據,例如:Word,int類型。由于1個字 = 16位也就是2個字節,所以地址必須是偶數,無需使用位偏移。
例如:DB1.DBW0表示數據塊1的第0個字節開始的16位數據
DBD(data block double word)數據塊雙字,用于訪問32位的數據,例如:DWord,Dint,Real類型。由于1個雙字 = 32位也就是4個字節,所以地址必須是4的整數,無需使用位偏移。
例如:DB1.DBD0表示數據塊1的第0個字節開始的32位數據
使用C#實現西門子S7通訊可以通過S7NetPlus,HslCommunication類庫來實現
1、使用S7NetPlus實現讀寫數據
// 第一個參數是CPU的型號// 第三個參數是PLC的機架(Rank)// 第四個參數是CPU的插槽(Slot)using (var plc = new Plc(CpuType.S71200, "127.0.0.1", 0, 1)){try{plc.Open();if (plc.IsConnected == false){this.textBox1.Text = this.textBox1 + "連接失敗" + Environment.NewLine;}#region 寫入數據// 寫入一個bool類型plc.Write("DB1.DBX0.0", true);// 寫入一個無符號整數ushort ushortValue = 3600;plc.Write("DB1.DBW2.0", ushortValue);// 寫入一個浮點數float floatValue = 3.14f;plc.Write("DB1.DBD4", floatValue);// 寫入一個有符號整數int intValue = 2025;plc.Write("DB1.DBD8", intValue);#endregion#region 讀取數據// 讀取一個bool類型var is_am = (bool)plc.Read("DB1.DBX0.0");this.textBox1.Text = this.textBox1.Text + "is_am=" + is_am + Environment.NewLine;// 讀取一個無符號的整數類型 - word 對應c#的就是ushort類型var second = (ushort)plc.Read("DB1.DBW2.0");this.textBox1.Text = this.textBox1.Text + "second=" + second + Environment.NewLine;// 讀取一個浮點數var pie = ((uint)plc.Read("DB1.DBD4")).ConvertToFloat();this.textBox1.Text = this.textBox1.Text + "pie=" + pie + Environment.NewLine;// 讀取一個有符號的整數var year = ((uint)plc.Read("DB1.DBD8")).ConvertToInt();this.textBox1.Text = this.textBox1.Text + "year=" + year + Environment.NewLine;#endregion}catch (Exception ex){this.textBox1.Text = this.textBox1 + ex.Message + Environment.NewLine;}}
2、使用HslCommunication實現讀寫功能
寫入:
plc = new SiemensS7Net(SiemensPLCS.S1200, "127.0.0.1");Random random = new Random();var flag = await plc.WriteAsync("DB1.DBX0", random.Next(0, 2) == 0 ? false : true);var int_value = await plc.WriteAsync("DB1.DBW2", (short)random.Next(0, 1000));var float_value = await plc.WriteAsync("DB1.DBD4", (float)random.Next(0, 10) / 10.0f);// 中文不能使用默認的Ascii編碼,需要使用UTF8編碼var arr = new string[3] { "中", "美", "日" };var string_value = await plc.WriteAsync("DB1.DBD8", arr[random.Next(0, 3)], Encoding.UTF8);await Task.Delay(1000, cts.Token);if (int_value.IsSuccess == false){this.Invoke(new Action(() => {this.textBox1.Text = "通訊失敗" + Environment.NewLine + this.textBox1.Text;}));continue;}
讀取:
plc = new SiemensS7Net(SiemensPLCS.S1200, "127.0.0.1");var flag = await plc.ReadBoolAsync("DB1.DBX0");var int_value = await plc.ReadInt16Async("DB1.DBW2");var float_value = await plc.ReadFloatAsync("DB1.DBD4");// 讀取中文不能使用默認的Ascii編碼,需要使用UTF8編碼var string_value = await plc.ReadStringAsync("DB1.DBD8", Encoding.UTF8);await Task.Delay(1000, cts.Token);if (int_value.IsSuccess == false){this.Invoke(new Action(() => {this.textBox1.Text = "通訊失敗" + Environment.NewLine + this.textBox1.Text;}));continue;}this.Invoke(new Action(() =>{this.textBox1.Text = "flag:" + flag.Content.ToString() + Environment.NewLine + this.textBox1.Text;this.textBox1.Text = "float_value:" + float_value.Content.ToString() + Environment.NewLine + this.textBox1.Text;this.textBox1.Text = "int_value:" + int_value.Content.ToString() + Environment.NewLine + this.textBox1.Text;this.textBox1.Text = "string_value:" + string_value.Content.ToString() + Environment.NewLine + this.textBox1.Text;}));