RS-485 电气特性
RS-485(TIA/EIA-485)是平衡差分传输标准,使用 A(非反相)和 B(反相)两根信号线传输数据。差分信号通过电压差表示逻辑状态,抗共模干扰能力强。
逻辑电平定义:
- 逻辑 1:A 比 B 高 200mV 以上(VA - VB > +200mV)
- 逻辑 0:B 比 A 高 200mV 以上(VB - VA > +200mV)
- 不确定区:|VA - VB| < 200mV
共模电压范围:-7V 至 +12V。收发器必须在此范围内正常工作,超出范围可能导致器件损坏或通讯失败。
MAX485 收发器原理
MAX485 是半双工 RS-485 收发器,典型电路包含 RO(Receiver Output)、DI(Driver Input)、DE(Driver Enable)、RE(Receiver Enable)、A、B 六个引脚。
MCU MAX485 RS-485总线
+-----+ +---------+ +-------+
| TX | ---> | DI | | |
| | | | | |
| RX | <--- | RO | | |
| | | | | |
| GPIO| ---> | DE | ---> | A |---+
| | | | | | |
| GPIO| ---> | RE | | B |---+
+-----+ +---------+ +-------+
DE(Driver Enable)和 RE(Receiver Enable)控制收发方向:
- DE = 1、RE = 0:发送模式,DI 数据驱动到 A/B 线
- DE = 0、RE = 1:接收模式,A/B 线数据从 RO 输出
通常将 DE 和 RE 连接在一起,由 MCU 单个 GPIO 控制。高电平发送,低电平接收。
STM32 控制 MAX485 的代码示例:
#include "stm32f1xx_hal.h"
#define RS485_DE_RE_PIN GPIO_PIN_1
#define RS485_DE_RE_PORT GPIOA
void RS485_Set_Mode_TX(void) {
HAL_GPIO_WritePin(RS485_DE_RE_PORT, RS485_DE_RE_PIN, GPIO_PIN_SET);
HAL_Delay(1); // 等待收发器切换
}
void RS485_Set_Mode_RX(void) {
HAL_GPIO_WritePin(RS485_DE_RE_PORT, RS485_DE_RE_PIN, GPIO_PIN_RESET);
HAL_Delay(1); // 等待收发器切换
}
// 发送数据
void RS485_Send_Data(uint8_t *data, uint16_t len) {
RS485_Set_Mode_TX();
HAL_UART_Transmit(&huart1, data, len, 1000);
RS485_Set_Mode_RX();
}
终端电阻
RS-485 总线特性阻抗约为 120Ω,传输线末端需并联 120Ω 终端电阻以消除信号反射。反射会导致波形畸变、误码率上升。
终端电阻安装位置:
- 总线两端各接一个 120Ω 电阻(A-B 之间)
- 短距离(<10米)可省略
- 长距离(>100米)必须安装
典型总线拓扑:
主机 节点1 节点2 节点3 节点4
| | | | |
+---+---+---+---+---+---+---+---+
| |
120Ω 120Ω
终端电阻计算:
// 终端电阻功耗计算
#define RS485_TERMINAL_RESISTANCE 120.0f
#define RS485_DRIVER_VOLTAGE 5.0f
float terminal_power = (RS485_DRIVER_VOLTAGE * RS485_DRIVER_VOLTAGE) /
RS485_TERMINAL_RESISTANCE;
// 结果约 0.208W,选用 1/4W 或 1/2W 电阻
空闲态偏置电阻
RS-485 总线空闲时,所有节点处于接收模式,总线处于高阻态。此时 A/B 线电压差可能小于 200mV,导致接收器输出不确定状态,引发误判。
偏置电阻解决此问题:在 A 线接上拉电阻到 VCC,B 线接下拉电阻到 GND,确保空闲时 A > B。
偏置电阻计算:
// 假设总线上有 N 个节点,每个节点输入阻抗 12kΩ(标准值)
#define NODE_COUNT 10
#define NODE_INPUT_IMPEDANCE 12000.0f
#define VCC 5.0f
#define TARGET_IDLE_DIFF 0.3f // 目标空闲差分电压 300mV
// 总输入阻抗
float total_input_impedance = NODE_INPUT_IMPEDANCE / NODE_COUNT; // 1200Ω
// 偏置电阻选择(经验值)
#define BIAS_RESISTANCE_UP 560.0f // A 线上拉
#define BIAS_RESISTANCE_DOWN 560.0f // B 线下拉
// 验证空闲差分电压
float va_idle = VCC * (total_input_impedance / (BIAS_RESISTANCE_UP + total_input_impedance));
float vb_idle = VCC * (total_input_impedance / (BIAS_RESISTANCE_DOWN + total_input_impedance));
float diff_idle = va_idle - vb_idle; // 应大于 200mV
常用偏置电阻组合:
- 560Ω / 560Ω:适用于 10-20 个节点
- 1kΩ / 1kΩ:适用于 5-10 个节点
- 2.2kΩ / 2.2kΩ:适用于 <5 个节点
偏置电阻仅在总线一端安装,通常在主机侧。
多节点负载能力
RS-485 标准定义单位负载(Unit Load)为 12kΩ 输入阻抗。标准收发器为 1 单位负载,最多支持 32 个节点(32 × 12kΩ = 375Ω ≥ 最小负载阻抗)。
低功耗收发器(1/4 单位负载、1/8 单位负载)可扩展节点数:
- 1/4 单位负载(48kΩ):最多 128 个节点
- 1/8 单位负载(96kΩ):最多 256 个节点
节点数计算:
#define UNIT_LOAD_IMPEDANCE 12000.0f
#define MIN_BUS_IMPEDANCE 375.0f
// 标准收发器最大节点数
uint16_t max_nodes_standard = UNIT_LOAD_IMPEDANCE / MIN_BUS_IMPEDANCE; // 32
// 1/4 单位负载收发器最大节点数
uint16_t max_nodes_quarter = (UNIT_LOAD_IMPEDANCE * 4) / MIN_BUS_IMPEDANCE; // 128
实际应用中建议预留 20% 余量,32 节点总线建议挂载不超过 25 个节点。
布线长度与波特率关系
RS-485 通讯距离受波特率限制,波特率越高,允许距离越短。理论关系:
最大距离(m) = 100000 / 波特率(bps)
实际应用参考:
| 波特率 | 最大距离 | 推荐距离 |
|---|---|---|
| 9600 | 1200m | 1000m |
| 19200 | 600m | 500m |
| 38400 | 300m | 250m |
| 57600 | 200m | 150m |
| 115200 | 100m | 80m |
长距离通讯需注意:
- 使用屏蔽双绞线(推荐 22AWG 或 24AWG)
- 屏蔽层单端接地(通常在主机侧)
- 避免与强电线路平行布线
- 总线拓扑为菊花链,避免星形连接
常见故障排查
波形畸变
现象:示波器观察 A/B 线波形,上升/下降沿缓慢、有过冲或振铃。
原因:
- 终端电阻未安装或阻值错误
- 总线过长,特征阻抗不匹配
- 分布电容过大(线缆过长、节点过多)
解决:
- 检查并安装 120Ω 终端电阻
- 缩短总线长度或降低波特率
- 减少节点数或使用低电容收发器
通讯丢包
现象:主站轮询从站,偶尔无响应或 CRC 错误。
原因:
- 总线空闲态偏置电阻缺失
- 接地不良,共模干扰
- 波特率不匹配
- 终端电阻功率不足,发热导致阻值变化
排查步骤:
// 1. 检查空闲态电压差
float measure_voltage_diff(void) {
float va = ADC_Read_Channel(A_CHANNEL);
float vb = ADC_Read_Channel(B_CHANNEL);
return va - vb; // 应大于 200mV
}
// 2. 检查终端电阻
float check_termination_resistance(void) {
// 断电状态下测量 A-B 之间电阻
return Measure_Resistance(A_PIN, B_PIN); // 应接近 120Ω
}
// 3. 验证波特率
void verify_baudrate(void) {
// 使用示波器测量位宽
// 位宽(μs) = 1000000 / 波特率
// 19200 波特率位宽应为 52.08μs
}
共地干扰
现象:通讯正常但偶尔出现大量错误码,设备地之间存在电位差。
原因:不同设备地电位不等,形成地环路电流。
解决:
- 使用光电隔离(光耦或数字隔离芯片)
- 屏蔽层单端接地
- 共模扼流圈抑制共模噪声
DE/RE 切换时序问题
现象:发送数据后立即切换到接收模式,导致最后一个字节丢失。
原因:收发器切换时间约 1-2μs,切换过快导致数据未完全输出。
解决:
void RS485_Send_Data_Fixed(uint8_t *data, uint16_t len) {
RS485_Set_Mode_TX();
HAL_UART_Transmit(&huart1, data, len, 1000);
// 等待最后一个字节完全发送(根据波特率计算)
uint32_t bit_time_us = 1000000 / 19200; // 19200 波特率
HAL_Delay((bit_time_us * 10) / 1000 + 2); // 10 位 + 余量
RS485_Set_Mode_RX();
}
完整电路设计
基于 STM32F103 和 MAX485 的完整电路:
3.3V
|
10k
|
PA1 ---+--- DE/RE
|
10k
|
GND
PA9 --- DI
PA10 --- RO
5V --- VCC
GND --- GND
GND --- A --- 120Ω --- B
|
560Ω --- 5V
|
560Ω --- GND
PCB 布局注意事项:
- A/B 线平行布线,等长等距
- 终端电阻靠近连接器
- 去耦电容(0.1μF)靠近 VCC 引脚
- 避免高速信号线穿过 RS-485 区域
总结
RS-485 总线设计关键点:
- 长距离必须安装 120Ω 终端电阻
- 空闲态需偏置电阻确保确定状态
- 节点数受单位负载限制,超节点数需用低功耗收发器
- 波特率与通讯距离成反比
- 布线采用菊花链拓扑,屏蔽层单端接地
- DE/RE 切换需留足够时序余量
按上述规范设计,可构建稳定可靠的 RS-485 通讯网络。
