ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

嵌入式四大通信总线:I2C、SPI、UART、I2S选型与实战对比

嵌入式四大通信总线:I2C、SPI、UART、I2S选型与实战对比 最近在调一块音频采集板板子上同时挂着好几类外设姿态传感器走 I2C、数字麦克风走 I2S、LCD 走 SPI、调试则全靠 UART。四条“总线”在一个系统里各干各的互不干扰。经常有刚入行的朋友问我i2c、i2s、spi、uart 到底有什么区别哪个更快什么时候该用哪个先把结论说在前面它们不是同一个维度的东西硬比速度没有意义。I2C 适合低速小包寄存器访问SPI 适合高速流式数据I2S 是音频专用流接口UART 是点对点透传和调试的万金油。一个成熟系统往往四种全都在用。这篇文章不打算按教科书顺序从“历史沿革”讲起而是从“为什么系统里有这么多总线”这个真实工程视角出发把四者的定位、物理层时序、选型逻辑和踩坑经验一次性说透。1. 四种总线为什么“各有各的活”先看流量模型再选型很多初学者喜欢把 I2C、SPI、UART 放在一起比“谁快谁慢”但真正决定总线选型的不是速度表上的数字而是设备产生的数据流量模型。传感器是“偶尔读几个字节”Flash 是“一次性灌几兆数据”音频是“永远按照固定节奏吐数据”调试口则是“只要有异常就想看两眼”。流量模型不同天生适合的总线就不同。1.1 寄存器型小包流量I2C 的舒适区温湿度传感器、RTC、触摸屏、EEPROM这类外设的特点是主控大部分时间只读几个字节偶尔写几个配置寄存器。它们对带宽完全没有要求但对“寻址能力”和“接线成本”很敏感。I2C 恰好是为这个场景设计的。一帧数据自带设备地址、寄存器地址支持连续读多字节两根线SDA、SCL就能挂几十个设备每个设备靠地址区分主控不需要为每个外设单独拉一根片选线。这个特性在 PCB 布局上非常值钱——传感器多了之后GPIO 和走线空间都很紧张I2C 的“两根线全搞定”是实打实的优势。所以在实际项目里你看到 I2C 几乎都是传感器、触摸屏、RTC、EEPROM、IO 扩展芯片。偶尔有人问“I2C 能不能传音频/传图像”不是不行是流量模型根本不匹配400kHz 下算上协议开销有效吞吐只有几十 KB/s传一帧 320x240 的 BMP 都要好几秒纯属自讨苦吃。这里还要多说一句标准 I2C 是主机主动轮询的从机不能主动往主机里写数据。所以经常有人问“I2C 从机怎么主动更新主机寄存器”标准做法是做不出来的。工程上的常规解法是从机拉一根独立的 INT 中断脚通知主机“我有新数据了”主机收到中断后再发起 I2C 读。触摸屏 GT911 就是这么干的触摸一触发INT 脚拉低主控赶紧来读。如果你在方案里承诺“从机主动推数据”八成是没想明白 I2C 的仲裁机制。1.2 块状流式流量SPI 的主场Flash 存储、LCD 屏幕、高速 ADC、SD 卡这类外设的特点是数据是大块大块地搬几百 KB 到几 MB 甚至更多而且要持续读写。SPI 在这里是绝对主力原因很直接速率高、全双工、没有地址帧、没有应答位时钟一拉就连续吐数据。SPI 的传输模型是“主控把 CS 拉低选中一个从机然后 SCK 打拍子双向同时移位”。整个过程几乎没有协议开销40MHz 的 SCLK 下标准四线 SPI 连续读的速率可以接近 5MB/s如果用上 Quad 模式四根数据线还能再翻几倍。这也是为什么 NOR Flash、SD 卡、LCD 驱动芯片都愿意用 SPI——它足够原始也就足够快。但 SPI 有个天然短板每个从机都需要一根独立的 CS 片选线。挂 5 个 SPI 设备就要占 5 个 GPIO挂 10 个就是 10 个。这就注定了 SPI 不适合做“一总线上挂几十个设备”的拓扑它更适合“少量高速设备一对一或一对几”。另外要提醒的是SPI 没有应答机制。主控发出一帧数据从机到底收到没有、处理得对不对协议层完全不知道。数据错了只能靠应用层做校验这也是很多 SPI 外设尤其 Flash要额外做 CRC 或者回读校验的原因。1.3 等速率连续流I2S 只干音频这一件事I2S 这个名字经常和 SPI 混在一起因为它的信号线很像 SPISCK、WS、SD。但它解决的问题完全不同——音频采样是等速率、连续、周期性的。44.1kHz 采样率下每秒钟固定产生 44100 个采样帧每个帧里左声道右声道各有 16 位或 24 位数据节奏绝不能乱。如果用 SPI 传音频你得自己在应用层拼帧先传左声道再传右声道还要保证每次传输间隔严格相同否则声音就断续。I2S 则把这件事固化在协议里WS 线的高低电平直接区分左右声道SCK 提供位时钟数据线按位对齐往外送。硬件自己就把帧结构维护好了软件只需要往 FIFO 里填数据。所以 I2S 几乎不会出现在非音频场景。你可能在 ESP32-C3、STM32、RK3588 的数据手册里看到 I2S 外设旁边大概率还跟着音频 Codec、数字麦克风、功放。想用 I2S 去传普通数据不是不行但它的帧结构和时钟比例都是围绕音频采样率设计的拿来干别的属于用牛刀杀鸡还要跟那堆 MCLK 分频系数较劲。1.4 点对点透传与调试UART 的地位很难被替代UART 是四者里最“老”的也是最“笨”的。没有时钟线没有地址没有片选就是两根线TX、RX按约定好的波特率收发。但恰恰是这份简单让它在嵌入式世界里活了几十年还不过时。调试日志就不用说了几乎 90% 的 MCU 调试信息都是 UART 打印出来的。更关键的是大量现成的无线模块、定位模块、蓝牙透传模块默认接口就是 UART。主控和这些模块之间不需要复杂的协议只要把波特率对上、把 TX/RX 交叉接好数据就通了。UART 的另一个隐性优势是生态和工具链非常成熟。从 PC 时代的 16550 标准到今天的各类 USB 转串口芯片驱动、终端软件、波形解读资料一大堆。我见过很多工程师把 UART 当“保底方案”系统里什么都可能没有但串口一定在——毕竟板子万一起不来还得靠它输出点东西。2. 物理层与时序的差异信号线、时钟机制决定速度天花板定位和流量模型只是“选谁”的理由真正决定“为什么 I2C 就是快不起来”“为什么 SPI 能做到几十兆”的是物理层设计。下面逐个拆开看。2.1 I2C两根线、开漏架构、仲裁与时钟拉伸I2C 的 SDA 和 SCL 都是开漏输出线上必须外接上拉电阻。开漏意味着任何设备都可以把线拉低但没人拉的时候线靠上拉电阻恢复高电平。这个设计的精妙之处在于多个设备挂在同一根线上不会短路因为谁都不会主动输出高电平只会选择“拉低”或“释放”。总线空闲是高电平任何设备拉低就算是“开始说话”。这套机制直接支撑了 I2C 的多主多从仲裁——两个主机同时发起传输时谁先拉低谁赢输的一方自动退出。但开漏架构也直接限死了速度。线上挂着上拉电阻和多个设备的寄生电容从低电平恢复高电平要靠电阻慢慢充电RC 常数决定了上升沿有多“肉”。总线电容越大、上拉电阻越大波形就越缓速率就越上不去。所以 I2C 高速模式做到 3.4Mbps 已经非常吃力实际系统里 400kHz 才是主流。一次典型的 I2C 读操作长这样START - 从机地址(7bit) R/W位 - ACK - 寄存器地址(8bit) - ACK - 重复START - 从机地址 读 - ACK - 数据字节 - ACK - STOP每传一个字节都要等对方的 ACK每开一帧都要有 START/STOP这些开销在实际计算吞吐时必须算进去。400kHz 下理论位速率是 50KB/s但算上地址、ACK、寄存器地址和 STOP有效数据率能到 40KB/s 就算不错了。另外I2C 还有“时钟拉伸”机制从机如果没准备好可以主动拉低 SCL让主机停下等一会儿。调试时如果你用逻辑分析仪抓 I2C 波形发现 SCL 低电平时间特别长往往就是从机在“拖堂”。现在有些控制器还支持自由数据模式、中断请求这类扩展功能本质都是在不破坏基本帧格式的前提下增加新通道。用之前一定先翻数据手册确认从机支持不支持别拿普通 I2C 从机去硬试。2.2 SPI推挽输出、全双工、无 ACK、片选即身份SPI 的四根线里SCLK、MOSI、MISO 都是推挽输出由主控驱动。推挽电路的特点是上升沿和下降沿都靠晶体管主动拉速度快、波形干净所以 SPI 的时钟轻轻松松上几十 MHz这是它能高速传输的根本原因。SPI 传输是真正的全双工MOSI 和 MISO 同时移动主控发一个字节的同时必定收到一个字节。你读 Flash 的时候主控其实也在往 MOSI 上发数据只不过发的是 0xFF 之类的“假数据”来提供时钟。CS 线是 SPI 的灵魂。CS 拉低从机就知道“这轮说的是我”开始接收或发送CS 拉高从机立即复位回空闲状态。高位还是低有效、CS 到第一个 SCLK 沿要有多少建立时间、传输结束 CS 拉高后要维持多久这些参数都写在从机数据手册里是 SPI 工程里最常见的细坑。SPI 没有 ACK、没有地址、没有流控所有协议规则要靠主从双方自己约定。同样是读一个 Flash 的 IDA 厂芯片可能要先发 0x9FB 厂可能要先发 0x4B这些“约定”完全取决于芯片设计厂商所以要特别注意“SPI 协议”这个概念并不像 I2C 那样有一个统一的协议层。至于 CPOL/CPHA 四种模式本质就是“时钟空闲高还是低”和“数据在上升沿采样还是下降沿采样”的组合。主从模式不匹配时现象非常典型读回的数据全是 0xFF 或者规律的错位。2.3 UART没有时钟线靠起始位校准对齐UART 最特别的地方是没有独立的时钟线收发双方各自用自己的时钟发生器。那它怎么保证节奏一致靠的是“起始位”。空闲时 TX 线是高电平。要发一个字节时先把线拉低一个位宽——这个低电平就是起始位接收方看到下降沿就开始以约定的波特率采样后续的位。一帧 8N1 的完整结构是1 位起始位低 8 位数据 1 位停止位高。空闲(高) | 起始位(低) | D0 D1 D2 D3 D4 D5 D6 D7 | 停止位(高) | 空闲(高)8N1 一共 10 个位宽所以 115200 波特率下理论最大有效数据率是 11520 字节/秒。这看起来很“慢”但对调试日志和模块透传来说完全够用。因为没有时钟线双方的波特率必须足够接近。收发两侧晶振误差和分频误差累计起来最好控制在 2%~3% 以内超过这个范围就会出现偶发乱码、丢字节。这也是为什么看到“UART 波形正常但数据是乱的”时第一反应是去量两边实际波特率而不是怀疑线路。工业场景里 UART 往往会转成 RS485用差分信号把传输距离拉到几十米甚至上百米但协议帧还是 UART 那一套。很多 PLC、仪表、电量采集设备之间跑的就是 MODBUS-RTU底层物理层是 RS485上层帧还是老面孔。2.4 I2S时钟由主控给数据天生按帧连续I2S 最小系统四根线SCK位时钟、WS左右声道选择、SD数据有些 Codec 还要求主控额外给 MCLK主时钟。SCK 和 WS 都由主机提供从机只管按节拍输出或接收数据。WS 的频率就是采样率例如 44.1kHz 或 48kHz。SCK 的频率是BCLK fs × 声道数 × 位宽48kHz、16bit、双声道就是 48k × 2 × 16 1.536MHz。MCLK 通常是 fs 的整数倍比如 256 × fs 12.288MHzCodec 内部用 MCLK 做 Delta-Sigma 调制和时钟恢复。I2S 的帧结构极其固定WS 拉高表示当前是右声道拉低表示左声道极性可配置每个声道的数据在 SCK 的某个边沿锁定高位在前。这套结构没有地址、没有应答、没有片选因为音频流就是“点对点全速跑”。用逻辑分析仪抓 I2S 波形时我习惯先算一遍 BCLK 和 WS 的实际频率再去看 WS 边沿和数据首位的对齐关系。这两个对上了基本就能断定主从方向时钟配置没问题剩下的问题多半在 Codec 寄存器配置或者 MCLK 缺失上。3. 一张表理清选型关键参数对照与“先看需求再定总线”的决策逻辑参数讲完直接上对照表。这张表是我给团队新人的入门速查卡覆盖了日常选型最关心的维度。维度I2CSPIUARTI2S信号线SDA SCLSCLK MOSI MISO CSTX RXSCK WS SD可选 MCLK时钟来源主机提供 SCL主机提供 SCLK无时钟线靠波特率同步主机提供 SCK / WS / MCLK典型速率100k / 400k / 1M / 3.4M bps10M ~ 50M bps9600 ~ 几 Mbps1.5M ~ 几十 Mbps随采样率走有效吞吐示例400kHz 下约 40KB/s40MHz 下约 5MB/s标准四线115200 下约 11.5KB/s48k/16bit/双声道约 192KB/s通信方向半双工全双工全双工全双工连续流拓扑多主多从靠地址区分一主多从靠 CS 区分点对点点对点一主一从错误检测有 ACK/NAK无靠应用层自行处理无标准校验靠帧格式无靠应用层协议开销地址 ACK START/STOP开销较大几乎无协议开销起始/停止位约占 20%无额外开销最典型应用传感器、RTC、EEPROM、触摸屏Flash、LCD、SD 卡、ADC 采样调试日志、蓝牙/GPS/4G 模块透传音频 Codec、数字麦克风3.1 从需求到总线的决策顺序我在实际项目里通常按下面这个顺序定总线基本不会错先看外设给你什么接口。很多外设的接口是固定的SHT30 只有 I2C 版W25Q128 只有 SPI 接口GT911 只有 I2C——这时候不用纠结把接口对号入座就行。能选接口的才进入下一步。判断数据量级。每次只读几个字节、寄存器配置多、要挂多个从机选 I2C大块搬运、持续高速读写选 SPI。判断流量模式。等速率的连续流尤其音频优先 I2S不规则、点对点、要长距离选 UART 加 RS485。数 GPIO 和引脚预算。引脚紧张就尽量把低速设备并到 I2C 上高速设备留给 SPI别用 CS 片选把引脚吃完。看一眼系统里已有的总线占用情况尽量把新设备挂到已有总线上少开新外设。总线负载别看单个设备要算总线上所有设备的等效电容和地址冲突。3.2 同一种设备换总线的案例成本与形态决定的差异有些事情不是技术决定的是成本和形态决定的。你可能会发现同一颗传感器芯片同时有 I2C 和 SPI 两个版本硬件设计时选哪个往往取决于主控还有几个空闲引脚、PCB 上还能不能布一根时钟线、以及软件同事更熟哪套驱动。Linux 下有个很经典的例子管理 PHY 芯片寄存器时标准做法是走 MDIO/MDC但有些板子没有 MDIO 控制器或者 PHY 芯片设计上就把管理通道挂到了 I2C 上驱动也就跟着走 I2C 去访问 PHY 寄存器。数据通道还是 MII/RGMII管理通道换了个总线而已。这就是典型的“同一种业务底层总线跟随硬件设计走”。所以选型的本质不是“哪个总线更好”而是“这个外设、这颗主控、这块板子天然适合走哪根线”。想明白这一点很多选择不用硬记看到外设类型自然就能判断。4. 工程落地最容易踩的差异坑片选时序、上拉、波特率与波形调试理论再熟不踩几个坑也很难真正理解这四种总线。下面这些是最近几年在项目里反复遇到的典型问题每一个都对应明确的排查思路。4.1 I2C地址换算、上拉电阻与 GT911 这类从机失灵I2C 第一个坑就是地址换算。数据手册写 7 位地址 0x68但实际代码里发送的字节可能是 0xD0 或 0xD1——因为最低位是读写位发送前要把地址左移一位。无数人卡在这一步逻辑分析仪一抓波形就明白了但没抓之前怎么都对不上。上拉电阻的取值也要特别注意。3.3V 系统里2.2kΩ 到 10kΩ 是常见范围。电阻取大了上升沿太缓高速模式下波形严重失真取小了总线空闲电流大低功耗设备直接超标。如果你发现 I2C 在 400kHz 下偶发 NAK先别砸驱动代码拿示波器看 SCL 上升沿是不是变成了“慢坡”是的话就把上拉电阻往小调。GT911 这种触摸屏 I2C 通信失败排查顺序我一般固定先看 INT 和复位引脚的时序符不符合要求再确认当前设备地址对不对GT911 的地址可以落在 0x5D/0x14 附近取决于 RST 引脚时序配置最后才去抓 I2C 波形看有没有 ACK。前两步解决掉的问题比想象中多因为触摸屏上电时序不规范时芯片可能根本没进入正常待命状态你发什么它都不理。Windows 下 I2C HID 设备报“代码 12 资源不足”这类问题常见原因是指纹、触摸板这类 I2C HID 设备占用的中断/资源冲突或者厂商驱动没装对。排查重点先放在清干净旧驱动、确认 BIOS 里 I2C 控制器没被禁用再用设备管理器逐项排除冲突设备一般都能定位到具体设备。4.2 SPI模式不匹配、软件/硬件片选与 CS 时间参数SPI 模式不匹配是出现频率最高的低级问题。主控配置成 Mode 0从机要 Mode 3表现出来就是读 Flash ID 永远是 0xFF或者显示屏花屏。先用逻辑分析仪抓波形数一下 SCK 空闲电平和数据采样沿再对照 CPOL/CPHA 表格改配置十分钟内就能解决。CS 片选这里有两个常见争论。软件片选用普通 GPIO 拉 CS灵活可以手动控制拉低时机但 CPU 在高频下处理中断、切换任务时CS 拉低和 SCK 第一个沿之间的时间不好精确保证容易引入毛刺。硬件片选 NSS 由外设自动管理时序稳定但在某些半双工或连续传输场景下硬件会自动把 NSS 拉高又拉低产生多余的片选脉冲反而把从机搞糊涂。我的经验是低速外设随便用软件片选高速连续传输尽量用硬件片选但前提是仔细读主控的参考手册确认硬件 NSS 在你要用的传输模式下行为符合预期。CS 的时间参数别忽略。很多 Flash 手册会规定 CS 拉低到 SCK 第一个上升沿至少要几百纳秒的建立时间传输结束 CS 拉高后到下一次拉低之间还有最小释放时间。这些参数在高速分频下尤其要紧。用示波器或逻辑分析仪量一下“CS 拉低 → SCK 第一个沿”的实际时间如果差得太极限就把 SPI 时钟分频调低一档或者调整软件里 CS 和数据的操作顺序。4.3 UART交叉接线、波特率误差与 USB 转串口驱动UART 排查里最基础的坑反而是最多的。TX 必须接对端的 RXRX 接对端的 TX两根线还要共地。很多人拿着两块开发板互发数据只接了 TX/RX 没接 GND波形看起来是有的数据就是乱码最后发现是参考地不一致导致的电平错位。波特率误差的排查要动脑子算。假设主控用 16MHz 晶振产生 115200 波特率分频误差可能大一点模块那边用无源晶振或内部 RC 振荡器误差也可能累计。两边各自看起来都在 115200但相对误差超过 3% 时数据错误率会急剧上升。遇到“偶尔乱码、重新上电又好一阵”的玄学问题优先量实际波特率别去改代码里那堆延时。USB 转串口芯片的驱动问题也是高频来访者。FT231x、FT232r 这类芯片经常因为驱动版本不匹配、或者系统更新以后旧驱动失效在设备管理器里出现感叹号。处理办法其实很朴素去芯片官网下对应版本驱动重装用系统自带的“更新驱动程序”让系统自动找装完以后把 USB 线拔插一次让它重新枚举。如果设备管理器能识别但不能打开串口多半是端口被别的程序占用了关掉串口助手或者换一个 COM 号就行。实在不行把板子插到另一个 USB 口测试排除线缆和供电问题。4.4 I2S主从方向、WS 极性与逻辑分析仪看波形I2S 的第一个判断点是主从方向。大部分板子上主控做主机提供 BCLK/WS/MCLKCodec 做从机。一旦方向反了两边时钟对不上Codec 要么没声音要么输出尖锐噪声。查这类问题先看原理图Codec 的 MCLK 引脚有没有接主控的时钟输出没有的话驱动里必须关掉 MCLK 相关的分频使能。WS 极性也是一个隐蔽的坑。标准 I2S 是 WS 高电平代表右声道但有些 Codec 默认相反或者支持自行配置左右声道映射。配置错了的表现往往是左右声道互换或者一个声道无声波形层面完全正常软件层面差一个寄存器位。用逻辑分析仪验证 I2S 波形时我的步骤是先量 WS 频率是不是等于采样率再量 BCLK 是不是等于 fs × 位宽 × 2最后看 SD 数据线上第一位和 WS 边沿是否对齐。这三个点一过主控侧的时序基本没问题。剩下的声音问题基本都集中在 Codec 寄存器配置、模拟增益、功放使能这些软件层面。调试工具方面现在的逻辑分析仪对 I2C、SPI、UART 的协议解析已经非常成熟抓下来直接就能看到 ACK、地址和字节内容。还有很多 USB 转 SPI/I2C 适配器支持 Python 调用写几行脚本就能模拟主控、做产测和快速验证比拿单片机改固件测试快得多。当年我只能拿示波器一格一格数电平现在有这个条件建议新手朋友务必把逻辑分析仪用起来。最后再分享一点个人体会四种总线在项目里从来不打架反而是很好的分工搭档。我现在拿到一块新板子第一件事不是看主控型号而是看原理图里每个外设挂在哪条总线上——传感器大概率在 I2CFlash 和屏幕在 SPI音频在 I2S调试口在 UART。按这个分类去读驱动代码脑子会清晰很多。如果你正在为“到底选哪个总线”纠结我的建议很直接先选外设再顺着外设选总线别反过来。外设能挂哪个就挂哪个能选的再看流量模型和引脚预算90% 的场合都不用纠结到参数层面。真正花时间的永远是那些片选时序、上拉电阻、地址换算和主从方向上的小问题。希望这篇对比能帮你少走几步弯路。
返回列表