一、核心原理

RDK 输出3.3V TTL 电平 UART(TX/RX)无硬件差分 485 控制器; RS485 总线是差分半双工总线(A/B 两根差分线),必须通过TTL 转 RS485 电平转换芯片做两层转换:

  1. 发送:RDK 单端 TTL TX → 芯片转为差分 A/B 信号输出到总线
  2. 接收:总线差分 A/B → 芯片转为单端 TTL RX 送入 RDK 常用转换芯片:MAX3485、SP3485(3.3V 供电,完美匹配 RDK IO 电平,不用分压)

二、完整硬件接线(以常用 /dev/ttyS1 为例)

RDK 40PIN 物理引脚(BOARD 编号):

  1. UART_TX:PIN8 → MAX3485 DI
  2. UART_RX:PIN10 → MAX3485 RO
  3. 收发控制 GPIO(任意空闲 IO,示例 PIN16)→ MAX3485 DE+/RE 短接点
  4. 3.3V 电源 PIN1 → 模块 VCC
  5. GND PIN6 → 模块 GND 外部总线:模块 A 接外设 485 A,模块 B 接外设 485 B

前置配置:启用 UART1

UART1 默认复用蓝牙,需关闭复用才能使用:

bash

运行

srpi-config
3 Interface Options → P8 Serial Port Hardware
关闭蓝牙占用UART1,保存后重启
sudo reboot

三、时序逻辑(半双工核心,决定通信是否丢包)

RS485 同一时刻只能发 / 收一种状态,切换时序规则:

  1. 发送前:GPIO 拉高,延时≥100us,等待芯片驱动电路稳定
  2. 写入串口数据,强制刷新缓冲区,确保所有字节送入移位寄存器
  3. 根据波特率计算传输耗时,等待整帧数据完全发送完毕
  4. GPIO 拉低,切回接收模式,释放总线供其他设备应答(只有发送完成后才能重新转入接收状态,才能拉低GPIO,否则容易出现丢包)

四、Python 完整通信代码(Hobot.GPIO + pyserial)

依赖安装

bash

运行

pip3 install pyserial
# 赋予串口、GPIO权限
sudo usermod -aG dialout,gpio $USER

python

运行

#!/usr/bin/env python3
import serial
import Hobot.GPIO as GPIO
import time
import signal
配置参数
UART_PORT = "/dev/ttyS1"
BAUDRATE = 9600
485收发切换GPIO BOARD引脚
DIR_PIN = 16
Ctrl+C退出处理,释放GPIO
def exit_handler(sig, frame):
GPIO.output(DIR_PIN, GPIO.LOW)
GPIO.cleanup()
exit(0)
signal.signal(signal.SIGINT, exit_handler)
class TTL2RS485:
def init(self):
# GPIO初始化,默认接收模式
GPIO.setmode(GPIO.BOARD)
GPIO.setup(DIR_PIN, GPIO.OUT)
GPIO.output(DIR_PIN, GPIO.LOW)
    # 打开3.3V TTL串口 8N1标准参数
    self.ser = serial.Serial(
        port=UART_PORT,
        baudrate=BAUDRATE,
        bytesize=8,
        parity=serial.PARITY_NONE,
        stopbits=1,
        timeout=0.05
    )

def send_frame(self, data: bytes):
    """发送485数据帧,严格时序控制"""
    # 拉高使能发送
    GPIO.output(DIR_PIN, GPIO.HIGH)
    time.sleep(0.0001)  # 100us建立时间
    # 写入数据并刷新缓冲区
    self.ser.write(data)
    self.ser.flush()

    # 计算一帧传输总耗时:1字节=10bit
    bit_time = 1 / BAUDRATE
    total_bit = len(data) * 10
    time.sleep(total_bit * bit_time + 0.0001)

    # 切回接收模式
    GPIO.output(DIR_PIN, GPIO.LOW)

def recv_data(self, length=32) -> bytes:
    """读取总线应答数据"""
    return self.ser.read(length)

def close(self):
    self.ser.close()
    GPIO.output(DIR_PIN, GPIO.LOW)
    GPIO.cleanup()
if name == "main":
rs485 = TTL2RS485()
try:
while True:
# Modbus读取寄存器示例指令
cmd = bytes([0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A])
print(f"发送帧: {cmd.hex()}")
rs485.send_frame(cmd)
time.sleep(0.08)
recv_buf = rs485.recv_data()
if recv_buf:
print(f"应答数据: {recv_buf.hex()}\n")
time.sleep(1)
finally:
rs485.close()

五、补充方案:多路 485 / 临时调试方案

方案 1:多路原生 TTL 转 485(量产推荐)

RDK 可用硬件 UART:ttyS1/ttyS2/ttyS3 每一路串口搭配独立 MAX3485 模块、独立 DIR 控制 GPIO,互不干扰; 优势:硬件 DMA 收发,无 USB 抖动,工业 Modbus 稳定可靠。

方案 2:USB 转 485 模块(快速扩展,无需占用 40PIN)

USB 插入 CH340 内置 TTL 转 485 芯片,系统生成 /dev/ttyUSB0

  • 优点:不用改硬件引脚、即插即用;
  • 缺点:热插拔设备号漂移、USB 调度存在毫秒级时延,高速场景易丢帧。

六、现场稳定通信必备硬件规范

  1. 共地必不可少 RDK、TTL 转 485 模块、远端 485 设备 GND 必须连通;长线无共地会产生压差,出现乱码、无应答。
  2. 总线终端电阻 通信线缆长度>10m、波特率≥19200 时,在总线最远端 A/B 之间焊接 120Ω 终端电阻,消除信号反射畸变。
  3. 电平匹配 必须选用3.3V 版本 MAX3485/SP3485,禁止 5V 版本芯片直连 RDK IO,会烧毁主控引脚。
  4. 差分双绞线布线 A/B 使用屏蔽双绞线,屏蔽层单端接地,降低电机、继电器电磁干扰。

七、常见故障排查

  1. 完全无应答 TX/DI、RX/RO 接反;DIR 引脚发送时未拉高;A/B 总线接反;无共地。
  2. 发送正常,收不到返回 发送完成未等待字节传输完毕就切接收,截断最后几位数据;缺少 100us 建立延时。
  3. 接收全是乱码 两端波特率 / 校验位不匹配;长线无终端电阻;地线断开。
  4. 只能短距离通信 未使用差分双绞线、无终端电阻、电磁干扰严重。
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐