第321篇 嵌入式通信协议SPI/I2C/UART/CAN
上篇聊了嵌入式C编程的实践。这篇聊嵌入式中最常用的四种通信协议——SPI、I2C、UART和CAN。做机器人开发,传感器数据采集、电机控制、调试日志,全都离不开这些总线。面试中这几类协议的对比是高频题。
UART:最朴素的串行通信
UART(Universal Asynchronous Receiver/Transmitter)是最简单的点对点通信协议。两根线(TX和RX),不需要时钟线,靠预设的波特率同步数据。
UART的帧格式:起始位(1位低电平)→ 数据位(5-9位,通常8位)→ 校验位(可选)→ 停止位(1-2位高电平)。没有时钟线意味着双方必须约定相同的波特率——常见的有9600、115200、921600。波特率误差要控制在2%以内,否则接收端会采样错误。
UART的优点是简单、通用,几乎所有MCU都有。缺点是点对点、速度有限(通常不超过几Mbps)、没有硬件流控时可能丢数据。
在机器人中,UART最常见的用途是调试串口(打印日志)和GPS模块、蓝牙模块等低速外设通信。
实际项目中UART有几个常见的坑:第一,DMA接收是必须的。如果用中断逐字节接收,高波特率下CPU会被中断淹没。用DMA+空闲中断(IDLE interrupt)检测一帧数据接收完毕,是标准做法。第二,数据对齐。如果发送端和接收端波特率不匹配,长时间运行后会累积误差导致乱码。解决方案是用硬件自动波特率检测(STM32的Auto Baud Rate功能)。第三,RS485。长距离UART通信要用RS485差分信号,需要控制收发方向(DE/RE引脚),在软件中要处理好方向切换的时序。
SPI:高速全双工
SPI(Serial Peripheral Interface)是同步、全双工的通信协议。四根线:SCK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。
SPI的工作方式很简单:主机产生时钟信号,每个时钟周期MOSI发送一位、MISO同时接收一位。数据像移位寄存器一样交换——主机发送的同时也在接收。
SPI的速度可以很快,常见的有10MHz、20MHz甚至80MHz。在机器人中,SPI常用于高速传感器(IMU、激光雷达前端)和Flash存储器。
SPI的变体需要注意:Mode 0-3(CPOL和CPHA的组合决定时钟极性和采样相位)、MSB/LSB优先。配置SPI时必须确保主机和从机的Mode一致,否则数据会错位。
多从机有两种接法:每个从机单独一根CS线(标准方式),或者所有从机串接成移位寄存器链(daisy-chain)。后者节省IO口,但延迟更大。
SPI的高速传输离不开DMA。手动用CPU逐字节传输,在20MHz以上时钟下效率极低。用DMA+SPI可以实现零CPU开销的块传输——配置DMA源地址、目标地址、传输长度,启动后DMA自动搬运数据。双缓冲(double buffer)模式可以让DMA传输和CPU处理并行:DMA往Buffer A写数据时,CPU处理Buffer B的旧数据。
I2C:省线的多设备总线
I2C(Inter-Integrated Circuit)只需要两根线:SCL(时钟)和SDA(数据),支持多主多从。每个从机有7位或10位的地址,主机通过地址选择通信对象。
I2C的通信过程:主机发START条件 → 发7位地址+1位读写方向 → 从机ACK → 传输数据 → 每个字节后跟ACK → 主机发STOP条件。
I2C的速度分三档:标准模式100kHz、快速模式400kHz、高速模式3.4MHz。实际项目中400kHz最常用。
I2C的关键细节:
- 开漏输出+上拉电阻。SDA和SCL都是开漏的,需要外接上拉电阻(通常4.7kΩ)。上拉电阻的大小影响通信速度——电阻太大上升沿慢,太小电流大。
- 时钟拉伸(clock stretching)。从机可以拉低SCL来让主机等待,这在从机处理较慢时很有用,但有些主机不支持这个特性。
- 总线冲突。多主设备同时通信时需要仲裁(arbitration),I2C通过"线与"逻辑自动仲裁——发出高电平但检测到低电平的主机退出。
I2C在机器人中常用于低速传感器(温湿度、气压、磁力计)和EEPROM。它的优势是省IO口,一个总线上可以挂几十个设备。
实际使用I2C时最常见的故障是总线死锁——从机拉低SDA不释放(通常发生在通信中途主机复位)。解决方法:主机手动发送9个SCK时钟脉冲,让从机释放SDA。更稳妥的做法是在驱动中加入总线恢复逻辑。另外,I2C的地址冲突也要注意——不同厂家的传感器可能使用相同的7位地址,挂在同一条总线上会冲突,这时需要用I2C多路复用器(比如TCA9548A)来隔离。
CAN:工业级可靠通信
CAN(Controller Area Network)是汽车和工业领域最常用的通信协议。两根差分线(CAN_H和CAN_L),抗干扰能力极强。
CAN的核心特性:
- 消息寻址。不是地址寻址,而是每个消息有一个标识符(ID),接收方通过ID过滤决定是否接收。这跟I2C的地址寻址完全不同。
- 非破坏性仲裁。多个节点同时发送时,ID值最小的优先发送,其他节点自动退出,不会破坏数据。
- 硬件CRC校验。每个CAN帧都有15位CRC,接收端硬件自动校验,错误帧自动重发。
- 差分信号。CAN_H和CAN_L的电压差表示逻辑状态,抗共模干扰能力强,可以走几十米的线缆。
CAN的数据速率:经典CAN最高1Mbps(总线长度不超过40米),CAN FD最高8Mbps,数据段最大64字节。在机器人中,CAN常用于电机驱动器通信(比如ODrive、Moteus)和多关节协调控制。
CAN总线的物理层也值得了解。CAN收发器(比如TJA1050)把MCU的TX/RX信号转换为差分信号。总线两端各需一个120Ω终端电阻,匹配线缆阻抗,防止信号反射。如果忘记加终端电阻,通信会在高波特率下出错。总线上节点越多,每个节点的输入阻抗并联后越低,所以有最大节点数的限制(经典CAN约110个节点)。
四种协议的对比
面试中经常让你对比这四种协议。核心维度:
| 维度 | UART | SPI | I2C | CAN |
|---|---|---|---|---|
| 线数 | 2(TX/RX) | 4+CS | 2(SCL/SDA) | 2(差分) |
| 速率 | ~1Mbps | ~80MHz | ~3.4MHz | ~8Mbps(FD) |
| 双工 | 全双工 | 全双工 | 半双工 | 半双工 |
| 多设备 | 不支持 | 需多CS | 地址寻址 | 消息仲裁 |
| 距离 | 短 | 短 | 短 | 长(差分) |
| 可靠性 | 低 | 中 | 中 | 高(CRC+重发) |
选择原则:短距离高速用SPI,短距离多设备省IO用I2C,长距离高可靠用CAN,简单调试用UART。
面试要点
SPI的四种模式。CPOL决定时钟空闲状态(0=低,1=高),CPHA决定采样边沿(0=第一边沿,1=第二边沿)。Mode 0最常用(空闲低电平,第一边沿采样)。面试时能画时序图说明CPOL和CPHA的含义,基本就过关了。
I2C的START和STOP条件。START:SCL高电平期间SDA从高到低。STOP:SCL高电平期间SDA从低到高。这两个条件不传输数据,只用于标记通信的开始和结束。
CAN的CSMA/CD+AMP。载波监听多路访问/碰撞检测+仲裁按消息优先级。这个机制保证了高优先级消息总能及时发送——在机器人控制中,急停信号的ID设得最小,确保最高优先级。
实际项目中如何选择协议。面试官经常给你一个场景让你选型。关键考虑因素:数据量(每秒多少字节)、实时性要求(延迟容忍度)、拓扑结构(点对点还是多点)、环境(干扰强度、距离)。把这些因素列清楚,选型自然就出来了。不要只背协议参数,要能结合场景分析。
给你的建议
实际项目中,这四种协议经常混合使用。一个典型的机器人系统:UART接GPS和蓝牙,SPI接IMU和Flash,I2C接气压计和磁力计,CAN接电机驱动器。
调试通信问题时,逻辑分析仪是最好的工具。一个几十块钱的逻辑分析仪可以抓取SPI/I2C/UART的波形,比示波器方便得多。CAN的调试需要专门的CAN分析仪(比如PCAN或Kvaser),但也可以用逻辑分析仪看差分信号。
写驱动时,先读芯片的数据手册确认时序要求(建立时间、保持时间),再配置MCU的外设寄存器。不要凭感觉配置——SPI的Mode配错一个位,数据就全是乱的。
上一篇:第320篇 嵌入式C编程实践
下一篇预告:第322篇 CAN总线深入解析
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)