前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【物联网设备端开发】ESP32 使用RS485模块实现Modbus通信

【物联网设备端开发】ESP32 使用RS485模块实现Modbus通信

作者头像
帐篷Li-物联网布道师
发布2024-03-20 08:09:11
4800
发布2024-03-20 08:09:11
举报

? 个人主页:帐篷Li ? 系列专栏:物联网设备端开发 ?? gitee地址:IOTDeviceSDK物联网设备端开发工具包 ??♂? 物联网设备上云提供开箱即用接入SDK,提供物联网设备端开发工具包

MODBUS是一种广泛使用的工业通信协议,它允许通过串行线路在不同设备之间进行通信和数据交换。RS485模块是一个在ESP32上实现MODBUS协议的硬件。在本教程中,我们将使用RS485模块在ESP32开发板上创建一个MODBUS主机和从机设备,并实现与MODBUS主机的通信。

一、实验效果

多个Modbus(Server)从机设备与一个Modbus主机(Client)设备进行通信。

1.1 元件说明
mnb4v465
mnb4v465
  1. 使用工业级芯片,传输距离可达上千米
  2. 具有高达正负15KV的防静电保护
  3. 芯片内置限摆率控制,大大减少信号干扰
  4. 接收器输入阻抗仅1/4单位,支持多设备连接,可连接128个设备
  5. 工作温度范围广,-40°C到85°C正常工作
  6. 支持热插拔,不会出现信号锁死问题
  7. 使用贴片大容量电解电容进行电源滤波
  8. 双瞬态抑制二极管过压保护
  9. 10欧电流保护电阻,提高信号完整性
  10. RS485和TTL信号单面布线,保证信号质量
  11. 大面积铺铜层,提高抗干扰能力
  12. 提供2.54mm间距洞洞焊接,方便二次开发
  13. 常用M3螺钉固定孔,安装可靠
  14. 120欧端接电阻,支持自动适配
  15. 提供发射/接收指示灯,方便调试
  16. 弯角插针设计,方便测试
  17. 支持3.3V和5V控制,兼容性强
1.2 引脚说明
  • RXD —— 接受数据
  • TXD ——传输数据
  • VCC —— 5V供电
  • GND —— 接地
  • A —— 非反相接收器输入和非反相驱动器输出
  • B —— 反相接收器输入和反相驱动器输出
1.3 BOM表
  • ESP32 N个
  • RS485模块 N个
  • 跳线
  • 屏蔽信号线

二、接线图

gfd98g8hg8fh7
gfd98g8hg8fh7

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 输出点,也称为输出继电器。通过控制线圈导通与否来改变继电器输出状态,实现弱电控制强电。

4lhk53lhk36
4lhk53lhk36

但实际上,在如今的 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(模拟量输入)

传感器数据输入

3.2 寄存器地址分配

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 地址指存放于控制器中的地址,这些控制器可以是 PLC,也可以是触摸屏,或者文本显示器。PLC 地址一般采用十进制描述,共有 5 位,其中第一位数字代表寄存器类型。
  • 寄存器 Modbus 协议地址指的是通信时使用的寄存器寻址地址,例如 PLC 地址 40001 对应寻址地址 0x0000,40002 对应寻址地址 0x0001。寄存器寻址地址一般使用十六进制描述。

细心的你会发现,PLC 寄存器地址 40003 对应的协议地址是 0x0002,PLC 寄存器地址 30003 对应的协议地址也是 0x0002,虽然通信时使用两个相同的 Modbus 协议地址,但是因为不同寄存器的功能码是不相同的,因此并不存在访问冲突。

四、Modbus 功能码

Modbus 功能码是 Modbus 消息帧(报文)的重要组成部分,是 Modbus 协议中通信事务处理的基础。

img
img

Modbus 功能码占用一个字节,取值范围是 1~127(即 0x01~0x7F)。同时,使用功能码 + 0x80 表示异常状态,即 129~255 代表异常码。

在 Modbus 标准协议中,一共规定了三类 Modbus 功能码。

  1. 公共功能码
    • 被明确定义的功能码;
    • 保证唯一性;
    • 由 Modbus 协会确认,并提供公开的文档;
    • 可进行一致性测试;
    • 包括协议定义的功能码和保留将来使用的功能码。
  2. 用户自定义功能码
    • 有两个用户自定义功能码区域,分别是 65~72 和 100~110;
    • 用户自定义,不保证唯一性。
  3. 保留功能码
    • 保留功能码是因为历史遗留原因,某些公司的传统产品上现行使用的功能码不作为公共使用。

本教程主要介绍公共功能码,下表展示了 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

字操作

多个

功能码的操作可分为两种:

  • 位操作 —— 最小单位为一位(bit),包括读线圈状态功能码 01、读离散输入状态功能码 02、写单个线圈功能码 05 和写多个线圈功能码 15;
  • 字操作 —— 最小单位为两个字节,包括读保持寄存器功能码 03、读输入寄存器功能码 04、写单个保持寄存器功能码 06 和写多个保持寄存器功能码 16。

五、功能码详解

5.1 0x01 读取线圈/离散量输出值
  • 该功能码用于读取从设备的线圈或离散量输出的状态,即各 DO(Discrete Output,离散输出)的 ON/OFF 状态。
  • 消息帧中指定了需读取的线圈起始地址和线圈数目。
  • 起始地址由 2 个字节构成,取值范围为 0x0000 到 0xFFFF。
  • 线圈数量由 2 个字节构成,取值范围为 0x0001 到 0x07D0(即十进制 1~2000)。
  • 需要注意,在 Modbus 协议规定的 PDU 中,规定所有线圈或寄存器地址从 0 开始计算。
5.2 0x02 读取离散量输入值
  • 该功能码用于读取从设备的离散输入,即 DI(Discrete Input)的 ON/OFF 状态。
  • 消息帧中指定了需读取的离散输入寄存器起始地址和数目,可读取 1~2000 个连续的离散量输入状态。
  • 如果从设备接受主设备的请求则回复功能码 02,并返回离散量输入各变量的当前状态(如果返回的 DI 数量不是 8 的整数倍,将用 0 填充最后数据字节的剩余位)。
  • 起始地址由 2 个字节构成,取值范围为 0x0000 到 0xFFFF。
  • 离散量数量由 2 个字节构成,取值范围为 0x0001 到 0x07D0(即十进制 1~2000),最多一次可读取 2000 个离散输入状态值。
5.3 0x03 读取保持寄存器值
  • 该功能码用于读取从设备保持寄存器的内容,不支持广播模式。
  • 消息帧中指定了需读取的保持寄存器的起始地址和数目,而保持寄存器中各地址的具体内容和意义则由设备开发者自行规定。
  • 起始地址由 2 个字节构成,取值范围为 0x0000 到 0xFFFF。
  • 寄存器数量由 2 个字节构成,取值范围为 0x0001 到 0x007D(即十进制 1~125),最多一次可连续读取 125 个寄存器值。
  • 需要注意,Modbus 的保持寄存器和输入寄存器是以字(Word)为基本单位的(1Word 等于 2Bytes)。因此,在读取时需要注意字节序(大小端)问题。
5.4 0x04 读取输入寄存器值
  • 该功能码用于读取从设备输入寄存器的内容,不支持广播模式。(与 03 功能码类似)
  • 消息帧中指定了需读取的输入寄存器的起始地址和数目,而输入寄存器中各地址的具体内容和意义则由设备开发者自行规定。
  • 起始地址由 2 个字节构成,取值范围为 0x0000 到 0xFFFF。
  • 寄存器数量由 2 个字节构成,取值范围为 0x0001 到 0x007D(即十进制 1~125),最多一次可连续读取 125 个寄存器值。
  • 同样需要注意字节序问题。
5.5 0x05 写单个线圈/单个离散输出
  • 该功能码用于将单个线圈寄存器(或离散输出)设置为 ON 或 OFF,支持广播模式。
  • 在广播模式下,所有从站设备的同一地址的值将被统一修改。
  • 消息帧中指定了需要变更的线圈地址和设定的状态值。
  • 起始地址由 2 个字节构成,取值范围为 0x0000 到 0xFFFF。
  • 目标数据(即查询报文中的 ON/OFF 状态)由报文数据字段的常数指定,0xFF00 表示 ON 状态,0x0000 表示 OFF 状态,其余所有值均是非法的。
  • 需要注意,在 Modbus 协议规定的 PDU 中,规定所有线圈或寄存器地址从 0 开始计算。
5.6 0x06 写单个保持寄存器
  • 该功能码用于更新从设备的单个保持寄存器的值,支持广播模式。
  • 在广播模式下,所有从站设备的同一地址的值将被统一修改。
  • 消息帧中需要指定从设备地址以及需要变更的保持寄存器地址和设定值。
  • 起始地址由 2 个字节构成,取值范围为 0x0000 到 0xFFFF。
  • 变更目标数据由 2 个字节构成,取值范围为 0x0000 到 0xFFFF。
  • 保持寄存器以字(Word)为基本单位,写入时需要注意目标数据的字节序问题。
5.7 0x08 诊断功能
  • 该功能码仅用于串行链路,主要用于检测主设备和从设备之间的通信故障,或检测从设备的各种内部故障,该功能不支持广播。
  • 查询报文中需要指定从设备地址、功能码(Modbus Command)以及子功能码(Diagnostic Sub-function)。其中,子功能码字段为 2 个字节,用于区别各诊断类型。
  • 在正常的响应报文中,从设备将原样回复功能码和子功能码。

常用的 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)

5.8 0x0B 获取通信事件计数器
  • 该功能码主要用于获取从设备通信计数器中的状态字和事件计数的值,不支持广播模式。
  • 可以通过在通信报文之前和之后读取通信事件计数值,来确定从设备是否正常处理报文。
  • 对于正常完成报文处理和传输的场合,事件计数器增加 1;而对于异常响应、轮询命令或读事件计数器(即 0x0B 功能码)的场合,则计数器不变。
  • 通过 0x08 诊断功能中的 0x01 子功能和 0x0A 子功能,可以复位事件寄存器。
5.9 0x0C 获取通信事件记录
  • 该功能码主要用于从从设备获取状态字、事件计数、报文计数以及事件字节字段。
  • 其中状态字和事件计数与功能码 0x0B 获取的值一致。
  • 报文计数器包含了加电重启、清除计数器之后的报文数量,报文计数与通过 0x08 诊断功能中的 0x0B 子功能码获取的值一致。
  • 事件字节字段包含 0~64 个字节,定义各种事件。
  • 正常情况下响应报文包括一个 2 Bytes 状态字字段、一个 2 Bytes 事件计数字段、一个 2 Bytes 消息计数字段以及 0~64 个字节的事件字段。
  • 由于事件字段是变长的,因此增加了一个 1 Byte 的数据长度字段,以方便读取响应数据。
5.10 0x0F 写多个线圈
  • 该功能码用于将连续的多个线圈(或离散输出)设置为 ON 或 OFF,支持广播模式。
  • 在广播模式下,所有从站设备的同一地址的值将被统一修改。
  • 消息帧中指定了需要变更的线圈起始地址和线圈数目。
  • 起始地址由 2 个字节构成,取值范围为 0x0000 到 0xFFFF。
  • 寄存器数量字段由 2 个字节构成,取值范围为 0x0001 到 0x07B0。
  • 数据字段中为逻辑 1 的位对应 ON,逻辑 0 的位对应 OFF。
5.11 0x10 写多个保持寄存器
  • 该功能码用于设置或写入从设备保持寄存器的多个连续的地址块(1~123个寄存器),支持广播模式。
  • 在广播模式下,所有从站设备的同一地址的值将被统一修改。
  • 消息帧中需要指定从设备地址以及需要变更的保持寄存器地址和数量。
  • 起始地址由 2 个字节构成,取值范围为 0x0000 到 0xFFFF。
  • 寄存器数量字段由 2 个字节构成,取值范围为 0x0001 到 0x007B(即十进制 1~123)。
  • 在实际开发中,该功能码常用于方便用户写入多字节类型的数据,例如浮点数值。因此,需要注意字节序问题。
5.12 0x11 报告从站 ID
  • 该功能码仅适用于串行链路,用于读取从站设备的 ID、类型描述、当前状态以及其他信息,不支持广播模式。
  • 查询报文中没有数据字段。
  • 响应消息的构成由从站设备决定。

总结

常用 Modbus 公共功能码下表所示。

其中,支持广播模式的功能码有:

  • 0x05 写单个线圈
  • 0x06 写单个保持寄存器
  • 0x0F 写多个线圈
  • 0x10 写多个保持寄存器

除了广播模式的报文以外,其他所有查询报文都希望能够获取一个正常的响应报文。如果一切正常,则从站设备将返回一个正常响应报文,该响应报文的功能码与请求报文的功能码一致。

另外,对于字操作的功能码,存在多字节存储的大小端问题,因此主站设备和从站设备必须保持一致的规则处理,约定 Modbus 传输中的数据字段的字节序。

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、实验效果
    • 1.1 元件说明
      • 1.2 引脚说明
        • 1.3 BOM表
        • 二、接线图
        • 三、线圈和寄存器
          • 3.2 寄存器地址分配
          • 四、Modbus 功能码
          • 五、功能码详解
            • 5.1 0x01 读取线圈/离散量输出值
              • 5.2 0x02 读取离散量输入值
                • 5.3 0x03 读取保持寄存器值
                  • 5.4 0x04 读取输入寄存器值
                    • 5.5 0x05 写单个线圈/单个离散输出
                      • 5.6 0x06 写单个保持寄存器
                        • 5.7 0x08 诊断功能
                          • 5.8 0x0B 获取通信事件计数器
                            • 5.9 0x0C 获取通信事件记录
                              • 5.10 0x0F 写多个线圈
                                • 5.11 0x10 写多个保持寄存器
                                  • 5.12 0x11 报告从站 ID
                                  • 总结
                                  相关产品与服务
                                  物联网
                                  腾讯连连是腾讯云物联网全新商业品牌,它涵盖一站式物联网平台 IoT Explorer,连连官方微信小程序和配套的小程序 SDK、插件和开源 App,并整合腾讯云内优势产品能力,如大数据、音视频、AI等。同时,它打通腾讯系 C 端内容资源,如QQ音乐、微信支付、微保、微众银行、医疗健康等生态应用入口。提供覆盖“云-管-边-端”的物联网基础设施,面向“消费物联”和 “产业物联”两大赛道提供全方位的物联网产品和解决方案,助力企业高效实现数字化转型。
                                  领券
                                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                                  http://www.vxiaotou.com