DEEP 151 · 第十三辑 · 小白电气课 · LEARN NOTES

收进学习手册 · 2026-09-11 · duck.whatled.com

解读 151 · 半双工 UART 入门

解读对象:概念课 · 以 duck-control/src/bus.rs 与 microduck-replica/rl-series/scripts/hl2915_bench.py 为教材
需要的前置:解读 46(总线架构)、解读 53(协议层)、解读 108(帧层 Rust 实现)

15 只舵机加一块 IMU 板,共用一根数据线聊天,还不许乱——这靠的是半双工 UART。代码里两个文件正好是它的"物理层"与"礼仪层"。

1. UART 与 8N1:把字节搬上线

UART 是最朴素的串口:一个字节一位一位地搬。怎么算"一位完了"?双方先约定格式——本项目全程用 1Mbps、8N1(bench 脚本文件头:"TTL 半双工,1 Mbps,8N1,低位在前")。8N1 翻译过来:每个字节前面加 1 个起始位、后面加 1 个停止位、中间 8 个数据位、不设校验位——10 位打包一个字节。1Mbps 即每微秒 1 位,所以每字节 10µs:一条 PING 指令 6 字节,应答也是 6 字节,线上往返约 120µs——你可以自己从 bench 的 packet() 数出来。

打开方式就在 bench 的 Bus.__init__:serial.Serial(port, baud, bytesize=8, parity="N", stopbits=1),与 8N1 逐字对应。要改就得两头一起改,这是串口通信"先约定后说话"的第一课。

2. 半双工:单车道,靠分时通行

全双工是双车道,收发各一根线;半双工是一根线,同一时刻只能一个方向——像对讲机,说完整句喊一声"over",再换对方。舵机总线就是这么一根 DATA 线,所以每个"回合"都是严格的两步,bench 的 transact() 写得明明白白:write() 发出指令 → flush() → 立刻转成收包等应答(等 0.1s,超时记一次失败)。说—听—说—听,谁也不能抢。

为什么一根线既能收又能发?三件事合起来:

3. 动手验证:从一条 PING 到十分钟拷机

hl2915_bench.py 1 发一条 PING,应答即通;hl2915_bench.py 4 --minutes 10 是终极验证:50Hz 连续收发 10 分钟统计丢包,PASS 线是丢包 <0.1%。bus.rs 那侧同样把"不听话怎么办"写死:主机超时 30ms(READ_TIMEOUT);连续 25 次读到一模一样的旧数据(半秒,50Hz)就要警告——线没断,但数据死了,这种"半故障"只有靠数出来的纪律才能抓住。

你带走的收获

延伸

什么鸭 WHATDUCK · 复刻学习笔记 ← 全部手册 · 首页