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

(六)YModbus读写数据:线圈、离散输入、保持寄存器、输入寄存器

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

Client 创建好以后,下一步就是选功能码、填地址、读数据。

这一步看起来简单,现场却经常出问题。

很多设备手册不会直接告诉你“请用 03 功能码从地址 0 开始读”。它可能写40001,也可能写Holding Register 1,还有些只给一张寄存器表,默认你懂它的习惯。

所以读写前,先把 Modbus 四类数据区分清楚。

数据区常见用途读功能码标准写功能码YModbus 返回
Coils可读写开关量0105/0Fbool[]
Discrete Inputs只读开关量02bool[]
Holding Registers可读写寄存器0306/10ushort[]
Input Registers只读寄存器04ushort[]

一句话记:线圈和保持寄存器通常能写,离散输入和输入寄存器通常只读。

当然,设备厂家不一定完全按名字设计业务。有些保持寄存器虽然理论上能写,实际也可能只允许读。能不能写,最终还是看设备手册和设备响应。

线圈:读写开关量

线圈用来表示布尔状态,常见的是输出点、启动位、复位位、报警清除位。

读线圈:

bool[]coils=awaitclient.ReadCoilsAsync(0,8);

写单个线圈:

awaitclient.WriteSingleCoilAsync(0,true);

写多个线圈:

awaitclient.WriteMultipleCoilsAsync(startAddress:0,values:new[]{true,false,true,true});

写线圈要小心。很多设备会把线圈映射成动作命令,比如启动、停止、复位。你在调试软件里点一下,设备那边可能真的动作。

我的习惯是,第一次接设备只读不写。等确认站号、地址、功能码都对,再做写入测试。

离散输入:只读开关量

离散输入也是布尔量,但一般是只读。

读离散输入:

bool[]inputs=awaitclient.ReadDiscreteInputsAsync(0,8);

它常见于这些状态:

  • 急停输入
  • 限位开关
  • 光电信号
  • 设备就绪
  • 报警状态

标准 Modbus 没有“写离散输入”的功能码。你如果在从站模拟器里改离散输入,那是模拟器内部改值,不是主站通过标准功能码写进去。

这个区别要分清楚,否则调试时会误以为主站能写所有状态。

保持寄存器:最常用,也最容易踩坑

保持寄存器用功能码03读取,用0610写入。

读保持寄存器:

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

写单个保持寄存器:

awaitclient.WriteSingleRegisterAsync(100,123);

写多个保持寄存器:

awaitclient.WriteMultipleRegistersAsync(startAddress:100,values:newushort[]{123,456,789});

保持寄存器返回的是ushort[],每个元素就是一个 16 位寄存器。

如果设备手册写40001 当前温度,程序里不一定填40001。多数情况下,40001是给人看的编号,真正协议地址要填0

这就是 Modbus 最常见的地址差 1。

第一次读保持寄存器时,我建议这样试:

ushort[]values=awaitclient.ReadHoldingRegistersAsync(0,1);

先读一个。通了,再扩大数量。不要上来就读一大段,报错以后反而不好判断是起始地址错、数量太大,还是跨了非法区域。

输入寄存器:读测量值很常见

输入寄存器用功能码04

ushort[]registers=awaitclient.ReadInputRegistersAsync(0,10);

很多仪表会把温度、压力、流量、重量放在输入寄存器里。但也有设备把这些值放在保持寄存器。

所以看到“测量值”不要直接猜功能码。手册写30001通常对应04,写40001通常对应03,但还是要看厂家说明。

如果你用03读不到,可以试04。反过来也一样。只要设备返回异常码或超时,就回到功能码和地址表上查。

地址一律按协议地址传

YModbus 的 API 里,地址都是协议地址,也就是从0开始。

比如设备手册写:

40001 当前速度 40002 当前压力

程序里通常写:

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

如果手册直接写:

地址 0 当前速度 地址 1 当前压力

那程序里也从0开始。

麻烦就在于不同厂家手册写法不统一。你要判断它给的是显示地址,还是协议地址。

读出来不对时,不要马上怀疑 YModbus。先把地址基准确认清楚。

一次读很多,用分块方法

Modbus 协议对一次读取数量有限制。

保持寄存器一次最多读 125 个,线圈一次也有数量限制。你要读几百个、上千个点位,就应该拆成多次请求。

YModbus 提供了分块辅助方法:

ushort[]registers=awaitclient.ReadHoldingRegistersInBlocksAsync(startAddress:0,quantity:1000);

写一大段保持寄存器也可以分块:

awaitclient.WriteHoldingRegistersInBlocksAsync(0,registers);

这些方法适合参数备份、地址表导出、批量采集。

不过现场第一次联调还是那句话:先小范围读通,再扩大。

MultiUnitClient只是多了站号参数

如果你用的是ModbusMultiUnitClient,方法名基本一样,只是第一个参数多了 UnitId / SlaveId。

ushort[]unit1=awaitclient.ReadHoldingRegistersAsync(1,0,10);ushort[]unit2=awaitclient.ReadHoldingRegistersAsync(2,0,10);

写入也是:

awaitclient.WriteSingleRegisterAsync(unitId:1,address:100,value:123);

这种写法很适合 TCP 网关和 RS485 多站号轮询。

读写前先核对这几件事

我自己接设备时,会先看这几项:

  • 手册写的是哪类数据区
  • 功能码是010203还是04
  • 地址是协议地址,还是40001这种显示地址
  • 一次读的数量有没有超过设备支持范围
  • 这个地址到底能不能写
  • 写入会不会触发设备动作

能读,不代表能写。

写成功,也不代表设备业务一定执行了。有些设备写完参数还要保存命令,有些设备必须在停机或远程模式下才接受。

到这里

YModbus 读写四类数据区,对应的方法其实很直接:

  • ReadCoilsAsync
  • ReadDiscreteInputsAsync
  • ReadHoldingRegistersAsync
  • ReadInputRegistersAsync
  • WriteSingleCoilAsync
  • WriteSingleRegisterAsync
  • WriteMultipleCoilsAsync
  • WriteMultipleRegistersAsync

真正要花心思的,不是记方法名,而是把功能码、地址、数量、站号和设备手册对上。

这些对上了,读写代码反而很简单。

http://www.rkmt.cn/news/1520127.html

相关文章:

  • NGA论坛浏览体验革命:用这个脚本告别传统浏览方式
  • 8分钟掌握KoboldCPP:本地AI文本生成神器快速精通指南
  • 成都买钢材怕踩坑?本地现货直供,保质保量工期不延误 - 四川盛世钢联营销中心
  • PP-OCRv6_medium_det_onnx完全指南:从1.5M到34.5M参数的革命性文本检测模型
  • 别再只玩游戏了!用LabVIEW解析X-Plane的UDP数据流,解锁飞行数据的二次开发
  • 掌控AMD Ryzen性能的钥匙:SMUDebugTool全面解析与实战指南
  • 2026温州龙港二手家电回收排行榜,推荐电话超实用(28字) - 资讯速览
  • Blender MMD Tools完整教程:5分钟学会导入MMD模型与动画
  • 2026年专业AI标书检测工具实测与选型指南:哪家比较靠谱? - 资讯速览
  • DRG Save Editor终极指南:3分钟学会深岩银河存档修改
  • 如何在5分钟内实现智能图像分层?Layerdivider终极指南
  • 嵌入式系统运行时完整性检查:RTIC硬件配置与安全实践
  • 如何彻底改变你的OBS录制工作流?源独立录制插件终极指南
  • 2026广州工程保洁服务商权威测评:合规资质与服务能力深度对比 - 互联网科技品牌测评
  • 如何快速构建可视化AI聊天界面:终极LangGraph集成方案
  • 2026沈阳全屋定制本地工厂优选:志铎全屋定制深耕匠心家装服务 - 资讯速览
  • 成都钢材采购哪家靠谱?本地现货源头厂家,工程终端专用 - 四川盛世钢联营销中心
  • Label Studio ML Backend:构建企业级AI辅助标注系统的核心技术架构
  • 5分钟快速检测:谁偷偷删除了你的微信好友?
  • 洛雪音乐多平台音频聚合架构:5大核心设计实现跨平台高可用音源系统
  • WindowResizer终极指南:如何轻松强制调整任意Windows窗口大小
  • 161887711_enhanced
  • Nine Patch Mesh插件:Godot中创建可伸缩3D网格的完整教程
  • LogExpert完全指南:Windows平台上最强大的日志分析工具
  • 告别手册恐惧:手把手教你用FPGA配置AD9739 DAC(附SPI时序与数据对齐避坑点)
  • 深度解析Metahuman-Stream项目SRS服务连接失败的实战指南
  • SPI主模式驱动:中断与DMA机制深度解析与实战指南
  • 3步实现内核级Root隐藏:SUSFS4KSU-Module完全指南
  • RTKLIB实时PPP定位保姆级教程:从Ntrip账号注册到RTK Monitor界面详解
  • SpringMVC 入门到实战 处理静态资源的过程 64