RS485通信超时全面排查:终端电阻、A/B线、DE方向控制、串口参数和Modbus一次讲透

前言
在 STM32、GD32、ESP32、PLC 或工业控制设备开发中,RS485 是非常常见的一种通信方式。
实际调试时,经常会遇到这样的现象:
text
主机发送请求
↓
串口发送函数执行成功
↓
等待从机回复
↓
一直没有收到数据
↓
Timeout
很多人看到"通信超时",第一反应就是:
是不是 Modbus 协议代码写错了?
实际上,RS485通信超时只是最终表现,并不能直接说明是哪一层出了问题。
问题可能发生在:
text
MCU UART
↓
DE/RE方向控制
↓
RS485收发器
↓
A/B差分线
↓
终端电阻
↓
线缆和拓扑
↓
对端RS485收发器
↓
对端UART
↓
Modbus/自定义协议
任何一个环节异常,都可能最终表现为:
text
Timeout
因此调试 RS485 最重要的不是反复修改超时时间,而是先判断:
到底是没有发送出去,还是已经发送出去但对端没有收到,还是对端收到了却没有回复,或者回复了但主机没有接收到。
本文将从物理层到协议层,详细讲解 RS485 通信超时的完整排查方法,包括:
- RS485到底是什么;
- UART和RS485有什么关系;
- A/B差分信号如何工作;
- 为什么需要120Ω终端电阻;
- A/B接反有什么现象;
- DE/RE方向控制为什么特别容易出错;
- 为什么TXE不能代表最后一个字节真正发送完成;
- 波特率、数据位、校验位、停止位如何影响通信;
- RS485和Modbus RTU是什么关系;
- 如何用示波器和逻辑分析仪定位故障;
- STM32中如何正确控制RS485收发方向;
- 通信超时应该按照什么顺序排查。
一、RS485到底是什么?
首先要明确:
RS485不是通信协议,它是一种电气接口标准。
RS485主要规定的是:
text
电压特性
差分信号
驱动能力
接收能力
总线连接形式
节点数量
共模范围等
RS485本身并不知道:
text
设备地址
功能码
寄存器
CRC
帧头
帧尾
这些属于更上层的通信协议。
例如:
text
RS485 + Modbus RTU
RS485 + 自定义协议
RS485 + Profibus某些物理实现
所以一定要区分:
text
RS485 = 物理层
Modbus RTU = 应用层/通信协议
这也是为什么:
RS485线路完全正常,并不代表Modbus一定能通信。
二、UART和RS485是什么关系?
很多初学者会把 UART 和 RS485 混在一起。
实际上可以这样理解:
text
MCU
↓
UART
↓
TX / RX
↓
RS485收发器
↓
A / B
↓
双绞线
UART产生的是:
text
单端数字信号
例如:
text
TX = 0V / 3.3V
RX = 0V / 3.3V
而RS485收发器负责将UART信号转换为:
text
差分信号
通过:
text
A
B
两根线传输。
另一端再通过RS485收发器,把差分信号恢复为UART RX数字信号。
所以完整链路是:
text
发送MCU UART_TX
↓
RS485 Transceiver
↓
A / B
↓
RS485 Transceiver
↓
接收MCU UART_RX
三、为什么RS485要使用差分信号?
普通UART直接使用单端信号:
text
TX
GND
当通信距离变长,或者现场存在:
text
电机
变频器
继电器
开关电源
大电流设备
时,很容易受到干扰。
RS485使用两根差分线:
text
A
B
接收器主要判断:
text
VA - VB
而不是单独判断某一根线相对于地的绝对电压。
如果外界噪声同时耦合到A、B:
text
A + 噪声
B + 噪声
那么差分计算:
text
(A + Noise) - (B + Noise)
= A - B
公共噪声在理想情况下会被抵消。
这就是差分通信抗干扰能力强的重要原因。
四、RS485为什么经常是半双工?
工程中最常见的是:
text
2线RS485
也就是:
text
A
B
一对差分线同时负责:
text
发送
+
接收
因此:
同一时刻通常只能由一个节点驱动总线。
这就是:
text
Half-Duplex
半双工
例如:
text
主机发送请求
↓
主机释放总线
↓
从机接管总线
↓
从机发送回复
因此RS485通信中有一个非常重要的东西:
text
方向控制
这通常就是:
text
DE
/RE
五、典型RS485收发器有哪些引脚?
常见RS485芯片可能包含:
text
RO
/RE
DE
DI
A
B
VCC
GND
可以简单理解:
text
DI
Driver Input
发送数据输入
RO
Receiver Output
接收数据输出
DE
Driver Enable
发送驱动使能
/RE
Receiver Enable
接收使能
A/B
差分总线
连接到MCU:
text
MCU TX ───── DI
MCU RX ←──── RO
GPIO ─────── DE
GPIO ─────── /RE
很多工程会把:
text
DE
/RE
连接到一起,由一个GPIO控制。
六、DE和/RE通常怎么控制?
典型半双工RS485:
发送状态
通常:
text
DE = 1
/RE = 1
也就是:
text
发送器开启
接收器关闭
如果DE和/RE绑在一起:
text
DIR = 1
→ 发送
接收状态
通常:
text
DE = 0
/RE = 0
即:
text
发送器关闭
接收器开启
于是:
text
DIR = 0
→ 接收
不过:
不同RS485收发器引脚定义可能不同,必须查看具体芯片数据手册。
不能机械认为所有芯片逻辑都完全一样。
七、RS485通信超时到底是什么意思?
假设主机发送:
text
01 03 00 00 00 02 CRC_L CRC_H
然后进入:
c
Wait_Response();
如果在规定时间内没有接收到符合要求的数据,就会:
text
Timeout
但是这个Timeout可能对应四种完全不同的情况。
情况1:主机压根没发出去
例如:
text
UART没启动
DE没有打开
RS485收发器没供电
TX引脚配置错误
情况2:主机发了,但是从机没收到
例如:
text
A/B接反
线路断开
终端异常
波特率不一致
信号畸变
情况3:从机收到,但没有回复
例如:
text
设备地址错误
CRC错误
功能码不支持
寄存器地址错误
从机程序异常
情况4:从机回复了,但主机没收到
例如:
text
主机DE没有及时关闭
主机一直占着总线
接收器没有打开
UART RX异常
回复时间窗口不合理
所以:
Timeout只是现象,第一步必须判断故障发生在哪一个方向。
八、第一步:先确认主机到底有没有发送数据
不要一看到:
c
HAL_UART_Transmit();
返回:
text
HAL_OK
就认为RS485总线一定已经有数据。
因为:
text
UART发送成功
和:
text
RS485差分总线真正发送成功
不是完全一回事。
建议检查:
text
MCU TX
↓
收发器DI
↓
CAN? ×
↓
RS485 A/B
正确链路应该是:
text
UART_TX
↓
DI
↓
RS485 Driver
↓
A/B差分波形
九、最简单的方法:先测UART TX
使用:
text
示波器
逻辑分析仪
直接观察:
text
MCU UART_TX
如果TX完全没有波形:
说明问题还没有到RS485层。
优先检查:
text
UART初始化
GPIO复用
波特率
发送函数
UART时钟
程序流程
十、如果TX有波形,A/B没有波形怎么办?
这时重点检查:
text
RS485收发器
尤其是:
text
供电
DE
DI
芯片损坏
A/B线路
例如:
text
TX有数据
↓
DI也有数据
↓
DE一直为0
那么发送驱动器没有开启。
结果:
text
A/B没有有效差分波形
从机自然收不到。
十一、第二个重点:120Ω终端电阻
RS485通信超时中非常常见的硬件问题就是:
text
终端电阻配置错误
典型长距离、高速RS485总线结构:
text
120Ω 120Ω
A ─────┬──────────────────────────────────┬────
│ │
B ─────┴──────────────────────────────────┴────
Node1 Node2 Node3 NodeN
重点是:
终端电阻通常加在总线物理两端,而不是每个节点都加。
十二、为什么终端电阻通常是120Ω?
双绞线具有一定:
text
特性阻抗
工程中常见RS485线缆特性阻抗约:
text
120Ω
如果线路末端没有匹配:
text
信号到达线缆末端
↓
发生反射
↓
反射波返回
↓
与原始信号叠加
↓
出现振铃和过冲
可能导致接收器错误判断。
尤其在:
text
高波特率
长线
复杂拓扑
情况下更加明显。
十三、为什么短距离低速时没终端也可能通信?
这是很常见的现象。
例如:
text
9600 baud
线长30cm
实验桌测试
即使没有120Ω,也可能完全正常。
于是开发者容易产生错觉:
终端电阻根本没必要。
但是当变成:
text
115200 baud
几十米电缆
复杂工业现场
多个节点
以后,反射问题就可能非常明显。
所以:
"实验桌上能通信"不能证明终端设计一定合理。
十四、断电测A/B阻值为什么经常约60Ω?
如果总线两端分别有:
text
120Ω
120Ω
两颗电阻在A/B之间形成并联:
text
R = 120 || 120
计算:
text
R = 60Ω
因此:
断电以后,从总线上测A与B之间,如果两端终端都存在,常见值约为60Ω。
这是非常好用的排查方法。
十五、测到不同电阻说明什么?
约60Ω
通常说明:
text
两个120Ω终端都存在
约120Ω
通常可能是:
text
只有一个终端
或者:
text
另一端线路断开
明显小于60Ω
可能:
text
终端电阻太多
例如4个节点全部加120Ω:
text
120 || 120 || 120 || 120
≈ 30Ω
总线负载过重。
接近无穷大
可能:
text
没有终端
线路断路
连接器未接
很小,例如几Ω
重点检查:
text
A/B短路
收发器损坏
PCB焊接问题
十六、为什么每个节点都加120Ω是错误的?
例如4个节点:
text
Node1
Node2
Node3
Node4
每个节点都接:
text
120Ω
等效:
text
120 / 4
=
30Ω
收发器驱动负载变得非常重。
结果可能出现:
text
差分幅度下降
波形变差
功耗增加
通信不稳定
所以通常应该:
只在总线物理两端终接。
十七、第三个重点:A/B线有没有接反?
这是RS485现场调试最经典的问题之一。
正常情况下:
text
主机 A ───────── 从机 A
主机 B ───────── 从机 B
如果接成:
text
主机 A ───────── 从机 B
主机 B ───────── 从机 A
差分极性就反了。
于是从机可能看到:
text
所有bit逻辑反向
自然无法正确解析UART数据。
最终表现:
text
主机发送正常
↓
从机无有效报文
↓
从机不回复
↓
主机Timeout
十八、但A/B命名并不完全统一
这是RS485非常坑的一点。
不同芯片、模块和设备厂家的:
text
A
B
命名习惯可能存在差异。
有的设备可能标:
text
A+
B-
有的可能:
text
A-
B+
还有:
text
D+
D-
因此:
不能永远只凭"A接A、B接B"判断。
最好查看:
text
收发器Datasheet
设备说明书
原理图
接口电气定义
确认:
text
哪个端子对应正差分
哪个端子对应负差分
必要时直接交换A/B进行验证。
十九、A/B接反最典型的现象
可能表现为:
text
TX波形正常
DE控制正常
A/B上有明显波形
主机发送函数正常
但是永远收不到从机回复
这种情况下:
交换A/B是非常值得快速尝试的一步。
但正式产品必须根据文档确认,而不是长期依靠"试出来"。
二十、第四个重点:DE方向控制
RS485半双工最容易产生的软件Bug,几乎都和:
text
DE
有关。
正常发送过程应该是:
text
默认接收
DE = 0
↓
准备发送
DE = 1
↓
UART发送数据
↓
等待最后一个bit真正发送完成
↓
DE = 0
↓
切回接收
↓
等待从机回复
关键就在:
什么时候把DE拉低。
二十一、DE拉高太晚会发生什么?
如果已经开始UART发送:
text
TX起始位已经出现
但DE还没有拉高:
text
RS485发送器还没有打开
那么最前面的:
text
起始位
第一个字节部分bit
可能丢失。
从机收到的是一个残缺帧。
自然不会回复。
所以:
DE必须在UART真正开始发送以前提前进入发送状态。
二十二、DE拉低太早会发生什么?
这是最经典的问题。
例如程序:
c
RS485_TX_ENABLE();
HAL_UART_Transmit(
&huart1,
tx_buf,
tx_len,
100
);
RS485_RX_ENABLE();
乍看没有问题。
但如果所使用的:
text
发送函数
中断方式
DMA方式
底层驱动
在"发送完成通知"时最后一个字节还没有真正完全离开TX引脚,就可能:
text
DE提前拉低
导致:
text
最后一个停止位被截断
甚至:
text
最后一个字节部分丢失
从机CRC校验失败以后不会回复。
于是:
text
主机Timeout
二十三、UART的TXE和TC有什么区别?
这是RS485必须理解的知识点。
UART经常存在:
text
TXE
和:
text
TC
两个概念。
TXE
可以理解为:
text
Transmit Data Register Empty
发送数据寄存器空。
它只表示:
可以向发送数据寄存器继续放下一个字节。
但此时:
text
发送移位寄存器
可能仍然正在把数据一位一位送到TX引脚。
所以:
text
TXE = 1
不能简单等价于:
text
整个串口帧已经发送完成
TC
TC:
text
Transmission Complete
表示:
数据寄存器和移位发送过程均已完成,最后一个停止位已经发送完成。
所以半双工RS485切换DE时:
应该确认真正的发送完成状态,而不能只看到发送寄存器空。
二十四、典型的DE控制流程
可以概念上写成:
c
void RS485_Send(
uint8_t *data,
uint16_t len)
{
RS485_DE_HIGH();
HAL_UART_Transmit(
&huart1,
data,
len,
100);
while (__HAL_UART_GET_FLAG(
&huart1,
UART_FLAG_TC) == RESET)
{
}
RS485_DE_LOW();
}
这里重点不是代码本身,而是思想:
text
拉高DE
↓
发送
↓
确认最后一位真正发完
↓
拉低DE
↓
接收
具体HAL版本是否已经在阻塞API内部等待TC,应结合对应STM32 HAL实现确认。
二十五、DE一直保持高会怎么样?
另外一种常见错误:
text
发送完成以后忘了关闭DE
于是:
text
主机一直处于发送状态
主机虽然没有继续发送数据,但是RS485发送器仍然占据总线驱动状态。
当从机准备回复:
text
Slave准备发送
但主机发送器没有释放总线。
就可能出现:
text
总线冲突
从机无法正常驱动
数据畸变
主机收不到回复
最终依然是:
text
Timeout
所以:
半双工RS485的关键不是只会"打开发送",而是必须"及时释放总线"。
二十六、示波器应该同时看TX和DE
排查DE问题,非常推荐同时观察:
text
CH1 = UART_TX
CH2 = DE
正确波形应该类似:
text
DE
┌──────────────────┐
_______│ │________
↑ ↑
发送前 真正发送完
TX
|_|‾|__|‾‾|_|...
需要满足:
text
DE先有效
↓
TX开始
↓
TX最后停止位结束
↓
DE再释放
如果看到:
text
TX还没结束
DE就已经掉下去了
问题基本就定位了。
二十七、第五个重点:波特率必须一致
RS485只是物理层。
UART的数据格式仍然必须匹配。
例如主机:
text
115200
从机:
text
9600
显然无法通信。
常见波特率:
text
9600
19200
38400
57600
115200
双方必须一致。
二十八、不只是波特率,整个UART格式都必须一致
例如:
主机:
text
9600
8 data bits
No parity
1 stop bit
即:
text
9600 8N1
从机:
text
9600
8 data bits
Even parity
1 stop bit
即:
text
9600 8E1
虽然:
text
Baud Rate一样
但是:
text
Parity不同
从机仍然可能不断出现:
text
Parity Error
Frame Error
无法正确识别报文。
所以必须一起检查:
text
Baud Rate
Data Bits
Parity
Stop Bits
二十九、为什么有时候低波特率正常,高波特率就超时?
例如:
text
9600正常
115200失败
这往往说明问题可能已经偏向物理层。
需要重点检查:
text
线路长度
终端电阻
布线拓扑
支线长度
线缆类型
屏蔽
接地
收发器速度
波形反射
因为波特率越高:
text
Bit时间越短
系统对:
text
上升沿
下降沿
传播延迟
反射
越敏感。
三十、RS485适合什么拓扑?
典型RS485推荐:
text
总线型
结构:
text
120Ω ─ Node1 ─ Node2 ─ Node3 ─ Node4 ─ 120Ω
中间节点使用:
text
较短支线
连接到主干。
而不是:
text
Node2
│
│
Node1 ────── 中心 ───── Node3
│
│
Node4
复杂星形结构。
三十一、为什么星形布线容易出问题?
因为每一个分支都可能形成:
text
阻抗不连续点
信号到达分叉处:
text
一部分继续向前
一部分进入支线
一部分发生反射
最终可能产生:
text
振铃
过冲
多次反射
边沿畸变
在低速短距离场景可能没问题。
但在:
text
高速
长距离
节点多
情况下问题会越来越明显。
三十二、第六个重点:偏置电阻和总线空闲状态
RS485发送器都释放总线以后:
text
没有节点主动驱动A/B
如果系统没有:
text
Failsafe Bias
总线差分状态可能不确定。
噪声可能导致接收器输出:
text
随机跳变
形成:
text
伪字符
UART错误
假数据
因此一些系统会使用:
text
上拉
下拉
形成总线偏置。
例如:
text
A → 上拉
B → 下拉
或者根据所使用收发器和极性定义设计。
三十三、是不是一定需要外部偏置电阻?
不一定。
很多现代RS485收发器内部已经提供:
text
Fail-Safe Receiver
可以在:
text
开路
短路
总线空闲
情况下保持稳定输出。
所以:
是否需要额外偏置电阻,应查看具体收发器数据手册和系统拓扑。
不能看到RS485就机械增加一堆上拉下拉。
三十四、偏置和终端电阻不是一回事
一定要区分:
终端电阻
例如:
text
120Ω
主要用于:
text
阻抗匹配
减少反射
偏置电阻
主要用于:
text
总线空闲时建立确定差分状态
两者解决的是完全不同的问题。
不要把:
text
120Ω终端
误认为:
text
上下拉偏置
三十五、第七个重点:共地和共模范围
有人会说:
RS485是差分通信,所以不需要GND。
这句话不够准确。
RS485确实主要通过:
text
A-B差分电压
传递数据。
但RS485收发器仍然具有:
text
共模输入范围
如果两个设备之间地电位差太大:
text
设备A GND
≠
设备B GND
可能导致A/B相对于本地地的共模电压超出收发器允许范围。
于是:
text
通信异常
收发器损坏
都有可能。
三十六、实验室调试时建议怎么做?
如果不是隔离RS485:
text
短距离实验
同一电源系统
通常应该确认:
text
GND参考连接合理
如果:
text
距离很长
强干扰
不同供电区域
地电位差大
则更适合考虑:
text
隔离RS485
例如:
text
数字隔离器
+
隔离DC/DC
+
RS485收发器
或者使用集成隔离RS485器件。
三十七、第八个重点:从机地址错误
如果底层物理通信完全正常,但是:
text
主机一直超时
就要进入协议层检查。
例如Modbus RTU请求:
text
01 03 00 00 00 02 CRC
第一个:
text
01
就是从机地址。
如果实际从机地址是:
text
02
那么:
text
地址01的请求
对从机02来说:
text
不是发给我的
它通常直接忽略。
结果:
text
主机等待
↓
没有回复
↓
Timeout
物理层可以完全正常。
三十八、RS485并不知道设备地址
再次强调:
text
RS485本身没有地址
设备地址来自:
text
Modbus RTU
自定义协议
因此:
text
RS485线路通了
并不代表:
text
从机一定会回复
必须继续检查协议。
三十九、第九个重点:CRC错误
Modbus RTU中:
text
CRC16
非常重要。
典型帧:
text
01 03 00 00 00 02 C4 0B
如果CRC计算错误:
text
从机收到整帧
↓
计算CRC
↓
发现错误
↓
直接丢弃报文
很多设备不会回复:
text
CRC错误
而是直接保持沉默。
于是主机只能看到:
text
Timeout
所以:
Modbus超时并不代表从机没收到,很可能是从机收到了但判定报文非法。
四十、Modbus CRC最常见的问题
包括:
text
CRC算法错误
CRC初始值错误
高低字节顺序错误
少算一个字节
多算一个字节
发送Buffer长度错误
Modbus RTU CRC通常:
text
CRC Low Byte先发送
CRC High Byte后发送
这一点很容易搞反。
四十一、第十个重点:功能码不支持
例如发送:
text
功能码 0x03
表示读取保持寄存器。
如果从机:
text
根本不支持0x03
按Modbus标准可能返回异常响应。
但一些自定义或者实现不完整的设备也可能:
text
直接不回复
所以要确认从机协议手册。
四十二、寄存器地址也可能写错
例如文档写:
text
40001
程序就直接发送:
text
0x40001
这是典型错误。
Modbus文档中:
text
40001
30001
有时只是:
text
逻辑编号
实际协议PDU中可能使用:
text
零起始偏移
例如:
text
40001
对应协议地址可能是:
text
0x0000
具体必须按照设备手册判断。
寄存器地址错误也可能导致:
text
异常响应
或者
无响应
四十三、第十一个重点:从机回复时间
RS485主从通信通常不是:
text
主机最后一个bit发完
↓
从机零延时马上回复
从机可能需要:
text
解析报文
校验CRC
读取寄存器
处理业务
准备回复
切换DE
因此存在:
text
Response Time
如果主机设置:
text
Timeout = 1 ms
但从机需要:
text
5 ms
那么从机其实完全正常。
只是主机:
text
等得太短
所以:
超时参数必须根据真实协议响应时间设置。
四十四、但不能通过无限增大Timeout解决问题
这是调试中很常见的错误:
text
100ms超时
↓
改成500ms
还不行
↓
改成2秒
还不行
↓
改成10秒
如果根本原因是:
text
A/B接反
DE没关闭
波特率错误
CRC错误
再大的Timeout也没有意义。
所以应该:
text
先定位
↓
再调整合理Timeout
而不是用Timeout掩盖问题。
四十五、Modbus RTU还需要注意帧间隔
Modbus RTU 使用:
text
时间间隔
区分帧。
经典规则中会涉及:
text
3.5个字符时间
等概念。
所以如果自己实现Modbus RTU接收状态机,还需要处理:
text
帧间隔
字节间隔
接收超时
如果时间判断严重错误:
text
一帧被拆成两帧
或者:
text
两帧粘成一帧
都会导致CRC失败。
四十六、一个字符时间怎么算?
假设:
text
9600 baud
8N1
一帧UART字符:
text
1起始位
8数据位
1停止位
共:
text
10 bit
一个字符时间:
text
10 / 9600
≈ 1.0417 ms
3.5字符:
text
≈ 3.65 ms
如果还有:
text
校验位
字符总bit数还会变化。
因此实际协议时间需要根据UART格式计算。
四十七、UART RX溢出也会导致"看起来像超时"
例如:
text
从机已经回复
但是主机:
text
CPU长时间关中断
UART数据没及时读取
出现ORE
结果:
text
数据丢失
协议帧不完整
CRC失败
上层最后仍然可能报告:
text
Timeout
所以还要检查:
text
ORE
FE
NE
PE
等UART错误状态。
四十八、使用DMA接收RS485时还要注意什么?
DMA很适合RS485连续接收。
例如:
c
HAL_UARTEx_ReceiveToIdle_DMA(
&huart1,
rx_buffer,
sizeof(rx_buffer));
但是要正确处理:
text
IDLE
DMA长度
缓冲区
重新启动
帧边界
如果:
text
DMA接收到回复
但软件没有正确获取长度:
text
上层仍然认为没有数据
最终还是:
text
Timeout
所以调试时不能只看:
text
RS485物理总线
还要检查:
text
UART RX是否真正进入Buffer
四十九、如何判断故障到底在哪一层?
这是整篇文章最重要的方法。
可以把通信分成四个观察点:
text
① UART_TX
② RS485 A/B
③ 对端UART_RX
④ 对端回复A/B
如果:
UART_TX没有波形
问题在:
text
MCU/UART/软件
UART_TX有,A/B没有
问题在:
text
DE
收发器
硬件
A/B有,对端RX没有
问题在:
text
A/B极性
收发器
线路
终端
波特率
对端RX有,但没有回复
问题偏向:
text
地址
CRC
协议
从机程序
对端已经回复,但主机RX没有
问题偏向:
text
主机DE未释放
主机接收器
UART RX
DMA
线路方向
这种分层定位效率非常高。
五十、示波器如何排查RS485?
推荐观察:
text
CH1:UART TX
CH2:DE
CH3:A
CH4:B
最理想。
如果通道不足,可以先看:
text
TX + DE
再看:
text
A + B
五十一、看A/B波形时重点看什么?
不要只看:
text
有没有跳变
还应该看:
text
差分幅度
上升沿
下降沿
振铃
过冲
噪声
空闲状态
如果出现:
text
明显多次振荡
边沿很慢
差分幅度不足
就需要重点排查:
text
终端
线缆
拓扑
负载
五十二、逻辑分析仪应该接在哪里?
如果使用普通逻辑分析仪:
不建议直接把普通单端数字逻辑分析仪随意接在RS485 A/B上当UART分析。
更合理的是观察:
text
收发器DI
收发器RO
也就是:
text
MCU TX
MCU RX
这些已经是标准数字电平。
这样可以直接使用:
text
UART Decoder
解码。
五十三、USB-RS485工具有什么用?
USB-RS485非常适合:
text
隔离主机问题
隔离从机问题
抓取协议
验证设备
例如:
测从机
使用:
text
PC + USB-RS485
直接访问从机。
如果正常:
text
从机和线路大概率没问题
问题可能在自己MCU主机。
测自己的主机
可以让:
text
MCU主机
发送给PC上的USB-RS485。
检查:
text
数据是否正确
CRC是否正确
波特率是否正确
这种"分段替换法"非常高效。
五十四、推荐的RS485通信超时排查流程
实际现场可以按照下面顺序。
第1步:确认供电和共地
检查:
text
MCU供电
RS485收发器供电
从机供电
GND参考
第2步:查看UART TX
确认主机到底有没有发送。
第3步:查看DE
确认:
text
发送前开启
发送期间保持
发送完成后及时关闭
第4步:查看A/B
确认存在正常差分波形。
第5步:检查A/B极性
不要完全相信字母。
结合:
text
Datasheet
设备说明书
实测
判断。
第6步:断电测终端
测:
text
A ↔ B
两个120Ω终端时通常约:
text
60Ω
第7步:核对UART参数
检查:
text
波特率
数据位
停止位
校验位
第8步:检查总线拓扑
确认:
text
主干清晰
支线短
两端终接
第9步:确认从机有没有收到
观察:
text
从机RO/UART_RX
或者查看从机调试日志。
第10步:检查协议
例如Modbus:
text
Slave Address
Function Code
Register
Length
CRC16
第11步:确认从机有没有回复
查看从机:
text
TX
DE
A/B
第12步:确认主机有没有及时切回接收
如果从机已经回复:
text
主机仍然收不到
重点检查主机:
text
DE
/RE
UART_RX
DMA
RX Buffer
五十五、快速排查口诀
可以直接记成:
先看TX,再看DE;
再看A/B和终端;
然后查波特率;
最后查地址、CRC和协议。
再压缩:
text
发送
↓
方向
↓
线路
↓
参数
↓
协议
五十六、典型案例1:A/B接反
现象:
text
UART TX正常
A/B有波形
DE正常
从机完全不回复
处理:
text
确认设备A/B极性定义
交换两根差分线验证
交换后立即恢复。
根因:
text
差分极性错误
五十七、典型案例2:DE一直高
现象:
text
主机发送正常
从机日志显示收到请求
从机也调用了发送
但主机一直收不到回复
示波器看到:
text
主机DE一直=1
说明:
text
主机没有释放总线
解决:
text
最后一个UART停止位发完
↓
DE切换为接收
五十八、典型案例3:DE拉低太快
现象:
text
从机偶尔回复
短帧正常
长帧容易失败
CRC经常错误
示波器发现:
text
最后一个字节没发完
DE已经拉低
导致:
text
尾部数据被截断
解决:
text
等待真正TC
再切换方向。
五十九、典型案例4:终端太多
现场:
text
5个节点
每个设备都拨码启用了:
text
120Ω
结果总线等效阻抗过低。
表现:
text
短距离偶尔能用
节点增加后不稳定
高速时大量超时
差分电压异常
解决:
text
只保留总线物理两端终端
六十、典型案例5:9600正常,115200失败
重点检查:
text
线长
拓扑
支线
120Ω终端
线缆阻抗
收发器型号
波形边沿
这种情况通常比"协议代码错误"更像:
text
物理层信号完整性问题
六十一、典型案例6:从机确实收到,但不回复
此时不要继续查120Ω。
直接进入协议层。
检查:
text
地址正确吗?
功能码正确吗?
寄存器正确吗?
长度正确吗?
CRC正确吗?
例如Modbus CRC错误时:
text
从机收到
↓
CRC失败
↓
直接丢弃
↓
不回复
主机最终只看到:
text
Timeout
六十二、典型案例7:从机回复了,主机还是超时
示波器已经看到:
text
从机A/B上确实出现回复波形
那么问题已经基本锁定到主机接收路径:
text
A/B
↓
主机收发器
↓
RO
↓
UART_RX
↓
DMA/中断
↓
Buffer
↓
协议解析
重点检查:
text
主机DE是不是仍然高
/RE有没有开启
UART RX引脚是否正确
DMA是否启动
RXNE是否触发
ORE是否出现
六十三、RS485和Modbus RTU完整关系
可以把整个系统理解成:
text
Modbus RTU
│
│ 地址
│ 功能码
│ 数据
│ CRC
↓
UART
│
│ 波特率
│ 数据位
│ 校验位
│ 停止位
↓
RS485收发器
│
│ DE/RE
↓
A/B差分总线
│
│ 终端
│ 拓扑
│ 线缆
↓
对端
每一层都可能造成:
text
Timeout
所以不要把所有问题都称为:
text
Modbus通信不通
最好明确是哪一层。
六十四、STM32简单RS485发送框架
例如:
c
#define RS485_TX_ENABLE() \
HAL_GPIO_WritePin(
RS485_DE_GPIO_Port,
RS485_DE_Pin,
GPIO_PIN_SET)
#define RS485_RX_ENABLE() \
HAL_GPIO_WritePin(
RS485_DE_GPIO_Port,
RS485_DE_Pin,
GPIO_PIN_RESET)
发送:
c
HAL_StatusTypeDef RS485_Send(
uint8_t *data,
uint16_t length)
{
HAL_StatusTypeDef ret;
RS485_TX_ENABLE();
ret = HAL_UART_Transmit(
&huart1,
data,
length,
100);
if (ret != HAL_OK)
{
RS485_RX_ENABLE();
return ret;
}
while (__HAL_UART_GET_FLAG(
&huart1,
UART_FLAG_TC) == RESET)
{
}
RS485_RX_ENABLE();
return HAL_OK;
}
核心逻辑:
text
DE发送
↓
UART发送
↓
等待TC
↓
DE接收
六十五、如果使用UART中断发送怎么办?
不能:
text
启动IT发送
↓
立即DE拉低
因为:
text
HAL_UART_Transmit_IT()
通常是非阻塞的。
函数返回以后:
text
实际发送还在继续
所以应该在真正的:
text
发送完成事件
以后再切回接收。
六十六、如果使用DMA发送怎么办?
同理:
text
HAL_UART_Transmit_DMA()
只是:
text
启动DMA发送
并不是函数返回时已经把整帧全部从TX物理引脚发完。
需要根据:
text
具体HAL实现
UART TC状态
发送完成回调
确认真正的物理发送完成时刻,再切换DE。
设计原则永远是:
DMA搬完数据,不等于最后一个UART停止位一定已经离开引脚。
六十七、为什么RS485故障最好不要一开始就改协议代码?
因为如果:
text
A/B接反
你修改CRC没有意义。
如果:
text
DE一直高
你修改从机地址没有意义。
如果:
text
收发器没供电
你把Timeout从100ms改成10秒仍然没意义。
所以一定按照层级:
text
物理层
↓
UART
↓
方向控制
↓
数据内容
↓
协议
逐层确认。
六十八、RS485通信超时快速对照表
| 现象 | 优先怀疑 |
|---|---|
| UART TX无数据 | UART初始化/程序 |
| TX有,A/B无波形 | DE/收发器 |
| A/B有,从机完全收不到 | A/B、参数、物理层 |
| 从机收到但不回复 | 地址/CRC/协议 |
| 从机已回复但主机收不到 | DE/RE/RX |
| 短距离正常,长距离失败 | 终端/线缆/拓扑 |
| 9600正常,115200失败 | 信号完整性 |
| 偶发CRC错误 | 反射/干扰/方向切换 |
| 最后一个字节异常 | DE切换过早 |
| 主机发送后一直超时 | DE未切回接收 |
| 增加节点以后失败 | 终端过多/拓扑 |
| 刚上电有乱码 | Bias/Failsafe |
| Modbus无回复 | 地址/功能码/CRC/寄存器 |
六十九、面试:RS485通信超时怎么排查?
如果面试官问:
RS485通信一直超时,你会怎么排查?
可以这样回答:
首先要把超时拆成发送和接收两个方向。
我会先使用示波器确认 MCU UART TX 是否有数据,如果TX有数据,再检查RS485收发器的DE控制以及A/B是否存在正常差分波形。
然后检查A/B极性、总线终端电阻和拓扑。典型RS485总线通常在物理两端分别配置120Ω终端,断电测A/B之间通常约为60Ω。
如果物理层正常,再检查主从双方UART参数,包括波特率、数据位、停止位和校验位。
半双工RS485还需要特别确认DE方向切换,发送前开启驱动,最后一个停止位真正发送完成以后才能释放DE并切回接收,否则可能截断最后一个字节或者导致主机持续占用总线。
如果这些都正常,再进入Modbus等协议层检查设备地址、功能码、寄存器地址、数据长度以及CRC。
最后通过示波器、逻辑分析仪或者USB-RS485工具确认从机是否真正收到请求以及是否已经发送回复,这样可以逐层确定故障位置。
七十、最终总结
RS485通信超时不是一个具体故障,而是:
某个通信环节失败以后,上层等待不到预期回复产生的最终结果。
整个链路:
text
主机程序
↓
UART
↓
DE
↓
RS485收发器
↓
A/B
↓
终端和线缆
↓
从机收发器
↓
从机UART
↓
协议处理
↓
从机回复
↓
主机接收
任何一层异常:
text
最终都可能Timeout
因此遇到RS485通信超时,可以按照下面顺序:
text
① 看UART TX有没有发送
② 看DE有没有正确切换
③ 看A/B有没有差分波形
④ 查A/B极性
⑤ 断电测终端电阻
⑥ 查波特率、数据位、校验位和停止位
⑦ 查总线拓扑和线缆
⑧ 确认从机是否收到请求
⑨ 查设备地址、功能码和CRC
⑩ 确认从机是否回复
⑪ 确认主机是否及时切回接收
⑫ 查UART RX、DMA和接收缓冲区
其中最容易踩的三个坑是:
text
A/B接反
DE切换时间错误
120Ω终端电阻配置错误
最后用一句话总结:
RS485通信超时时,不要第一时间修改Timeout和协议代码。先确认数据有没有真正从UART进入A/B总线,再检查终端、A/B极性和DE方向控制,最后才进入波特率、CRC、设备地址和Modbus协议层排查。