Modbus | Modbus协议回顾

Jul 22, 2025

为什么最多247个从站?

这是因为Modbus协议中的设备地址字段是1个字节(8位),但有一些地址是保留的,不能分配给普通的从站设备。

具体解释如下:

  • 地址范围:地址字段为1个字节,可以表示0~255(十进制),即256个地址。
  • 地址 0:地址0是广播地址,主站发出的消息所有从站都能接收,但不会回应,因此不能分配给具体设备。
  • 地址 1~247:实际分配给从站设备的地址是1~247,也就是247个从站地址。这是Modbus协议标准所规定的。
  • 地址 248~255:这些地址在标准协议中是保留的,暂未用作普通从站地址。

标准Modbus中数据是如何存储的?

信息在从设备中存储于四种不同的表中。

有两张表用于存储开/关(离散)值(线圈),另外两张表用于存储数值(寄存器)。

线圈和寄存器各自都有只读表和读写表。

每张表有9999个数值。 每个线圈或接点占1位,并被分配一个从0000到270E之间的数据地址。 每个寄存器占1字=16位=2字节,也同样有从0000到270E之间的数据地址。

线圈/寄存器编号数据地址类型表名
1-99990000 到 270E读写离散输出线圈 Discrete Output Coils
10001-199990000 到 270E只读离散输入接点 Discrete Input Contacts
30001-399990000 到 270E只读模拟量输入寄存器 Analog Input Registers
40001-499990000 到 270E读写模拟量输出保持寄存器 Analog Output Holding Registers

线圈/寄存器编号可以视为位置名称,因为它们不会出现在实际报文中。数据地址才会被用在消息里。

例如,第一个保持寄存器,编号为40001,对应的数据地址是0000。

这两个值之间的差值称为偏移量(offset)

每张表有不同的偏移量:1、10001、30001和40001。

四个表明的解释

1. 离散输出线圈 (Discrete Output Coils)

  • 定义:又称“线圈”或“Coil”,代表可控制的开关量输出,通常是开/关(ON/OFF)状态。
  • 典型用途:用于驱动继电器、指示灯、打开/关闭机械设备等。
  • 读/写属性:通常可由主机读取其状态,也可以写入改变其状态(例如,让某个线圈通电或断电)。
  • 数据类型:每个线圈占1位(二进制),值为0或1。
  • 例子:你可以通过写线圈打开或关闭一个电磁阀。

2. 离散输入接点 (Discrete Input Contacts)

  • 定义:又称“输入接点”或“Discrete Inputs”,反映现场设备的开关量输入信号。
  • 典型用途:用于检测按钮、限位开关、传感器等的开/关状态。
  • 读/写属性:只读。主机只能读取其状态,不能控制它们。
  • 数据类型:每个接点占1位(二进制),值为0或1。
  • 例子:检测一个安全门是否被打开或关闭。

3. 模拟量输入寄存器 (Analog Input Registers)

  • 定义:用于存储现场设备的模拟量输入值(如电压、电流、温度等)。
  • 典型用途:读取模拟传感器(如温度传感器、压力传感器等)的数据。
  • 读/写属性:只读。主机只能读取其值,不能写入。
  • 数据类型:每个寄存器通常占16位(2字节),表示一个整数值。
  • 例子:读取温度传感器采集到的当前温度。

4. 模拟量输出保持寄存器 (Analog Output Holding Registers)

  • 定义:用于存储需要输出到现场设备的模拟量控制值,也可用来保存设备的一些配置参数。
  • 典型用途:用来控制变频器的转速、阀门的开度、输出电流/电压等。
  • 读/写属性:可读可写。主机可以读取当前值,也可以写入新值来改变控制输出。
  • 数据类型:每个寄存器通常占16位(2字节)。
  • 例子:向变频器的保持寄存器写一个新速度设定值,从而控制电机转速。

总结对比

名称英文典型功能读写属性数据类型
离散输出线圈Discrete Output Coils控制输出设备开关读写1位
离散输入接点Discrete Input Contacts采集输入设备状态只读1位
模拟量输入寄存器Analog Input Registers采集模拟量输入只读16位
模拟量输出保持寄存器Analog Output Holding Registers输出模拟量或参数读写16位

为什么输出是控制,输入是采集?

1. 为什么输出是控制?

  • 离散输出线圈(Discrete Output Coils)和模拟量输出保持寄存器(Analog Output Holding Registers)之所以称为“输出”,是因为它们用来控制现场设备,是主控系统输出到现场的控制信号
    • 你通过Modbus写这些“输出”,其实是在远程控制设备,比如打开/关闭继电器、设置阀门的开度、调节电机速度等。
    • 这些动作都是“输出”到现场,所以叫输出。

2. 为什么输入是采集?

  • 离散输入接点(Discrete Input Contacts)和模拟量输入寄存器(Analog Input Registers)称为“输入”,是因为它们用来采集现场设备的状态,输入到主控系统
    • 比如检测按钮是否按下、传感器是否有信号、温度是多少等。
    • 现场设备的状态“输入”到系统里,所以叫输入。
    • 比如:你读输入寄存器,其实就是在“采集”现场的数据。

3. 为什么容易误解?

很多初学者会本能地把“输入”理解为“我要输入参数”(往设备里写),把“输出”理解为“我要输出数据”(从设备里读)。但在工业自动化和Modbus规范里,输入输出是站在主控系统(如PLC或上位机)对现场设备的视角来定义的:

  • 输出(Output)”:主控系统控制外部设备,“我输出一个动作/信号给现场”。
  • 输入(Input)”:主控系统采集外部信号,“我采集到一个来自现场的数值”。

4. 举例区分

  • 离散输出线圈(Output Coils): 你通过主机指令让某个设备“动作”或“打开/关闭”,这就是输出控制。
  • 离散输入接点(Input Contacts): 你通过主机读取按钮、开关等现场设备的状态,这就是输入采集。

5. 现实生活类比

比如:

  • 你用遥控器(主机)控制电视(现场设备)的电源开关,这个“开关”就是输出线圈(你控制电视)。
  • 你用遥控器(主机)读取电视屏幕上当前的频道号,这个“频道号”就是输入寄存器(你采集、读取电视的信息)。

总结

在Modbus和大部分工业协议中,“输出”通常指你控制外部设备的部分,“输入”通常是你采集外部设备状态的部分。这跟一般日常生活的“输入输出”说法确实不同,但这就是自动化行业和Modbus约定的命名方式。

离散(Discrete)与模拟量(Analog)含义

1. 离散(Discrete)

  • “离散”在自动化和电气专业里,一般特指只有两种状态的信号,也称为数字信号,例如“开/关”、“有/无”、“1/0”等。
  • 线圈(Coils)和输入接点(Discrete Inputs)实际就是用**一位(bit)**来表示“要不要通电”、“这个按钮是否按下”——没有中间态。
  • 在Modbus里,这些只表示0和1,不能存储中间的数值,所以叫离散

举例:

  • 电机是否启动?(离散信号:1=启动,0=未启动)
  • 灯泡是否亮?(离散信号)

2. 模拟量(Analog)

  • “模拟量”指的是可以连续变化的物理量或数值,比如温度、压力、电压、流量等。
  • 在Modbus里,所有需要存储这类“连续”数值的地方,实际上都用寄存器(Register)表示;每个寄存器可以存储0~65535(2字节/16位)的值。
  • 这些寄存器的内容通常代表的是某种模拟测量值数据,不是开或关这么简单,就是一个范围内的某个具体数值。

举例:

  • 温度是23.7℃(模拟量),压力是5.2 bar(模拟量)
  • 你需要寄存器来存储和表示这些数值

为什么线圈叫“离散”,寄存器叫“模拟量”?

  1. 线圈(Coil)和输入接点:
    • 只关心“开/关”,
    • 只占1位(Bit),
    • 没有中间数值,
    • 所以叫“离散”(Discrete)。
  2. 输入寄存器和输出保持寄存器:
    • 每个寄存器可以存储一个具体的数值(16位整数),
    • 可用于表示类似电流、温度、速度等信息,
    • 这些是“模拟量”(Analog),可连续变化。

表格总结

名称英文传输内容数据类型作用举例
离散输出线圈Discrete Output Coils开关状态1位打开/关闭一个某设备
离散输入接点Discrete Input Contacts开关状态1位检测按钮是否被按下
模拟量输入寄存器Analog Input Registers连续数值16位读取温度、压力传感器
模拟量输出保持寄存器Analog Output Holding Registers连续数值16位控制阀门的开度、设置电机转速

什么是功能码?

主机发送的第二个字节就是功能码(Function code)。这个数字告诉从机要访问哪一个表,以及是读取还是写入表中的数据。

功能码操作表名
01(01 hex)读取离散输出线圈(Discrete Output Coils)
05(05 hex)单点写入离散输出线圈(Discrete Output Coil)
15(0F hex)多点写入离散输出线圈(Discrete Output Coils)
02(02 hex)读取离散输入接点(Discrete Input Contacts)
04(04 hex)读取模拟量输入寄存器(Analog Input Registers)
03(03 hex)读取模拟量输出保持寄存器(Analog Output Holding Registers)
06(06 hex)单点写入模拟量输出保持寄存器(Analog Output Holding Register)
16(10 hex)多点写入模拟量输出保持寄存器(Analog Output Holding Registers)

单播和广播

1. Modbus RTU(串口,RS-485等)

单播

  • 单播是Modbus最常见的通信方式。
  • 主站(Master)指令中SlaveID(从站地址)为具体设备地址(1~247之间的某个数),只有地址匹配的从站才会响应并返回数据,其他从站忽略此请求。

广播

  • 通过SlaveID地址设置为0(0x00),意味着广播。
  • 所有从站设备都必须接受并处理这条指令,但不会有任何从站发回响应(以避免总线冲突)。
  • 常用于如“全部清零”、“全部写入寄存器”等一对多操作(比如初始化所有从站)。

2. Modbus TCP(以太网)

  • 标准Modbus TCP理论上是基于IP网络的点对点通信(单播,服务器/客户端结构),通常每台设备有唯一IP,所以广播使用极少。

TCP下的“广播”?

  • 大多数Modbus TCP实现并不支持广播(即,不会有标准从站响应UDP广播或IP组播)。
  • Modbus TCP只保留了UnitID字段来兼容网关场景,但实际数据传输依赖于唯一的IP地址(主机名),所以常规都是单播
  • 个别厂家在特定应用下做了扩展(比如通过UDP广播向所有设备刷写配置),但这不是协议层面标准,只适用于特定产品。

3. 总结对比

单播广播
Modbus RTU支持(常用)支持(地址0)
Modbus TCP支持(常用)基本不支持,协议无定义

常见场景举例

  • 单播:主站向1号从站请求状态,SlaveID=1→1号从站响应。
  • 广播:主站发送全体写入,SlaveID=0→所有从站执行,无人响应。

结论:

Modbus确实有单播和广播,RTU支持广播(SlaveID=0),TCP标准下基本只用单播。

Modbus TCP

ADU 与 PDU

以 Modbus RTU 消息为例,将消息开头的 SlaveID(从站地址)和结尾的 CRC 校验去掉,剩下的就是 PDU(协议数据单元,Protocol Data Unit)。

下面是一个 Modbus RTU 请求的例子,请求地址为 17 的从设备的模拟输出保持寄存器(Holding Registers)#40108 到 40110 的内容。

11 03 006B 0003 7687
  • 11:SlaveID(从站地址)(17 = 0x11 16进制)
  • 03:功能码(读取模拟输出保持寄存器)
  • 006B:请求的第一个寄存器地址(40108-40001=107=0x6B 16进制)
  • 0003:请求的寄存器数量(读取3个寄存器,从40108到40110)
  • 7687:CRC(循环冗余校验),用于错误检测

去掉SlaveID和CRC后,就得到了PDU:

03 006B 0003

说明:

ADU(应用数据单元)= 协议头(比如SlaveID或者MBAP头部)+ PDU + 校验。

在Modbus RTU中,ADU由[SlaveID][PDU][CRC]组成;而在Modbus TCP中,ADU由[MBAP Header][PDU]组成(MBAP头里含UnitID,没有CRC)。

Modbus RTU和Modbus TCP调试

调试工具指令“逻辑”一致,但“封装和通讯方式”不同

1. 指令内容(功能码、寄存器号、数据等)是通用的

  • 比如你在调试工具里设置“读保持寄存器(功能码03)”,起始地址40001,读取2个寄存器,这个“命令内容”逻辑RTU、TCP下是一致的。
  • 举个例子,调试工具一般会让你选择:
    • 功能码(如03)
    • 地址(如40001或0偏移)
    • 数据长度
    • 填好后点击发送

2. 封装方式不同(工具会帮你处理)

  • Modbus RTU
    • 工具会把你的指令包装成串口协议的二进制帧(末尾加CRC校验),通过串口(COM口)发出去。
  • Modbus TCP
    • 工具会把你的指令包装成以太网TCP协议的报文(加MBAP头,不需要加CRC),走网络端口(通常502)发出去。

3. 使用方式基本一样,只需注意如下差别

  • 选择通讯方式
    • RTU → 需要选择串口、波特率、校验、站号等
    • TCP → 需要输入IP地址、端口号、站号
  • 指令设置界面基本一模一样(寄存器、功能码、数据等)
  • 只能用在对应设备上:RTU工具发串口、TCP工具发网线。不能串口连着,工具选TCP,也不能反过来。

4. 底层数据格式完全由调试工具自动组包

  • 大部分Modbus调试工具(比如Modbus Poll、Modscan、Simply Modbus等)都支持RTU和TCP两种模式,你只需要选对通讯方式,填对参数即可。

举例

  • 你在调试工具选“读03寄存器,站号为1,地址为40001,长度为1”,
    • RTU模式下,工具帮你通过串口发出 01 03 00 00 00 01 CRC
    • TCP模式下,工具帮你通过网口发出 MBAP头 01 03 00 00 00 01
  • 你只需要关心功能和参数,不用自己手动封包!

总结

  • 逻辑通用:你会用一种Modbus调试工具,切换RTU和TCP,参数设置基本一样。
  • 物理层和底层数据帧不通用,硬件连接方式&通讯设置要选对。

你要做的只是一句话

“选对通讯方式(串口还是TCP),填好常规参数,其他都是通用的。”


  • https://www.modbustools.com/modbus.html
  • https://www.simplymodbus.ca/
  • GPT-4.1
https://inasa.dev/posts/rss.xml