UART、I2C、SPI 三大串行协议对比与选型
UART、I2C、SPI 三大串行协议对比与选型
做嵌入式开发,串行通信协议是绕不开的基本功。UART、I2C、SPI 这三大协议几乎出现在每一个项目中,但它们的特性、适用场景和”坑点”差异很大。选错了协议,轻则布线复杂,重则通信不稳、调试困难。
本文从硬件连接到软件要点,把三者讲清楚,并给出选型建议。
一、三大协议速览
| 特性 | UART | I2C | SPI |
|---|---|---|---|
| 引脚数 | 2(TX/RX) | 2(SCL/SDA) | 4(SCLK/MOSI/MISO/CS) |
| 通信方式 | 异步 | 同步 | 同步 |
| 拓扑 | 点对点 | 多主多从(总线) | 一主多从 |
| 速度 | 常用 115200bps | 100k/400k/1M/3.4M | 可达几十 MHz |
| 硬件复杂度 | 最低 | 中等(需上拉电阻) | 较高(独立 CS 线) |
二、UART:最朴素的异步通信
UART 不需要时钟线,靠双方约定一致的波特率来”同步”,因此叫异步通信。它是从设备调试、GPS、蓝牙模块(透传)、串口屏的首选。
/* STM32 HAL 库 UART 收发示例 */
uint8_t buf[32];
/* 阻塞发送 */
HAL_UART_Transmit(&huart1, buf, sizeof(buf), 100);
/* 中断接收(常用方式) */
HAL_UART_Receive_IT(&huart1, buf, 1);
UART 的坑主要有两个:一是波特率不匹配导致乱码;二是没有硬件流控时容易丢数据。高速大数据量场景下,要配合 DMA 使用。
三、I2C:两根线的总线标配
I2C 用一根数据线 SDA + 一根时钟线 SCL,就能挂载上百个设备(通过 7 位或 10 位地址区分)。特别适合传感器、EEPROM、RTC、PMIC 这类低速外设。
/* 读取一个 I2C 传感器的寄存器 */
uint8_t reg = 0x0F; /* 寄存器地址 */
uint8_t data = 0;
HAL_I2C_Master_Transmit(&hi2c1, SENSOR_ADDR, ®, 1, 100);
HAL_I2C_Master_Receive(&hi2c1, SENSOR_ADDR, &data, 1, 100);
I2C 有两个经典坑:
- 必须加上拉电阻(典型 4.7kΩ 到 VCC),否则总线无法拉高;很多”读不到数据”的问题其实是没有上拉。
- 总线死锁:主机复位时从机可能还在拉低 SDA,导致总线一直被占用。解决办法是软件上做九脉冲恢复。
四、SPI:高速外设的利器
SPI 是同步通信,速度快、协议简单,是小屏(OLED/TFT-LCD)、Flash(W25Q 系列)、ADC/DAC、IMU 等高速外设的首选。代价是每个从设备都要一根独立的 CS(片选)线。
/* SPI 读取 W25Q64 Flash 的 JEDEC ID */
uint8_t cmd = 0x9F;
uint8_t id[3] = {0};
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); /* 拉低 CS */
HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);
HAL_SPI_Receive(&hspi1, id, 3, 100);
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); /* 拉高 CS */
SPI 的坑主要在时钟极性(CPOL)和相位(CPHA)这两个模式参数上——主从双方必须配置一致,否则数据错位。另外要留意 CS 的时序,很多从设备要求 CS 在传输前后有足够的高电平间隔。
五、选型决策
记住几个原则:
- 点对点、低速、调试/透传 → UART
- 总线多设备、低速、引脚紧张 → I2C
- 点对点/多从、高速、大吞吐 → SPI
- 超长距离或抗干扰要求高 → 考虑 RS485(UART 的差分扩展)或 CAN
实际项目中三者经常同时出现:主控用 UART 接调试串口,用 I2C 挂传感器,用 SPI 驱动屏幕和 Flash。熟练区分并正确选型,是嵌入式工程师的基本素养。
总结
UART 胜在简单通用,I2C 胜在省引脚和支持总线拓扑,SPI 胜在速度。三者没有绝对的优劣,关键是根据速率需求、引脚预算、设备拓扑、抗干扰要求来匹配。搞懂了这三根”线”,你就打通了 90% 嵌入式外设通信的任督二脉。