从电气特性、时序原理到STM32 HAL代码实现,系统对比三大串行通信协议,提供可直接落地的嵌入式物联网项目通信接口选型决策矩阵
I2C、SPI、UART是嵌入式系统中最核心的三种串行通信协议。对于一个典型的物联网终端设备——如同时通过I2C连接温湿度传感器、SPI连接LoRa无线模块、UART连接4G通信模组的RTU远程终端——三种协议的正确选型与配置直接决定系统的通信效率、功耗表现和长期稳定性。本文从协议架构、电气特性、性能参数到代码实现进行全维度对比,帮助工程师建立科学的通信接口选型决策框架。
I2C(Inter-Integrated Circuit)由飞利浦公司于1982年推出,采用两根信号线:SDA(数据线)和SCL(时钟线)。其核心特征是支持多主多从架构,通过7位或10位地址寻址从设备,总线仲裁依靠线与逻辑实现。
I2C的时序分为四种信号:起始条件(S)、停止条件(P)、应答(ACK)和非应答(NACK)。标准模式速率100kbps,快速模式400kbps,快速模式+ 1Mbps,高速模式3.4Mbps。在实际MCU项目中,400kbps是最常用的工作速率,足以满足大多数传感器的数据吞吐需求。
SPI(Serial Peripheral Interface)由Motorola提出,采用四线结构:MOSI(主出从入)、MISO(主入从出)、SCK(时钟)和CS(片选)。与I2C不同,SPI为每个从设备分配独立的CS线,实现点对点通信,天然支持全双工数据传输。
SPI的时钟极性(CPOL)和时钟相位(CPHA)组合成四种工作模式(Mode 0~3),不同外设芯片对模式要求各异。例如W25Q128闪存通常使用Mode 0,而ILI9341 TFT驱动芯片要求Mode 0或Mode 3。STM32的SPI外设最高支持50MHz时钟(受限于GPIO翻转速度和PCB布线),实际工程中10~20MHz是可靠工作的常用范围。
UART(Universal Asynchronous Receiver/Transmitter)是最古老的串行通信方式,仅需TX和RX两根线即可完成全双工通信。其异步特性意味着收发双方必须预先约定相同的波特率,典型值包括9600、115200、921600bps。
UART帧结构包含起始位(1bit)、数据位(5~9bit)、校验位(可选)和停止位(1~2bit)。以115200bps、8N1配置为例,每传输1字节实际需要10bit时间,理论有效吞吐量为11.52KB/s。在嵌入式开发中,UART因其简单可靠,广泛用于调试输出、GPS模块通信、蓝牙模组对接等场景。
| 对比维度 | I2C | SPI | UART |
|---|---|---|---|
| 信号线数量 | 2根(SDA+SCL) | 4根(MOSI+MISO+SCK+CS) | 2根(TX+RX) |
| 通信方式 | 半双工 | 全双工 | 全双工 |
| 拓扑结构 | 多主多从总线 | 一主多从(每从独CS) | 点对点 |
| 寻址方式 | 7位/10位地址 | 硬件片选CS | 无地址,直连 |
| 典型速率 | 100k~400kbps | 10~20MHz | 115200~921600bps |
| 最大理论速率 | 3.4Mbps(Hs模式) | 50MHz+(受限于物理层) | 10Mbps+(RS-485) |
| 流控制 | 时钟拉伸(Clock Stretching) | 无(需软件协议层) | RTS/CTS硬件流控(可选) |
| 错误检测 | ACK/NACK | 无硬件校验 | 奇偶校验位(可选) |
| 引脚扩展性 | 优(总线挂载多设备) | 差(每从需独CS) | 差(仅点对点) |
I2C总线采用开漏输出结构,必须外接上拉电阻。阻值选择需要权衡上升时间与功耗:阻值过小会增加总线电流(I = VCC/R),阻值过大会导致上升时间超标。
根据NXP I2C规范,标准模式(100kbps)要求上升时间tr ≤ 1000ns,快速模式(400kbps)要求tr ≤ 300ns。上升时间近似公式为tr ≈ 0.847 × R × Cb,其中Cb为总线电容(典型值50~200pF)。以3.3V供电、Cb=100pF、目标tr=200ns为例:
R ≈ tr / (0.847 × Cb) = 200ns / (0.847 × 100pF) ≈ 2.36kΩ
工程实践中,3.3V系统常用2.2kΩ~4.7kΩ,5V系统常用4.7kΩ~10kΩ。若总线挂载设备较多或走线较长,应适当减小阻值或采用总线缓冲器(如PCA9515)。
SPI的高速时钟信号对PCB布线敏感。当SCK频率超过10MHz时,走线长度、阻抗匹配和串扰成为关键问题。经验法则:SCK走线长度应控制在λ/20以内(λ为信号波长),对于20MHz信号,λ=15m,λ/20=750mm。这意味着在常规PCB尺寸下,布线长度通常不是限制因素,但过孔和连接器会引入阻抗不连续。
为降低串扰,MOSI/MISO与SCK之间应保持至少3倍线宽间距;若使用四层板,将高速SPI信号布置在内层(带状线)可有效抑制EMI。对于超过30cm的板间连接,建议在SCK线串联22~47Ω端接电阻,抑制信号反射。
标准UART使用TTL电平(0V/3.3V或0V/5V),通信距离通常限制在1~2米。工业场景中需要通过电平转换芯片扩展:
在RTU远程终端设计中,RS-485是连接Modbus从设备的标准物理层。终端电阻(120Ω)应安装在总线两端,中间节点不应挂载终端电阻,否则会导致信号衰减。
| 应用场景 | 推荐协议 | 理由 | 典型外设 |
|---|---|---|---|
| 低速传感器(温度/湿度/压力) | I2C | 2线简单、总线挂载、功耗低 | SHT30、BMP280、MPU6050 |
| 高速数据采集(ADC/Flash/显示屏) | SPI | 全双工、速率高、实时性好 | W25Q128、ADS1256、ST7735 |
| 无线模组通信(4G/LoRa/蓝牙) | UART | 标准化AT指令、距离远(RS-485) | EC200S、E22-400T30D、HC-05 |
| EEPROM/FRAM存储 | I2C或SPI | I2C省引脚,SPI速度快 | AT24C256、FM25L16 |
| 多传感器阵列(8+设备) | I2C | 仅需2线,地址分配灵活 | 多个同型号传感器(需地址引脚) |
| 实时控制(电机驱动/DAC) | SPI | 低延迟、确定性时序 | MCP2515、DAC8830 |
在电池供电的物联网设备中,接口功耗是选型关键。以3.3V供电、100kbps速率为例,三种协议的静态与动态功耗对比如下:
结论:对于低功耗传感器节点,I2C和UART优于SPI;需要高速 burst 传输时,SPI的效率更高。
// I2C1 初始化配置(400kbps Fast Mode)
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
HAL_I2C_Init(&hi2c1);
// 发送测量命令并读取数据(SHT30地址0x44)
uint8_t cmd[2] = {0x2C, 0x06}; // 单次测量,重复性高
uint8_t data[6]; // T_msb, T_lsb, T_crc, H_msb, H_lsb, H_crc
HAL_I2C_Master_Transmit(&hi2c1, 0x44<<1, cmd, 2, 100);
HAL_Delay(15); // 等待测量完成
HAL_I2C_Master_Receive(&hi2c1, 0x44<<1, data, 6, 100);
// 数据解析
uint16_t temp_raw = (data[0] << 8) | data[1];
float temperature = -45 + 175 * ((float)temp_raw / 65535);
// SPI1 初始化配置(18MHz, Mode 0, MSB First)
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL=0
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA=0
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 72MHz/4=18MHz
HAL_SPI_Init(&hspi1);
// 页写入(256字节/页)
HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET);
uint8_t cmd[4] = {0x02, (addr>>16)&0xFF, (addr>>8)&0xFF, addr&0xFF}; // Page Program
HAL_SPI_Transmit(&hspi1, cmd, 4, 100);
HAL_SPI_Transmit(&hspi1, buffer, len, 1000);
HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET);
// USART2 初始化配置(115200bps, 8N1)
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(&huart2);
// 启动DMA循环接收(缓冲区256字节)
#define RX_BUF_SIZE 256
uint8_t rx_buffer[RX_BUF_SIZE];
HAL_UART_Receive_DMA(&huart2, rx_buffer, RX_BUF_SIZE);
// DMA半传输/传输完成中断回调处理环形缓冲区数据
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart == &huart2) {
// 处理后半缓冲区 rx_buffer[RX_BUF_SIZE/2] ~ rx_buffer[RX_BUF_SIZE-1]
process_uart_data(&rx_buffer[RX_BUF_SIZE/2], RX_BUF_SIZE/2);
}
}
在复杂的嵌入式项目中,三种协议常共存于同一MCU。以STM32F407为例,其具备3个I2C、3个SPI和4个UART外设,引脚规划需遵循以下原则:
当3.3V MCU与5V外设混用时,需进行电平转换。I2C总线可使用TXS0102/PCA9306双向电平转换器;SPI单向信号可用简单的分压电阻(如MISO线使用1.8kΩ+3.3kΩ分压);UART可使用TXB0102或带方向控制的自动切换芯片。
I2C以极简的2线架构和总线扩展能力成为传感器网络的首选;SPI凭借全双工和高吞吐优势主导高速外设通信;UART则以标准化和远距离传输特性(RS-485)在工业互联中不可替代。在实际物联网项目中,没有绝对最优的协议,只有最适合场景的组合。工程师应根据数据速率、引脚资源、功耗预算和物理距离四个维度建立量化评估模型,在方案设计初期完成通信架构的合理规划,避免后期因接口瓶颈导致的全局返工。
本文基于沧州艾诺威电子设计有限公司多个工业物联网项目的实战经验整理,涵盖RTU远程终端、无线传感器节点、工业数据采集终端等产品线的通信接口设计规范。
沧州艾诺威电子 — 国家高新技术企业,20+项国家专利
嵌入式系统开发 · 物联网方案 · AI智能硬件 · 一站式交付
电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应