🌈 个人主页:帐篷Li 🔥 系列专栏:物联网设备端开发 💪🏻 gitee地址:IOTDeviceSDK物联网设备端开发工具包 🤵♂️ 物联网设备上云提供开箱即用接入SDK,提供物联网设备端开发工具包
MODBUS是一种广泛使用的工业通信协议,它允许通过串行线路在不同设备之间进行通信和数据交换。RS485模块是一个在ESP32上实现MODBUS协议的硬件。在本教程中,我们将使用RS485模块在ESP32开发板上创建一个MODBUS主机和从机设备,并实现与MODBUS主机的通信。
多个Modbus(Server)从机设备与一个Modbus主机(Client)设备进行通信。
ESP32 | 连接 | RS485模块 |
---|---|---|
GND | <-> | GND |
GPIO 17 | <-> | RXD |
GPIO 16 | <-> | TXD |
5V | <-> | VCC |
把所有RS485的模块的A和B,分别A连接A,B连接B,全部连接起来。
在 Modbus 的内容中多次提到线圈(coil)和寄存器(register)的概念,尤其是 Moddbus功能码中,操作的对象基本上都是线圈和寄存器。
在 Modbus 协议中之所以仍然称为线圈和寄存器,完全是历史原因。在 PLC 应用领域,一个线圈就代表一个 PLC 输出点,也称为输出继电器。通过控制线圈导通与否来改变继电器输出状态,实现弱电控制强电。
但实际上,在如今的 Modbus 设备中,它们都只是对应一块内存区域而已。其中,线圈代表位操作(bit),表示一个布尔变量;寄存器代表字操作(word),表示一个整型变量(当然也可以通过多个字的组合,表示浮点数以及其他复合数据结构)。在 Modbus 协议中,字(word)的长度是 16 位,即 2 个字节。
3.1 寄存器种类说明
在 Modbus 协议中,所有数据均存放于寄存器中。根据存放的数据类型以及各自读写特性,可以将寄存器分为四个部分,这四个部分可以连续也可以不连续,完全由开发者决定。
下表展示了四类寄存器的含义以及与 PLC 的类比。
寄存器种类 | 含义 | PLC | 示例 |
---|---|---|---|
线圈状态 (Coil Status) | 输出端口(可读可写) | DO(数字量输出) | 电磁阀输出、LED 显示 |
离散输入状态 (Input Status) | 输入端口(只读) | DI(数字量输入) | 拨码开关、微动开关 |
保持寄存器 (Holding Register) | 输出参数(可读可写) | AO(模拟量输出) | PID 运行参数、阈值上下限 |
输入寄存器 (Input Register) | 输入参数(只读) | AI(模拟量输入) | 传感器数据输入 |
Modbus 寄存器地址分配如下表所示,同样参照了 PLC 寄存器地址的分配方法。
寄存器种类 | 寄存器PLC地址 | 寄存器Modbus协议地址 | 简称 |
---|---|---|---|
线圈状态 | 00001~09999 | 0000H~FFFFH | 0x |
离散输入状态 | 10001~19999 | 0000H~FFFFH | 1x |
保持寄存器 | 40001~49999 | 0000H~FFFFH | 4x |
输入寄存器 | 30001~39999 | 0000H~FFFFH | 3x |
该表中的 PLC 地址可以理解为 Modbus 协议地址的变种,在触摸屏和 PLC 编程中应用较为广泛。
细心的你会发现,PLC 寄存器地址 40003 对应的协议地址是 0x0002,PLC 寄存器地址 30003 对应的协议地址也是 0x0002,虽然通信时使用两个相同的 Modbus 协议地址,但是因为不同寄存器的功能码是不相同的,因此并不存在访问冲突。
Modbus 功能码是 Modbus 消息帧(报文)的重要组成部分,是 Modbus 协议中通信事务处理的基础。
Modbus 功能码占用一个字节,取值范围是 1~127(即 0x01~0x7F)。同时,使用功能码 + 0x80 表示异常状态,即 129~255 代表异常码。
在 Modbus 标准协议中,一共规定了三类 Modbus 功能码。
本教程主要介绍公共功能码,下表展示了 Modbus 协议中的部分公共功能码。
代码 | 名称 | 英文 | 寄存器 PLC 地址 | 位/字操作 | 操作数量 |
---|---|---|---|---|---|
01 | 读线圈状态 | Read Coils | 00001~09999 | 位操作 | 单个或多个 |
02 | 读离散输入状态 | Read Discrete Inputs | 10001~19999 | 位操作 | 单个或多个 |
03 | 读保持寄存器 | Read Holding Registers | 40001~49999 | 字操作 | 单个或多个 |
04 | 读输入寄存器 | Read Input Registers | 30001~39999 | 字操作 | 单个或多个 |
05 | 写单个线圈 | Write Single Coil | 00001~09999 | 位操作 | 单个 |
06 | 写单个保持寄存器 | Write Single Register | 40001~49999 | 字操作 | 单个 |
15 | 写多个线圈 | Write Multiple Coils | 00001~09999 | 位操作 | 多个 |
16 | 写多个保持寄存器 | Write Multiple Registers | 40001~49999 | 字操作 | 多个 |
功能码的操作可分为两种:
常用的 Modbus 诊断子功能码定义如下:
功能码 | 子功能码 | 描述 | 说明 |
---|---|---|---|
08 | 00(0x00) | Return Data Query (Loop-back) | 原样返回查询报文 |
08 | 01(0x01) | Restart Communications | 用于初始化并重新启动从站设备 其中,报文字段 0x00, 0x00 表示保持事件记录 0xFF, 0x00 表示清除事件记录 |
08 | 02(0x02) | Return Diagnostic Register | 返回诊断寄存器内容 |
08 | 03(0x03) | Change ASCII Input Delimiter | |
08 | 04(0x04) | Force Listen Only Mode | 强制被寻址的从站设备进入只听模式 使其与网络中的其他设备断开,不返回响应 |
08 | 10(0x0A) | Clear Counters and Diagnostic Registers | 清除计数器和诊断寄存器 |
08 | 11(0x0B) | Return Bus Message Count | 返回总线报文计数值 |
08 | 12(0x0C) | Return Bus Communication Error Count | 返回总线通信 CRC 出错计数 |
08 | 13(0x0D) | Return Bus Exception Error Count | 返回总线异常计数 |
08 | 14(0x0E) | Return Slave Message Count | 返回从站设备接收的报文数量 |
08 | 15(0x0F) | Return Slave No Response Count | 返回从站设备没有返回响应的报文数量 |
08 | 16(0x10) | Return Slave NAK Count | |
08 | 17(0x11) | Return Slave Busy Count | 返回从站设备响应忙的报文数量 |
08 | 18(0x12) | Return Bus Character Overrun Count | 返回总线字符超限的报文数量 |
08 | 19(0x13) | Return IOP Overrun Count (884) | |
08 | 20(0x14) | Clear Overrun Counter and Flag (884) |
常用 Modbus 公共功能码下表所示。
其中,支持广播模式的功能码有:
除了广播模式的报文以外,其他所有查询报文都希望能够获取一个正常的响应报文。如果一切正常,则从站设备将返回一个正常响应报文,该响应报文的功能码与请求报文的功能码一致。
另外,对于字操作的功能码,存在多字节存储的大小端问题,因此主站设备和从站设备必须保持一致的规则处理,约定 Modbus 传输中的数据字段的字节序。