[具身智能-576]:RDK X5 3.3V TTL UART 外接 RS485 外设完整实现方案
·
一、核心原理
RDK 输出3.3V TTL 电平 UART(TX/RX),无硬件差分 485 控制器; RS485 总线是差分半双工总线(A/B 两根差分线),必须通过TTL 转 RS485 电平转换芯片做两层转换:
- 发送:RDK 单端 TTL TX → 芯片转为差分 A/B 信号输出到总线
- 接收:总线差分 A/B → 芯片转为单端 TTL RX 送入 RDK 常用转换芯片:MAX3485、SP3485(3.3V 供电,完美匹配 RDK IO 电平,不用分压)
二、完整硬件接线(以常用 /dev/ttyS1 为例)
RDK 40PIN 物理引脚(BOARD 编号):
- UART_TX:PIN8 → MAX3485 DI
- UART_RX:PIN10 → MAX3485 RO
- 收发控制 GPIO(任意空闲 IO,示例 PIN16)→ MAX3485 DE+/RE 短接点
- 3.3V 电源 PIN1 → 模块 VCC
- 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 同一时刻只能发 / 收一种状态,切换时序规则:
- 发送前:GPIO 拉高,延时≥100us,等待芯片驱动电路稳定
- 写入串口数据,强制刷新缓冲区,确保所有字节送入移位寄存器
- 根据波特率计算传输耗时,等待整帧数据完全发送完毕
- 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 调度存在毫秒级时延,高速场景易丢帧。
六、现场稳定通信必备硬件规范
- 共地必不可少 RDK、TTL 转 485 模块、远端 485 设备 GND 必须连通;长线无共地会产生压差,出现乱码、无应答。
- 总线终端电阻 通信线缆长度>10m、波特率≥19200 时,在总线最远端 A/B 之间焊接 120Ω 终端电阻,消除信号反射畸变。
- 电平匹配 必须选用3.3V 版本 MAX3485/SP3485,禁止 5V 版本芯片直连 RDK IO,会烧毁主控引脚。
- 差分双绞线布线 A/B 使用屏蔽双绞线,屏蔽层单端接地,降低电机、继电器电磁干扰。
七、常见故障排查
- 完全无应答 TX/DI、RX/RO 接反;DIR 引脚发送时未拉高;A/B 总线接反;无共地。
- 发送正常,收不到返回 发送完成未等待字节传输完毕就切接收,截断最后几位数据;缺少 100us 建立延时。
- 接收全是乱码 两端波特率 / 校验位不匹配;长线无终端电阻;地线断开。
- 只能短距离通信 未使用差分双绞线、无终端电阻、电磁干扰严重。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)