第一次用逻辑分析仪同时抓这四条总线的时候,我才真正体会到,所谓的对比,不能只看速率表格。同样是"串行通信",I2C、I2S、SPI、UART从线数、时钟来源到数据格式,几乎没有一个地方是相同的。这篇文章想做的事很简单,就是把这四种嵌入式开发里出镜率最高的通信协议放到一起,掰开揉碎讲清楚它们各自的原理、适用场景和真实调试中会遇到的坑。无论你是刚入门选型,还是做主控板调不通中断,这份对比都能让你少走一些弯路。
很多人问:"为什么会有这么多协议?就不能统一成一种吗?"答案是不能,因为四种协议解决的问题方向完全不一样。UART 解决的是"两个设备隔着不太远的距离可靠通信",SPI 解决的是"主控和从机之间快速吞吐大量数据",I2C 解决的是"只用两根线挂一大堆低速外设",而 I2S 解决的是"数字音频的节奏怎么严格对齐"。真正的区别不在"哪个快哪个慢",而在于各自的适用边界。下面我从机制开始拆,最后给选型方法和踩坑记录。
1. 先搞明白:这四条总线本质上在解决一件什么事
1.1 从一根线的串行传输说起
并行总线现在还在用的场景不多了,嵌入式里绝大多数通信都是串行——数据按位排着队走一根线或几根线。为什么?因为并行线在高速下会有严重的信号偏移和串扰问题,十六根线同时翻转,PCB 布局和时序约束能把人逼疯。串行虽然位传输速率低一点,但线少、成本低、可靠,而且可以通过提高时钟频率把总吞吐做得很高。
这四种协议都属于串行通信,但它们对"时钟"的态度完全不同。SPI 和 I2S 是同步串行,发送方和接收方共用一根时钟线,边沿到了就采样,双方不用猜。UART 是异步串行,没有时钟线,全靠双方预先约好一个波特率,靠起始位的下降沿来对齐节奏。I2C 是同步和异步的混合体,它有 SCL 时钟线,但挂同一总线上的多个设备要能协调占用总线,因此还带一套地址、应答和仲裁机制。这个本质区别决定了后面几乎所有行为差异。
1.2 四种协议的"社会分工"和选型直觉
我用一个不算严谨但好记的比喻来建立直觉。UART 像两个人打电话,一条线给 A 说、一条线给 B 说,全程独占,谁也不用等别人。SPI 像老板叫某个下属来办公室单独汇报,老板是主,下属是从,老板说一句、下属答一句,全双工,效率很高,但老板得一个个叫,线也得多拉几根。I2C 像一群人开电话会议,所有人都并线在同一根线上,每个人有分机号,主持人喊到谁谁说话,说完还要回一声"收到";因为人多了要避免同时开口,所以协议内置了应答和仲裁规则。I2S 则像一支乐队的指挥,指挥棒(BCLK)和总指挥(WS 声道选择)同步所有乐手,数据一声接一声按严格的节拍输出,不需要地址,不需要应答,因为它是点对点的音频流。
从这个比喻就能看明白:选型不是挑一个"最好的",而是找一个"最不别扭的"。低速率、设备多、引脚紧张,优先 I2C;高速率、大数据块、从机数量少,优先 SPI;两个设备之间简单传数据没有任何从机结构,用 UART 最直接;只要你传输的是音频数据流,I2S 无可替代。下面把这四种协议的机制拆开。
2. 四种协议的底层工作机制逐项拆解
2.1 I2C:两根线挂一总线,靠地址和设备自己"说话"
I2C 由 Philips(现在的 NXP)在 1982 年提出,全称 Inter-Integrated Circuit。它只有两根信号线:SDA(数据线)和 SCL(时钟线)。这两根线是开漏结构,必须外接上拉电阻,空闲时都被拉高。开漏意味着设备只能把线拉低,不能主动推高,所以"高电平"完全靠上拉电阻提供。理解了这一点,你就能理解为什么 I2C 适合挂多个设备且不需要额外的片选线——所有设备都并在同一对线上。
一次 I2C 传输的完整过程是这样的:
- 起始条件:SCL 为高时,SDA 从高拉低。这个下降沿告诉总线上所有设备"要开始了一帧传输"。
- 地址阶段:主机在 SCL 的每个高电平期间,通过 SDA 送入一个字节,前 7 位是从机地址,第 8 位是读写标志。总线上的每个从机都会检查这 7 位是不是自己的地址。
- 应答阶段:第 9 个时钟脉冲,被寻址的从机把 SDA 拉低,表示"我在,继续"。没有设备应答,主机就应在 SCL 高电平检测 SDA 保持高,然后可以发停止条件或者重试。
- 数据阶段:继续发若干字节,每字节后面都跟一个 ACK 位。
- 停止条件:SCL 为高时,SDA 从低拉高。
数据采样有个关键规则:SDA 电平必须在 SCL 为高时保持稳定,只有在 SCL 为低时 SDA 才允许变化。很多人第一次用 GPIO 模拟 I2C 时踩坑,就是因为在 SCL 拉高后立刻改 SDA,导致从机采到错误数据。正确的软件实现是先改 SDA,再拉高 SCL,再拉低 SCL,最后再改下一次数据。
I2C 常见速率档位:标准模式 100 kbit/s、快速模式 400 kbit/s、快速+ 模式 1 Mbit/s、高速模式 3.4 Mbit/s。实际项目里 100 kbit/s 和 400 kbit/s 用得最多。典型外设包括温湿度传感器(SHT30、AHT20)、气压计、EEPROM 芯片、触摸屏控制器(比如 GT911)、实时时钟等。它是嵌入式里每比特代价最低的板内总线之一。
2.2 SPI:一根时钟带四根线,全双工高速传输
SPI 由 Motorola 提出,全称 Serial Peripheral Interface。标准四线分别是:
- SCLK:串行时钟,由主机产生,决定通信速率。
- MOSI:主出从入,主机发送数据给从机。
- MISO:主入从出,从机发送数据给主机。
- CS/SS:片选,低电平有效。主机拉低哪个从机的 CS,哪个从机就被激活。
SPI 没有地址的概念,靠的就是 CS 这根独立的片选线。你要挂四个从机,就得准备四根 CS。也正因为这样,SPI 非常灵活,主机可以随时决定跟谁通信,不需要像 I2C 那样发送地址字节,协议本身的开销小得多。
SPI 是全双工的。在每一个 SCLK 周期内,主机通过 MOSI 发一位,同时从机通过 MISO 回一位。所以它的吞吐率很高,常见 SCLK 在 10 MHz 到几十 MHz,性能好的器件甚至能跑到 100 MHz 以上。但这也带了麻烦:SPI 没有应答机制。主机写一个寄存器,从机有没有收到,SPI 协议本身完全不关心。你必须通过读回寄存器确认内容对不对,这个特点后面避坑章节还会重点提。
SPI 有四种工作模式,本质是时钟极性和相位组合。CPOL 决定时钟空闲时是低电平还是高电平,CPHA 决定数据在第一个边沿采样还是第二个边沿采样。对应关系如下表:
| 模式 | CPOL | CPHA | 空闲电平 | 采样边沿 | 常见场景 |
|---|---|---|---|---|---|
| Mode 0 | 0 | 0 | 低 | 上升沿 | 最常见,很多 Flash、屏幕、传感器 |
| Mode 1 | 0 | 1 | 低 | 下降沿 | 部分音频/协议芯片 |
| Mode 2 | 1 | 0 | 高 | 下降沿 | 部分特定器件 |
| Mode 3 | 1 | 1 | 高 | 上升沿 | 很多 SD 卡协议 |
如果你的主控和从机模式不匹配,会出现一个极其迷惑的现象:数据完全错位,读上来的东西是一堆乱七八糟的比特。调试遇到这种问题,第一反应就应该是核对四模式。
2.3 UART:没有时钟线的异步串口,靠双方约定速率
UART 的全称是 Universal Asynchronous Receiver/Transmitter,它定义的是一种异步串行帧格式。没有 SCLK、没有 SDA、没有 CS,通常就两条线:TX 和 RX,交叉连接。通信的前提是双方事先约定好完全相同的波特率,比如 9600、115200、460800 等。
UART 帧的基本结构:空闲状态为高电平;一帧从起始位开始,起始位是一个位宽的低电平;然后是数据位,通常 8 位,LSB 在前;接着是可选的校验位;最后是停止位,1 或 2 个位宽的高电平。接收方就是靠检测到高到低的跳变,认定起始位来了,然后按照约定的波特率,在每个位的中间点采样一次,避免采样到信号抖动区域。
正因为是异步的,双方的时钟误差非常关键。一般 UART 要求波特率误差控制在 ±2% 到 ±3% 以内。举个实际例子,用 24 MHz 晶振跑 115200 波特率,分频系数是 24000000 / 115200 ≈ 208.33。取整 208 后实际波特率是 24000000 / 208 ≈ 115384,误差约 0.16%,完全没问题。但如果你用一颗非标准晶振而分频系数取整误差很大,可能出现"近距离没问题、稍微拉长线就乱码"的情况。
UART 的应用面很广:调试日志输出、GPS 模块、蓝牙模块、RS-485 总线、老式工控设备。它最大的优势是简单、点对点、跨设备通用,缺点是只能一对一,且速率上限通常比 SPI 低。RS-232 电平与 TTL 电平还不一样,RS-232 用正负电压表示逻辑,TTL 用 3.3V/5V 和 0V 表示逻辑,拿 TTL 和 RS-232 混接,轻则通信失败,重则烧引脚。
2.4 I2S:为音频量身定做的同步串行接口
I2S 全称 Inter-IC Sound,是 Philips 为数字音频设备之间的音频数据传输定义的接口。它和前三者的最大区别是:它不传控制命令,只传音频数据流。典型场景是单片机接音频 Codec、ADC、DAC、数字麦克风,比如在 ESP32 上接一个 I2S 解码板播放 WAV 音乐,或者用 I2S 麦克风做语音采集。
I2S 的核心线有三根:
- BCLK:位时钟,每个脉冲对应一个音频数据位。
- WS/ LRCK:声道选择信号。低电平通常表示左声道,高电平表示右声道(或者是反过来,看具体约定)。
- SD:串行数据线,用来传音频采样值。
它的时序特点是:数据先发高位(MSB first),而且数据和 WS 边沿之间通常有 1 个 BCLK 的延迟。这是标准 I2S 格式;此外还有"左对齐""右对齐"DSP/TDM 等变体,不同 Codec 手册里都会写明支持哪种对齐方式。
举个具体数字说明速率关系。如果你的音频系统是 48 kHz 采样率、16 bit 位宽、双声道,那么 BCLK = 48000 × 16 × 2 = 1.536 MHz。如果位宽是 24 bit,BCLK = 2.304 MHz。很多 I2S 器件还要求额外的主时钟 MCLK,一般取采样率的整数倍,比如 128 × 48 kHz = 6.144 MHz,256 × 48 kHz = 12.288 MHz。MCLK 用于内部的 Delta-Sigma 调制器和时钟恢复,配置不对会导致音频设备完全不出声或者发出刺耳噪声。
I2S 没有地址、没有 ACK、没有仲裁,本质上是一条流式单向或双向管道。它既可以配置为主机模式,由主控产生 BCLK 和 WS,也可以配置为从机模式,让外部 Codec 做主。选主从模式要看系统中哪个设备更容易提供稳定时钟,这里面有讲究,后面踩坑部分再说。
3. 把四个协议放同一张表里:关键差异一眼看清
3.1 关键维度横向对比总表
| 维度 | I2C | SPI | UART | I2S |
|---|---|---|---|---|
| 信号线数量 | 2(SDA、SCL) | 4(SCLK、MOSI、MISO、CS) | 2(TX、RX) | 3~4(BCLK、WS、SD、可选MCLK) |
| 同步/异步 | 同步(有 SCL) | 同步(有 SCLK) | 异步(无时钟线) | 同步(有 BCLK) |
| 时钟来源 | 主机产生 SCL | 主机产生 SCLK | 双方各自约定波特率 | 主机产生 BCLK/WS |
| 拓扑结构 | 多主多从总线 | 一主多从,每从一根 CS | 点对点 | 点对点(可TDM扩展) |
| 寻址方式 | 7位/10位地址 + ACK | 硬件片选 CS | 无寻址 | 无寻址 |
| 应答机制 | 有 ACK/NACK | 无应答 | 无应答 | 无应答 |
| 全双工 | 否(半双工) | 是 | 是 | 可单向也可配置双数据线 |
| 典型速率 | 100k~3.4Mbit/s | 几十 MHz 甚至更高 | 通常 9600~921600 bit/s | BCLK 通常在 1~4 MHz |
| 抗干扰能力 | 一般,依赖上拉质量 | 较好,推挽输出 | TTL 一般,RS-485 很强 | 较好,但时钟敏感 |
| 典型应用 | 传感器、EEPROM、触摸屏 | Flash、屏幕、SD卡、ADC | 调试口、GPS、蓝牙、RS-485 | 音频 Codec、数字麦克风、DAC |
这张表基本上把所有关键差异都放出来了。但我必须强调,表格只能帮你快速回忆,真正的理解在于那些"表格里没写的坑"。比如 I2C 半双工,意味着同一时刻只能有一个方向的数据流动,你要读一个传感器寄存器,得先写寄存器地址、再切换方向读数据,这个过程本身就有协议开销。SPI 全双工,看起来是同时收发,但在实际项目里大部分场景并不是真的利用双向带宽,但它的优势是没有方向切换的延迟,所以特别适合连续大块数据读写。
3.2 表中几个"看似不起眼却决定成败"的差异
第一,同步 vs 异步决定了你调试时看什么波形。SPI 和 I2S 的数据有效性永远和时钟边沿挂钩,只要时钟还在,数据就能被采样;UART 则完全依赖起始位和波特率,线上一旦出现长时间干扰,接收端可能反复尝试同步,表现为连续乱码。调 UART 先看电平空闲状态是否是稳定的高电平,再看起始位下降沿是否干净;调 SPI/I2S 则优先看时钟频率是否在器件支持范围、数据建立时间是否足够。
第二,有没有应答机制,决定了错误能不能被立刻发现。I2C 自带 ACK,从机没收到或不响应,主机在第九个时钟就能感知,所以"写命令失败"通常比较容易暴露。SPI 没有 ACK,表面上读写正常,但可能从机根本没接到有效的 CS 低电平或数据线被别的信号干扰。我有一次调 STM32 的 SPI 读 Flash,读回来的 ID 永远是 0xFF,时钟和数据波形看着都对,最后发现是 CS 引脚初始化成开漏输出,拉低能力不够,换推挽输出就好了。这就是典型的"没有 ACK 的排查成本"。
第三,I2S 的时钟频率不是随便定的,它跟采样率严格挂钩。不像 SPI 你可以随时把 SCLK 从 1 MHz 调到 10 MHz,I2S 的 BCLK 和 WS 必须跟采样率和位宽匹配,否则音频采样率会发生偏移。这个约束让 I2S 的调试变得很"敏感"——你改了一个采样率,MCLK 也要跟着改;你用了外部晶振给 Codec 做主时钟,主控恢复出来的音频流有可能出现周期性的"卡顿"或"爆音",本质是主从数据速率不匹配。
4. 选型不靠背参数,靠反向问需求
4.1 三个真实项目场景的选型过程
我拿三个我实际做过的项目来说明选型逻辑。
第一个项目是做一个温湿度采集小模块,主控是一颗国产 Cortex-M0 单片机,要从板上读一个 SHT30 传感器,还要挂一个小的 EEPROM 存校准参数。这个场景的典型选择就是 I2C。为什么?传感器输出的是几字节温度湿度数据,一次读取几十个字节顶天了,对速率完全没压力;而 I2C 只需要两根线,引脚占用最少,还能让传感器和 EEPROM 共用一条总线。你说 SPI 行不行?也行,但每个设备要多一根 CS 引脚,而且对这么低速的应用完全没必要。
第二个项目是驱动一块 1.8 寸 TFT 彩屏,分辨率 128×160,RGB565,刷一帧大约要 128×160×2 = 40960 字节。如果我用 I2C 的 400 kHz 速率刷屏,理论需要 40960×8÷400000 ≈ 0.82 秒,实际带上地址和 ACK 开销要超过 1 秒,这个刷新率会让人觉得屏幕卡到没法用。换成 SPI,SCLK 跑到 24 MHz,光传输就是 40960×8÷24000000 ≈ 13.7 毫秒,加上 DMA 的辅助,刷屏完全顺滑。所以选屏场景不看别的,先算数据量,再算可接受延迟,直接决定协议。
第三个项目是做一个简易录音笔,需要 I2S 数字麦克风采集音频,再通过 I2S DAC 播放。这个场景没有任何悬念,必须用 I2S,因为数字音频的时序精度要求在这里,用 SPI 去模拟音频时序会让你为"保持每个采样点间隔完全一致"付出巨大代价。I2S 天生就是为音频流设计的,WS 自动切换左右声道,BCLK 按位驱动数据线,主控只需要用 DMA 搬数据。所以协议选型往往不是横向比较谁更好,而是纵向看这个应用的核心诉求是什么。
4.2 我自己总结的"五问选型法"
如果你拿不准选哪个,可以按这五个问题往下走:
- 传的是什么?连续音频流,选 I2S;大块数据读改写,选 SPI;分散的小命令小参数,选 I2C;任意文本/字节流,选 UART。
- 要挂多少设备、还剩几根引脚?设备多且引脚紧张,I2C 优势大;设备少且需要高吞吐,SPI 更优;点对点且简单,UART 最省心。
- 需要从机主动上报吗?I2C 支持多主和从机时钟拉伸,部分场景下从机可以通过某种机制通知主机,但整体上主从模型为主。UART 天然支持设备任意时刻发送数据,比如 GPS 一直往外吐 NMEA 语句,所以 GPS 模块用 UART 最自然。
- 距离远不远?板内几厘米,I2C/SPI/I2S 都没问题;板间接线超过几十厘米甚至几米,UART 转 RS-485 才是可靠方案。SPI 拉长线会因信号完整性问题出现错误,I2C 长线加上大上拉电阻会导致边沿变慢、时序超标。
- 对成本和通用性的要求?非常简单、几十厘米内、只想点对点传数据,UART 是所有 MCU 的标配,几乎不会出问题;想在总线上扩设备又不想重新布线,I2C 能让你用最少的线挂最多的芯片。
这套方法不保证你选到"最优解",但能帮你避开最低级的错误:用 I2C 去刷屏、用 UART 去传大文件、用 SPI 去接数字麦克风——这些组合不是不能跑,而是会让你在调试和性能上付出不必要的代价。
5. 实测避坑:四条总线各自的老玩家才知道的坑
5.1 I2C:上拉电阻和地址冲突是两大入门杀手
I2C 最常被忽略的问题就是上拉电阻取值。电阻太小,比如 100Ω,SDA 拉低时电流过大,低电平可能达不到器件阈值,还会增加功耗;电阻太大,比如 100kΩ,RC 常数太大,SCL 和 SDA 的上升沿变得很缓,在高速模式下可能被判定为时序违规。一般 3.3V 系统取 2.2kΩ 到 4.7kΩ,5V 系统取 4.7kΩ 到 10kΩ,总线上设备越多、线越长,上拉电阻要适当选小一些去补偿电容。
其次是地址冲突。I2C 的 7 位地址空间里,某些地址是保留的(比如 0x00 是 general call),而很多传感器厂商把默认地址做成 0x48、0x4E 这类常见值。如果一块板子上挂了两颗相同型号的传感器,而它们又没有可配置的地址引脚,就会撞车,主机发命令时两个芯片都会应答。解决方案包括用 TCA9548A 这样的 I2C 多路复用器,或者干脆换一颗支持地址配置的器件。排查地址冲突时,用逻辑分析仪抓一下 ACK 阶段,两条不同器件的总线上如果看到"同一个地址出现了两次 ACK",基本就可以断定撞车了。
还有一个坑叫时钟拉伸。有些从机处理速度慢,会在某个阶段把 SCL 拉低来暂停通信,让主机等它准备好。支持时钟拉伸的是标准行为,但如果你用的 MCU 硬件 I2C 外设不支持,或者你的软件实现里没有处理 SCL 被外部拉低的情况,就可能直接超时死掉。遇到这种问题,很多人的第一反应是"死循环了",实际上应该怀疑主机没有正确响应从机的时钟拉伸。
5.2 SPI:片选毛刺和"读回校验"缺一不可
SPI 的 CS 片选线是低电平有效,这就带来一个毛刺问题。如果你的主控在初始化时 CS 引脚还没配置成推挽输出,或者你用的是软件控制 CS(片选和数据通过 GPIO 分别控制),飞线干扰或代码执行顺序不当,从机端可能收到一个极窄的低脉冲,误以为主机要开始通信。解决方法是:CS 引脚尽快配置为推挽输出并默认拉高,最好利用硬件外设的自动 NSS 功能;如果一定要软件 CS,要在拉低 CS 后加至少几百纳秒的等待,保证从机稳定进入工作状态。
第二件事是没有 ACK 不代表不检查。SPI 写数据后,一定要习惯性地读回寄存器验证。比如写 Flash 的状态寄存器、写音频 Codec 的控制寄存器,写入后读回判断是否一致。我做过一个项目,SPI 写 ADC 的配置寄存器,示波器看波形完全正确,但 ADC 输出就是不对,最后读回寄存器发现配置寄存器的 D3 位没有生效,原因是该位是保留位,要求写固定值,手册里小字写了"must be written as 1",我没看。这种问题只有读回校验才能快速暴露。
第三是总线上多个从机的 MISO 要三态。SPI 的 MISO 是所有从机共用的,如果某个从机的 MISO 不是高阻态输出,而它的 CS 又没被拉低,就会和当前活跃从机的 MISO 打架,导致数据错误。选从机芯片时看一下 datasheet 的 MISO 是否支持高阻态,不支持就必须在 CS 电路上做额外处理,或者每个从机串电阻隔离。
5.3 UART:波特率算不对,一切白搭
UART 看似简单,但波特率误差是个隐蔽的坑。很多低成本 MCU 的波特率发生器是整数分频的,如果你的系统主频不是波特率的整数倍,实际波特率就会有偏差。通讯距离短、时钟容限大时看不出来,一旦线一长、双方时钟误差叠加,接收端就出现误码。排查方法是查看芯片参考手册里波特率寄存器的分频表,计算最接近实际值的那一档,必要时改用系统 PLL 提供精确时钟。
还有一个高频问题:TTL UART 和 RS-232 混接。TTL 电平逻辑"1"是 2.4V 以上,"0"是 0.5V 以下;RS-232 则是"1"为 -3V 到 -15V,"0"为 +3V 到 +15V。如果把两个 TTL 设备和 RS-232 设备直接连线,电平范围不对等,芯片可能识别不了。解决办法很简单,中间加一颗 MAX3232 之类的电平转换芯片。接 RS-485 则要配置方向控制引脚,半双工模式下方向和收发切换的时序要处理好,A/B 线不能接反,终端电阻也不要随便加。
5.4 I2S:主时钟和左右声道对齐搞错就出怪声
I2S 的问题往往不是"完全没有声音",而是"有声音但不对"。最常见的现象是播放出来的声音有持续爆音、左右声道错乱、或者采样率漂移。爆音的根源多半是 MCLK 没配好。很多 Codec 需要一个稳定的主时钟 MCLK,通常是 256 × fs 或 512 × fs。如果你的主控给 I2S 外设的时钟源算出来不是整数比,输出采样率就会偏离标称值,内部的 Delta-Sigma 调制器工作不正常,噪声就出来了。
左右声道对齐同样关键。不同的音频 Codec 可能要求标准 I2S 格式、左对齐格式或右对齐格式。标准 I2S 的数据位会比 WS 跳变晚一个 BCLK;左对齐格式则是数据和 WS 同时变化。如果你在代码里用标准 I2S 发,而 Codec 配置成了左对齐格式,声音听起来可能是破的,或者左右声道混在一起。调试 I2S 时,逻辑分析仪同时抓 BCLK、WS 和 SD 三根线,用"每 1 bit 对应 BCLK 一个周期、每 16 bit 对应 WS 半周期"这个节奏去对,很快就能看出来是哪种格式。
还有一个容易被忽视的点:主从模式的选择。如果外部 Codec 需要自己产生时钟并让主控去跟它同步,那主控 I2S 就要配成从模式。从模式下主控不能随便暂停 DMA 或改变时钟,否则可能出现 FIFO 溢出或下溢,表现为"忽快忽慢"。我自己做 ESP32-C3 接 I2S DAC 播放音频时,就把 I2S 外设配成主模式,由主控统一产生 BCLK/WS,这样时钟链路最简单,软件上少很多麻烦。
5.5 通用习惯:抓波形永远比猜更快
最后说一条贯穿所有协议的经验:无论你调哪条总线,先把逻辑分析仪或示波器接上去,抓真实波形。我调试的固定动作是先看波形再写代码。I2C 抓起始条件、地址 ACK、停止条件;SPI 抓 CS 下降沿到第一个 SCLK 上升沿的间距、模式匹配情况;UART 抓起始位下降沿和停止位高电平;I2S 抓 BCLK 和 WS 的关系。波形不会骗人,它能帮你把"代码问题"和"硬件问题"快速区分开。
这四条总线发展到今天都已经是极其成熟的技术,随便一颗单片机都内置了对应的硬件外设。但它们不是替代关系,而是互补关系:UART 管点对点、SPI 管高速率、I2C 管多设备、I2S 管音频流。你越早建立这种"按需求选型"的意识,后面踩的坑就越少。哪怕只是记着"先算数据量、再看设备数、最后想时钟来源"这三句话,你在项目里做通信方案时就能少纠结很多。