Modbus 与 RS485

在工业通信、单片机外设扩展、PLC 采集系统中,常见说法是 RS485扩展485通信扩展,不是“985扩展”。

更准确的理解是:

RS485 是通信硬件接口,Modbus 是通信协议。
485扩展 = 给主控板增加 RS485 总线通信能力。
Modbus RTU over RS485 = 用 RS485 这条线,按照 Modbus RTU 的格式收发数据。

很多传感器、电表、变送器、继电器模块会写:

通信接口:RS485
通信协议:Modbus RTU
波特率:9600
数据格式:8N1 / 8E1
设备地址:1

这时候就表示:硬件上用 RS485,软件上用 Modbus RTU 协议。


1. 一句话理解

1.1 Modbus 是什么?

Modbus 是一种工业通信协议。

它规定了主机和从机之间如何传递数据,例如:

  • 主机怎么读取从机的数据;
  • 主机怎么写入从机的寄存器;
  • 从机返回的数据格式是什么;
  • 数据中如何包含设备地址、功能码、寄存器地址、数据长度和校验。

可以简单理解为:

Modbus 规定“数据包怎么组织、怎么读写、每个字节是什么意思”。


1.2 RS485 是什么?

RS485 是一种物理通信接口标准。

它主要规定的是电气层面的东西,例如:

  • 使用 A/B 两根差分线传输;
  • 适合较远距离传输;
  • 抗干扰能力比普通 TTL 串口更强;
  • 可以在一条总线上挂多个设备;
  • 常用于工业现场。

可以简单理解为:

RS485 规定“信号怎么在线上传输”。


1.3 485扩展是什么?

485扩展就是给 STM32、单片机、开发板或上位机增加 RS485 通信接口。

STM32 自带的是 UART 串口,一般是:

TX
RX
GND

而 RS485 设备使用的是:

A
B
GND / 屏蔽地

所以中间需要 RS485 收发器,例如:

  • MAX485
  • SP3485
  • SN65HVD 系列
  • 隔离型 RS485 模块

基本连接关系如下:

STM32_TX  --->  DI     RS485收发器     A  ---> RS485总线A
STM32_RX  <---  RO                    B  ---> RS485总线B
GPIO      --->  DE / RE方向控制
GND       ----  GND

2. Modbus 和 RS485 的关系

很多人会把 Modbus 和 RS485 混在一起说,但它们不是同一层的东西。

名称所在层次主要作用类比
RS485物理层 / 电气接口负责信号传输道路、电话线
UART串口通信方式负责字节发送和接收车辆行驶方式
Modbus RTU应用层协议负责数据格式和读写规则说话规则、报文格式
Modbus TCP应用层协议通过以太网传输 Modbus 数据网络版 Modbus

所以实际工程里常见的结构是:

应用层:Modbus RTU 协议
        ↓
串口层:UART,9600 / 8N1 等参数
        ↓
物理层:RS485差分总线
        ↓
设备层:传感器、电表、变送器、PLC、继电器模块

最常见说法:

RS485 上跑 Modbus RTU。


3. Modbus 的具体内容

3.1 主从结构

传统 Modbus RTU 通信一般采用 一主多从 结构。

主机:STM32 / PLC / 上位机 / 工控机
  |
  | RS485总线
  |
从机1:温湿度传感器
从机2:电表
从机3:继电器模块
从机4:压力变送器

特点:

  1. 通常由主机主动发起查询。
  2. 从机一般不主动发数据。
  3. 每个从机都有唯一设备地址。
  4. 同一时刻通常只能有一个设备发送数据。
  5. 主机轮询不同从机,依次读取数据。

3.2 常见 Modbus 类型

3.2.1 Modbus RTU

这是单片机、PLC、工业传感器中最常见的形式,通常跑在 RS485 或 RS232 上。

特点:

  • 数据是二进制格式;
  • 通信效率较高;
  • 每一帧末尾有 CRC 校验;
  • 适合 STM32、PLC、变送器、电表等设备;
  • 调试时一般用串口工具查看十六进制数据。

3.2.2 Modbus ASCII

这是较早的一种串口格式,数据用 ASCII 字符表示。

特点:

  • 人眼更容易看懂;
  • 效率比 RTU 低;
  • 实际新项目中没有 Modbus RTU 常见。

3.2.3 Modbus TCP

这是跑在以太网 TCP/IP 上的 Modbus。

特点:

  • 常用端口为 502;
  • 不使用 RTU 里的 CRC,而是依靠 TCP/IP 传输机制;
  • 常见于工控机、PLC、网关、服务器、SCADA 系统。

3.3 Modbus 数据区

Modbus 中经常会看到这些地址类型:

地址类型常见地址表示数据类型常见用途
Coil00001 起1 bit继电器开关、线圈输出
Discrete Input10001 起1 bit开关量输入
Input Register30001 起16 bit只读模拟量输入
Holding Register40001 起16 bit可读写参数、采集数据

需要特别注意:

说明书里的 40001 不一定代表报文里的地址就是 40001
很多设备把 40001 作为保持寄存器的第一个地址,但在实际 Modbus 报文中起始地址要写成 0x0000

例如:

说明书写:温度寄存器地址 40001
实际报文起始地址:00 00
功能码:03

这就是很多初学者最容易踩的坑之一。


3.4 常见功能码

功能码十六进制作用
010x01读取线圈状态
020x02读取离散输入
030x03读取保持寄存器
040x04读取输入寄存器
050x05写单个线圈
060x06写单个保持寄存器
150x0F写多个线圈
160x10写多个保持寄存器

在传感器采集项目中,最常用的是:

03:读保持寄存器
04:读输入寄存器
06:写单个参数
10:写多个参数

3.5 Modbus RTU 报文格式

一个典型的 Modbus RTU 请求帧如下:

[设备地址] [功能码] [起始地址高字节] [起始地址低字节] [寄存器数量高字节] [寄存器数量低字节] [CRC低字节] [CRC高字节]

例如读取 1 号设备,从地址 0 开始的 2 个保持寄存器:

01 03 00 00 00 02 C4 0B

含义:

字节含义
01从机地址为 1
03功能码,读取保持寄存器
00 00起始寄存器地址
00 02读取 2 个寄存器
C4 0BCRC16 校验,低字节在前

从机可能返回:

01 03 04 00 FA 02 58 XX XX

含义:

字节含义
01从机地址
03功能码
04后面数据区有 4 个字节
00 FA第 1 个寄存器数据,例如 250
02 58第 2 个寄存器数据,例如 600
XX XXCRC 校验

如果说明书规定:

温度 = 原始值 / 10
湿度 = 原始值 / 10

那么:

温度 = 250 / 10 = 25.0℃
湿度 = 600 / 10 = 60.0%

4. RS485 扩展的具体内容

4.1 为什么不用普通串口直接接工业设备?

STM32 的 UART 通常是 TTL 电平:

3.3V / 0V
TX / RX
点对点通信
传输距离较短
抗干扰能力一般

工业现场常用 RS485:

差分信号 A/B
可以远距离传输
抗干扰能力更强
支持多节点挂接
适合现场布线

所以当 STM32 要接工业传感器、变送器、电表等设备时,通常需要增加 RS485 收发器。


4.2 RS485 为什么抗干扰更强?

RS485 使用差分信号。

它不是单独看某一根线相对 GND 的电压,而是看 A 和 B 两根线之间的电压差。

逻辑状态 ≈ A 与 B 的电压差

外界干扰通常会同时影响 A、B 两根线,但两根线的电压差变化较小,所以接收端还能识别出正确数据。

这就是 RS485 适合工业环境的原因之一。


4.3 半双工 RS485

最常见的是二线制半双工 RS485:

A ----------- A ----------- A
B ----------- B ----------- B

特点:

  • A/B 两根线既用于发送,也用于接收;
  • 同一时刻只能一个设备发送;
  • 多个设备共用一条总线;
  • 需要方向控制。

STM32 接 MAX485 一类芯片时,需要控制 DE 和 RE:

模式DE/RE状态
接收00接收总线数据
发送11 或 0驱动总线发送数据
禁用01收发都关闭

很多项目中会把 DE 和 /RE 接在一起,用一个 GPIO 控制:

GPIO = 1:发送
GPIO = 0:接收

4.4 STM32 接 RS485 的典型接线

以 MAX485 / SP3485 类芯片为例:

STM32_TX  ----> DI
STM32_RX  <---- RO
GPIO      ----> DE
GPIO      ----> /RE
GND       ----  GND

MAX485_A  ----> RS485_A
MAX485_B  ----> RS485_B

如果 DE 和 /RE 合并控制:

STM32_GPIO ----> DE
STM32_GPIO ----> /RE

程序中:

发送前:GPIO = 1,切换到发送模式
发送中:UART发送 Modbus 请求帧
发送后:等待 UART TC 发送完成标志
完成后:GPIO = 0,切换回接收模式
接收中:等待从机响应

特别注意:

发送完不能立刻切回接收,必须等待 UART 的 TC 标志。
如果只等 TXE 标志,最后一个字节可能还没真正发完,导致 CRC 或尾字节丢失。


4.5 RS485 总线布线

推荐方式是总线型,也叫手拉手、菊花链:

主机 ---- 从机1 ---- 从机2 ---- 从机3 ---- 从机4

不推荐星型:

        从机1
          |
从机2 --- 主机 --- 从机3
          |
        从机4

原因是星型分支容易造成反射,通信不稳定。


4.6 终端电阻

RS485 长线通信时,通常需要在总线两端加终端电阻。

常见值:

120Ω

布置原则:

总线最前端加一个
总线最末端加一个
中间节点不要随便加

示意:

[120Ω] 主机 ---- 从机1 ---- 从机2 ---- 从机3 [120Ω]

注意:

  1. 终端电阻不是每个设备都加。
  2. 只加在总线两端。
  3. 短距离、低速率时,有时不加也能跑,但工程上要根据距离、速率和现场干扰判断。
  4. 加太多终端电阻会加重驱动负载,可能导致通信失败。

4.7 偏置电阻

当总线上没有设备发送时,A/B 线可能处于悬空或不确定状态。
为了让空闲状态稳定,常加入偏置电阻。

常见做法:

A 上拉到 VCC
B 下拉到 GND
A 与 B 之间接终端电阻

作用:

  • 保证总线空闲时有确定状态;
  • 避免接收器误判成随机数据;
  • 提高通信稳定性。

实际是否需要、阻值多大,要看收发器芯片、终端电阻、节点数量和线缆情况。


5. STM32 中实现 Modbus RTU + RS485 的基本流程

5.1 硬件层

需要准备:

  1. STM32 一个 USART;
  2. RS485 收发器;
  3. 一个 GPIO 控制 DE/RE;
  4. A/B 总线接外部设备;
  5. 必要时加终端电阻、偏置电阻、隔离电源和 TVS 保护。

5.2 串口参数

主机和从机必须完全一致:

波特率:9600 / 19200 / 115200
数据位:8
校验位:None / Even / Odd
停止位:1 / 2

常见配置:

9600, 8N1
9600, 8E1

其中:

8N1 = 8位数据位,无校验,1位停止位
8E1 = 8位数据位,偶校验,1位停止位

工业设备一定要以说明书为准。


5.3 软件流程

主机读取一个从机数据的大致流程:

开始
  ↓
配置串口和RS485方向控制GPIO
  ↓
组织Modbus请求帧
  ↓
计算CRC16
  ↓
切换RS485为发送模式
  ↓
通过UART发送请求帧
  ↓
等待UART发送完成
  ↓
切换RS485为接收模式
  ↓
等待从机返回
  ↓
判断是否超时
  ↓
校验CRC
  ↓
解析功能码和寄存器数据
  ↓
转换成实际物理量
  ↓
更新系统数据 / UI显示 / 语音提示

5.4 伪代码示例

void RS485_SetTx(void)
{
    GPIO_SetBits(RS485_DE_PORT, RS485_DE_PIN);
}

void RS485_SetRx(void)
{
    GPIO_ResetBits(RS485_DE_PORT, RS485_DE_PIN);
}

bool Modbus_ReadHoldingRegisters(uint8_t slave_addr,
                                 uint16_t start_addr,
                                 uint16_t reg_num,
                                 uint16_t *out_regs)
{
    uint8_t tx_buf[8];
    uint8_t rx_buf[64];

    tx_buf[0] = slave_addr;
    tx_buf[1] = 0x03;
    tx_buf[2] = start_addr >> 8;
    tx_buf[3] = start_addr & 0xFF;
    tx_buf[4] = reg_num >> 8;
    tx_buf[5] = reg_num & 0xFF;

    uint16_t crc = Modbus_CRC16(tx_buf, 6);
    tx_buf[6] = crc & 0xFF;
    tx_buf[7] = crc >> 8;

    RS485_SetTx();
    UART_SendBytes(tx_buf, 8);
    UART_WaitTC();
    RS485_SetRx();

    int len = UART_ReceiveWithTimeout(rx_buf, sizeof(rx_buf), 200);
    if (len <= 0)
    {
        return false;
    }

    if (!Modbus_CheckCRC(rx_buf, len))
    {
        return false;
    }

    if (rx_buf[0] != slave_addr || rx_buf[1] != 0x03)
    {
        return false;
    }

    for (int i = 0; i < reg_num; i++)
    {
        out_regs[i] = (rx_buf[3 + i * 2] << 8) | rx_buf[4 + i * 2];
    }

    return true;
}

6. 在 FreeRTOS 项目中的设计建议

如果在 STM32 + FreeRTOS 项目中加入 Modbus RTU + RS485,不建议在 LVGL 回调或主界面刷新函数中直接读 Modbus。

更合适的设计是单独建立一个任务:

Modbus_Task

任务职责:

  1. 定时轮询 RS485 从机;
  2. 发送 Modbus 请求;
  3. 等待响应;
  4. 校验 CRC;
  5. 解析寄存器;
  6. 更新全局数据结构;
  7. 通知 UI 或传感器数据处理模块。

推荐结构:

Modbus_Task
   ↓
读取RS485传感器
   ↓
解析温湿度/PM2.5/光照/电表等数据
   ↓
写入 g_sensor_data
   ↓
LVGL_Task 定时刷新界面
   ↓
Voice_Task 根据状态组合播报

这样做的好处:

  • UI 不会被串口等待卡住;
  • 传感器采集逻辑更清晰;
  • 语音播报和界面刷新不会直接抢串口资源;
  • 出错时可以单独定位 Modbus 通信问题。

7. 和项目的结合方式

如果你的项目后续要扩展 RS485 传感器,可以这样描述:

系统可通过 RS485 扩展接口接入支持 Modbus RTU 协议的外部传感器或变送器。主控通过 USART 与 RS485 收发器连接,并利用方向控制引脚完成半双工收发切换。软件上按照 Modbus RTU 帧格式组织查询命令,读取从机寄存器数据,经过 CRC 校验和数据换算后,将结果送入传感器数据结构,再由界面刷新任务显示在页面上。该方式便于系统后续扩展工业传感器、电表或其他采集模块。

STM32F407
  |
  | USART + RS485收发器
  |
RS485总线
  |
Modbus xxx变送器
Modbus xxx
Modbus xxx变送器
Modbus 继电器模块

这样本地传感器可以分为两类:

类型示例接入方式
普通单点传感器DHT22、GP2Y1014AU、光敏电阻GPIO / ADC
工业扩展传感器RS485温湿度、RS485空气质量、电表RS485 + Modbus RTU

8. 常见问题和排查方法

8.1 A/B 接反

现象:

完全无响应
偶尔收到乱码
CRC一直错误

处理:

交换 A/B 两根线再试

注意:不同厂家对 A/B、D+/D- 的标注可能不完全统一。


8.2 DE/RE 方向控制错误

现象:

主机发得出去,但收不到
从机有响应但主机没收到
只收到自己发出去的数据

处理:

  1. 发送前切换 TX;
  2. 等待 UART TC;
  3. 发送完成后切回 RX;
  4. 不要只等待 TXE。

8.3 CRC 字节顺序写错

Modbus RTU 的 CRC 是:

低字节在前,高字节在后

例如 CRC = 0x0BC4,帧里应写:

C4 0B

而不是:

0B C4

8.4 寄存器地址偏移错误

说明书写:

40001

你报文里可能要写:

00 00

说明书写:

0001

你报文里可能要写:

00 01

也可能要写:

00 00

具体要看厂家说明。有些文档是从 1 开始,有些是从 0 开始。


8.5 终端电阻乱加

错误做法:

每个节点都加120Ω

正确做法:

只在总线两端加

如果每个设备都加,会导致总线负载过重,信号幅度下降,通信反而失败。


8.6 多个从机地址重复

现象:

一发查询,两个设备同时回复
数据冲突
CRC错误
通信不稳定

处理:

给每个从机设置不同地址

8.7 波特率、校验位不一致

必须保证主机和从机一致:

波特率
数据位
校验位
停止位

只要其中一个不一致,通信就可能失败。


8.8 轮询太快

有些低成本传感器响应慢,如果主机连续快速查询,可能出现:

超时
丢帧
返回上一帧数据
设备卡死

建议:

每个设备查询之间留 50 ms ~ 200 ms 间隔
超时时间根据设备说明书设置

9. 表述

9.1 简短版

Modbus 是工业控制领域常用的通信协议,主要用于主机与从机设备之间的数据读写。RS485 是一种差分式串行通信接口,具有抗干扰能力较强、传输距离较远、可多节点挂接等特点。实际应用中,常将 Modbus RTU 协议运行在 RS485 总线上,用于读取传感器、仪表或扩展模块中的寄存器数据。


9.2 项目结合版

为提高系统的扩展能力,后续可预留 RS485 通信接口,使主控能够接入支持 Modbus RTU 协议的外部环境传感器或工业变送器。硬件上,STM32 通过 USART 与 RS485 收发器连接,并通过方向控制引脚完成半双工收发切换;软件上,主控按照 Modbus RTU 帧格式发送查询命令,接收从机返回的数据后进行 CRC 校验和寄存器解析,再将换算后的环境数据用于界面显示和状态判断。该方式能够增强系统对不同类型传感器的兼容性,也便于后续扩展和维护。


10. 最小实现清单

如果要真正做一个 STM32 的 Modbus RTU + RS485 扩展,至少需要:

硬件

  • STM32 USART 一路;
  • RS485 收发芯片或模块;
  • DE/RE 方向控制 GPIO;
  • A/B 双绞线;
  • 必要时增加 120Ω 终端电阻;
  • 必要时增加偏置电阻;
  • 工业现场建议加隔离、TVS、防反接保护。

软件

  • 串口初始化;
  • RS485 方向控制;
  • Modbus CRC16;
  • 请求帧组包;
  • 接收超时机制;
  • 响应帧 CRC 校验;
  • 功能码判断;
  • 寄存器数据解析;
  • 异常码处理;
  • 多从机轮询机制。

调试工具

  • USB 转 RS485 调试器;
  • 串口助手;
  • Modbus Poll / Modbus Slave 等调试软件;
  • 示波器或逻辑分析仪;
  • 设备寄存器说明书。

11. 结论

可以把两者的关系总结为:

Modbus:通信协议,规定数据怎么读写。
RS485:物理接口,规定信号怎么传输。
485扩展:给主控增加 RS485 通信能力。
Modbus RTU + RS485:工业现场最常见的串口总线通信组合。

对于 STM32 项目来说,真正落地时要注意三件事:

  1. 硬件要接对:TX/RX、DE/RE、A/B、GND、终端电阻。
  2. 协议要写对:地址、功能码、寄存器、CRC、字节序。
  3. 时序要控制好:发送前切 TX,发送完成后切 RX,接收要有超时和校验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值