当前位置: 首页 > news >正文

(三)YModbus上手:先把寄存器读出来

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

前面两篇先把为什么做 YModbus、Modbus 协议的基本概念讲了一遍。

这一篇开始写代码。

不用一上来就想着把所有功能码都用一遍,也不用急着研究各种高级封装。

工控调试里,第一步通常很简单:

我能不能连上设备,并且读到一组正确的寄存器?

只要这一步通了,后面写参数、读 float、批量轮询、多设备采集,都是在这个基础上往上加。

先记住几个参数

用 YModbus 读设备之前,先把下面几个东西搞清楚:

参数RTU 场景TCP 场景
连接方式串口,比如COM3IP 和端口,比如192.168.1.10:502
设备编号slaveIDunitId
功能码比如03读保持寄存器一样
起始地址协议地址,通常从0开始一样
数量要读几个线圈或寄存器一样

这里特别注意地址。

如果设备手册写的是40001,很多时候代码里要填的是0,不是40001

因为40001通常表示“保持寄存器区第 1 个点”,而不是报文里真的发送地址40001

从 RTU 开始

现场最常见的还是 Modbus RTU。

比如电脑通过 USB 转 RS485 接一个仪表,仪表站号是1,波特率9600,我们想读保持寄存器地址0开始的 4 个寄存器。

用 YModbus 大概就是这样:

usingSystem.IO.Ports;usingYModbus.Clients;usingYModbus.Serial;usingSerialPortport=new("COM3"){BaudRate=9600,DataBits=8,Parity=Parity.None,StopBits=StopBits.One,ReadTimeout=2000,WriteTimeout=2000};port.Open();byteslaveID=1;ushortstartAddress=0;ushortquantity=4;awaitusingModbusClientclient=ModbusSerialClientFactory.CreateRtu(slaveID,port,leaveOpen:true);ushort[]registers=awaitclient.ReadHoldingRegistersAsync(startAddress,quantity);foreach(ushortvalueinregisters){Console.WriteLine(value);}

这段代码做的事情其实很直白:

  1. 打开串口
  2. 创建 RTU client
  3. 用功能码03读取保持寄存器
  4. 拿到ushort[]结果

YModbus 里ReadHoldingRegistersAsync对应的就是功能码03

如果现场读不到,先不要急着改代码,先查这几件事:

  • 串口号是不是对的
  • 波特率是不是对的
  • 校验位是不是对的
  • slaveID是不是对的
  • 地址是不是应该从0开始
  • 设备是不是支持功能码03

很多现场问题,最后都是这些参数里有一个没对上。

写保持寄存器

读通以后,再考虑写。

比如从地址100开始写 3 个保持寄存器:

ushortstartAddress=100;ushort[]values=newushort[]{1,2,3};awaitclient.WriteMultipleRegistersAsync(startAddress,values);

这个方法对应功能码16,也就是0x10

如果只写一个寄存器,可以用:

awaitclient.WriteSingleRegisterAsync(100,123);

这个对应功能码06

写操作要比读操作谨慎。

读错了,大多数时候只是读不到或者数据不对。写错了,可能会把设备参数改掉,甚至影响现场动作。

所以刚开始调试时,我一般建议:

  • 先读
  • 再写不影响设备运行的测试地址
  • 确认设备手册里的写入范围
  • 确认写入值有没有单位和倍率

比如手册写“温度设定值,单位 0.1 ℃”,那你想写25.0 ℃,可能实际要写250

TCP 怎么写

Modbus TCP 的代码更短一些,因为不用自己配置串口参数。

比如连接127.0.0.1:1502,UnitId 是1

usingYModbus.Clients;awaitusingModbusClientclient=awaitModbusClientFactory.CreateTcpAsync(host:"127.0.0.1",port:1502,unitId:1);ushort[]registers=awaitclient.ReadHoldingRegistersAsync(0,4);foreach(ushortvalueinregisters){Console.WriteLine(value);}

这里再强调一下:

CreateTcpAsync创建的是 Modbus TCP client,它会主动连接对方的 TCP server。

这个 client/server 是 TCP 通讯关系,不要简单理解成主站/从站。

你在代码里填的unitId,更多是 Modbus 报文里的 Unit Identifier。直连普通 TCP 设备时,很多设备填1就可以;如果是 TCP 转 RTU 网关,它后面可能挂了多个 RTU 设备,这时unitId往往就对应后面的 RTU 站号。

一个 client 固定一个 UnitId

上面的ModbusClient有一个特点:创建时就指定了slaveIDunitId

也就是说,它适合这种场景:

我现在主要跟一个设备通讯。

比如:

awaitusingModbusClientclient=awaitModbusClientFactory.CreateTcpAsync("192.168.1.10",502,unitId:1);

后面这个client发出去的请求,默认都发给unitId = 1

如果你要在同一条连接里轮询多个 UnitId,可以用ModbusMasterClient

awaitusingModbusMasterClientmaster=awaitModbusClientFactory.CreateTcpMasterAsync("192.168.1.10",502);ushort[]unit1=awaitmaster.ReadHoldingRegistersAsync(1,0,10);ushort[]unit2=awaitmaster.ReadHoldingRegistersAsync(2,0,10);

这样每次调用时都可以传不同的 UnitId。

这在网关场景很有用。

读 float 和 int32

Modbus 寄存器本身是 16 位的。

但现场很多数据不是 16 位,比如:

  • int32
  • uint32
  • float
  • double

这种数据一般会占多个寄存器。

YModbus 里可以先读原始寄存器:

ushort[]registers=awaitclient.ReadHoldingRegistersAsync(0,2);

也可以用 typed helper 直接转成 .NET 类型:

usingYModbus.Clients;usingYModbus.Protocol;floattemperature=awaitclient.ReadHoldingRegisterSingleAsync(startAddress:0,wordOrder:ModbusWordOrder.HighWordFirst,byteOrder:ModbusByteOrder.BigEndian);

这里最容易出问题的是字节序和字顺序。

如果读出来的 float 特别离谱,比如一个温度读成了一个很大的数,先别怀疑设备坏了,优先查:

  • 高字在前还是低字在前
  • 每个寄存器内部是不是大端
  • 手册里有没有写 ABCD、CDAB、BADC、DCBA 这种顺序

YModbus 里用ModbusWordOrderModbusByteOrder来控制这件事。

RetryOptions 什么时候用

工业现场通讯不一定每次都很稳。

偶尔一次超时、设备忙、网关后面的设备没响应,都可能遇到。

YModbus 里可以在创建 client 时传ModbusRetryOptions

usingYModbus.Transports;ModbusRetryOptionsretryOptions=new(){RetryCount=2,RetryDelayMilliseconds=100};awaitusingModbusClientclient=awaitModbusClientFactory.CreateTcpAsync("192.168.1.10",502,unitId:1,retryOptions:retryOptions);

这里的RetryCount = 2,意思是第一次请求失败后,最多再重试 2 次。

重试不是万能的。

如果地址错了、功能码错了、站号错了,重试多少次都没用。

它更适合处理偶发性的通讯抖动。

先跑 samples

如果你刚拿到项目,不想一上来就写代码,可以先跑 sample。

TCP 可以先启动一个本地从站模拟:

dotnet run--project.\samples\YModbus.Sample.TcpSlave

再开一个终端读它:

dotnet run--project.\samples\YModbus.Sample.TcpClient--127.0.0.1 1502 1 0 4

RTU 需要真实串口设备,比如:

dotnet run--project.\samples\YModbus.Sample.RtuClient--COM3 9600 1 0 4

这几个参数分别是:

参数含义
COM3串口号
9600波特率
1slaveID
0起始地址
4读取数量

先把 sample 跑通,再复制里面的关键代码到自己的项目里,会比一开始就硬写省很多时间。

我建议的调试顺序

用 YModbus 调设备时,我建议按这个顺序来:

  1. 先确认通讯方式:RTU 还是 TCP
  2. RTU 先确认串口参数,TCP 先确认 IP 和端口
  3. 先读保持寄存器,不要一上来就写
  4. 手册写40001时,代码里优先试地址0
  5. 先读ushort[]原始值,再处理floatint32
  6. 原始值对了,再做单位、倍率、字节序转换
  7. 最后再考虑批量轮询、重试、异常处理

这样排查起来会比较稳。

很多时候不是库的问题,也不是设备的问题,而是地址、功能码、站号、字节序这些基础信息没有对齐。

写在最后

YModbus 的目标不是把 Modbus 包装得看不见。

我更希望它做两件事:

  • 常见读写操作写起来简单
  • 真出问题时,还能看得懂底层到底在干什么

所以你会看到它既有ReadHoldingRegistersAsync这种直接可用的方法,也保留了slaveIDunitId、功能码、寄存器地址这些 Modbus 里本来就很重要的概念。

对工控调试来说,这样反而更踏实。

因为现场最怕的不是代码多写几行,而是出了问题以后完全不知道从哪里查。

http://www.gsyq.cn/news/1512465.html

相关文章:

  • 昆明名表回收深度测评(2026)|黄金波动下,劳力士欧米茄变现谁更稳 - 奢侈品回收评测
  • 别再死记硬背了!用‘矛盾特殊性’搞定你的Spring Boot多环境配置难题
  • 2026 无锡顶奢手表江诗丹顿回收,权威鉴定精准估价无套路 - 奢侈品回收评测
  • 揭秘!贴片式弹簧顶针生产厂家的那些事儿 - 信息热点
  • 2026 最新!海南海口注册公司流程 费用,新手零踩坑指南 - 信息热点
  • 实测福州本地手表回收:欧米茄全系列报价,海马超霸星座哪家高? - 奢侈品回收评测
  • 从WMS到WMTS:为什么你的Web地图加载慢?聊聊瓦片金字塔技术的演进与实战
  • 终极3步方案:无需Steam客户端轻松下载创意工坊模组
  • 别再乱选了!南宁 7 家黄金回收实地测评,套路全曝光 - 奢侈品回收评测
  • 考临床执医,听谁的课?解析阿虎医考阳光、楚然老师 - 医考机构品牌测评专家
  • iPhone USB网络共享驱动完整指南:5分钟解决Windows连接难题
  • 2026年随身WiFi品牌深度测评:从行业乱象到品质标杆的选型指南 - 信息热点
  • 2026 年 6 月海口黄金回收靠谱机构公示|本地正规回收指南 - 开心测评
  • Snap Hutao:重新定义你的原神桌面游戏体验
  • 高端腕表百达翡丽变现指南!2026 无锡正规回收龙头推荐 - 奢侈品回收评测
  • MSBA8100基带加速器:异构计算如何重塑基站信号处理架构
  • 旺季篇|亚马逊2026 Prime Day最后12天冲刺清单!这5件事现在做还来得及
  • 急着周转资金,宁波出奢侈品包包多久能回款? - 奢侈品交易观察员
  • 2026年最新长沙GEO优化公司推荐 AI获客全链路解决方案 - 第三方测评
  • 成都配眼镜避坑指南,新手常见误区与2026靠谱推荐 - 配眼镜新资讯
  • 2026年廊坊GEO优化公司推荐榜:基于技术实力与服务效能的深度评测 - 信息热点
  • EIS™企业专属智能系统
  • 石家庄宝格丽包袋回收:蛇头包、手提包、配件类一篇讲全 - 奢侈品回收测评
  • 便捷!跨境商使用外贸货源跨境手办交易平台,口碑持续走高 - 13425704091
  • 河北电焊防爆墙厂家排行:实测维度下的合规之选 - 奔跑123
  • NSK LSFT5032-2.5 滚珠丝杠技术解析
  • 扎根甬城多年奢品回收,磨损老花包也正常估价 - 奢侈品交易观察员
  • 3个必学技巧:彻底解决ExplorerPatcher任务栏属性打不开的困扰
  • 终极指南:macOS通过HoRNDIS实现Android USB网络共享的完整解决方案
  • 推模型 vs 拉模型:两种数据传递方式