ESC
输入关键词搜索文章标题和内容

13种嵌入式总线,90%的坑都写在示波器上

本文由 linuxROS 整理发布,首发于 linuxros.cn,转载请注明出处。

13种嵌入式总线,90%的坑都写在示波器上

导读

总线调不通,别急着翻代码,先上示波器看看波形。十个问题九个栽在电气和时序上,协议本身反而没什么好说的。结合手上几个项目的踩坑经历,把板内、工业、高速、实时四类 13 种总线整理了一遍,配了 8 张流程图,每种总线写了症状→根因→修复,波形正常什么样、异常什么样也画了。下次出问题对着查,省得翻 datasheet。


选型决策全景图

flowchart LR A(["新项目总线选型"]) --> B{"通信距离?"} B -->|"板内 < 30cm"| C{"数据量 / 速率需求?"} B -->|"工业 / 车载 > 1m"| D{"实时性要求?"} B -->|"外设拓展"| E{"设备类型?"} C -->|"低速传感器群"| F["I2C"] C -->|"高速 Flash / 射频"| G["SPI / QSPI"] C -->|"调试 / 点对点模块"| H["UART"] C -->|"音频数据流"| I["I2S"] C -->|"PMIC 电源管理"| J["SMBus"] D -->|"硬实时 / 高可靠"| K{"单帧数据量?"} D -->|"大带宽 / 非实时"| L["以太网"] K -->|"≤ 8 字节"| M["CAN 2.0"] K -->|"≤ 64 字节"| N["CAN FD"] D -->|"低速辅助"| O["LIN"] D -->|"多节点采集"| P["RS485"] E -->|"显示屏 / 摄像头"| Q["MIPI DSI / CSI"] E -->|"SD 卡 / WiFi 模块"| R["SDIO"] E -->|"通用 USB 设备"| S["USB 2.0 / OTG"] E -->|"SRAM / 并口屏"| T["FSMC / FMC"] E -->|"多轴伺服"| U["EtherCAT"] style A fill:#ECEFF1,stroke:#37474F,stroke-width:2px style B fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style C fill:#E3F2FD,stroke:#1565C0,stroke-width:2px style D fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style E fill:#F3E5F5,stroke:#7B1FA2,stroke-width:2px style K fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style F fill:#E3F2FD,stroke:#1565C0 style G fill:#E3F2FD,stroke:#1565C0 style H fill:#E3F2FD,stroke:#1565C0 style I fill:#E3F2FD,stroke:#1565C0 style J fill:#E3F2FD,stroke:#1565C0 style M fill:#E8F5E9,stroke:#2E7D32 style N fill:#E8F5E9,stroke:#2E7D32 style P fill:#E8F5E9,stroke:#2E7D32 style O fill:#E8F5E9,stroke:#2E7D32 style L fill:#FFF8E1,stroke:#F57F17 style Q fill:#F3E5F5,stroke:#7B1FA2 style R fill:#F3E5F5,stroke:#7B1FA2 style S fill:#F3E5F5,stroke:#7B1FA2 style T fill:#FFF8E1,stroke:#F57F17 style U fill:#FFF8E1,stroke:#F57F17

一、板内短距离总线:板上器件通信

I2C 通信时序全流程

flowchart TB S(["START:SCL 高时 SDA 拉低"]) --> A["主机发送 7bit 从机地址 + 1bit R/W"] A --> B{"从机回 ACK?"} B -->|"ACK = 0"| C["主机发送 8bit 数据 / 寄存器地址"] B -->|"NACK = 1"| N1["从机无响应 → 发 STOP 重试"] C --> D{"从机回 ACK?"} D -->|"ACK"| E{"还有数据?"} D -->|"NACK"| N2["从机拒收 → 发 STOP 排查"] E -->|"是"| C E -->|"否"| P(["STOP:SCL 高时 SDA 拉高"]) N1 --> P N2 --> P style S fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style A fill:#E3F2FD,stroke:#1565C0 style B fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style C fill:#E3F2FD,stroke:#1565C0 style D fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style E fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style N1 fill:#FFEBEE,stroke:#C62828 style N2 fill:#FFEBEE,stroke:#C62828 style P fill:#FFEBEE,stroke:#C62828,stroke-width:2px

关键时序约束:SDA 只在 SCL 低电平时变化,SCL 高电平时采样。START/STOP 是仅有的例外——SCL 高电平时 SDA 翻转。

1. I2C:两根线挂一堆传感器的省 IO 之王

特性:2 线(SDA/SCL),开漏输出,必须外部上拉(典型 4.7kΩ for 3.3V);半双工;一总线多设备,靠 7 位或 10 位地址寻址;速度等级:Standard 100kbps / Fast 400kbps / Fast+ 1Mbps / High-Speed 3.4Mbps。

优点:极省 IO,两根线能挂 100+ 个设备;布线简单,BOM 成本低;传感器、EEPROM、RTC、PMIC 几乎都带 I2C 接口。

缺点:速率低,大批量数据搬运吃力;开漏驱动弱,上拉电阻选不好波形就烂;半双工效率打折扣;单设备死机(SCL 拉低不放)会拖垮整条总线。

波形对比:正常 vs SCL 被从机卡死

正常 I2C 写操作(发送从机地址 0x50 + 数据):
         START  A6  A5  A4  A3  A2  A1  A0  W   ACK  D7  D6  ...
SCL: ___/‾‾‾\__/‾\__/‾\__/‾\__/‾\__/‾\__/‾\__/‾\__/‾\__/‾‾‾\__/‾\__/‾\__
SDA: ‾‾‾\_____________________________/‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\__________/‾‾‾‾‾‾‾‾
              (SDA 只在 SCL 低电平期间变化)

SCL 被从机卡死(时钟拉伸超时):
         START  A6  A5  A4  A3  A2  ...
SCL: ___/‾‾‾\__/‾\__/‾\__/‾\_________________________________________
SDA: ‾‾‾\_____________________________/‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
                                      ↑ 从机将 SCL 拉低不放
                                      总线彻底锁死,所有设备无法通信

最常见坑:

  • 症状:I2C 通信卡死,SDA 或 SCL 持续低电平,所有设备无法通信,只能硬件复位恢复。
  • 根因:从机(如 EEPROM)在写周期内拉低 SCL 不放(时钟拉伸),或 SDA 被意外拉低导致总线认为仍在传输中。上拉电阻过大(>10kΩ)导致上升沿过缓,400kHz 时电平无法在 SCL 上升沿前稳定。
  • 修复:开启 MCU I2C 硬件超时检测(如 STM32 的 TIMOUT 功能),超时后软件切 GPIO 发 9 个时钟脉冲恢复总线。多设备时重新计算等效上拉:Rp = (VCC - V_OL) / I_OL,3.3V 下挂 3 个设备建议 2.2kΩ 起步。

比如 STM32F407 写 AT24C02 后未等 5ms 写周期就发下一帧,EEPROM 拉死 SCL,整条总线瘫痪——加 ACK 轮询 + 硬件超时即可避免。

I2C 总线锁死恢复流程

flowchart TB A(["I2C 通信超时 / 无响应"]) --> B{"检测 SDA 或 SCL<br>是否被拉低?"} B -->|"SCL 低"| C["从机时钟拉伸卡死"] B -->|"SDA 低"| D["从机数据线卡死"] B -->|"均为高"| E["非总线锁死<br>检查地址 / 上拉"] C --> F["软件复位:SCL 切为 GPIO<br>输出 9 个时钟脉冲<br>切回 I2C 功能"] D --> F F --> G{"SDA 恢复高电平?"} G -->|"是"| H(["总线恢复<br>重新发起通信"]) G -->|"否"| I["硬件故障:检查焊接<br>上拉电阻 / 从机供电"] style A fill:#FFEBEE,stroke:#C62828,stroke-width:2px style B fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style C fill:#F3E5F5,stroke:#7B1FA2 style D fill:#F3E5F5,stroke:#7B1FA2 style E fill:#E3F2FD,stroke:#1565C0 style F fill:#E3F2FD,stroke:#1565C0 style G fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style H fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style I fill:#FFEBEE,stroke:#C62828

2. SPI:独立片选、全双工的高速主力

SPI 四种模式对比

flowchart TB subgraph M0["Mode 0:CPOL=0, CPHA=0"] direction LR A0["CLK 空闲=低"] --> B0["上升沿采样"] --> C0["下降沿移位"] end subgraph M1["Mode 1:CPOL=0, CPHA=1"] direction LR A1["CLK 空闲=低"] --> B1["上升沿移位"] --> C1["下降沿采样"] end subgraph M2["Mode 2:CPOL=1, CPHA=0"] direction LR A2["CLK 空闲=高"] --> B2["下降沿采样"] --> C2["上升沿移位"] end subgraph M3["Mode 3:CPOL=1, CPHA=1"] direction LR A3["CLK 空闲=高"] --> B3["下降沿移位"] --> C3["上升沿采样"] end M0 -.-> M1 M1 -.-> M2 M2 -.-> M3 style M0 fill:#E3F2FD,stroke:#1565C0,stroke-width:2px style M1 fill:#E3F2FD,stroke:#1565C0,stroke-width:2px style M2 fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style M3 fill:#FFF8E1,stroke:#F57F17,stroke-width:2px

CPOL 决定空闲电平,CPHA 决定采样边沿。 主从双方 Mode 必须完全一致,差一个 bit 就全乱。

特性:4 线(CLK/MOSI/MISO/CS),推挽输出,全双工同步通信;单主机架构,每设备独立片选线;速率可达几十 MHz,远超 I2C。

优点:速率高、全双工效率好;推挽驱动比 I2C 开漏抗干扰强;单设备故障互不影响,不像 I2C 一挂全挂。

缺点:极耗 IO,每多一个设备多一根 CS 线;无硬件应答/校验,全靠协议层保证;不支持多主机;多设备布线繁琐,CS 线飞到怀疑人生。

波形对比:Mode 0 正常 vs Mode 3 错配到 Mode 0 的从机

Mode 0 (CPOL=0, CPHA=0) — 正常通信:
CLK:  ___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___
         ↑采样  ↑采样  ↑采样  ↑采样  ↑采样  ↑采样  ↑采样  ↑采样
MOSI:  ___< D7 >< D6 >< D5 >< D4 >< D3 >< D2 >< D1 >< D0 >_____________________
MISO:  ___< X7 >< X6 >< X5 >< X4 >< X3 >< X2 >< X1 >< X0 >_____________________

Mode 3 (CPOL=1, CPHA=1) 的 MCU 去读 Mode 0 的 Flash:
CLK:  ‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾
                ↑采样  ↑采样  ↑采样  ↑采样  ↑采样  ↑采样  ↑采样  ↑采样
MISO:  ___< X7 >< X6 >< X5 >< X4 >< X3 >< X2 >< X1 >< X0 >_____________________
       ↑ Flash 在 CLK 上升沿输出数据,但 MCU 在下降沿采样
       采样点正好落在数据变化期 → 读到的是不确定的中间态 → 全 0xFF 或随机值

最常见坑:

  • 症状:读取 Flash/传感器返回全 0xFF 或 0x00,或数据字节间错位(如 0x12 0x34 变成 0x24 0x68——左移一位)。
  • 根因:CPOL/CPHA 四种模式中主从配置不一致。CubeMX 默认生成 Mode 0(CPOL=Low, CPHA=1Edge),但开发者常手动改为 Mode 3 或忘记核对。W25Q128 等 SPI Flash 同时支持 Mode 0 和 Mode 3(CPHA 必须为 0),关键在于主从双方必须一致——任意一方配错,采样边沿错开半个周期,数据全乱。
  • 修复:对着从设备 datasheet 的 SPI 时序图确认 CPOL/CPHA。示波器双通道同时抓 CLK 和 MOSI,看 CLK 的第一个跳变沿和 MOSI 数据的对齐关系——数据必须在 CLK 采样沿之前稳定。CubeMX 里 SPI 的 CPOL 和 CPHA 两个参数,不是选一个就行,两个都要对。

比如 STM32F103 配成 Mode 3 去读 W25Q128(驱动按 Mode 0),JEDEC ID 返回全 0xFF——示波器一看采样沿错位,对齐后秒好。

3. QSPI:Flash 专用四线并行通道

特性:在 SPI 基础上扩展为四线并行(DQ0~DQ3),专为 NOR Flash 设计的高速接口;支持单线/双线/四线模式动态切换。

优点:读写速度是普通 SPI 的四倍,大容量 Flash(如 128MB+)的首选方案;支持 XIP(片内执行),代码可直接从 Flash 运行。

缺点:通用性差,基本只用于存储类器件;四线模式切换时序复杂,调试难度高;对 PCB 布线等长有一定要求。

最常见坑:

  • 症状:Flash 上电后无法挂载,读 ID 正确但读数据全 0xFF,或 XIP 模式下程序跑飞进 HardFault。
  • 根因:四线模式切换命令未正确发送——需通过 0x31(写状态寄存器-2)置位 QE(Quad Enable)位,或发 0x38 进入 QPI 模式。QE 位未置位时,Flash 仍工作在单线/双线模式,Quad Read 命令无效。地址偏移计算错误——四线模式下地址需按 4 字节对齐,未对齐的地址会导致数据错位。
  • 修复:初始化序列严格按照 datasheet 的步骤:① 读状态寄存器确认 QE 位=1 ② 发 Quad Read 命令(不是普通 Read)③ 确认 dummy cycle 数量匹配。启动阶段的 QSPI 配置是 Boot ROM 管的,如果 Boot 阶段配错,主程序再怎么改都没用——检查 Boot 引脚和 option byte。

4. UART/TTL 串口:最通用的调试和模块通信接口

特性:TX/RX 异步点对点通信,无时钟线,靠双方约定波特率同步;全芯片兼容,从 51 到 Cortex-A 都带。

优点:协议最简单,上手成本为零;调试打印、蓝牙/WiFi/4G 模块通信的最通用方案;一个串口搞定所有。

缺点:无时钟同步,高波特率(>1Mbps)时时钟偏差容易丢帧;只能点对点,不支持多机组网;没有硬件流控时容易溢出。

波形对比:正常 115200 bps vs 波特率偏差 2%

正常 115200 bps(时钟精度 ±0.5%):
        起始位  B0   B1   B2   B3   B4   B5   B6   B7  停止位
RX: ‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾
       ↑采样点始终在 bit 中心,数据可靠

波特率偏差 2%(实际 113000 bps vs 期望 115200):
        起始位  B0   B1   B2   B3   B4   B5   B6   B7  停止位?
RX: ‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾‾‾\___/‾
       ↑        ↑        ↑        ↑        ↑        ↑        ↑        ↑        ↑
       采样点逐步偏移,到 B7 时已偏离中心 16% → 可能采样到相邻 bit 或停止位

最常见坑:

  • 症状:常温下通信正常,设备升温后(50°C+)出现间歇性乱码;或两个不同 MCU 之间 115200 偶发丢帧,57600 则正常。
  • 根因:波特率时钟源偏差。内部 RC 振荡器温漂可达 ±1.5%,两个设备各偏 ±1% 就超过 2% 的容限。高波特率下单个 bit 宽度仅 8.7μs(115200),采样点偏移 1μs 就开始错位。校验位配置不匹配(None/Even/Odd)也会导致看似乱码的问题。
  • 修复:示波器量一个 bit 宽度反推实际波特率——实际波特率 = 1 / bit宽度。若偏差 >2%,换外部晶振或降波特率。STM32 用 HSI 跑 115200 勉强,ESP32 用外部 40MHz 晶振则没问题。双方统一校验位配置,建议都用 8N1。

比如 STM32 用内部 HSI 跑 115200,55°C 温箱里波特率漂到 111700(偏差 -3%),HC-05 蓝牙模块收到全是乱码——换外部晶振或降 57600 解决。

5. I2S:音频专用同步总线

特性:音频专用同步串行总线,传输 PCM 数据流;独立时钟线(BCLK)和字选线(LRCK),严格区分左右声道。

优点:音质稳定,同步机制保证音频数据不丢不重;DSP/Codec 芯片几乎标配 I2S;适合语音、音频播放设备。

缺点:只能传音频,通用性为零;仅支持点对点(或一主一从);配错采样率直接出爆音。

最常见坑:

  • 症状:播放音频出现爆音、无声、声音速度变快/变慢(如 44.1kHz 的音频被当成 48kHz 播放,音调偏高)。
  • 根因:采样率(44.1k/48k)、位深(16/24/32bit)、主从模式(Master/Slave)三方配置不匹配。典型场景:DSP 配置为 48kHz/16bit/Master,Codec 配置为 44.1kHz/24bit/Slave——三端全错,任意一端不对都会出问题。
  • 修复:三步对齐:① 确认 Codec 的 MCLK 频率(通常 256×fs),② 根据 MCLK 反推采样率,③ 将 DSP 的 I2S 外设配置与 Codec 完全对齐。注意:有些 Codec 要求 MCLK = 256×fs,有些要求 384×fs,不匹配也会出问题。

6. SMBus:I2C 的严格子集,电源管理专用

特性:I2C 的子集,时序更严格,带超时(35ms)和故障恢复机制;主要用于智能电池、PMIC、温度监控等电源管理场景。

优点:自带超时检测,防总线卡死,比裸 I2C 靠谱;电源管理芯片(如充电 IC、电量计)的标配接口。

缺点:速率极低(10k~100kHz),场景单一,不是 PMIC 基本用不上。

最常见坑:

  • 症状:电量计(如 BQ27426)间歇性读取失败,电量显示在 30%→80% 之间跳变,充电状态指示灯乱闪。
  • 根因:SMBus 的 35ms 超时机制比 I2C 严格,I2C 模式下能容忍的慢响应在 SMBus 下被判定为超时。I2C 驱动直接访问 SMBus 设备时,时序裕量不够。
  • 修复:SMBus 设备必须用 SMBus 协议栈访问(Linux 内核 drivers/i2c/busses/i2c-smbus.c),不要裸用 I2C 读写。确认超时配置:SMBus 规范要求从机在 25ms 内响应,主机超时 35ms。

二、工业/车载长线总线:抗干扰、多节点

CAN 总线仲裁机制

flowchart TB A(["多个节点同时请求发送"]) --> B["各节点发送帧 ID<br>从 MSB 开始逐位仲裁"] B --> C{"当前 bit:<br>自身发送 vs 总线电平?"} C -->|"一致"| D{"帧 ID 还有<br>剩余位?"} C -->|"不一致<br>发隐性读到显性"| E["仲裁失败<br>立即停止发送<br>转为只听模式"] D -->|"是"| B D -->|"否"| F(["仲裁胜出<br>继续发送数据帧<br>低 ID 优先权最高"]) E --> G["等待当前帧传输完成<br>下次总线空闲重新竞争"] style A fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style B fill:#E3F2FD,stroke:#1565C0 style C fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style D fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style E fill:#FFEBEE,stroke:#C62828 style F fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style G fill:#F3E5F5,stroke:#7B1FA2

CAN 仲裁核心:显性电平(逻辑 0)覆盖隐性电平(逻辑 1)。帧 ID 越小(开头 0 越多),优先级越高。这是 CAN 非破坏性逐位仲裁的基础。

RS485 半双工方向切换时序

flowchart TB T1(["MCU 拉高 DE/RE"]) --> T2["等待 10-50μs<br>收发器稳定"] T2 --> T3["发送数据帧"] T3 --> T4["等待最后一字节<br>移位完成"] T4 --> T5(["拉低 DE/RE<br>切回接收模式"]) T1 -.->|"⚠ 切换过早"| P1["最后一字节未发完<br>就被截断"] T2 -.->|"⚠ 未等稳定"| P3["帧头数据丢失"] T5 -.->|"⚠ 切换过晚"| P2["总线被占用<br>收不到从机应答"] style T1 fill:#E3F2FD,stroke:#1565C0,stroke-width:2px style T2 fill:#E3F2FD,stroke:#1565C0 style T3 fill:#E3F2FD,stroke:#1565C0 style T4 fill:#E3F2FD,stroke:#1565C0 style T5 fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style P1 fill:#FFEBEE,stroke:#C62828 style P2 fill:#FFEBEE,stroke:#C62828 style P3 fill:#FFEBEE,stroke:#C62828

1. RS485:工业采集的差分长线标配

特性:差分 AB 线,半双工;一主多从,支持 32~256 个节点;千米级传输距离(1200m at 19200bps);常跑 Modbus RTU 协议;两端必须各加 120Ω 终端电阻。

优点:差分信号抗干扰极强,工厂变频器、电机旁边照样跑;距离远、节点多、成本极低,工业传感器采集的事实标准。

缺点:半双工需收发方向切换(DE/RE 引脚控制),切换时机不好就丢数据;无硬件校验,依赖上层协议 CRC;终端电阻匹配不当导致信号反射。

波形对比:正常 RS485 收发切换 vs DE 过早拉低

正常切换(发完最后一字节 → 等 1 字节时间 → 拉低 DE):
TX:  [Byte0][Byte1][Byte2][Byte3][Byte4][CRC_L][CRC_H]  ←UART移位完成
DE:  ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\___
                                              ↑ 等 1 字节时间后拉低
AB:  ▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂
                                              完整帧发送完毕 ✓

DE 过早拉低(TX 移位寄存器还没发完 CRC_H):
TX:  [Byte0][Byte1][Byte2][Byte3][Byte4][CRC_L][CRC_H]
DE:  ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\_______________
                                          ↑ 提前拉低,CRC_H 被截断
AB:  ▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂
                                              从机收到的帧 CRC 校验失败

最常见坑:

  • 症状:主机发送正常,从机从不回复;或批量安装后部分从机通信正常、部分完全无响应。总线两端示波器量到的波形质量差异巨大。
  • 根因:① 终端电阻缺失——未加 120Ω 导致信号在总线末端反射,反射波叠加到原信号上造成电平误判;② DE 切换时序错误——UART 的 TX 完成中断(TC)触发时,数据还在移位寄存器里,立即拉低 DE 会截断最后一字节;③ 偏置电阻未加——空闲时 AB 线电压差 <200mV,处于不确定状态。
  • 修复:① 总线物理两端各焊 120Ω(中间节点不加),用示波器差分探头看 AB 波形,眼睛图应清晰张开;② DE 拉低前等待 1 字节时间:delay_us(1000000 / baudrate * 10);③ 主机端加偏置电阻(A 上拉 680Ω 到 VCC,B 下拉 680Ω 到 GND),保证空闲时 A > B。

比如 8 个传感器跑 Modbus RTU,末端没焊 120Ω 终端电阻,信号反射导致末端 3 个从机不响应——示波器一看过冲振铃,补焊即好。

来自 linuxros.cn · linuxROS

2. CAN 2.0:车载工控的容错之王

特性:差分双线(CAN_H/CAN_L),多主竞争仲裁;硬件 CRC 校验、ACK 应答、故障节点自动脱离;帧 ID 决定优先级,低 ID 赢仲裁;车载、工控、医疗的通信标准;两端各 120Ω 终端电阻。

速率与距离对照:

波特率 最大距离
1 Mbps 40 m
500 kbps 100 m
250 kbps 200 m
125 kbps 500 m
10 kbps 6 km

优点:抗干扰极强,差分+硬件 CRC+重传机制,噪声环境稳如狗;实时性好,仲裁机制保证高优先级帧不丢;总线容错高,单节点故障不炸网,自动脱离。

缺点:单帧仅 8 字节有效载荷,大数据传输效率低;总线负载率超过 60% 时延显著增大;成本比 485 贵,需要 CAN 控制器+收发器。

波形对比:正常 CAN 差分波形 vs 无终端电阻时的反射

正常 CAN 差分波形(两端各 120Ω,500kbps):
CAN_H:  ‾‾‾\_____/‾‾‾‾‾\_____/‾‾‾‾‾\_____/‾‾‾‾‾\_____/‾‾‾‾‾‾‾‾‾‾‾‾‾‾
CAN_L:  _____/‾‾‾‾‾\_____/‾‾‾‾‾\_____/‾‾‾‾‾\_____/‾‾‾‾‾\_____/‾‾‾‾‾‾‾‾‾‾‾
差分:   ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
        边沿干净,差分幅值 ≥2V,总线阻抗匹配 60Ω

无终端电阻(反射严重):
CAN_H:  ‾‾‾\__/‾\__/‾‾‾\__/‾\__/‾‾‾\__/‾\__/‾‾‾\__/‾\__/‾‾‾‾‾‾‾‾‾‾‾‾‾‾
CAN_L:  ___/‾‾\/__\/___/‾‾\/__\/___/‾‾\/__\/___/‾‾\/__\/___/‾‾‾‾‾‾‾‾‾‾‾‾‾‾
         ↑边沿振铃(Ringing),多个反射波叠加
差分:   ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
        边沿振铃导致差分幅值在采样点附近波动 → 误判逻辑电平 → 错误帧

最常见坑:

  • 症状:CAN 分析仪显示错误帧激增,TEC(发送错误计数)和 REC(接收错误计数)持续攀升,最终节点进入 Bus-Off 状态(TEC>255),主动脱离总线。
  • 根因:① 终端电阻缺失或只焊一端——总线阻抗不匹配导致信号反射,波形边沿振铃严重,采样点附近电平不确定;② 波特率不统一——常见 500k/250k/125k 混用,位定时参数(Prescaler/SJW/BS1/BS2)不匹配,采样点位置偏移。
  • 修复:① 总线物理两端各焊 120Ω(CAN 终端电阻不同于 RS485,是并在 CAN_H 和 CAN_L 之间的),用万用表量 CAN_H 和 CAN_L 之间电阻应为 60Ω(两个 120Ω 并联);② 所有节点统一波特率和位定时参数,用 CAN 分析仪确认实际波特率,不要只看代码配置。

比如 4 节点 CAN 总线只焊了一个终端电阻(CAN_H/CAN_L 电阻 120Ω 而非 60Ω),新增节点后错误帧暴涨——两端各补 120Ω 后恢复。

3. CAN FD:兼容 CAN 2.0 的高速升级版

特性:兼容 CAN 2.0,仲裁段保持 1Mbps,数据段可升至 8Mbps;单帧 payload 最大 64 字节;BRS 位控制速率切换。

优点:保留 CAN 的可靠性和容错机制,数据吞吐量大幅提升;适配 BMS 电池管理、伺服驱动器、固件升级等大数据场景;向下兼容 CAN 2.0 控制器。

缺点:老设备不兼容 CAN FD 帧格式,混合组网时需注意;硬件成本更高,FD 控制器和收发器都贵一截。

最常见坑:

  • 症状:CAN FD 节点和 CAN 2.0 节点混接后,CAN 2.0 节点持续报错并进入 Bus-Off,FD 节点发送的帧全部无应答。
  • 根因:CAN 2.0 控制器不认识 FD 帧的 BRS 位和扩展数据段,将其判定为格式错误(Form Error),发送错误帧破坏总线。CAN FD 只在数据段加速,但 CAN 2.0 控制器连仲裁段后的 FDF 位都解析不了。
  • 修复:组网前用 CAN 分析仪确认所有节点的协议版本。如果必须混用,FD 节点的 BRS 位必须关闭(降级为 CAN 2.0 速率),或使用 CAN FD 屏蔽模式(FD Shield Mode)过滤 FD 帧。最好是全网统一升级或统一降级。

4. LIN:车载低速辅助单线总线

特性:单线(对地参考),主从轮询架构;速率 2.4k~19.2kbps;主要用于车窗、车灯、座椅、雨刮等低优先级车载外设。

优点:线束成本极低,单线搞定;协议简单,普通 MCU 的 UART 就能软件模拟 LIN 主从。

缺点:速率极慢,无强容错机制;干扰稍大就丢帧,不能用于安全相关功能。

最常见坑:

  • 症状:LIN 从机间歇性不响应,主机的 schedule table 轮询到该从机时无应答,下一个周期又恢复正常。
  • 根因:LIN 物理层是单线对地参考,没有差分抗干扰能力。电磁干扰(如电机启动、继电器吸合)直接耦合到 LIN 线上,导致从机误判帧头或 ID。schedule table 的时隙设置过紧,从机响应时间不够。
  • 修复:① LIN 线远离大电流走线,必要时加共模扼流圈;② 增大 schedule table 中该从机的响应时隙(从 10ms 放宽到 20ms);③ 从机端增加 LIN 收发器(如 TJA1021)而不是直接用 MCU 引脚模拟,收发器自带波形整形和限流保护。

三、高速外设总线:图像、存储、外设拓展

总线六维对比矩阵

flowchart TB subgraph RATE["速率维度"] direction LR A1["UART ~1M"] --> A2["I2C 100k~3.4M"] --> A3["SPI ~50M"] --> A4["QSPI ~200M"] --> A5["SDIO ~200M"] --> A6["MIPI ~10G"] --> A7["USB 480M"] --> A8["ETH 100M~1G"] --> A9["EtherCAT 100M"] end subgraph DIST["距离维度"] direction LR B1["板内 <0.3m"] --> B2["USB <5m"] --> B3["CAN 1M 40m"] --> B4["CAN 125k 500m"] --> B5["RS485 1200m"] --> B6["ETH 100m"] end subgraph IO["IO 占用维度"] direction LR C1["I2C 2pin"] --> C2["UART 2pin"] --> C3["CAN 2pin"] --> C4["RS485 2pin"] --> C5["SPI 3+n"] --> C6["MIPI 4~10"] --> C7["FSMC 20~30"] end style RATE fill:#E3F2FD,stroke:#1565C0,stroke-width:2px style DIST fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style IO fill:#FFF8E1,stroke:#F57F17,stroke-width:2px

1. SDIO:SD 卡和 WiFi 模块的高速通道

特性:SD 卡、SDIO WiFi 模块专用高速总线;支持 1-bit/4-bit 模式;速率远高于 SPI 模式的 SD 卡访问。

优点:比 SPI 模式速度快,CPU 占用低;SD 卡和 WiFi 模块驱动现成。

缺点:专用性强,基本只用于存储卡和 WiFi 外设;高速模式 PCB 布线要求高,等长、阻抗都要对。

最常见坑:

  • 症状:SD 卡在 4-bit 模式下频繁挂载失败、读写超时,降到 1-bit 模式后正常;或高速模式下随机出现 CRC 错误。
  • 根因:CLK 线和 DATA0~DATA3 线不等长,高速模式(50MHz SDR)下时钟和数据到达时间不一致,setup/hold 时间不满足。SDIO 的 CLK 走线质量直接影响最高可用速率。
  • 修复:① 4 条 DATA 线等长控制在 ±2mm 以内,CLK 线可以比 DATA 线略短(提前到达给 setup 留余量);② 如果无法改板,降速到 25MHz 或改用 1-bit 模式;③ 确认 CLK 线上串联 33Ω 终端电阻抑制反射。

2. MIPI DSI/CSI:屏和摄像头的差分高速通道

特性:差分高速串行接口,DSI(Display Serial Interface)用于显示屏,CSI(Camera Serial Interface)用于摄像头;D-PHY v1.3 每 lane 2.0~2.5Gbps,v2.0 可达 3.5Gbps/lane;差分阻抗 100Ω;多 lane 并行传输。

优点:带宽大,功耗低、EMI 小,适合高清手持设备;手机、平板、嵌入式 HMI 的标配。

缺点:协议复杂,初始化序列调试难度高;PCB 差分对等长要求严苛,偏差 1mm 都可能出问题;成本高,需要专用控制器。

最常见坑:

  • 症状:屏幕冷启动正常,运行 5~10 分钟后出现花屏、横条纹、局部闪烁;或摄像头图像有固定位置的横条纹噪声。
  • 根因:差分对内线长不匹配——P 线和 N 线长度差超过 1mm,导致差分信号偏斜(skew),眼图在高温下闭合。差分阻抗不是 100Ω——走线宽度/间距/介质厚度不匹配,阻抗偏差 >10% 导致信号反射。
  • 修复:① 每条差分对的 P/N 线长差控制在 0.5mm 以内;② 差分对之间等长控制在 2mm 以内;③ 阻抗计算用 PCB 厂提供的层叠参数,不能直接用默认值。如果已经打样,降 lane 速率(从 500Mbps 降到 400Mbps)能临时缓解。

比如 RK3568 的 MIPI DSI 差分对线长差 2.5mm,50°C 老化 5 分钟眼图闭合、屏幕花屏——重新 layout 等长控制 0.3mm 后正常。

3. USB 2.0/OTG:生态最全的通用外设接口

特性:差分 D+/D-,支持热插拔、设备枚举、HUB 级联;OTG 支持主机/设备双角色切换;速率 1.5Mbps(Low)/12Mbps(Full)/480Mbps(High)。

优点:生态最全,U 盘、摄像头、键鼠、虚拟串口、网卡、4G 模块都能接;即插即用,用户无感。

缺点:协议栈重,占用 MCU 资源多;距离短(标准 5 米);实时性差,不适合硬实时控制业务。

最常见坑:

  • 症状:USB 设备频繁枚举失败,dmesg 显示 device descriptor read/64, error -71 或 -110;设备管理器里设备反复出现又消失。
  • 根因:① VBUS 供电不足——USB 2.0 标准要求 VBUS 提供 500mA,劣质线材线阻大导致设备端电压跌落(<4.75V);② 走线过长——超过 1.5 米的 USB 线,D+/D- 差分信号衰减严重,眼图闭合;③ 线材屏蔽差——差分阻抗不匹配导致信号反射。
  • 修复:① 换短而粗的 USB 线(1 米以内),用带磁环的屏蔽线;② 自供电设备(如 4G 模块)必须外接电源,不要依赖 VBUS;③ 抓 USB 枚举过程的 bus reset 和 descriptor 交互,确认是供电问题还是信号完整性问题。

四、并行总线与工业实时总线

1. FSMC/FMC:并行地址数据总线,刷屏快但已淘汰

特性:并行地址/数据总线,STM32 的 FSMC/FMC 可驱动 SRAM、NOR Flash、并口 LCD;地址和数据线分离,瞬时吞吐量大。

优点:瞬时吞吐量大,刷并口屏流畅;可直接映射到内存地址空间,读写如访存。

缺点:巨耗 IO(地址+数据 20~30 根线),EMI 干扰大,PCB 布线噩梦;小型设备基本淘汰,被 QSPI/SPI LCD 替代。

最常见坑:

  • 症状:并口 LCD 屏幕闪烁、花屏、颜色错乱;SRAM 读写数据偶尔出错,且错误不可复现。
  • 根因:① 时序参数配置不准——地址建立时间(ADDSET)、数据建立时间(DATAST)、地址保持时间(ADDHLD)与设备的 datasheet 不匹配;② 布线串扰——20~30 根并行线同时翻转,相邻线间串扰严重,导致数据误采。
  • 修复:① 对着屏/SRAM 的 datasheet 逐项填时序参数,不要用默认值。ADDSET = (t_AS / t_HCLK) - 1,DATAST = (t_DS / t_HCLK) - 1,算完之后再加 1 个周期留余量。② 并行线之间加地线隔离,走线尽量短(<5cm),必要时串联 22Ω 电阻抑制反射。

2. 普通以太网:大带宽远距离组网

特性:TCP/IP 协议栈,支持跨网段通信;百兆/千兆带宽;RJ45 或 MII/RMII 接口。

优点:数据量大,适合传输视频流、日志、固件包;可跨网通信,不受物理距离限制;协议栈、驱动、工具链都很全。

缺点:无硬实时,延时抖动大(毫秒级);TCP/IP 协议栈耗资源,小 MCU 跑不动;需要 PHY 芯片和网络变压器。

最常见坑:

  • 症状:TCP 通信正常数小时后出现数据解析异常,日志显示"粘包"——两帧数据粘在一起,或"分包"——一帧数据被拆成两次接收。
  • 根因:TCP 是流式协议,不保证消息边界。发送方调用 3 次 send("hello"),接收方可能 1 次 recv 就收到 "hellohellohello",也可能分 5 次收到。应用层没有定义帧边界(长度前缀、分隔符、或定长帧),裸用 TCP 收数据必然出问题。
  • 修复:应用层必须定义帧边界,三种方案:① 长度前缀——每帧前 2 字节表示帧长度(Modbus TCP 方式);② 分隔符——帧尾加 \r\n(HTTP 方式);③ 定长帧——所有帧固定长度。推荐方案①,最可靠。

3. EtherCAT:多轴伺服的硬实时以太网

特性:工业硬实时以太网,基于"飞读飞写"(on-the-fly)机制,从站逐帧处理数据不等待;分布式时钟(DC)同步精度 < 100ns;支持线型/星型/环型拓扑。

优点:实时性顶级,多轴运动同步精度可达亚微秒级;适合伺服驱动、机器人关节、CNC 等硬实时场景;总线利用率 80%~97%。

缺点:成本高,需要专用从站控制器(ESC);开发难度大,协议栈复杂;普通嵌入式设备极少用,工控场景专用。

最常见坑:

  • 症状:多轴伺服运动中,某几个轴的运动轨迹明显滞后于其他轴,示波器看脉冲输出不同步;或 Wireshark 抓 EtherCAT 帧发现 Working Counter 值异常(正常应为 0,非 0 表示从站处理异常)。
  • 根因:① 从站 XML 配置文件(ESI 文件)中的 PDO 映射与实际固件不一致——SM 通道配置偏移、PDO 条目数量或顺序不匹配;② 分布式时钟(DC)校准失败——主站未正确同步各从站的系统时钟,导致 SYNC0 信号产生时间不一致。
  • 修复:① 用 TwinCAT 或 EtherCAT Master 工具重新扫描从站,导出正确的 ESI 文件,确保 PDO 映射与固件一致;② 检查 DC 配置——SYNC0 周期(通常 1ms)、Shift Time(从站处理延迟),用 Wireshark 抓 ARMW 和 FRMW 命令确认从站是否正确处理。Working Counter 每帧都检查,非 0 就是有问题。

总线故障排查决策树

flowchart TB START(["总线通信异常"]) --> Q1{"通信完全不通<br>还是偶尔丢数据?"} Q1 -->|"完全不通"| Q2{"用示波器看<br>总线上有波形吗?"} Q1 -->|"偶尔丢数据"| Q3{"什么类型的总线?"} Q2 -->|"无波形"| A1["检查供电 / 引脚配置<br>检查 GPIO 复用 / 时钟"] Q2 -->|"有波形但不对"| A2["查波特率 / 时序参数<br>I2C:查上拉电阻<br>SPI:查 CPOL/CPHA<br>UART:查波特率 / 校验位"] Q3 -->|"差分总线<br>RS485/CAN"| Q4{"终端电阻加了没?<br>120Ω 两端各一个"} Q3 -->|"I2C"| Q5{"上拉电阻对了吗?<br>3.3V 用 4.7k 起步"} Q3 -->|"SPI"| Q6{"CPOL/CPHA<br>主从一致吗?"} Q3 -->|"UART"| Q7{"波特率偏差<br>超过 2% 了吗?"} Q4 -->|"没加"| A3["补焊 120Ω 终端电阻<br>两端各一个,中间不加"] Q4 -->|"加了"| A4["查差分波形质量<br>查收发切换延时<br>查共地"] Q5 -->|"没加"| A5["加 4.7kΩ 上拉到 VCC"] Q5 -->|"加了"| A6["查总线电容 / 降速<br>查从机是否卡死 SCL"] Q6 -->|"不一致"| A7["对齐 Mode 0/1/2/3"] Q6 -->|"一致"| A8["查 CS 时序 / 布线长度<br>降速试试"] Q7 -->|"超了"| A9["换精度更高的时钟源<br>或降波特率"] Q7 -->|"没超"| A10["查流控 / 查接线<br>查电平匹配"] style START fill:#FFEBEE,stroke:#C62828,stroke-width:2px style Q1 fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style Q2 fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style Q3 fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style Q4 fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style Q5 fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style Q6 fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style Q7 fill:#FFF8E1,stroke:#F57F17,stroke-width:2px style A1 fill:#FFEBEE,stroke:#C62828 style A2 fill:#FFF8E1,stroke:#F57F17 style A3 fill:#E8F5E9,stroke:#2E7D32 style A4 fill:#FFF8E1,stroke:#F57F17 style A5 fill:#E8F5E9,stroke:#2E7D32 style A6 fill:#FFF8E1,stroke:#F57F17 style A7 fill:#E8F5E9,stroke:#2E7D32 style A8 fill:#FFF8E1,stroke:#F57F17 style A9 fill:#E8F5E9,stroke:#2E7D32 style A10 fill:#FFF8E1,stroke:#F57F17

快速工程选型口诀

flowchart TB subgraph 板内["板内短距 < 30cm"] direction LR A1["多传感器省IO"] --> A2["I2C"] B1["高速Flash/射频"] --> B2["SPI/QSPI"] C1["调试/模块通信"] --> C2["UART"] D1["音频设备"] --> D2["I2S"] end subgraph 工业["工业/车载 > 1m"] direction LR E1["多节点采集"] --> E2["RS485"] F1["高可靠控制"] --> F2["CAN/CAN FD"] G1["低速辅助"] --> G2["LIN"] end subgraph 外设["高速外设"] direction LR H1["屏/摄像头"] --> H2["MIPI"] I1["SD卡/WiFi"] --> I2["SDIO"] J1["通用外设"] --> J2["USB"] end subgraph 实时["实时控制"] direction LR K1["多轴伺服"] --> K2["EtherCAT"] end style 板内 fill:#E3F2FD,stroke:#1565C0,stroke-width:2px style 工业 fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style 外设 fill:#F3E5F5,stroke:#7B1FA2,stroke-width:2px style 实时 fill:#FFF8E1,stroke:#F57F17,stroke-width:2px
  • 板内多传感器、省 IO → I2C
  • 板内高速 Flash、射频 → SPI/QSPI
  • 调试打印、模块通信 → UART
  • 工业长线多设备采集 → RS485
  • 车载、电机、高可靠控制 → CAN/CAN FD
  • 音频设备 → I2S
  • 高清屏、摄像头 → MIPI
  • 外接通用外设 → USB
  • 多轴伺服实时控制 → EtherCAT

总结

总线选型没有银弹,核心是在需求约束下做权衡。记住三条原则:

  1. 距离决定物理层:板内走 TTL/CMOS 电平,长线走差分(RS485/CAN),屏/摄像头走 MIPI LVDS。
  2. 实时性决定协议层:软实时跑 TCP/IP,硬实时必须上 CAN 或 EtherCAT。
  3. 出问题先上示波器:抓波形比看代码快十倍,终端电阻、上拉电阻、阻抗匹配这三个词记牢。波形不对,代码再对也没用。

13 种总线,从板内到工业长线到高速外设全齐了。每种总线都附了真实调试案例和波形对比,下次选型对着流程图走一遍,出问题对着波形图查一遍,比翻 datasheet 快。

版权声明

作者linuxROS
协议本作品采用 CC BY-NC-SA 4.0 许可协议:署名-非商业性使用-相同方式共享
关注欢迎关注微信公众号 linuxROS,获取更多机器人 / 嵌入式 / Linux 干货
返回首页