线圈、离散量、寄存器、功能码:Modbus 最容易让人上头的部分,一次讲透

摘要:学 Modbus 时,真正让新手脑壳发麻的,通常不是 CRC,也不是抓包软件,而是这几样东西:CoilDiscrete InputInput RegisterHolding Register,再加上一串 0102030405060F10。名字不短,含义还容易串台。本文就把这几样东西摆在桌面上,一件一件脱掉概念外套,看到底谁是干什么的。

关键词:Modbus、Coil、Discrete Input、Holding Register、Input Register、功能码

如果说上一篇是在帮你认识 Modbus 这个人,那这一篇,就是要带你看清它的脾气和习惯。

很多人刚入门的时候,最容易出现一种状态:功能码记了一堆,报文也抄了几条,但脑子里还是糊成一锅粥。看见 01 不知道是在读谁,看见 40001 也不知道自己摸到的是哪一块。别急,这不叫笨,这叫第一次和工业协议“肢体接触”还没找对节奏。

一、先记住一个总框架:Modbus 其实就 2 个维度

你可以把 Modbus 的四大数据模型看成一个 2 x 2 表格:

  • 一个维度是:1 bit 还是 16 bit
  • 另一个维度是:只读 还是 可读可写

这么一拆,整个世界突然就安静了。
在这里插入图片描述

对应关系如下:

  • Coil1 bit,可读可写
  • Discrete Input1 bit,只读
  • Input Register16 bit,只读
  • Holding Register16 bit,可读可写

你先别急着背英文,先记这句人话:

  • 开关量里,能改的是 Coil
  • 开关量里,只能看的是 Discrete Input
  • 数值量里,只能看的是 Input Register
  • 数值量里,能看也能改的是 Holding Register

这套分类逻辑,比很多人的感情观都清晰。

二、为什么线圈和离散输入都是 1 bit,还要分成两类

这是很多人第一次看到 Modbus 时最疑惑的地方:既然都是 0/1,那干嘛不干脆放一起?

答案很简单,因为它们虽然都只有一位,但“身份”不一样。

1. Coil:能读,也能写

Coil 通常表示“可控的开关量”,也就是主站不仅能看它当前状态,还能直接改它。

常见例子:

  • 启动命令
  • 停止命令
  • 继电器输出使能
  • 蜂鸣器开关
  • 某个内部逻辑标志位

说白了,Coil 就是那种“你不但能看,还能上手”的对象。

2. Discrete Input:只能读,不能写

Discrete Input 通常表示设备当前检测到的输入状态。它反映的是现场真实信号,所以你只能看,不能改。

常见例子:

  • 急停按钮是否按下
  • 限位开关是否触发
  • 门磁是否闭合
  • 某个故障输入是否有效

这个对象很像现场传回来的实况直播。你可以围观,但不能隔空篡改。按钮按没按,不是你在主站里写个 1 就能硬掰回来的。

在这里插入图片描述

所以记忆方法非常简单:

  • Coil = 我能控制
  • Discrete Input = 我只能观察

三、寄存器又是什么,为什么一上来就是 16 位

前面那两类是开关量,属于“要么有,要么没有”。但工业现场更多时候要交换的是数值,比如:

  • 温度
  • 压力
  • 电压
  • 电流
  • 转速
  • 设定值
  • 报警码
  • 计数值

这时候就轮到寄存器登场了。

在 Modbus 里,一个寄存器固定是 16 bit,也就是 2 字节。你可以把它理解成一个个标准小格子,每个格子里放一个数。

1. Input Register:只读数值

它通常放设备“测出来”的东西。

比如:

  • 当前温度
  • 当前压力
  • 当前频率
  • 当前转速
  • 实时采样值

主站能做的事只有一个:读。

2. Holding Register:可读可写数值

它通常放设备“给你调”的东西。

比如:

  • 温度设定值
  • 转速目标值
  • 通信地址参数
  • 报警阈值
  • 工作模式

主站不仅能读,还能写进去改参数。

在这里插入图片描述

一句话总结:

  • Input Register 更像是“实时体征”
  • Holding Register 更像是“可调整参数”

一个是让你看状态,一个是让你动手。至于动手之后设备愿不愿意配合,那就看厂家文档和现场权限了。

四、为什么很多手册里会出现 0x、1x、3x、4x

你在设备手册里,经常会看到这种写法:

  • 00001
  • 10001
  • 30001
  • 40001

这不是厂家闲得蛋疼在玩数字排列组合,而是在提示你它属于哪个数据区。

  • 0x:Coil
  • 1x:Discrete Input
  • 3x:Input Register
  • 4x:Holding Register

注意,这种写法更多是“文档语义地址”,不是你报文里原样发出去的数值。很多时候:

  • 手册写 40001
  • 实际程序里要填的是偏移地址 0

这个坑后面我们会单独展开,不然一篇文章还没发完,读者先被地址偏移狠狠干懵了。

五、功能码到底是什么

如果说四大数据模型回答的是“你在碰谁”,那功能码回答的就是“你想对它干什么”。

Modbus 常用功能码并不多,但很实用。你只要先拿下这 8 个,绝大多数现场场景都能覆盖。

在这里插入图片描述

1. 读相关

  • 01:读线圈 Read Coils
  • 02:读离散输入 Read Discrete Inputs
  • 03:读保持寄存器 Read Holding Registers
  • 04:读输入寄存器 Read Input Registers

2. 写相关

  • 05:写单个线圈 Write Single Coil
  • 06:写单个寄存器 Write Single Register
  • 0F:写多个线圈 Write Multiple Coils
  • 10:写多个寄存器 Write Multiple Registers

你会发现,功能码其实也很老实:

  • 读开关量,用 0102
  • 读寄存器,用 0304
  • 写单个,用 0506
  • 写多个,用 0F10

没有太多弯弯绕,基本就是谁和谁配对,握手姿势非常固定。

六、数据模型和功能码怎么配起来看

真正实战时,你脑子里最好形成下面这张对照表。

数据对象位宽读写属性常用功能码
Coil1 bit可读可写01050F
Discrete Input1 bit只读02
Input Register16 bit只读04
Holding Register16 bit可读可写030610

也就是说:

  • 想看一个可控开关状态,用 01
  • 想写一个可控开关,用 050F
  • 想看现场输入信号,用 02
  • 想看实时数值,用 04
  • 想看参数值,用 03
  • 想改参数值,用 0610

在这里插入图片描述

这张图特别适合拿去做文章里的“防迷路路标”。读者一迷糊,就让他回来对照一眼,立刻知道自己该摸哪个对象,用哪个功能码。工业通信讲究方向感,不然一顿操作猛如虎,最后读错地址像给空气抛媚眼。

七、几个最容易混淆的点,一次说透

1. 0102 都是读 1 bit,到底差在哪

差在对象不同。

  • 01 读的是 Coil
  • 02 读的是 Discrete Input

虽然都是读 0/1,但一个是“可控位”,一个是“现场输入位”。别看它们都只有一位,身份完全不一样。

2. 0304 都是读寄存器,到底差在哪

差在寄存器类型不同。

  • 03 读的是 Holding Register
  • 04 读的是 Input Register

一个偏参数,一个偏实时值。

3. 0506 为什么一个写线圈,一个写寄存器

因为写的对象不同。

  • 05 写的是单个 Coil
  • 06 写的是单个 Holding Register

开关量和数值量,当然不能用同一套写法。一个是在拨开关,一个是在填参数。

4. 0F10 为什么看起来像两个不太像十进制的数字

因为它们通常按十六进制写。

  • 0F 等于十进制 15
  • 10 等于十进制 16

协议文档、抓包软件、技术交流里,写十六进制更常见。别看到 0F 就以为有人键盘按滑了。

八、实战里怎么快速判断自己该读哪种对象

你可以直接按信号类型来想:

场景 1:我要看按钮有没有按下

这是现场输入状态,优先联想到:

  • 数据对象:Discrete Input
  • 功能码:02

场景 2:我要下发一个启动命令

这是一个可控开关量,优先联想到:

  • 数据对象:Coil
  • 功能码:050F

场景 3:我要读取当前温度

这是实时测量值,优先联想到:

  • 数据对象:Input Register
  • 功能码:04

场景 4:我要修改目标温度

这是参数设定值,优先联想到:

  • 数据对象:Holding Register
  • 功能码:0610

只要你把“信号的性质”先想清楚,后面的对象和功能码基本就能顺着推出来。

九、这篇你最该记住的 5 句话

第一,Modbus 的四大数据模型,本质上就是 bit/16bit只读/可写 的组合。

第二,CoilDiscrete Input 都是 1 bit,但前者可控,后者只读。

第三,Input RegisterHolding Register 都是 16 bit,但前者偏实时值,后者偏参数值。

第四,功能码本质上就是“你要对哪个对象做什么动作”。

第五,实战里别先背代码,先判断信号属于哪一类,再去选功能码,效率会高很多。

到这里,你已经把 Modbus 最核心的概念地基打得差不多了。下一篇我们就开始上硬菜,正式拆 Modbus RTU 报文:地址、功能码、数据区、CRC,到底一帧一帧是怎么长出来的。到那一步,抓包就不再只是看热闹,而是能看出门道,甚至看出对面设备到底是在配合,还是在装死。

Logo

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

更多推荐