25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

13 KiB

Modbus 学习文档

基本概念

Modbus 基本概念

Modbus 是一种工业通信协议,主要用于控制器、触摸屏、仪表、传感器和驱动器之间的数据交换。

Modbus 规定了通信双方如何组织地址、功能码、数据和校验信息,但不规定设备内部必须采用什么硬件或如何存储数据。某个寄存器代表温度、速度还是报警状态,需要由设备的通信说明书确定。

Modbus 具有以下特点:

  • 协议结构简单,容易实现。
  • 采用请求和应答方式通信。
  • 支持位数据和 16 位寄存器数据。
  • 支持串口和以太网。
  • 不同厂商的工业设备可以按照统一报文格式交换数据。

在 Modbus 串口通信中,设备分为主站和从站:

  • 主站主动发出请求,并等待从站应答。
  • 从站接收并处理属于自己的请求,然后返回应答。
  • 从站一般不能在没有请求的情况下主动发送业务数据。

应用场景

Modbus 常见于以下工业控制场景:

  • PLC 与触摸屏之间交换状态和控制数据。
  • PLC 读取温度、压力、流量等仪表数据。
  • PLC 设置变频器频率并读取运行状态。
  • 上位机监控多台 PLC 或现场设备。
  • 多台从站通过 RS-485 总线连接到同一个主站。
  • 工业网关在 Modbus RTU 与 Modbus TCP 之间转换。

Modbus 适合周期性读取和写入少量工业数据。它没有统一规定变量名称,因此通信前通常需要准备地址表,明确每个线圈和寄存器的用途、数据类型、读写权限及单位。

三种通信模式

Modbus RTU

Modbus RTU 使用二进制方式传输数据,通常运行在 RS-485 或 RS-232 接口上。

主要特点:

  • 数据紧凑,传输效率较高。
  • 使用 CRC16 校验。
  • 通过总线静默时间判断帧边界。
  • 是串口设备中最常见的 Modbus 模式。

Modbus ASCII

Modbus ASCII 把每个数据字节转换为两个 ASCII 字符发送。

例如:

数据字节 0x3A -> 字符 '3' 和 'A'

主要特点:

  • 报文以冒号 : 开始。
  • 报文以回车和换行结束。
  • 使用 LRC 校验。
  • 便于通过文本终端观察,但传输效率低于 RTU。

Modbus TCP

Modbus TCP 运行在 TCP/IP 网络上,默认使用 TCP 端口 502。

主要特点:

  • 使用以太网通信。
  • 报文包含 MBAP 报文头。
  • TCP 已经提供传输校验,因此不再附加 RTU 的 CRC16。
  • 可以同时建立多个网络连接。

三种模式对比

对比项 Modbus RTU Modbus ASCII Modbus TCP
常用接口 RS-485、RS-232 RS-485、RS-232 以太网
数据形式 二进制 ASCII 字符 二进制
校验方式 CRC16 LRC TCP/IP 校验
帧边界 静默时间 起止字符 MBAP 长度字段
传输效率 较低

三种模式的外部封装不同,但功能码和主要数据含义基本一致。

广播模式与单播模式

单播模式

主站使用从站地址 1~247访问指定从站。从站处理请求并返回应答。

主站发送请求 -> 指定从站处理请求 -> 从站返回应答

主站可以根据应答判断本次事务是否成功。如果规定时间内没有收到应答,则可以进行超时或重试处理。

广播模式

地址 0 是 Modbus 串口通信中的广播地址。主站向地址 0 发送请求时,所有从站都可以接收并执行。

广播模式具有以下特点:

  • 广播只适合写操作。
  • 从站执行广播写请求后不能返回应答。
  • 广播读请求没有实际意义,应被从站忽略。
  • 主站无法确认每个从站是否执行成功。

广播请求不能产生应答,是因为多个从站同时发送数据会造成总线冲突。

事务处理流程

一次 Modbus 请求和应答过程称为一个事务。

主站事务处理流程

确定从站地址和操作内容
        |
生成请求数据
        |
添加功能码和校验信息
        |
发送请求帧
        |
启动应答超时计时
        |
接收从站应答
        |
检查地址、功能码、长度和校验
        |
处理正常应答或异常应答

主站需要处理以下情况:

  • 收到正确的正常应答。
  • 收到从站异常应答。
  • 等待应答超时。
  • 应答 CRC 或 LRC 错误。
  • 应答地址与请求地址不一致。
  • 应答功能码与请求功能码不匹配。
  • 应答长度或字节数错误。

从站事务处理流程

接收请求帧
    |
检查帧长度和校验
    |
检查从站地址
    |
检查功能码
    |
检查数据地址、数量和字节数
    |
执行读取或写入
    |
生成正常应答或异常应答
    |
添加校验并发送

从站应先完成报文校验和参数检查,再修改内部数据。CRC 错误、帧不完整或单播地址不属于本机的请求通常直接丢弃。

超时与重试

主站发送请求后,如果在规定时间内没有收到完整且正确的应答,则本次事务超时。

主站可以进行有限次数重试:

发送请求
  -> 超时
  -> 第一次重试
  -> 仍然超时
  -> 第二次重试
  -> 仍然超时
  -> 判断从站离线

重试次数不能无限增加,否则离线设备会长期占用通信总线。

寄存器相关概念

四种数据区

Modbus 定义了四个相互独立的数据区。

数据区 数据宽度 访问权限 读取功能码 常用写入功能码
线圈 Coils 1 bit 读/写 0x01 0x05、0x0F
离散输入 Discrete Inputs 1 bit 只读 0x02
保持寄存器 Holding Registers 16 bit 读/写 0x03 0x06、0x10
输入寄存器 Input Registers 16 bit 只读 0x04

不同数据区相互独立,可以拥有相同的地址。例如,线圈地址 0 和保持寄存器地址 0 不冲突,因为访问它们所使用的功能码不同。

线圈

一个线圈只保存一个二进制状态:

0 = OFF
1 = ON

多个线圈在报文中按位打包。请求中的第一个线圈放在第一个数据字节的最低位 bit0。

寄存器

一个 Modbus 寄存器为 16 位,占 2 字节。

  • 无符号数范围:0~65535。
  • 有符号数范围:-32768~32767。

Modbus 只规定寄存器宽度,不规定寄存器中的数据类型。一个实际变量可以使用一个或多个寄存器表示:

  • 16 位整数:占用 1 个寄存器。
  • 32 位整数:占用 2 个寄存器。
  • 32 位浮点数:占用 2 个寄存器。
  • 字符串:占用多个连续寄存器。

使用多个寄存器表示一个数据时,通信双方必须约定高低字顺序。

逻辑编号与协议地址

部分资料使用 00001 表示第一个线圈,使用 40001 表示第一个保持寄存器。这些是便于阅读的逻辑编号,不一定是报文中的实际地址。

例如:

逻辑编号 40001 -> 报文地址通常为 0x0000
逻辑编号 40002 -> 报文地址通常为 0x0001

不同设备软件可能采用从 0 开始或从 1 开始的显示方式。通信时应以设备手册和实际发送的报文地址为准。

数据帧格式

Modbus RTU 基本帧格式

Modbus RTU 报文由以下字段组成:

字段 长度 说明
从站地址 1 字节 单播地址 1~247,广播地址 0
功能码 1 字节 表示读取或写入操作
数据 可变 起始地址、数量、字节数和数据值
CRC16 2 字节 低字节先发送,高字节后发送

Modbus RTU ADU 的最大长度为 256 字节。

地址、数量和寄存器值等 16 位字段采用高字节在前:

数值 0x1234 -> 发送 12 34

CRC 在线路上采用低字节在前:

CRC 计算结果 0x0A84 -> 发送 84 0A

CRC16

Modbus RTU 的 CRC16 参数如下:

  • 初始值:0xFFFF
  • 多项式:0xA001
  • 计算范围:从站地址、功能码和数据字段。
  • 接收方重新计算 CRC,并与报文最后两个字节比较。

CRC 不正确的报文应直接丢弃,不能返回异常应答。

T1.5 与 T3.5

Modbus RTU 通过静默时间区分报文:

  • T1.5:1.5 个字符的传输时间。
  • T3.5:3.5 个字符的传输时间。

一帧内部的字节应连续发送。如果相邻字节间隔超过 T1.5,当前报文可能被判定为不完整。两帧之间至少保持 T3.5 的静默时间。

波特率高于 19200 bit/s 时,通常建议采用:

  • T1.5:750 μs。
  • T3.5:1.75 ms。

0x01 功能码

功能码 0x01 用于读取线圈。

请求帧格式

字段 长度
从站地址 1 字节
功能码 0x01 1 字节
起始地址 2 字节
线圈数量 2 字节
CRC 2 字节

请求读取从站 1 的线圈地址 0,共读取 1 个线圈:

01 01 00 00 00 01 FD CA

字段解释:

01       从站地址
01       功能码
00 00    起始地址
00 01    读取数量
FD CA    CRC

线圈读取数量的标准范围为 1~2000。

应答帧格式

字段 长度
从站地址 1 字节
功能码 0x01 1 字节
数据字节数 1 字节
线圈数据 N 字节
CRC 2 字节

如果线圈地址 0 为 ON:

01 01 01 01 90 48

线圈按最低位优先排列:

数据字节 bit0 -> 请求中的第 1 个线圈
数据字节 bit1 -> 请求中的第 2 个线圈
...
数据字节 bit7 -> 请求中的第 8 个线圈

最后一个数据字节中没有使用的高位应置 0。

0x03 功能码

功能码 0x03 用于读取保持寄存器。

请求帧格式

字段 长度
从站地址 1 字节
功能码 0x03 1 字节
起始地址 2 字节
寄存器数量 2 字节
CRC 2 字节

请求读取从站 1 的保持寄存器地址 0,共读取 1 个寄存器:

01 03 00 00 00 01 84 0A

保持寄存器读取数量的标准范围为 1~125。

应答帧格式

字段 长度
从站地址 1 字节
功能码 0x03 1 字节
数据字节数 1 字节
寄存器数据 N 字节
CRC 2 字节

假设保持寄存器地址 0 的值为 0x1234

01 03 02 12 34 B5 33

其中:

02       后续数据占 2 字节
12 34    寄存器值

读取多个寄存器时,数据按照寄存器地址递增顺序排列。

0x0F 功能码

功能码 0x0F 用于写多个线圈。

请求帧格式

字段 长度
从站地址 1 字节
功能码 0x0F 1 字节
起始地址 2 字节
线圈数量 2 字节
数据字节数 1 字节
线圈数据 N 字节
CRC 2 字节

把地址 0~7 的 8 个线圈写成 0x55

01 0F 00 00 00 08 01 55 3E AA

字段解释:

01       从站地址
0F       功能码
00 00    起始地址
00 08    写入 8 个线圈
01       数据字节数
55       线圈数据
3E AA    CRC

线圈写入数量的标准范围为 1~1968。

数据字节数的计算方法:

数据字节数 = (线圈数量 + 7) / 8,采用整数除法

应答帧格式

正常应答回显起始地址和实际写入数量:

字段 长度
从站地址 1 字节
功能码 0x0F 1 字节
起始地址 2 字节
写入数量 2 字节
CRC 2 字节

应答示例:

01 0F 00 00 00 08 54 0D

0x10 功能码

功能码 0x10 用于写多个保持寄存器。

请求帧格式

字段 长度
从站地址 1 字节
功能码 0x10 1 字节
起始地址 2 字节
寄存器数量 2 字节
数据字节数 1 字节
寄存器数据 N 字节
CRC 2 字节

从地址 10 开始写入两个寄存器,数据分别为 0x12340x5678

01 10 00 0A 00 02 04 12 34 56 78 08 E4

字段解释:

01          从站地址
10          功能码
00 0A       起始地址
00 02       写入 2 个寄存器
04          数据字节数
12 34       第一个寄存器的数据
56 78       第二个寄存器的数据
08 E4       CRC

寄存器写入数量的标准范围为 1~123,数据字节数必须等于寄存器数量乘以 2。

应答帧格式

正常应答回显起始地址和实际写入数量:

字段 长度
从站地址 1 字节
功能码 0x10 1 字节
起始地址 2 字节
写入数量 2 字节
CRC 2 字节

应答示例:

01 10 00 0A 00 02 61 CA

异常应答帧

当请求报文校验正确,但从站无法执行请求时,从站可以返回异常应答。

异常功能码等于原功能码加 0x80

0x01 -> 0x81
0x03 -> 0x83
0x0F -> 0x8F
0x10 -> 0x90

异常应答格式:

字段 长度
从站地址 1 字节
异常功能码 1 字节
异常码 1 字节
CRC 2 字节

常见异常码:

异常码 名称 含义
0x01 非法功能 从站不支持该功能码
0x02 非法数据地址 请求地址不存在或访问范围越界
0x03 非法数据值 数量、字节数或数据值不合法
0x04 从站设备故障 从站执行请求时发生内部错误
0x06 从站设备忙 从站暂时不能处理请求

例如,从站 1 对 0x03 请求返回非法数据地址:

01 83 02 C0 F1