参考:
https://www.ti.com.cn/cn/lit/an/zhcaa89d/zhcaa89d.pdf?ts=1755140419109
https://www.analog.com/cn/resources/app-notes/an-960.html

RS485

RS485、TTL与串口协议的关系

许多初学者容易混淆这几者,实际上它们分属通信协议栈的不同层级:

TTL: 是一种电平标准,通常指 0V 和 5V(或 3.3V)的单端信号,这是许多MCU内部UART模块直接输出的电平

RS485: 这是一种物理层标准,定义了差分信号的电气特性。它与TTL最大的区别在于,RS485采用差分信号,而TTL是单端信号

串口协议:是一种数据链路层协议,它定义了数据帧的格式,包括起始位、数据位、校验位和停止位。

简单来说,TTL/RS485 决定了“信号的形态”,而串口协议决定了“信号的内容”。通常,我们会使用 RS485收发器(常见如MAX485等)作为电平转换芯片,将MCU的TTL电平信号转换为RS485的差分信号,以便在总线上进行数据传输

什么是总线?什么是差分?为什么要差分传输?

几个核心概念:

总线(Bus): 总线可以理解为一种公共的通信通道,在总线型网络中,所有设备都共享同一条物理线路。这种架构非常适合多点通信,即一个设备可以在一条线路上与多个设备进行通信

差分信号: 差分信号是一种通过两根线之间的电压差来传输信息的信号。这两根线通常被称为A和B(或H和L)

与此相对的是单端信号,它只使用一根信号线和地线间的电压差来传输信息

为什么要差分传输? 差分信号最大的优点在于其强大的抗干扰能力。在环境中,电磁噪声会同时叠加到A和B两根线上。由于噪声是共模的,接收器只关心A和B之间的电压差,因此这些共模噪声会被有效抵消。这使得差分信号能够在长距离和高噪声环境下实现可靠通信。

RS485中的差分信号

485利用了差分信号的优势,将数据以差分电压的形式进行传输

发送端:RS485收发器根据MCU发出的TTL信号,产生相应的差分电压。例如,当TTL为高电平时,它会让A线的电压高于B线;当TTL为低电平时,它会让B线的电压高于A线

接收端:接收器持续监测A和B两线的电压差。只要电压差超过一个设定的阈值(例如±200mV),它就能判断出是逻辑“1”还是“0”,并将其转换回MCU可以理解的TTL电平

由于差分信号能有效抵御干扰,485总线能够支持长达1200米的通信距离,并且允许多达32个(在某些新规范下更多)设备挂载到同一总线上

RS485、CAN与以太网:物理层与协议层的类比

为了更好地理解485这种分层思想,我们可以将它扩展到其他常见的通信协议中,如CAN和以太网

  • RS485
    • 物理层: 485差分信号
    • 数据链路层: 未定义
  • CAN
    • 物理层: CAN_H和 CAN_L差分信号。与RS485 类似,它也是通过两根线之间的电压差来传递信号。
    • 协议层: 已定义。CAN 不仅仅是一个物理标准,它是一个完整的协议,定义了独特的数据帧格式,包括仲裁段、数据段、CRC 校验等
  • 以太网:
    • 物理层: 这层定义了信号的电气或光学特性,例如 100Base-TX(双绞线,差分信号)和 100Base-FX(光纤,光信号)
    • 数据链路层: 这层定义了MAC帧格式,包括源MAC地址和目的MAC地址。这层还负责访问控制,决定哪个设备可以在什么时候使用物理介质

收发器

485收发器是一种专用芯片,它的核心功能是作为MCU和RS485总线之间的电平转换器和驱动器

电平转换: MCU的UART接口输出的是TTL 电平(例如 0V 和 3.3V/5V),而 485总线需要的是差分信号。收发器就负责将单端TTL信号“翻译”成差分信号,反之亦然

总线驱动: 收发器内部包含强大的驱动器,能够输出足够的电流和电压来驱动总线,确保信号在传输过程中保持其完整性

一个收发器芯片的引脚示意

一个典型的485 收发器会有四对主要引脚,用于和单片机以及总线进行连接

  • 与 MCU 连接:

    • DI (Driver Input): 输入引脚,将单片机的TXD引脚连接到这里,当单片机要发送数据时,它会通过 TXD向DI输入TTL 电平信号
    • RO (Receiver Output): 输出引脚,将单片机的RXD引脚连接到这里。收发器从总线上接收到差分信号后,会将其转换成TTL电平,并通过RO输出给单片机的RXD
  • 与 RS485 总线连接:

    • A/B: RS485 差分总线引脚,这两个引脚直接连接到RS485的通信总线上,收发器通过A和B之间的电压差进行数据的发送和接收

DIR控制引脚

DIR控制引脚是485收发器的核心,尤其是在半双工(Half-Duplex)模式下

半双工意味着总线在同一时间只能发送或接收数据,不能同时进行。为了避免多个设备同时向总线发送数据造成冲突,每个收发器都必须能够被使能(Enable)或禁用(Disable),这就是DIR引脚的作用

  • 当DIR为高电平(逻辑1)时:
    收发器的发送器被使能。它会根据DI引脚上的TTL信号,将数据发送到A/B总线上
    同时,接收器通常会被禁用,或者在某些芯片中,其输出会处于高阻态,避免自己的发送信号“回环”到单片机的RXD引脚

  • 当DIR为低电平(逻辑0)时:
    收发器的发送器被禁用,进入高阻态,从而释放对总线的控制权
    接收器被使能,开始监听A/B总线上的差分信号,并将接收到的数据通过RO引脚输出给单片机。

  • 如何控制 DIR 引脚?
    通常,DIR引脚由单片机的一个GPIO引脚控制。需要严格控制这个GPIO引脚的电平,以实现正确的收发时序:
    发送前: 将DIR引脚拉高
    发送数据: 单片机通过TXD发送数据
    发送完成: 等待最后一个数据位发送完毕后,将 DIR 引脚拉低,禁用发送器,并使能接收器,从而可以开始接收其他设备发来的数据

以stm32 HAL库为例

#define RS485_DIR_GPIO_Port  GPIOB
#define RS485_DIR_Pin        GPIO_PIN_0

// 宏定义用于控制DIR引脚
#define RS485_DIR_TX()    HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_SET)
#define RS485_DIR_RX()    HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_RESET)

/**
  * @brief  使用UART发送数据到RS485总线
  * @param  pData: 要发送的数据指针
  * @param  size: 数据大小,单位字节
  * @param  timeout: 发送超时时间,单位ms
  */
int uartSendData(uint8_t *pData, uint16_t size, uint32_t timeout)
{
    // 1. 发送前:将 DIR 引脚拉高
    RS485_DIR_TX();

    // 2. 发送数据:调用HAL库的阻塞式发送函数,这个函数会等待所有数据发送完成
    if(0 != HAL_UART_Transmit(huart, pData, size, timeout))
    {
    	return -1;
    }
	
    // 等待发送移位寄存器清空(即最后一个字节完全发出)
    while (HAL_UART_GetState(huart) != HAL_UART_STATE_READY);

    // 将 DIR 引脚拉低,禁用发送器,并使能接收器
    RS485_DIR_RX();
     
    return 0;
}

以stm32 LL 库为例

#define RS485_DIR_GPIO_Port  GPIOB
#define RS485_DIR_Pin        GPIO_PIN_0

// 宏定义用于控制DIR引脚
#define RS485_DIR_TX()    HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_SET)
#define RS485_DIR_RX()    HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_RESET)

/**
  * @brief  使用UART发送数据到RS485总线
  * @param  pData: 要发送的数据指针
  * @param  size: 数据大小,单位字节
  */
void uartSendData(uint8_t *pData, uint16_t size)
{
    RS485_DIR_TX();
    
    // 逐字节发送数据
    for (uint16_t i = 0; i < Size; i++)
    {
        // 阻塞式等待发送数据寄存器为空
        while (!LL_USART_IsActiveFlag_TXE(USARTx));
        
        // 发送一个字节
        LL_USART_TransmitData8(USARTx, pData[i]);
    }
    
    // 发送完成:等待最后一个数据位发送完毕
    //    这里等待发送完成标志位TC (Transmission Complete)
    //    确保最后一个字节已完全移出发送移位寄存器
    while (!LL_USART_IsActiveFlag_TC(USARTx));
    
    // 将 DIR 引脚拉低,禁用发送器,并使能接收器
    RS485_DIR_RX();
}

全双工RS485:四线双向通信

常见的RS485为半双工,如图所示

在这里插入图片描述
半双工RS485 使用一根差分信号线(即两根导线,A/B)。所有设备的驱动器和接收器都连接到这同一条总线上

半双工的本质是分时共享。由于总线上只有一个物理信道,所有设备必须轮流使用

发送数据: 当一个设备需要发送数据时,它的 RS485 收发器会通过DIR(或 DE)使能引脚切换到发送模式。此时,它会驱动总线,输出差分信号

接收数据: 在其他时间,所有其他设备(包括发送方自己)的收发器都必须切换到接收模式,监听总线上的信号

双向传输,但不同时: 数据可以在任意两个设备之间双向传输,但一次只能在一个方向上进行

全双工如图所示
在这里插入图片描述

全双工RS485使用两对独立的差分信号线(即四根导线)。这两对线通常被称为发送总线和接收总线

全双工的本质是并行通信。它通过使用独立的物理信道,实现了发送和接收的同步进行

发送数据: 一个设备的TX永久性地连接到发送总线上。当它需要发送数据时,它直接驱动这条总线

接收数据: 另一个设备的接收器RX永久性地连接到另一条接收总线上。它持续监听这条总线,接收数据

发送和接收各有专用通道,互不干扰。这使得主从设备可以同时进行通信

主从配置: 全双工通常采用主/从配置。主设备有一条专用的发送总线,从设备有一条专用的发送总线。通常,主设备的发送总线连接到所有从设备的接收端,而所有从设备的发送总线则连接到主设备的接收端

无需使能引脚(或简化): 在严格的主/从全双工配置中,由于发送和接收通道是分开的,驱动器使能引脚(DIR)不再是必需的,或者其控制逻辑被大大简化,主设备的发送器始终处于使能状态,从设备的接收器也始终处于使能状态

在这里插入图片描述

线缆类型

双绞线是一种常见的通信电缆类型,顾名思义,它由一对或多对相互缠绕在一起的绝缘导线组成。这种缠绕并非随意,而是为了一个关键目的:抵消电磁干扰

在这里插入图片描述

当电信号流经导线时,会产生电磁场,外部的电磁干扰源也会在导线上感应出电流。通过将两根导线紧密地缠绕在一起,任何外部噪声都会以几乎相同的强度和方向同时作用于这两根导线上,形成共模干扰

485使用差分信号传输数据,这意味着接收器只关心两根线之间的电压差,在双绞线中,485的A和B两根信号线被紧密缠绕。当外部噪声耦合到电缆上时,它会以共模方式均匀地作用于A 和 B 两根线上

终端电阻

在485总线的两端,通常会连接一个120Ω的电阻,这被称为终端电阻(Termination Resistor)。作用是减少信号反射

  • 为什么需要终端电阻?

当一个电信号在传输线上前进,到达总线的末端时,如果总线突然“断开”,信号的能量会因为阻抗不匹配而反射回来

信号反射:电信号在总线末端会产生反射,这些反射信号会沿着总线原路返回,与即将到来的新信号叠加在一起。这会扭曲波形,产生毛刺和抖动,导致接收器无法正确识别逻辑电平,从而引发通信错误。这个问题在高速和长距离通信中尤为突出

终端电阻的作用就是匹配总线的特性阻抗,从而吸收信号的能量,防止反射

特性阻抗: 每一种电缆都有其固有的特性阻抗,它是由电缆的物理结构决定的。工业RS485标准电缆的特性阻抗就是120Ω

能量吸收:在总线的两端串联一个120Ω的电阻,就相当于为信号提供了一个阻抗匹配的“出口”。当信号到达总线末端时,其能量会被这个电阻消耗掉,从而有效消除反射
在这里插入图片描述
在噪声环境下的应用通常将120Ω 电阻替换为两个60Ω电阻,组成一个低通滤波器,用于提供额外的共模噪声滤除能力(右半部分)

宜使用精度为1%的电阻,确保两个滤波器的频率降幅相等,较大的电阻容限(即20%)会导致滤波器转折频率不同,并且共模噪声会转换为差分噪声,从而使接收器的抗扰性降低

总线从空闲态到激活态,第一位数据易被破坏

在半双工485总线通信中,有一个常被忽视但又极具工程价值的现象:数据帧的第一位(更准确说是起始位及其的首个数据位)最容易出错

  • 空闲态与激活态

在 RS-485 总线空闲时,没有设备驱动,总线处于高阻态,差分电压接近零,通常会通过偏置电阻将空闲态维持在一个微弱的正差分电压,对应逻辑“1”

当某个节点准备发送时,驱动器使能(DE 拉高),差分驱动器开始工作,发送起始位(逻辑“0”)

起始位恰好出现在总线从弱驱动 → 强驱动的瞬间,物理层的过渡还没完全稳定,链路层就已经开始

  • 为什么第一位更容易出错

RS-485收发器在DE拉高后,需要一定时间才能稳定输出,如果MCU在DE刚拉高就立刻发送起始位,可能导致起始沿被“台阶化”或拖尾

总线存在寄生电容、电感,首次强驱动会触发瞬态振铃、反射,导致首个下降沿畸变,采样点可能落在错误的电平区间

为什么帧头爱用0x55与0xAA

在串口、RS485等异步通信中,0x55和0xAA是两个高频出现的字节

  • 二进制与波形特征

    • 0x55 → 01010101

    • 0xAA → 10101010

在UART发送时,这两个字节会产生占空比接近50%的交替波形,这种波形在示波器上表现为规则的方波,每个比特都有一次跳变

对于物理层调试而言,方波是最容易观察和诊断的信号之一,因为任何失真、抖动或毛刺都会被放大、显现

  • 易于诊断

50%占空比方波的频谱特性非常均衡,可以让我们快速观察到过冲、振铃、抖动等硬件问题

在示波器上,波形应当规律且对称;一旦某位畸变,肉眼即可察觉

  • 方便验证波特率

方波周期固定,通过测量其频率即可反推出比特时间,验证波特率设置,例如:波特率为9600bps,串口设置为8N1时,方波频率应约4.8kHz,周期约208.33μs

在485通信中的实际应用

由于帧头的脆弱性,以及0x55/0xAA 在时序验证上的优势,许多通信协议在发送真正的数据帧之前,会先发送一串特殊的字节序列来进行“热身”

无论哪一方(主设备或从设备),在发送数据之前,通常会先连续发送4个0xAA或0x55字节,接收方在接收到至少一个这样的字节后,才认为数据流是正常的

  • 典型做法:

发送方在DE置高后,不直接发数据,而是先发N个(如4个)0x55或0xAA

接收方只要捕获到至少一个这样的字节,就进入同步状态,准备接收真正的数据帧

常见问题

1. 基础与物理层

Q:RS485与TTL信号有什么区别?
A: TTL是单端电平(0/3.3V或0/5V),RS485是差分电平(A/B线电压差),差分可抗干扰、长距离传输

Q:差分信号为什么抗干扰?
A: 外界噪声叠加在两根线同样方向(共模),接收器只关心A-B电压差,共模噪声被抵消

Q:终端电阻120Ω的作用?
A: 匹配总线特性阻抗,减少信号反射

Q:总线空闲态电平与起始位为什么会出错?
A: 半双工从高阻→驱动瞬态,DE刚拉高时输出不稳定,首位容易畸变

2. 收发器与半/全双工

Q:DIR/DE引脚如何控制?
A: 高电平→发送,低电平→接收;发送前拉高、发送完成后拉低

Q:半双工多节点如何避免冲突?
A: 使用主从轮询协议或总线仲裁机制。

Q:全双工与半双工的区别?
A: 半双工:两线共用,分时通信;全双工:四线分开,可同时收发

3. 软件层与UART协议

Q:为什么帧头常用0x55/0xAA?
A: 01010101 / 10101010,占空比50%,便于波形同步和调试

Q:波特率过高+长线通信怎么保证可靠?
A: 软件增加超时重发、FIFO/DMA缓冲,硬件用终端电阻和优质双绞线

Q:DMA发送完成标志与TC标志有什么区别?
A: DMA完成不保证最后一位已发出,TC表示发送移位寄存器空,DE过早拉低导致末字节丢失

Q:CRC校验如何在噪声环境保证?
A: 软件校验+重发机制。长线/高噪声环境可增加重发计数与间隔

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐