C#与三菱,西门子,台达,基恩士,等各品牌plc通讯源码。
搞过工控的老铁都知道,PLC通讯就像和不同方言的人聊天——三菱说MC协议,西门子玩S7,台达可能掏出Modbus,基恩士说不定甩个自定义二进制包。今天咱们就用C#这把瑞士军刀,直接捅穿这些通讯协议的窗户纸。
三菱PLC的MC协议:字节流掰扯艺术
三菱的FX/Q系列常用MC协议(MELSEC Communication),本质就是TCP发特定格式的字节包。上代码感受下:
// 创建TCP客户端 using var client = new TcpClient("192.168.1.10", 5002); NetworkStream stream = client.GetStream(); // 构造读取D100寄存器的指令帧(ASCII模式) string command = "500000FF03FF000018001004010000D100000001"; byte[] sendBytes = Encoding.ASCII.GetBytes(command); // 发指令 stream.Write(sendBytes, 0, sendBytes.Length); // 收响应(建议异步处理) byte[] buffer = new byte[1024]; int bytesRead = stream.Read(buffer, 0, buffer.Length); string response = Encoding.ASCII.GetString(buffer, 0, bytesRead); // 解析数据(比如D100的值在特定偏移位) int value = Convert.ToInt32(response.Substring(42, 4), 16);关键点:
- 指令帧里的
D100要转成ASCII码44313030(别手抖) - 三菱的响应可能带协议头,需要截取有效数据段
- 如果上二进制模式,处理高低字节顺序会让人怀疑人生(记得用
BitConverter)
西门子S7-1200的暴力读写
西门子的S7协议属于典型的“文档劝退型”,好在有开源库S7NetPlus救命:
using S7.Net; var plc = new Plc(CpuType.S71200, "192.168.0.1", 0, 1); plc.Open(); // 读DB块数据 var dbValue = plc.Read("DB1.DBD4"); // 读DB1中DWORD地址4 if (dbValue is uint result) { Console.WriteLine($"温度值:{result / 10.0}℃"); } // 写BOOL量(控制电机启停) plc.Write("Q0.0", true); plc.Close();避坑指南:
- DB块编号和偏移量必须和PLC程序完全对应
- 读写前一定要确认PLC的存储区类型(V/M/Q/I区对应不同地址格式)
- 遇到连接超时?检查下PLC侧的防火墙和TSAP设置
台达PLC的Modbus TCP骚操作
台达的DVP系列支持Modbus TCP,用NModbus库分分钟拿捏:
using Modbus.Device; TcpClient client = new TcpClient("192.168.1.5", 502"); ModbusIpMaster master = ModbusIpMaster.CreateIp(client); // 读保持寄存器(比如温度设定值) ushort[] registers = master.ReadHoldingRegisters(1, 100, 1); int temperature = registers[0]; // 写单个线圈(启动信号) master.WriteSingleCoil(1, 0, true); // 站号1,线圈地址0注意:
- 台达的Modbus地址可能和手册标注的差1(比如D100对应地址99)
- 线圈和寄存器的读写方法别混用,Modbus功能码会报错
基恩士KV系列的二进制直连
基恩士的协议比较野,直接上Socket发二进制包:
byte[] packet = new byte[] { 0x50, 0x00, // 固定头 0x00, 0x00, // 包长度(后面填充) 0xFF, 0xFF, 0xFF, 0xFF, // 客户端ID 0x01, 0x04, // 命令码(读命令) 0x00, 0x00, 0x00, 0x00, // 数据地址 0x00, 0x08 // 读取长度 }; // 计算长度并填充 ushort length = (ushort)(packet.Length - 2); BitConverter.GetBytes(length).CopyTo(packet, 2); // 发送并接收数据...暗黑技巧:
- 地址转换可能需要用基恩士的KV Studio查内存映射
- 响应中的状态码藏在第9字节(0x00表示成功)
搞PLC通讯就像拆盲盒——永远不知道下一个协议有多反人类。但核心套路就那几个:组包/解包、处理字节序、应对超时重连。源码虽好,可别忘了一边喝枸杞茶一边查厂商的协议手册(虽然他们可能写了个寂寞)。最后送各位一句话:没有print不了的PLC,只有头不够铁的程序员。