上个月刚完成某汽车零部件厂产线数据采集系统的年度维护系统连续运行12个月零数据丢失1000个点位数据准确率99.99%平均采集延迟稳定在25ms以内。很多同行问我为什么不用WinCC、组态王这些现成的组态软件反而用C#从零开发。答案很简单客户需要后续对接MES系统和YOLO视觉检测系统定制化需求极强组态软件的灵活性和扩展性根本无法满足。今天把这个项目从架构设计到现场踩坑的完整经验分享出来所有代码和方案都经过工业现场验证。一、项目背景与技术选型客户有6条汽车轴承装配产线每条产线配备1台西门子S7-1214C PLC需要采集温度、压力、电机转速、阀门状态、计数器等共1000个点位的数据。原有问题各产线独立运行数据无法集中管理没有历史数据存储无法进行质量追溯报警信息只能在本地查看无法远程推送技术选型理由Modbus TCP工业通用以太网协议兼容性最好后续可无缝对接三菱、欧姆龙等其他品牌PLCC# .NET 8性能优异开发效率高原生支持工业级异步IO可部署在Windows和国产化系统上SQLite MySQL本地SQLite存储实时数据云端MySQL存储历史数据兼顾性能和可靠性二、整体系统架构设计我们采用了经典的四层分层架构严格遵循高内聚低耦合原则确保系统的可维护性和可扩展性。西门子S7-1200 PLC集群Modbus TCP通信层数据处理与缓存层业务逻辑层数据展示层 WPF本地数据库 SQLite云端数据库 MySQL报警与通知模块MES系统接口各层核心职责通信层负责与PLC的底层通信实现连接管理、数据读写、心跳检测数据处理层负责数据解析、格式转换、异常值过滤、数据缓存业务逻辑层实现数据统计、报警判断、历史数据查询、数据上报等业务功能展示层负责实时数据展示、趋势图、报警列表、参数设置等用户交互三、PLC端关键配置90%的坑都在这里很多新手配置完Modbus TCP一直连不上或者读取的数据全是乱码90%都是因为PLC端配置错误。1. 启用Modbus TCP服务器打开TIA Portal V17进入PLC属性页面找到Modbus TCP服务器选项启用服务器功能端口保持默认的502。关键设置勾选允许远程客户端通过Modbus TCP访问此PLC最大连接数设置为8S7-1200最大支持8个并发连接超时时间设置为30秒2. DB块配置最容易踩的坑创建一个全局DB块用于存储所有需要采集的变量必须取消优化的块访问选项。西门子的优化块访问会自动重新排列变量在内存中的位置导致Modbus TCP无法按照固定偏移量读取数据。这是新手最容易犯的错误没有之一。3. 变量地址规划将所有变量按照数据类型连续排列布尔量开关量集中放在DB块的前100个字节16位整数转速、计数器放在接下来的200个字节32位浮点数温度、压力放在最后400个字节这样可以最大限度地减少批量读取的次数提高采集效率。四、C#端核心实现我们没有使用任何第三方Modbus库直接基于.NET 8的System.Net.Sockets实现。第三方库虽然方便但存在版权风险而且出了问题很难排查。1. 核心连接与批量读取代码publicclassModbusTcpClient:IDisposable{privatereadonlyTcpClient_client;privateNetworkStream_stream;publicasyncTaskboolConnectAsync(stringip,intport502){_client.Connect(ip,port);_stream_client.GetStream();returnawaitHeartbeatAsync();}publicasyncTaskbyte[]ReadHoldingRegistersAsync(ushortstartAddr,ushortcount){byte[]requestBuildReadRequest(startAddr,count);await_stream.WriteAsync(request);byte[]buffernewbyte[9count*2];await_stream.ReadAsync(buffer);returnbuffer.AsSpan(9,count*2).ToArray();}}2. 1000点位批量采集优化如果逐个读取1000个点位需要至少100次请求总耗时超过2秒完全无法满足实时性要求。我们实现了一个地址合并算法将连续的地址合并成一个批量请求最多一次读取125个寄存器Modbus TCP协议限制。优化后1000个点位只需要8次请求完整采集时间稳定在20-30ms比逐个读取快了100倍。3. 数据类型转换西门子PLC采用大端字节序而C#默认是小端字节序直接转换会得到错误的数值。publicstaticfloatGetFloat(byte[]data,intoffset){byte[]bytesdata.AsSpan(offset,4).ToArray();Array.Reverse(bytes);returnBitConverter.ToSingle(bytes,0);}publicstaticshortGetInt16(byte[]data,intoffset){return(short)((data[offset]8)|data[offset1]);}五、工业级稳定性保障机制工业软件和普通软件最大的区别就是必须7×24小时不间断运行任何一次停机都可能造成巨大的经济损失。1. 自动重连机制采用指数退避算法实现自动重连第一次断开后1秒重连第二次断开后2秒重连以此类推最大重连间隔为30秒这样可以避免频繁重连导致PLC崩溃同时保证网络恢复后系统能尽快恢复正常。2. 心跳检测机制每30秒向PLC发送一次心跳包读取一个固定地址的寄存器如果连续3次心跳失败则判定为连接断开触发自动重连。3. 数据缓存与断点续传在本地SQLite数据库中缓存所有采集数据当与云端MES系统断开连接时数据会保存在本地。网络恢复后自动将未上传的数据批量上传到云端确保数据不丢失。4. 全局异常处理与日志使用Serilog实现分级日志系统记录Debug、Info、Warn、Error四个级别的日志。所有外部调用都用try-catch包裹一个模块出现异常不会影响整个系统的运行。六、现场踩坑实录1. 大批量采集时频繁断连现象系统运行一段时间后PLC连接突然断开无法重新连接。原因S7-1200的Modbus TCP服务器有一个隐藏的限制每秒最多处理50个请求。如果请求频率过高PLC会主动拒绝连接。解决方法在每次请求之间加入10ms的延迟同时优化地址合并算法减少请求次数。2. 浮点数数据偶尔出现异常值现象偶尔会读取到非常离谱的浮点数比如1.234e38。原因当PLC正在写入一个浮点数时我们正好读取了这个地址导致读取到了不完整的数据。解决方法在PLC端为每个浮点数添加一个校验位或者连续读取两次只有两次结果一致时才认为数据有效。3. 工控机重启后时间错误导致数据混乱现象工控机断电重启后系统时间恢复到出厂设置导致历史数据时间戳错误。解决方法在PLC中添加一个系统时间变量上位机启动时自动同步PLC的时间而不是依赖工控机的系统时间。七、性能测试结果我们对系统进行了72小时连续压力测试测试环境如下工控机i5-104008G内存256G SSDWindows 10 LTSCPLC6台西门子S7-1214C点位数量1000个测试结果测试项目测试结果1000个点位完整采集时间20-30msCPU使用率15-20%内存占用80-100MB连续运行72小时内存泄漏3MB数据准确率99.99%平均无故障时间3600小时八、项目总结这个项目从开发到验收用了3周时间目前已经稳定运行12个月客户非常满意。最大的收获工业软件的核心不是功能有多花哨而是稳定性和可靠性。一个能稳定运行10年的简单系统远比一个功能丰富但经常出问题的系统更有价值。后续计划在现有系统的基础上接入YOLO视觉检测模块实现产品缺陷的自动识别和数据关联进一步提高产线的自动化水平。
C# + Modbus TCP + 西门子S7-1200:1000点位工业数据采集系统稳定运行12个月总结
上个月刚完成某汽车零部件厂产线数据采集系统的年度维护系统连续运行12个月零数据丢失1000个点位数据准确率99.99%平均采集延迟稳定在25ms以内。很多同行问我为什么不用WinCC、组态王这些现成的组态软件反而用C#从零开发。答案很简单客户需要后续对接MES系统和YOLO视觉检测系统定制化需求极强组态软件的灵活性和扩展性根本无法满足。今天把这个项目从架构设计到现场踩坑的完整经验分享出来所有代码和方案都经过工业现场验证。一、项目背景与技术选型客户有6条汽车轴承装配产线每条产线配备1台西门子S7-1214C PLC需要采集温度、压力、电机转速、阀门状态、计数器等共1000个点位的数据。原有问题各产线独立运行数据无法集中管理没有历史数据存储无法进行质量追溯报警信息只能在本地查看无法远程推送技术选型理由Modbus TCP工业通用以太网协议兼容性最好后续可无缝对接三菱、欧姆龙等其他品牌PLCC# .NET 8性能优异开发效率高原生支持工业级异步IO可部署在Windows和国产化系统上SQLite MySQL本地SQLite存储实时数据云端MySQL存储历史数据兼顾性能和可靠性二、整体系统架构设计我们采用了经典的四层分层架构严格遵循高内聚低耦合原则确保系统的可维护性和可扩展性。西门子S7-1200 PLC集群Modbus TCP通信层数据处理与缓存层业务逻辑层数据展示层 WPF本地数据库 SQLite云端数据库 MySQL报警与通知模块MES系统接口各层核心职责通信层负责与PLC的底层通信实现连接管理、数据读写、心跳检测数据处理层负责数据解析、格式转换、异常值过滤、数据缓存业务逻辑层实现数据统计、报警判断、历史数据查询、数据上报等业务功能展示层负责实时数据展示、趋势图、报警列表、参数设置等用户交互三、PLC端关键配置90%的坑都在这里很多新手配置完Modbus TCP一直连不上或者读取的数据全是乱码90%都是因为PLC端配置错误。1. 启用Modbus TCP服务器打开TIA Portal V17进入PLC属性页面找到Modbus TCP服务器选项启用服务器功能端口保持默认的502。关键设置勾选允许远程客户端通过Modbus TCP访问此PLC最大连接数设置为8S7-1200最大支持8个并发连接超时时间设置为30秒2. DB块配置最容易踩的坑创建一个全局DB块用于存储所有需要采集的变量必须取消优化的块访问选项。西门子的优化块访问会自动重新排列变量在内存中的位置导致Modbus TCP无法按照固定偏移量读取数据。这是新手最容易犯的错误没有之一。3. 变量地址规划将所有变量按照数据类型连续排列布尔量开关量集中放在DB块的前100个字节16位整数转速、计数器放在接下来的200个字节32位浮点数温度、压力放在最后400个字节这样可以最大限度地减少批量读取的次数提高采集效率。四、C#端核心实现我们没有使用任何第三方Modbus库直接基于.NET 8的System.Net.Sockets实现。第三方库虽然方便但存在版权风险而且出了问题很难排查。1. 核心连接与批量读取代码publicclassModbusTcpClient:IDisposable{privatereadonlyTcpClient_client;privateNetworkStream_stream;publicasyncTaskboolConnectAsync(stringip,intport502){_client.Connect(ip,port);_stream_client.GetStream();returnawaitHeartbeatAsync();}publicasyncTaskbyte[]ReadHoldingRegistersAsync(ushortstartAddr,ushortcount){byte[]requestBuildReadRequest(startAddr,count);await_stream.WriteAsync(request);byte[]buffernewbyte[9count*2];await_stream.ReadAsync(buffer);returnbuffer.AsSpan(9,count*2).ToArray();}}2. 1000点位批量采集优化如果逐个读取1000个点位需要至少100次请求总耗时超过2秒完全无法满足实时性要求。我们实现了一个地址合并算法将连续的地址合并成一个批量请求最多一次读取125个寄存器Modbus TCP协议限制。优化后1000个点位只需要8次请求完整采集时间稳定在20-30ms比逐个读取快了100倍。3. 数据类型转换西门子PLC采用大端字节序而C#默认是小端字节序直接转换会得到错误的数值。publicstaticfloatGetFloat(byte[]data,intoffset){byte[]bytesdata.AsSpan(offset,4).ToArray();Array.Reverse(bytes);returnBitConverter.ToSingle(bytes,0);}publicstaticshortGetInt16(byte[]data,intoffset){return(short)((data[offset]8)|data[offset1]);}五、工业级稳定性保障机制工业软件和普通软件最大的区别就是必须7×24小时不间断运行任何一次停机都可能造成巨大的经济损失。1. 自动重连机制采用指数退避算法实现自动重连第一次断开后1秒重连第二次断开后2秒重连以此类推最大重连间隔为30秒这样可以避免频繁重连导致PLC崩溃同时保证网络恢复后系统能尽快恢复正常。2. 心跳检测机制每30秒向PLC发送一次心跳包读取一个固定地址的寄存器如果连续3次心跳失败则判定为连接断开触发自动重连。3. 数据缓存与断点续传在本地SQLite数据库中缓存所有采集数据当与云端MES系统断开连接时数据会保存在本地。网络恢复后自动将未上传的数据批量上传到云端确保数据不丢失。4. 全局异常处理与日志使用Serilog实现分级日志系统记录Debug、Info、Warn、Error四个级别的日志。所有外部调用都用try-catch包裹一个模块出现异常不会影响整个系统的运行。六、现场踩坑实录1. 大批量采集时频繁断连现象系统运行一段时间后PLC连接突然断开无法重新连接。原因S7-1200的Modbus TCP服务器有一个隐藏的限制每秒最多处理50个请求。如果请求频率过高PLC会主动拒绝连接。解决方法在每次请求之间加入10ms的延迟同时优化地址合并算法减少请求次数。2. 浮点数数据偶尔出现异常值现象偶尔会读取到非常离谱的浮点数比如1.234e38。原因当PLC正在写入一个浮点数时我们正好读取了这个地址导致读取到了不完整的数据。解决方法在PLC端为每个浮点数添加一个校验位或者连续读取两次只有两次结果一致时才认为数据有效。3. 工控机重启后时间错误导致数据混乱现象工控机断电重启后系统时间恢复到出厂设置导致历史数据时间戳错误。解决方法在PLC中添加一个系统时间变量上位机启动时自动同步PLC的时间而不是依赖工控机的系统时间。七、性能测试结果我们对系统进行了72小时连续压力测试测试环境如下工控机i5-104008G内存256G SSDWindows 10 LTSCPLC6台西门子S7-1214C点位数量1000个测试结果测试项目测试结果1000个点位完整采集时间20-30msCPU使用率15-20%内存占用80-100MB连续运行72小时内存泄漏3MB数据准确率99.99%平均无故障时间3600小时八、项目总结这个项目从开发到验收用了3周时间目前已经稳定运行12个月客户非常满意。最大的收获工业软件的核心不是功能有多花哨而是稳定性和可靠性。一个能稳定运行10年的简单系统远比一个功能丰富但经常出问题的系统更有价值。后续计划在现有系统的基础上接入YOLO视觉检测模块实现产品缺陷的自动识别和数据关联进一步提高产线的自动化水平。