GitHub 项目地址:https://github.com/lidecong133/YModbus

工具下载:YModbusTools v1.0.0
CSDN 下载:主站工具 / 从站工具
运行环境:.NET 8.0,桌面工具建议安装 Microsoft .NET 8 Desktop Runtime

做工业上位机、设备调试、数据采集、PLC 联机,绕不开一个协议:Modbus。

它看起来很朴素。

一个站号,一个功能码,一个地址,一个数量。

读寄存器,写线圈,查状态,拿数据。

但只要到现场,事情马上就不朴素了。

客户说“这个设备支持 Modbus RTU”,然后给你一张寄存器表。

表里写着 40001,程序里到底填 0 还是 1

PLC 工程师说“值在 D100”,那它对应保持寄存器地址 100,还是 4096 + 100,还是被网关重新映射过?

设备厂家说“浮点数按标准 Modbus”,你读出来两个寄存器,一个是 17142,一个是 59769,到底是高字在前,还是低字在前?

RS485 总线上三个设备都说自己是 1 号站,主站一轮询就开始超时。TCP 明明能 ping 通,读寄存器却一直返回非法地址。写入命令显示成功,设备却一点反应没有。

这些问题都不是“Modbus 有多高深”。

真正麻烦的是,现场把协议、接线、地址表、PLC 程序、网关映射、设备响应时间、数据类型全揉在一起了。

YModbus 这个项目,就是想把这些东西拆开讲清楚,也做成能直接拿来调试的工具。

这个系列解决什么问题

这个系列不是单纯的 API 文档。

如果只想看方法签名,API 文档当然更快。但现场调试很少是“方法不会调”这么简单。

更常见的是这些问题:

  • 不知道 TCP、RTU、ASCII 到底该选哪个
  • 不清楚 UnitIdSlaveId 是不是一回事
  • 不知道线圈、离散输入、保持寄存器、输入寄存器该用哪个功能码
  • 看见 4000130001D0VW1000x1000 就开始犹豫
  • 读出来的数值明显不对,但分不清是比例系数、字节序还是地址偏移
  • 设备偶尔超时,不知道该加重试,还是先查接线和响应时间
  • 想测试主站程序,但真实从站设备不在手边
  • 想让 AI Agent 或脚本帮忙读数,却又担心误写真实设备

所以这个系列会把三件事放在一起讲:

协议怎么理解。

YModbus 代码怎么写。

现场怎么验证和排查。

我更希望它像一本调试笔记,而不是一份冷冰冰的接口清单。

YModbus现在包括哪些能力

YModbus 的核心目标,是做一个自己可控、结构清楚、适合现场调试的 Modbus 基础库和工具链。

现在项目大致分成几块。

模块 作用
YModbus 核心协议、TCP Client、请求响应模型、重试、寄存器转换
YModbus.Serial RTU / ASCII 串口 Client,基于 SerialPort 接入
YModbus.Slave TCP / RTU / ASCII 从站模拟、数据区、异常和延迟模拟
YModbus.Cli 命令行读写、扫描站号、扫描地址、自定义功能码
YModbus 主站工具 主力产品:连接真实设备,读写寄存器和线圈,看报文,保存现场配置
YModbus 从站工具 主力产品:模拟设备,制造正常、异常、慢响应、不响应等测试场景
Workbench Agent Bridge 让脚本或 AI Agent 通过本地 HTTP 控制正在运行的桌面工具

主力产品:主站工具和从站工具

如果只看代码库,YModbus 更像一个开发组件。

但真正到现场,很多人不想先写一段 C#,也不想先研究 NuGet 包。他们要的是一个能打开就用的工具:填 IP、填串口、填站号、点读取、看结果、看报文。

所以 YModbus 的主力产品,是主站工具和从站工具。

主站工具面向真实设备。

它要解决的是“我怎么尽快判断这个设备能不能读、地址对不对、数据对不对”。

它应该能做这些事:

  • 连接 Modbus TCP、RTU、ASCII 设备
  • 读取线圈、离散输入、保持寄存器、输入寄存器
  • 写单个线圈、单个寄存器、多个线圈、多个寄存器
  • 按周期轮询,观察数据变化
  • 用十进制、十六进制、有符号整数、浮点数等方式显示数据
  • 显示 TX / RX 原始报文
  • 保存连接参数、地址表、显示格式和调试工作区

现场调设备时,主站工具就是第一把扳手。

比如客户说“温度在 40001”,主站工具可以先用功能码 03 读地址 0,再读地址 1,马上判断是不是地址偏移。

客户说“这个寄存器是浮点数”,主站工具可以先看两个原始寄存器,再切换字序和显示方式,不用一上来就改上位机程序。

客户说“写入成功但设备没动作”,主站工具可以先写从站模拟器,再写真实设备,写完立刻读回,判断是通讯写入问题,还是 PLC 程序、设备模式、保存命令、互锁条件的问题。

从站工具面向主站程序。

它要解决的是“真实设备不在手边,或者真实设备不方便制造故障时,我怎么测试主站程序”。

它应该能做这些事:

  • 模拟 TCP、RTU、ASCII 从站
  • 维护线圈、离散输入、保持寄存器、输入寄存器四类数据区
  • 手动修改数据,观察主站下一轮读取是否正确
  • 接收主站写入,并在表格里看到数据变化
  • 模拟非法地址、非法功能、设备忙等异常响应
  • 模拟慢响应和不响应
  • 记录主站发来的请求报文
  • 保存和复现某个测试场景

从站工具的价值,是把“设备当前是什么状态”变成“我想让设备表现成什么状态”。

你可以让它今天像一台温控表,明天像一台称重仪表,也可以让它故意返回异常码,测试主站程序会不会只显示一句“读取失败”。

真实设备往往很难配合你制造异常。

从站工具可以。

所以这两个工具不是 samples,也不是附带 demo。

核心库是底座,CLI 是自动化入口,主站工具和从站工具才是最直接面向现场调试人员的产品形态。后面第 12 篇和第 13 篇,会分别展开它们怎么用。

主站工具和从站工具已经提供 GitHub 下载入口:YModbusTools v1.0.0 下载。这个版本提供 Windows x64 的 YModbus.MasterAppYModbus.SlaveApp zip 包,运行前需要安装 .NET 8.0 运行环境;如果系统提示缺少桌面运行时,优先安装 Microsoft .NET 8 Desktop Runtime。

主站工具和从站工具也保留了 CSDN 备用下载入口:

核心库里常见的读取保持寄存器,应该像这样直接:

ushort[] registers = await client.ReadHoldingRegistersAsync(0, 4);

如果走 TCP,可以用 ModbusClientFactory.CreateTcpAsync

如果走 RTU,可以用 ModbusSerialClientFactory.CreateRtu

如果一个 TCP 网关下面挂多个站号,可以用 CreateTcpMultiUnitAsyncIModbusMultiUnitClient

如果要把两个寄存器转成 floatint32double,可以走 RegisterConverter,但前提是你先把字序和字节序确认清楚。

命令行工具也尽量按现场习惯设计。

比如先读一个保持寄存器:

ymodbus read-holding-registers --host 192.168.1.20 --port 502 --unit-id 1 --address 0 --quantity 1

写入命令默认是 dry-run,真正写入要加 --confirm

这个设计不是多此一举。现场写 PLC 或仪表,宁可多确认一次,也不要手滑写错地址。

为什么还要自己做

.NET 里不是没有 Modbus 库。

简单读几个寄存器,很多库都能完成。

但我想要的是一套更贴近自己工作方式的东西。

第一,代码结构要能看懂。

工业通讯库不是黑盒越大越好。现场出了问题,最后总要能追到请求怎么拼、响应怎么解析、异常怎么抛、超时怎么处理。

第二,主站和从站都要有。

只会读设备不够。很多时候真实设备不在手边,或者你要证明“主站程序发得对不对”,这时从站模拟器比真实设备更好用。

第三,调试工具和代码库要互相打通。

现场工程师可能更喜欢点工具,开发者可能更喜欢写代码,AI Agent 和脚本更适合调 CLI 或 HTTP 接口。底层逻辑如果是一套,问题就更容易复现。

第四,文档要能讲人话。

协议文档当然要严谨,但现场更需要知道:

先读哪个地址?

超时先查什么?

写入前怎么防误操作?

PLC 说 D100 时,上位机到底该问什么?

这也是为什么我把文章写成系列,而不是只写 README。

这套文章怎么读

现在文章已经不只是一个计划,而是按实际调试路径展开到了 PLC 专题。

如果你是第一次看,建议按下面这个顺序读。

阶段 文章 适合解决的问题
先建立协议感觉 02 Modbus协议入门 主站/从站、TCP/RTU/ASCII、功能码、地址、报文、异常码
先跑通一次读取 03 YModbus上手 用最小代码读寄存器,理解 TCP 和 RTU 的基本参数
看库的整体能力 04 YModbus功能介绍 Client、Serial、Slave、转换、重试、CLI
写主站代码 05 Client创建06 读写数据区 TCP、RTU、ASCII 怎么创建,线圈和寄存器怎么读写
处理数值 07 寄存器类型转换 intfloatdouble、比例系数、字节序、字序
处理失败 08 异常、超时、重试 区分网络问题、协议异常、地址错误和设备响应慢
模拟设备 09 从站模拟10 多UnitId模拟 没有真实设备时怎么测试主站,网关多站号怎么模拟
用工具调试 11 CLI12 主站工具13 从站工具 主站工具和从站工具是主力产品;CLI 适合脚本和自动化
查现场问题 14 现场常见问题 不通、超时、数据不对、写入没动作、偶发失败
自动化和AI 15 AI Agent自动化 CLI、本地 HTTP、未来 MCP 怎么安全地服务自动化
连接PLC 16 PLC连接总览 西门子、三菱、汇川、台达这类 PLC 先问什么
看具体PLC专题 17 S7-200 SMART18 S7-120019 FX3U20 汇川PLC21 台达PLC 具体品牌和型号的 Modbus 角色、地址映射、联调顺序

第 16 篇是总览,不是要替代后面的 PLC 专题。

它解决的是“PLC 到底有没有开 Modbus、走 TCP 还是 RTU、谁是主站谁是从站、地址表该怎么要”。

后面的 17 到 21 篇,才是针对具体 PLC 的现场说明。

几个贯穿全系列的经验

第一,先确认角色。

PLC 是 Server / Slave,YModbus 才作为 Client / Master 去读。

PLC 如果自己是 Client / Master,YModbus 就要反过来做 Server / Slave 模拟器。

这个方向错了,后面全错。

第二,先读固定值。

我很喜欢让 PLC 侧先放一个 1234

不管是西门子、三菱、汇川还是台达,先读一个固定寄存器。这个固定值读对了,说明链路、站号、功能码、地址映射至少通了一半。

固定值都读不对,不要急着讨论浮点数。

第三,地址表要写 Modbus 地址,不要只写 PLC 软元件。

只写 D100DB10.DBW0VW1100M0,对上位机来说还不够。

更好的表应该写成:

Modbus地址 功能码 PLC变量 类型 说明
0 03 通信测试值 UInt16 固定 1234
1 03 设备状态 UInt16 0 停止,1 运行
10 03 温度原始值 Int16 实际值 = 原始值 / 10
0 01 运行中 Bool Coil

有了这种表,软件工程师、PLC 工程师、设备厂家就能说同一种话。

第四,写入一定要有安全边界。

读错值,最多是判断错。

写错地址,可能就是设备误动作。

所以写 PLC 时,不要直接写输出点。更稳的是做命令区、触发位、接收位、完成位和结果码,让 PLC 程序自己判断互锁和安全条件。

CLI 默认 dry-run,桌面工具写入前确认,AI Agent 不自动加 --confirm,都是为了这个边界。

第五,原始报文是最有说服力的证据。

现场争论“软件没问题”没有意义。

能拿出请求帧、响应帧、功能码、异常码、地址和原始寄存器值,问题就会快很多。

YModbus和AI Agent

后面第 15 篇专门讲了自动化调用。

这里先说一个原则:不要一开始就让 AI 去点界面。

更稳的路线是:

先让 CLI 能稳定读写,并且输出 JSON。

再让桌面工具提供本地 Agent Bridge,只监听 127.0.0.1,并要求 X-YModbus-Agent-Token

最后如果要接 MCP,也应该包在这层稳定接口上,而不是直接操纵 WinForms 控件。

这样 AI Agent 可以帮你做这些事:

  • 读取几个寄存器
  • 扫描站号
  • 对比读回值
  • 生成诊断报告
  • 打开工作区
  • 控制从站模拟器启动或停止

但写入真实设备,仍然要有明确确认。

工控自动化里,能调用不等于应该随便调用。

写在最后

YModbus 不是为了证明“我也能写一个 Modbus 库”。

它更像是把工控调试里经常散落在不同地方的东西收回来:

协议概念。

代码库。

命令行。

桌面工具。

从站模拟。

主站工具和从站工具这两个真正面向现场的产品。

现场排查经验。

具体 PLC 连接案例。

这些东西串起来以后,Modbus 就不会只是手册里那几页寄存器表,也不会只是代码里一行 ReadHoldingRegistersAsync

你会知道自己为什么这么读、读错了先查哪里、什么时候该看报文、什么时候该问 PLC 工程师要地址映射表。

这才是我做 YModbus,也继续写这个系列的原因。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐