前言
工业自动化领域,PLC(可编程逻辑控制器)是核心控制设备,而上位机软件常通过 Modbus RTU 协议与其通信。但开发和测试阶段,往往面临一个现实问题:没有真实的 PLC 设备,或者设备数量有限、调试成本高。有没有办法在不购买硬件的情况下,模拟一个功能完整的 PLC?答案是肯定的。
本文介绍一个基于 C# WinForm 开发的轻量级 PLC 模拟器,它不仅能模拟 D 寄存器(保持寄存器)和 M 寄存器(线圈),还支持串口通信、指令生成、数据持久化,配合虚拟串口工具,即可搭建完整的上位机测试环境。
项目介绍
项目本质上是一个 Modbus RTU 从站(Slave)模拟器。它运行在 Windows 上,通过 SerialPort 监听串口请求,并按照 Modbus 协议规范响应读写操作。
开发可以将其视为一台"虚拟 PLC",用于测试 SCADA 系统、HMI 软件或任何基于 Modbus 的上位机程序。项目完全使用 C# 编写,界面直观,功能聚焦,特别适合学习、原型验证和日常调试。
项目功能
1、寄存器模拟
内置 65536 个 D 寄存器(ushort 类型)和 65536 个 M 寄存器(bool 类型),覆盖绝大多数三菱等主流 PLC 的地址空间。
2、实时监控与编辑
通过 DataGridView 实时查看和修改 D/M 寄存器的值,支持滚动浏览任意地址段。
3、**串口通信
支持配置 COM 口、波特率、数据位、校验位、停止位和流控,模拟真实 485 通信环境。
4、Modbus 指令生成器
可手动构造读取、单写、批量写入等标准 Modbus RTU 指令(如 01、03、05、06、0F、10 功能码),并自动计算 CRC 校验。
5、数据持久化
支持将当前寄存器状态保存为 .plc 文件,下次启动可加载恢复,便于复现测试场景。
6、从站 ID 可配置
默认 ID 为 1,可根据需要修改,适配不同主站配置。
项目特点
零硬件依赖:配合 VSPD(Virtual Serial Port Driver)等虚拟串口工具,可在一台电脑上创建成对的虚拟 COM 口(如 COM3/COM4),上位机连 COM3,模拟器连 COM4,实现闭环测试。
界面友好:深色主题搭配清晰的数据表格,支持按需刷新指定地址范围,避免一次性加载海量数据卡顿。
协议兼容性强:严格遵循 Modbus RTU 帧格式,支持常见功能码,能与大多数标准 Modbus 主站无缝对接。
开发即调试:直接在界面上修改寄存器值,上位机立刻能读到变化;反之,上位机写入的数据也会实时反映在表格中,极大提升调试效率。
代码结构清晰:核心逻辑集中在 SimpleModbusSlave 类中,UI 与通信解耦,便于二次开发或集成到其他项目。
项目技术
语言与框架:C# + .NET Framework + WinForm
串口通信:System.IO.Ports.SerialPort
协议实现:自研 SimpleModbusSlave,处理 Modbus RTU 请求解析、CRC 校验(查表法)、寄存器读写
数据存储:内存数组(ushort[] HoldingRegisters, bool[] Coils)
UI 刷新:通过 Timer 定时轮询更新 DataGridView,避免跨线程操作
文件格式:自定义文本格式(.plc),包含 [DRegisters] 和 [MRegisters] 两个节,便于人工检查
项目代码
public byte[] ProcessRequest(byte[] request){if (request == null || request.Length < 4) returnnull;// Check CRCif (!CheckCRC(request)) returnnull;byte slaveAddress = request[0];byte functionCode = request[1];if (slaveAddress != SlaveId) returnnull; // Ignore if not for us// Strip CRC for processing// request length includes 2 bytes CRCtry{switch (functionCode){case0x03: // Read Holding Registersreturn HandleReadHoldingRegisters(request);case0x06: // Write Single Registerreturn HandleWriteSingleRegister(request);case0x10: // Write Multiple Registers (16)return HandleWriteMultipleRegisters(request);case0x01: // Read Coilsreturn HandleReadCoils(request);case0x05: // Write Single Coilreturn HandleWriteSingleCoil(request);case0x0F: // Write Multiple Coils (15)return HandleWriteMultipleCoils(request);default:return GenerateExceptionResponse(functionCode, 0x01); // Illegal Function}}catch (Exception){return GenerateExceptionResponse(functionCode, 0x02); // Illegal Data Address (or other error)}}private byte[] HandleReadHoldingRegisters(byte[] request){// Request: [SlaveAddr][Func][StartAddrHi][StartAddrLo][CountHi][CountLo][CRC][CRC]ushort startAddress = (ushort)((request[2] << 8) | request[3]);ushort count = (ushort)((request[4] << 8) | request[5]);if (startAddress + count > HoldingRegisters.Length)return GenerateExceptionResponse(request[1], 0x02);byte byteCount = (byte)(count * 2);byte[] response = newbyte[3 + byteCount + 2]; // Addr, Func, ByteCount, Data..., CRCresponse[0] = SlaveId;response[1] = 0x03;response[2] = byteCount;for (int i = 0; i < count; i++){ushort val = HoldingRegisters[startAddress + i];response[3 + i * 2] = (byte)(val >> 8);response[3 + i * 2 + 1] = (byte)(val & 0xFF);}AddCRC(response);return response;}项目效果
启动程序后,选择虚拟串口(如 COM4),设置波特率(通常 9600),点击"打开",模拟器即进入监听状态。此时,任何向该串口发送的合法 Modbus RTU 请求都会被解析并返回响应。
例如,上位机发送"读取 D100~D109",模拟器会从内存数组中取出对应值打包返回。同时,用户可在界面中直接编辑 D105 的值为 1234,上位机下一次读取时就能看到更新。
指令生成器还能帮助开发快速构造测试报文,验证主站解析逻辑是否正确。整个过程无需任何物理 PLC,节省成本又提高效率。
项目源码
项目核心代码已完整提供,结构简洁,无外部依赖。
为了防止丢失,可以在评论区留言关键字「PLC模拟器」,即可获取完整源码地址。
总结
这个 PLC 模拟器虽小,却解决了工业软件开发中的一个关键痛点:让上位机开发不再受制于硬件。无论是学习设计,还是在家远程调试,它都能提供一个稳定、灵活、免费的测试环境。
更重要的是,通过这个工具能深入理解 Modbus 协议的底层机制,为后续开发更复杂的工业通信程序打下基础。如果大家正在做 Modbus 相关项目,不妨试试这个"虚拟 PLC",或许能省下不少时间和设备预算。
评论 (0)