当前位置:首页>排行榜>UART、SPI、I2C:到底怎么选?

UART、SPI、I2C:到底怎么选?

  • 更新时间 2026-11-05 00:22:02
UART、SPI、I2C:到底怎么选?

调一个 I2C 温湿度传感器,读回来全是 0xFF,怀疑芯片焊坏了——结果是 SDA/SCL 的上拉电阻没接,总线一直浮在高电平,0xFF 就是“压根没通信”的默认值。

后来换 SPI 的 Flash,读回来也是全 0xFF——这次是片选 CS 没拉、或者时钟相位(CPHA)配错,主机压根没收到数据。

再往后串口接一个 GPS 模块,收的全是乱码——波特率、数据位、停止位三样里总有一项没对上。

三种总线都叫“串行”,但一个是异步、两个是同步,线数、时钟、地址、应答机制全不一样。各自最容易出的坑也不同:UART 坏在“约定对不上”,SPI 坏在“时钟相位错”,I2C 坏在“上拉和地址”。这篇把它们放到一起对比,讲清差异、逐个拆坑,最后给一句怎么选。

一、先分清:一个异步,两个同步

嵌入式里说的“串行通信”,就是数据一个 bit 一个 bit 按顺序发。但同样是串行,分两大类:

  • 同步:收发双方共用一根时钟线,谁发数据、什么时候采样,都由这根时钟决定。SPI 的 SCK、I2C 的 SCL 就是这种。
  • 异步:没有时钟线,双方事先约好一个速度(波特率),靠起始位来对齐,剩下的自己数。UART 就是这种。

这个区别决定了后面所有的坑:同步协议不怕“速度差一点”,因为时钟说了算;异步协议全靠双方约定,任何一项没对上就乱码。

顺带解释两个词,后面会反复用到:

  • 全双工:收发各走各的线,能同时发、同时收(UART 的 TX/RX、SPI 的 MOSI/MISO)。
  • 半双工:一根线又要发又要收,同一时刻只能一个方向(I2C 的 SDA)。

二、一张总对比表

维度
UART
SPI
I2C
信号线
2 根(TX/RX)+ 地
4 根(SCK/MOSI/MISO/CS)+ 地
2 根(SCL/SDA)+ 地
时钟
无(异步,靠波特率约定)
有,主机供 SCK
有,主机供 SCL
方向
全双工
全双工
半双工
拓扑
点对点
一主多从(星型,靠片选)
一主多从(总线,靠地址)
寻址
无
无(靠 CS 硬件片选)
有(7 位 / 10 位地址)
应答
无(可选校验位)
无(发了不管收到没)
有(ACK/NACK)
速率
常见 9600~115200,可到几 Mbps
最快,MHz~几十 MHz
100k / 400k / 1M / 3.4M
距离
较远(RS232/485 更远)
短(板内)
短(板内)
上拉电阻
不需要
不需要
必须(开漏 + 上拉)
典型场景
调试日志、GPS/蓝牙模块、PC
Flash、TFT 屏、ADC、WiFi 模块
传感器、EEPROM、RTC

这张表不用背,看到“哪一列能对上你的需求”,再往下看对应那一节的坑就行。

三、UART:没有时钟,全靠“约定”

UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)最老也最常见,TX、RX 两根线,接模块、接电脑、打日志都靠它。

一个字节是怎么发出去的

空闲时 TX 保持高电平。开始发一个字节:

  1. 先拉低一个 bit,叫起始位(告诉对方“我要开始了”);
  2. 然后发数据位,常见 8 位;
  3. 可选加一个校验位;
  4. 最后拉高 1~2 个 bit,叫停止位。

这一整套叫“一帧”。常用写法是 8N1:8 数据位、无校验(None)、1 停止位。

波特率是什么

波特率(Baud rate)= 每秒钟发送的符号数。没有时钟,双方必须约好同一个波特率,否则收到的就是乱码。

比如 115200 波特率,每个 bit 大约 8.68 微秒。收发双方的晶振都有误差,误差太大、或者长时间连续发,采样点会慢慢漂到 bit 边界上,照样出错。这就是为什么异步通信别选太高波特率、也别在没流控时连续大量发。

最容易踩的四个坑

  1. 波特率不匹配:最常见。设备默认 9600,你按 115200 收,全是乱码。调试第一步永远是先确认“两边波特率是不是一样”。
  2. 帧格式不匹配:数据位、停止位、校验位,8N1 和 8E1(偶校验)混用也会乱。
  3. 电平标准搞混:UART 只是“协议”,实际信号电平有好几种:   - TTL(3.3V / 5V):MCU 引脚直接出来的那种,空闲高、起始位低。   - RS232:±3V~±15V,而且逻辑是反的。TTL 直接接 RS232 口,轻则不通,重则烧引脚,中间要加电平转换芯片(MAX232 之类)。   - RS485:差分信号(A/B 两根线),抗干扰强、能拉很远、还能挂多机,工业现场常用。
  4. 没有流控会丢数据:UART 全双工但收发独立,接收方来不及处理就会丢。要可靠就用硬件流控(RTS/CTS)或软件流控(XON/XOFF)。

怎么验证

逻辑分析仪抓 TX 波形,量第一个 bit 的宽度,反推波特率(115200 → 8.68µs)。看到乱码,大概率是波形对、波特率/帧格式不对。

四、SPI:快,但“发了不管收到没”

SPI(Serial Peripheral Interface)是同步全双工,四根线,速度最快,常见于 Flash、TFT 屏、ADC、WiFi 模块。

四根线是干什么的

  • SCK / SCLK:时钟,由主机产生,从机自己不产时钟。
  • MOSI(Master Out Slave In):主机发、从机收。
  • MISO(Master In Slave Out):从机发、主机收。
  • CS / SS:片选,低有效。一个从机一根 CS,主机拉低哪个,哪个从机才参与通信。

全双工:发的同时也在收

SPI 最特别的一点:时钟每跳一下,主机通过 MOSI 发一个 bit,同时通过 MISO 收一个 bit。所以你想读数据,也得先“发点东西”把时钟跑起来——这也是为什么读 SPI 寄存器时,经常看到“先写一个假字节(dummy)再读”:

// 读一个字节:SPI 是发一个同时收一个,所以读也要发uint8_t spi_read_byte(void){    // 发 0xFF 纯粹是为了产生 8 个时钟,把从机的数据”顶”出来    return spi_transfer(0xFF);}

最大的坑:CPOL 和 CPHA

SPI 没有规定“时钟边沿怎么用”,主机和从机可以各用各的。为了对齐,有了两个参数:

  • CPOL(时钟极性):空闲时 SCK 是高还是低。0 = 空闲低,1 = 空闲高。
  • CPHA(时钟相位):数据在哪个边沿被采样。0 = 第一个边沿采样,1 = 第二个边沿采样。

两个参数组合出 4 种模式:

模式
CPOL
CPHA
采样边沿
数据变化边沿
Mode 0
0
0
上升沿
下降沿
Mode 1
0
1
下降沿
上升沿
Mode 2
1
0
下降沿
上升沿
Mode 3
1
1
上升沿
下降沿

主机和从机的模式必须一致,否则读回来就是错位的数据,最常见就是全 0xFF 或全 0x00。多数器件文档会直接告诉你用 Mode 0 还是 Mode 3,照着配就行;不放心就抓波形看边沿。

两个容易被忽略的细节:

  • 改 CPOL/CPHA 之前先关掉 SPI,很多 MCU 要求这些配置位在 SPI 使能状态下改动会出问题。
  • CPHA=0 时,CS 要每个字节拉高一次;CPHA=1 时 CS 可以一直拉低。所以“从机片选常接低”这种接法,只对 CPHA=1 有效。

其他几个坑

  1. 没有应答机制:SPI 主机发了就发了,从机收没收到、数据对不对,主机不知道。可靠场景下固件要自己加校验(读回一个固定 ID 寄存器,或加 CRC)。
  2. CS 没拉 / 忘拉高:CS 低有效,传输前拉低、传完拉高。多个从机时 CS 拉错了,数据就发给了别的芯片。
  3. MOSI/MISO 接反:硬件上最容易犯的错,读回来全 0xFF 先查这两根线。
  4. 速度别一上来就拉满:先低速调通再提速。高速(几十 MHz)在长排线上会有振铃、往返延迟,导致 MISO 采样错位(有的 MCU 提供 LATE_MISO_SAMPLE 这类延迟采样来补救)。
  5. 多从机想省 CS 脚:可以用“菊花链”,把上一级的 MISO 接到下一级的 MOSI,数据一路串行移位过去。省脚,但速度慢、协议绕,一般只在从机特别多时用。

怎么验证

逻辑分析仪同时抓 CS、SCK、MOSI、MISO。重点看两件事:CS 有没有在传输前拉低、SCK 的空闲电平和采样边沿对不对得上器件文档。

五、I2C:省线,但“上拉和地址”两个坑最多

I2C(Inter-Integrated Circuit,也写作 IIC / TWI)只有 SCL、SDA 两根线,却能挂一堆器件,是传感器、EEPROM、RTC 的首选。代价是:它有两个 I2C 独有的坑——上拉电阻和地址。

起始和停止,是两根线上的“暗号”

I2C 用两根线上的电平跳变来表示“开始”和“结束”:

  • 起始条件(START):SCL 为高时,SDA 从高跳低。
  • 停止条件(STOP):SCL 为高时,SDA 从低跳高。

一次传输从 START 开始、STOP 结束。读写传感器时经常是“先写寄存器地址,再读数据”,中间用重复起始(Repeated Start)把两段连起来,不释放总线。

为什么一定要上拉电阻

I2C 的两根线是开漏(open-drain)输出:任何器件只能把线“拉低”,不能主动“拉高”。所以总线上必须外接上拉电阻到电源,让空闲时线回到高电平。

  • 不接上拉 → 总线浮空 → 读回来全 0xFF(开头那个坑)。
  • 上拉阻值有讲究:太小,器件拉低时电流大、拉不到合格的低电平;太大,线从低回到高的时间(上升沿)变慢,高速时采样出错。

常见取值:100kHz 用 4.7k,400kHz 用 2.2k 左右,1MHz 用 1k 左右。拿不准就先 4.7k、降到 100kHz 调通再说。

地址:7 位还是 8 位,是最经典的坑

I2C 每个器件有个地址,主机先发地址,匹配上的从机才回应。地址有两种写法,混了就“没应答”:

  • 7 位地址:比如 0x68(常见于 RTC、IMU)。实际发送时会把这 7 位左移 1 位,末位补 0(写)或 1(读),变成 0xD0 / 0xD1。
  • 8 位地址:有些 datasheet 直接写“写地址 0xD0、读地址 0xD1”,这已经是左移并带上读写位的了。

驱动库(比如 STM32 HAL)要的是 7 位地址。所以 datasheet 写 0xD0,你代码里得写 0x68,或者把 0xD0 右移一位。地址对不上,从机不认,主机就一直收 NACK。

// datasheet 写 8 位写地址 0xD0 / 读地址 0xD1,对应 7 位地址是 0x68#define DEV_ADDR_7BIT  0x68// HAL 的地址参数 = 7 位地址左移一位(HAL 内部会再拼上读写位)#define DEV_ADDR_HAL   (DEV_ADDR_7BIT << 1)   // 0xD0

ACK / NACK:每发一个字节,对方都要“回一句”

I2C 每传完 8 个 bit,第 9 个 bit 是应答位:

  • 接收方把 SDA 拉低 = ACK(收到了);
  • 接收方保持高 = NACK(没收到 / 没有这个器件)。

所以“地址发出去后收到 NACK”,几乎等于“没有器件在这个地址上”——先查地址写法,再查器件供电。还有个细节:主机读最后一个字节时,要主动回一个 NACK,告诉从机“不用再发了”,然后发 STOP。

时钟拉伸和死锁

从机如果一时处理不过来(比如正在转换),可以把 SCL 拉低,让主机“等等”。这叫时钟拉伸(clock stretching)。主机必须支持“等 SCL 真正变高再继续”,不能用固定延时。

问题在于:如果从机卡死了,SCL 就永远低,总线死锁。恢复办法:把 SCL 当普通 GPIO,手动发 9 个时钟脉冲,让从机把 SDA 释放掉,再发一个 STOP。

其他几个坑

  1. 地址冲突:两个器件地址一样,都响应,数据就乱。
  2. 速率与线长:总线电容、线长、上拉阻值共同决定能跑多快。器件多了、线长了,就降速。
  3. 多主仲裁:I2C 允许挂多个主机,靠“线与”和仲裁决定谁说话。但嵌入式里绝大多数是单主机,遇到多主先确认是不是配错了。

怎么验证

逻辑分析仪用 I2C 解码,直接看地址、读写位、ACK/NACK、数据。先看第 9 个 bit 有没有 ACK,没有就先查地址和上拉。

六、到底怎么选

先回答三个问题:要快吗?能占几根线?要挂几个器件?

你的需求
选
理由
要高速、大数据量、板内
SPI
全双工、时钟快、无地址应答开销
线少、要挂一堆低速器件
I2C
两根线挂上百个器件、有地址和应答
点对点、接电脑/模块、要简单
UART
两根线、几乎人人支持、好调试
距离远、工业现场
UART + RS485
差分抗干扰、能拉很远、可多机

一句话概括它们的性格:SPI 快、I2C 省、UART 简单。

七、读回 0xFF,是三种总线共用的“没通信”信号

调外设时,读寄存器全是 0xFF(或全是 0x00),别急着怀疑芯片坏,先按总线对号入座:

总线
读回全 0xFF,先查
UART
波特率/帧格式对不对、电平标准对不对、对方到底发没发
SPI
CS 拉没拉低、CPOL/CPHA 对不对、MOSI/MISO 接反没
I2C
上拉电阻接没接、地址(7 位/8 位)写对没、有没有 ACK

最后一句实用的

三条排查口诀,背下来能省很多时间:

  • UART 乱码 → 先对波特率,再对帧格式,最后量电平。
  • SPI 读 0xFF → 先查 CS,再对 CPOL/CPHA,最后查 MOSI/MISO 接线。
  • I2C 读 0xFF → 先查上拉,再看 ACK,最后查地址。

三者共通的判断:先确认“物理上的线和电平对不对”,再确认“协议参数对不对”,最后才怀疑芯片和代码。

相关阅读

  • 《数组指针 vs 指针数组:名字反过来,用法全变了》
  • 《a、&a、&a[0]:地址一样,凭什么说它们不一样?》
  • 《网口调试绕不开的基础常识:IPv4、IPv6、PoE、交换机和子网掩码》

「外设与通信」方向后续还会单点展开:SPI 四种模式的波形实拍、I2C 上拉电阻怎么算、UART 电平标准(TTL/232/485)选型。

随机文章