SPI、UART与I2C总线技术对比与应用指南 SPI、UART、I2C总线的区别与联系1. 串行通信总线概述在现代嵌入式系统中串行通信总线因其布线简单、成本低廉等优势已成为芯片间通信的主要方式。本文将深入分析三种最常用的串行总线协议SPI、UART和I2C从工作原理、电气特性到应用场景进行系统对比。2. SPI总线技术解析2.1 基本特性SPI(Serial Peripheral Interface)是一种高速、全双工、同步串行通信总线具有以下核心特征3~4线接口(SCLK, SDI, SDO, CS)主从式工作模式硬件实现简单无流控机制2.2 信号定义标准SPI总线包含以下信号线信号线方向功能描述SCLK主→从同步时钟信号SDI从→主主设备数据输入/从设备数据输出SDO主→从主设备数据输出/从设备数据输入CS主→从从设备片选信号2.3 工作原理SPI数据传输基于时钟边沿触发主设备通过CS线选中目标从设备主设备产生SCLK时钟信号(频率通常1-50MHz)数据在时钟上升沿/下降沿改变在相反的边沿采样每次传输至少需要8个时钟周期完成1字节传输2.4 工程应用特点优势全双工通信硬件实现简单传输速率高时钟由主设备控制时序灵活局限无硬件流控机制多从机系统需要较多GPIO通信距离短(通常30cm)典型应用场景Flash存储器、ADC/DAC转换器、显示屏驱动等。3. UART通信协议分析3.1 基本特性UART(Universal Asynchronous Receiver Transmitter)是异步串行通信协议主要特点包括2线制(TX, RX)全双工通信无时钟信号波特率可配置3.2 帧结构标准UART帧包含起始位(1位低电平)数据位(5-9位)校验位(可选)停止位(1-2位高电平)3.3 关键参数参数典型值波特率300bps-3Mbps数据位8位校验方式无/奇/偶校验停止位1位3.4 工程应用特点优势实现简单支持长距离通信(配合电平转换)广泛兼容性局限异步通信需严格匹配波特率效率低于同步协议无多设备寻址机制典型应用调试接口、Modem通信、GPS模块等。4. I2C总线深度解析4.1 基本特性I2C(Inter-Integrated Circuit)是半双工同步串行总线核心特征2线制(SCL, SDA)多主多从架构硬件地址寻址总线仲裁机制4.2 协议层次I2C通信包含以下阶段起始条件(SDA在SCL高电平时拉低)地址帧(7/10位)读写位应答位数据帧(8位)停止条件(SDA在SCL高电平时拉高)4.3 速度模式模式速率特点标准模式100kbps基本速率快速模式400kbps兼容标准模式高速模式3.4Mbps需要特殊硬件支持4.4 工程应用特点优势硬件资源占用少支持多主设备内置地址机制总线仲裁避免冲突局限半双工通信上拉电阻影响传输距离速率低于SPI典型应用传感器、EEPROM、RTC时钟等。5. 三种总线对比分析5.1 技术参数对比特性SPIUARTI2C通信方式同步异步同步数据方向全双工全双工半双工信号线数量3-422最大速率50Mbps3Mbps3.4Mbps寻址方式硬件片选无软件地址典型应用Flash, ADC调试接口传感器5.2 选型建议高速场景优先考虑SPI多设备组网选择I2C简单调试使用UART长距离通信UART电平转换GPIO受限I2C或软件SPI6. 硬件设计注意事项6.1 SPI设计要点多从机系统需合理规划CS信号注意时钟极性(CPOL)和相位(CPHA)配置高速传输时控制走线长度6.2 UART设计要点两端设备波特率误差应2%长距离传输需添加RS232/485转换芯片注意TX/RX交叉连接6.3 I2C设计要点上拉电阻取值4.7kΩ-10kΩ总线电容不超过400pF注意地址冲突问题7. 软件模拟实现7.1 GPIO模拟SPI// 主机发送1字节 void SPI_WriteByte(uint8_t data) { for(uint8_t i0; i8; i) { CLK_LOW(); if(data 0x80) MOSI_HIGH(); else MOSI_LOW(); delay_us(1); CLK_HIGH(); data 1; delay_us(1); } }7.2 GPIO模拟I2C// I2C起始条件 void I2C_Start(void) { SDA_HIGH(); SCL_HIGH(); delay_us(5); SDA_LOW(); delay_us(5); SCL_LOW(); } // I2C停止条件 void I2C_Stop(void) { SDA_LOW(); SCL_HIGH(); delay_us(5); SDA_HIGH(); delay_us(5); }7.3 软件UART实现// 9600bps 8N1 发送 void UART_Tx(uint8_t data) { TX_LOW(); // 起始位 delay_us(104); // 1/9600秒 for(uint8_t i0; i8; i) { if(data 0x01) TX_HIGH(); else TX_LOW(); data 1; delay_us(104); } TX_HIGH(); // 停止位 delay_us(104); }