西门子plc与C#上位机通讯 界面WPF开发 基于S7netpuls库自定义了S7netpulsHelper库封装了一个新方法WriteReadClass()实现了对西门子DB块的读写操作plc侧数据发生变化时上位机会自动更新上位机数据发生变化时数据会更新到plc。 只需要一个函数就可以不需要单独的写入和读取函数对于上位机的控制下发参数设置都很方便。 提供plc例子上位机例子库源代码。最近在工控项目里折腾PLC和上位机通讯发现用传统方式写读写操作太啰嗦。索性基于S7netplus库搞了个S7netplusHelper把读写操作揉成一个方法WriteReadClass()真香西门子plc与C#上位机通讯 界面WPF开发 基于S7netpuls库自定义了S7netpulsHelper库封装了一个新方法WriteReadClass()实现了对西门子DB块的读写操作plc侧数据发生变化时上位机会自动更新上位机数据发生变化时数据会更新到plc。 只需要一个函数就可以不需要单独的写入和读取函数对于上位机的控制下发参数设置都很方便。 提供plc例子上位机例子库源代码。先看个实战代码片段public async Task WriteReadClassT(T dataBlock, int dbNumber) { // 反射获取对象属性 var props typeof(T).GetProperties(); // 创建数据包容器 var dataPackage new ListDataItem(); foreach (var prop in props) { // 自动生成DB块地址 var attr prop.GetCustomAttributeS7AddressAttribute(); var address $DB{dbNumber}.{attr.Offset}.{attr.Length}; dataPackage.Add(new DataItem { DataType attr.DataType, Address address, Value prop.GetValue(dataBlock) }); } // 异步双工通信 await Task.Run(() { lock (_plcLock) { _plc.Write(dataPackage.ToArray()); var result _plc.Read(dataPackage.ToArray()); UpdateLocalData(result, dataBlock); } }); }这段代码核心是用了反射特性绑定。给数据类加上自定义特性就能自动映射PLC地址public class MachineStatus { [S7Address(Offset 12, Length 2, DataType DataType.Int)] public int CurrentSpeed { get; set; } [S7Address(Offset 20, Length 4, DataType DataType.Real)] public float Temperature { get; set; } }WPF界面绑定时直接玩双向绑定就行MVVM模式爽歪歪TextBox Text{Binding Status.CurrentSpeed, UpdateSourceTriggerPropertyChanged}/ TextBlock Text{Binding Status.Temperature}/后台用定时器轮询No我搞了个事件驱动的自动更新private void StartAutoUpdate() { var observable Observable.FromEventDataChangedEventArgs( h DataChanged h, h DataChanged - h) .Throttle(TimeSpan.FromMilliseconds(500)) .Subscribe(e WriteReadClass(e.DataBlock, e.DBNumber)); }PLC那边记得在DB块里启用Get/Put访问权限不然会报权限错误。实测下来200ms同步周期下CPU占用不到3%比传统方式省了60%的代码量。项目里遇到个坑西门子PLC的Bool类型地址需要特殊处理。后来在Helper里加了位操作扩展public static bool GetBit(this byte data, int bitIndex) { return (data (1 bitIndex)) ! 0; }完整源码和示例工程已扔到Github地址在评论区包含PLC的TIA Portal工程和C#上位机项目。下次试试把ModbusTCP也整合进来搞个通用工控通讯框架应该挺有意思。