恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
嵌入式串行总线对比:I2C、SPI、UART、I2S的原理与选型
首页
资讯中心
/
嵌入式串行总线对比:I2C、SPI、UART、I2S的原理与选型
嵌入式串行总线对比:I2C、SPI、UART、I2S的原理与选型
发布时间:2026/9/28 4:00:37
我最早入行的时候被这几种总线折腾得不轻。手头一片传感器要接主控数据手册上写着I2C接口另一片DAC写着SPI音频编解码器又是I2S——偏生UART还要用波特率这个单位跟其它几个格格不入。等到把I2C、I2S、SPI、UART这四类总线从头到尾捋了一遍再看周边电路和示波器波形才真正明白为什么嵌入式系统里它们各占一席。这篇文章就把我积累的对比心得写出来适合刚接触嵌入式通信协议、想系统搞清四种总线区别的开发者也适合已经用了一段时间、但遇到时序问题总靠猜的人。内容不是照抄数据手册的口诀而是从为什么这么设计讲起再落到调试和选型上。1. 四种串行总线的出身与定位差异1.1 UART从RS-232时代走来的异步老兵UART的历史可以追溯到计算机还没有完整总线概念的年代最广为参考的行业标准之一是16550系列UART。它的核心思路很简单一根发送线TX、一根接收线RX两端各自按约定的波特率采样电平变化。没有专门的时钟线收发双方靠的是预先知道大家要用同一个速度说话。数据帧从低电平起始位开始后面跟着数据位校验位可选最后是停止位。这种各管各钟的异步方式决定了UART最适合两片设备之间一台对一台的通信。它不需要在PCB上多拉一根时钟也让设备之间没有主从之分谁都可以先开口。很多老式工业仪表、GPS模块、蓝牙透传模块至今还在用UART对接因为接口语义简单随便一颗MCU的串口外设就能跑起来。但UART的劣势也很明显一是速度受波特率限制常用范围从9600到921600不等再往上受时钟精度和导线长度约束明显二是没有设备寻址机制多台设备之间通信得靠额外硬件或协议层解决三是收发两端时钟偏差大了就会出乱码。所以它不是一个总线意义上的协议更像是一条串行管道。1.2 SPI为了快而生的同步主从总线SPISerial Peripheral Interface诞生时打的招牌就是快。它用四根线完成全双工通信SCLK提供共享时钟MOSI从主机发往从机MISO从从机发往主机CS片选信号单独选定某个从机。因为时钟由主机主动产生从机只要跟着边沿采样速率可以轻松跑到几十MHz比UART那种靠波特率对表的方式高效得多。SPI是典型的主从结构主机掌握节奏和片选引脚。你可以把CS想象成点名CS拉低那个从设备就被选中才开始听到SCLK上的脉冲。也正因如此SPI天然适合传感器、Flash、ADC/DAC这类对吞吐率有要求的外设。我做FPGA与SPI ADC对接时SCLK跑几十兆赫连续采样的数据能直接送入FIFO这要是换UART传光换算波特率就已经劝退了。缺点是引脚占用偏高每加一个从机通常要再加一根CS加上半双工场景下的广播能力弱如果多个从机想主动上报数据协议层处理起来相当别扭。它在硬件上很高效在多个设备共享总线这件事上并不擅长。1.3 I2C用最少引脚换灵活性的小网线I2CInter-Integrated Circuit的思路与SPI相反在把引脚占用压到极致一根SCL时钟线加一根SDA数据线就够挂一片总线上几十个设备。每个设备有独立地址主机发起起始条件送出目标地址和读写位从机应答。这就是为什么I2C常被形容成嵌入式世界的小网线——它确实是一个多主可仲裁的总线结构。I2C的好处不只是省引脚。因为地址和读写方向都在数据帧里定义一条总线能接大量低速外设——EEPROM、温湿度传感器、触摸控制器、实时时钟都很常见。我在调试GT911触摸屏时整条I2C总线上除了它还有一颗PMIC和一颗距离传感器三颗芯片地址不冲突一次扫描就能全部枚举出来。代价是速率不如SPI标准模式100kHz快速模式400kHz高速模式也就1MHz出头3.4MHz的超高速模式在普通MCU上很少用。I2C还要在SDA和SCL上配上拉电阻如果上拉选得太大边沿爬升慢高速率下波形会惨不忍睹。这个后面专门讲。1.4 I2S只为数字音频而生的专用总线I2SInter-IC Sound跟上面三者都不太一样它是为数字音频流设计的点对点同步串行总线。典型引脚包括BCLK位时钟、LRCK左右声道帧同步和SD串行数据部分设备还会额外带一根MCLK主时钟用来给音频PLL提供精准时钟源。I2S之所以要单独存在是因为音频数据要求时序精密且持续稳定中间卡顿或抖动会直接被耳朵捕捉。LRCK在一个位时钟周期内拉高/拉低分别代表右/左声道SD按从高位到低位的顺序在BCLK边沿送出采样点数据。这个时分复用结构让左右声道能严格对齐不会出现相位偏差。写代码驱动ESP32-C3的I2S输出音频时最直接的体会就是配置完BCLK和LRCK极性后音频流真是行云流水完全不用像UART那样担心采样率偏了之后声音变调。但它也是四种总线里最专的一种基本没有设备寻址和多设备共享能力就是两条设备之间传音频流。如果在一条板上同时存在主控、DAC、ADC就得靠多路I2S或TDM模式扩展。我把这四个的横面对比直接放到下面的表格里方便照着眼睛抓重点。特性UARTSPII2CI2S时钟来源各自独立异步主机产生SCLK主机产生SCL从机可时钟拉伸主机产生BCLK/LRCK引脚数量2TX/RX4可选MISO精简2SDA/SCL3~4BCLK/LRCK/SD/MCLK通信方向全双工全双工半双工全双工音频流单向典型拓扑结构点对点一主多从CS选择多主多从地址寻址点对点或少量芯片的TDM常用速率9600~1M数十MHz级别100k/400k/1M/3.4M取决于采样率与位深寻址能力无无靠CS有7位/10位地址无典型场景日志、蓝牙透传、GPSFlash、ADC/DAC、显示屏控制器温度/湿度传感器、EEPROM、触摸屏音频DAC/ADC、蓝牙音频、智能音箱2. 时序、帧格式与速率真正拉开差距的地方2.1 时钟从哪里来同步与异步的分水岭四者最大的分野是同步与异步。UART没有时钟线接收端在波特率时钟下定时采样RX线。两端的振荡器误差必须控制在一定范围比如通常要求误差小于2%~3%。误差一大采样点逐渐偏移到数据位边缘轻则偶发乱码重则完全对不上。这个特性在调试中很反直觉你逻辑分析仪直接解析没问题因为分析仪同步采样了完整波形可是实际MCU的UART外设可能已经在临界点挣扎了。SPI、I2C、I2S则是同步协议发送端和接收端对着同一根时钟线操作。因此速率的提升更多受制于线上的上升沿、下降沿时间和接收端的建立保持时间而对两端振荡器精度没那么敏感。这也是为什么SPI敢跑几十MHzI2C跑通400kHz并没那么痛苦。协议设计的取舍从根上决定了它们各自的适用面。2.2 数据帧里藏着哪些规矩UART一帧的时序特别像一段口语对话空闲时TX线保持高电平发送起始位先拉低宣告我开始说了然后按低位先行的顺序送出数据位可选的校验位用来做奇偶检错最后停止位拉高表示这句说完了。接收端专门检测下降沿来找到起始位避开采样在数据中间最稳的位置。帧结构简单开销也就1~2个bit短报文传输效率很高。SPI的数据帧就更简单了SCLK每一个脉冲MOSI/MISO各送出一个bit。因为没有起始位、停止位这类开销吞吐效率极高。但SPI有个经典陷阱叫CPOL和CPHA它们决定时钟空闲极性以及采样点落在哪个边沿。四张模式表让不少初学者卡壳——表格我放在后面调试时直接对照就好。I2C的帧格式则是最复杂的先是SCL高电平时SDA出现下降沿也就是起始条件然后主机送7位地址加1位读写标志被选中的从机在第9个时钟周期把SDA拉低表示应答读写数据每个字节后面同样跟一个应答位最后在SCL高电平时SDA出现上升沿即停止条件。理解起始条件与停止条件的电平组合是看懂I2C时序图的第一步大多数挂死在总线上的故障都出在这两个边沿上。I2S的帧结构又不一样。LRCK在每个声道采样周期切换高低电平标示当前数据属于左还是右声道SD在BCLK的边沿同步送出每一个位。以16bit采样率为例一个声道采样点会占16个BCLK周期。有些器件会支持32bit槽位来兼容不同位深和格式但基本原理是TDM的雏形——用固定的时隙划分左右声道。2.3 速率与效率不能只看表格里的MHz很多人第一眼看到SPI几十MHz、UART最大到1M多就说SPI最快。实际传输效率要综合时钟速率、帧开销、协议开销和从机响应速度几方面看。对于大批量连续数据——比如从Flash里倒数据、给显示屏刷新一帧画面——SPI是绝对王者I2C受应答位和地址帧开销拖累传大块数据时等于每个字节多付1个bit的确认费明显吃亏UART没有应答机制但每帧至少要付1个起始位和1~2个停止位的开销短报文时效率还行长报文时等于周期性交税。I2S的效率取决于音频采样率和位深。比如48kHz、16bit、双声道数据率就只有约1.536Mbps但是对实时性和抖动要求远高于I2C这类低速传感器总线。速率只是冰山一角在规定时间内稳定送到才是音频场景真正的考核目标。2.4 SPI模式表调试时直接查模式CPOLCPHA时钟空闲电平采样边沿Mode 000低电平上升沿Mode 101低电平下降沿Mode 210高电平下降沿Mode 311高电平上升沿多数SPI Flash、SD卡、常见ADC支持Mode 0或Mode 3。设备数据手册通常会把时序图画得很细调试时不要想当然地套默认模式先用逻辑分析仪抓一把再用模式逐个试比在代码里盲猜快得多。我有一次在一块板上调RK3588的SPI接口接NOR Flash启动引导折腾了一上午最后发现从机只支持Mode 0而内核设备树默认配成了Mode 3。设备树里spi-mode或者spi-cpha/cpol参数检查一下这种低级问题就避免掉了。3. 引脚拓扑与硬件设计那些决定成败的细节3.1 I2C开漏为什么必须配外部上拉I2C的SDA和SCL引脚内部是开漏结构只能主动拉低不能主动输出高电平。想让线变高必须靠外部上拉电阻。选电阻不能随手焊一个4.7k就算数阻值太大RC充电时间常数很长上升沿爬得像蜗牛400kHz模式下时序容易违规阻值太小灌入电流偏大低电平电压可能压不住还增加损耗。常规1.8V系统用1~2k3.3V系统用2.2~4.7k5V系统用4.7~10k实际值依据总线上的设备数量和走线长度微调——总线挂得越多、线越长上拉就要适当选小一些来保边沿。用软件GPIO模拟I2C时也要注意同样问题。很多开发者只在代码里把SDA配成推挽输出结果从机设备多或走线长时波形边沿叠加上冲下冲通信时好时坏。真遇到诡异问题先示波器看SDA的上升沿是否圆了。3.2 SPI的片选硬件片选与软件片选之争SPI的CS引脚至少有两种玩法。硬件片选由MCU的SPI外设自动控制发送数据时自动拉低、结束时拉高甚至SPI的FIFO特性支持下可以连续帧无缝片选。这设计在配合DMA高速搬运数据时很常用——我习惯把操作Flash的片选交给硬件管理避免CPU中断造成片选毛刺。软件片选则让任意GPIO口自己决定拉高拉低。它能任意扩展从机数量也让代码在片选时序上更可控比如某些传感器要求CS拉低后必须等一段时间再发起SCLK。但软件片选容易踩坑发送完一帧数据后如果马上拉高CS从机可能还没来得及处理最后一个bit如果发送函数的缓冲还没刷新完你又切了别的任务CS毛刺会被从机误识别成新命令。我的经验是高吞吐场景尽量用硬件片选加DMA特殊时序传感器才用软件片选并在CS变低前加个几个us级别的延时。3.3 电平匹配、共地与信号完整性四种总线里除I2C是开漏天然包含电平兼容的灵活性其余在对接不同电压设备时都得小心。SPI和UART的电平转换一般用双向电平转换芯片加MOSFET方案或者干脆选带VIO引脚、支持电平直接对接的器件。I2C则可以通过上拉电阻拉到合适电平——比如3.3V主控接5V器件SDA/SCL上拉至5V会产生电平不匹配应上拉至3.3V或者用转换芯片。共地问题同样关键。板内通信时地平面通常完整问题不大板间接UART或者跨接SPI时两头地之间存在电位差轻则通信错乱重则烧接口。调试时摸一下两边外壳是不是同电位是最便宜也最容易被忽略的排障手段。信号完整性上SPI高速时钟线布板要注意串阻和回流地I2C则要注意上拉电阻位置离主控越近越好。I2S的信号线虽然速率不算特别高但音频应用对BCLK抖动敏感尽量缩短走线、加粗地线避免与开关电源的SW节点平行走线。3.4 I2S走线和时钟的音频特殊要求I2S的BCLK往往由音频主时钟MCLK分频而来MCLK的抖动会直接影响DAC还原出来的声音质量。树莓派这类单板机接USB声卡或I2S DAC时偶尔出现爆音很大一部分原因就是软件时钟管理引入的抖动过大或者板载I2S走线离WiFi天线太近。调试音频问题不要只盯协议格式先看BCLK波形是否干净、LRCK是否稳定。用逻辑分析仪看I2S波形时我习惯把BCLK和LRCK同时抓上确认它们对齐关系没跑偏。4. 调试工具与常见故障排查实录4.1 逻辑分析仪是你最重要的帮手四种协议都基于电平变化和时钟沿逻辑分析仪是最合适的观察工具。卖二三十块钱的逻辑分析仪配Sigrok/PulseView足够抓I2C、SPI、UART还有I2S解码器。调试时按顺序接好通道UART接RX/TXSPI接SCLK/MOSI/MISO/CSI2C接SCL/SDAI2S接BCLK/LRCK/SD。采样率至少要比信号速率高4倍实际我习惯做到8~10倍否则边沿细节看不清。波形抓回来别急着看解码结果先看原始波形形状。I2C的起始停止条件对不对ACK是否存在SPI的CS是否在实际数据前后留足了保护时间UART起始位下降沿是否干净这些细节在解码器眼里会被翻译掉但bug往往藏在原始波形里。4.2 读波形以I2C写EEPROM为例拿最常见的I2C写EEPROM场景来走一遍。主机发出起始条件然后发送7位设备地址和0写位EEPROM拉低ACK。接着主机连发两个字节的片内寄存器地址和数据每发一字节等一个ACK。写完以后主机发停止条件。如果示波器上ACK始终是高说明总线上存在地址不匹配、应答时序不对或设备根本没上电。如果ACK在某个字节后消失通常是设备正处于内部写周期此时它不响应外部访问要等数毫秒。这个现象常常让人误以为代码死锁其实读器件手册里的写周期时间就豁然开朗。还有一类更隐蔽的问题I2C从机主动更新主机寄存器。比如某些触摸芯片检测到手势时想主动通知主控而I2C协议本身又不允许从机先开口。现场总线上经常看到主机正在写配置时从机强行拉低SCL做时钟拉伸或者干脆在一个不顺眼的时刻尝试发起通信导致总线仲裁错误。遇到这种局面不能光在主机侧死等合理的做法是在从机允许的中断引脚上把事件信号引出来或者在总线空闲时才允许从机切地址方向。4.3 我在实际项目中踩过的三个坑第一个坑是GT911的I2C通信失败。当时现象是主机偶尔扫不到触摸控制器地址复位后第一次通信正常但一段时间后就再没应答。用逻辑分析仪看发现SDA线上每到扫描时就会出现一个莫名其妙的低电平毛刺。最后定位到问题是触摸控制器的INT引脚被配置成开漏输出但没有接上拉当它想拉高电平却拉不上去时造成了电平悬浮间接干扰了同一条I2C总线的SDA。修复方案很简单给INT加上拉电阻问题消失。排查I2C问题永远要把同总线上所有引脚的电平状态纳入怀疑范围。第二个坑是I2C总线挂死。现象是主机发完起始条件后一直收不到ACK后续代码卡在等待标志位上。翻示波器SDA一直低SCL却还在继续翻转。原因是某个从机在极端情况下内部逻辑跑飞死死把SDA拉低不放。解决思路是加总线恢复机制在启动阶段连续切换SCL若干次再把SDA进行一次停止条件强制释放总线如果SCL也被拉死只能用硬件复位或电源循环。不少驱动库已经内置了这种Bus Recovery流程但很多应用工程师根本不知道它存在遇到问题只会重启浪费不少时间。第三个坑是UART接收端的乱码与波特率偏差。某次接一个蓝牙透传模块标称波特率115200主机也是115200但抓包能看到数据位中间有翻转毛刺接收端偶发丢字节。后来一量模块实际波特率偏了约2.5%恰好卡在容忍边界上。解决方式是改用更精确的时钟源或者把波特率降到57600偏差占比随之变小。UART调试时遇到时好时坏先怀疑时钟精度而不是先怀疑协议配置。5. 项目选型什么场景该用谁5.1 一张表快速决定总线选择项目里真正到选型环节时不需要背一大堆特性按下面几个问题的优先级走一遍答案基本就出来了。判断维度优先考虑的协议原因需要高速、大批量连续传输数据如Flash读写、屏显SPI时钟高、开销低、全双工需要挂载多个低速外设传感器、EEPROM、RTCI2C两根线挂几十个设备有地址寻址仅两台设备简单通信日志、透传、GPS、工业仪表UART简单可靠工具链成熟点对点天然匹配传输的是音频流DAC、ADC、蓝牙音频I2S帧结构与音频采样天然对应时分复用左右声道设备可能有多主机同时发起通信多MCU互连、热插拔状态I2C多主模式带仲裁和时钟同步实际项目里很少只用一种总线。一块主控板上SPI伺候Flash和无线模块I2C挂了一排传感器UART接调试口和蓝牙透传I2S接音频Codec这是最常见的长相。选型时不要为了统一总线而强行把SPI设备挂上I2C转接芯片多一层转换就多一层故障点得不偿失。5.2 混合使用的常见组合与设计思路混合使用总线时要考虑电源域、电平域和中断引脚的分配。比如一颗MCU的3.3V电源域下既有SPI Flash又有I2C传感器就无需电平转换但如果传感器是5V版本I2C总线又已经挂在3.3V上拉就得选支持宽电压的器件或加转换电路。时钟域也要分开考虑。SPI高速时钟和I2C低速时钟在PCB上最好分区走线避免高速SCLK的谐波耦合到I2C的SDA上引起偶发误码。I2S的MCLK如果和SPI的SCLK频率接近走线尤其要拉开距离——我曾经在调试一块音频板时MCLK与SPI Flash的SCK在PCB上平行走了5厘米导致音频底噪明显后来把I2S走线换到内层并加地隔离底噪立刻降下来。中断引脚分配同样是重点UART没那么多花样SPI从机要主动上报事件时通常配一个IRQ脚I2C触摸屏和传感器也爱用INT脚。设计时先列一张所有中断引脚电平属性表避免两个开漏中断引脚都靠同一个上拉导致电平互相影响。5.3 新兴场景GPIO模拟、USB转总线与FPGA很多时候主控的硬件外设不够用或者要临时验证方案GPIO模拟就显得很有价值。用GPIO模拟I2C是最常见的模拟SPI的难度要更大一些因为高频下时钟的抖动和GPIO翻转延迟容易让时序不合格。Python调用USB模拟SPI接口这类玩法在实验室里也常出现用一块USB转SPI适配器在PC上直接读写SPI设备适合原型验证但不太适合量产实时控制。FPGA配合SPI ADC时硬逻辑可以保持严格的时钟关系这种场景我强烈建议把SPI的CPOL/CPHA参数直接做成可配置寄存器调试时能少改很多代码。I2C扩展话题也值得多提一句当一条总线上设备太多或地址冲突时I2C多路复用器如TCA9548A可以把总线分成几个独立分支。调试这类拓扑时别忘了地址扫描要在正确的通道上做——我在调试一块板子时设备总是不在预期地址上枚举出来最后发现扫描器落在了默认通道目标设备却在另一路分支换了通道后立刻识别。这个问题看似低级但真实项目中特别容易踩。5.4 最后几句实操体会四种协议用久了我的心得是不要神化任何一种总线。SPI快但引脚多I2C省线但速度慢UART简单但没寻址I2S专精但只服务音频。真正的高手不会去争谁最强而是拿到需求后快速判断该用谁然后第一时间用逻辑分析仪把初始化时序抓下来存档——这个习惯帮我省了无数回头排查的力气。还有个小技巧把四类协议的关键参数写在一个头文件里比如总线基地址、引脚号、模式、速率、超时时间方便随时对比查阅。下次接手新板子时光看头文件就能快速定位这条总线配得有没有常识而不是等到运行异常再一片片量波形。