← 返回基础原理库

I2C 总线:两根线挂一串设备

最后更新 2026-06-20
⏱ 约 8 分钟 🟢 软件/低风险

你接 OLED 屏会发现,不管它显示多复杂,信号线就两根:SDA 和 SCL。再接一个气压传感器,还是接这两根。这就是 I2C 的魔法——一条总线挂一串设备。它怎么做到不打架的?

两根线是什么

I2C 是一种半双工的两线制总线。半双工的意思是:收和发共用同一条数据线,同一时刻只能有一个方向在跑,不能边发边收。这两根线各管一件事:

  • SDA(数据线,Serial Data):车上运的货——也就是每一个 bit 的数据。
  • SCL(时钟线,Serial Clock):司机打的节拍——由主控发出,大家跟着这个节奏一位一位收发,不会乱。

数据什么时候算数、什么时候变,全看 SCL 的节拍卡着。所以 I2C 是同步总线(有独立时钟线),这点和只有一根 TX/RX、双方各自约定波特率的 UART 不一样。

只用两根线就能同时管地址、数据、方向,靠的是一套约定:SCL 高电平期间 SDA 拉低表示"开始"(Start)、拉高表示"停止"(Stop),中间每个时钟周期传一位。你不用手写这些时序,驱动都封好了,但知道有这么回事,遇到逻辑分析仪抓波形时才看得懂。

公交车 + 门牌号:主从和 7 位地址

把 I2C 想成一条公交线路,主控(ESP32)是司机,挂在线上的每个设备是一个站点:

  • 通信永远由主控发起,从设备只被动应答,这叫主从模式
  • 每个从设备出厂时就有一个7 位地址当"门牌号"(如 OLED 常见 0x3C)。7 位意味着理论上能编 128 个地址(实际有几个保留),足够挂一大串。
  • 主控在总线上先喊出地址"0x3C 听着",只有这个地址的设备会应答(拉低 SDA 给一个 ACK),其它设备装没听见。

所以你能在同两根线上挂 OLED、传感器、扩展板一大串,靠地址点名,互不干扰——这正是 I2C 最省线的原因:加一个设备,不用多拉一根线。

为什么必须上拉电阻

这是 I2C 最容易被忽略、又最容易坑人的地方。I2C 的 SDA、SCL 都是开漏(open-drain)输出:设备只能把线往下拉到低电平,没法主动把它拉高。为什么这么设计?因为总线上挂着好几个设备,如果谁都能主动输出高、又有谁输出低,就会电源对地打架烧管子。开漏让大家只会拉低、松手就放开,天然不会冲突(关于开漏的原理见 GPIO 输出模式)。

代价是:没人拉高,线就一直悬空。所以必须外接上拉电阻到 VCC,把默认状态提到高电平。典型值 4.7kΩ(3.3V 系统常用 4.7k,走线短、速度低可以更大到 10k,快速模式或多设备可减到 2.2k)。很多模块板已自带上拉,裸芯片或自己画板就必须补上——缺上拉是 I2C 不通的头号原因,现象是扫描不到任何设备。上拉怎么选值,见 上拉电阻

时钟速率有几档

SCL 的节拍快慢就是通信速率,常用两档:

  • 标准模式 100kHz:最稳,兼容性最好,绝大多数传感器和小屏够用。
  • 快速模式 400kHz:刷屏、读大量数据时用,速度快 4 倍。

还有 1MHz(Fast-mode Plus)、3.4MHz(高速)等,但外围器件不一定支持,且走线、上拉都更挑。没把握就先跑 100k,通了再往上提。速度越高,上拉电阻要越小、走线要越短,否则波形爬不起来会误码。

从设备忙不过来:时钟拉伸

有些从设备收到命令后数据一时准备不好——比如一个温湿度传感器要现场做一次转换。I2C 给了它一个"喊暂停"的机制,叫时钟拉伸(clock stretching):从设备在本该松开 SCL 的时候偏偏继续把它按住不放,主控一看时钟线还是低的,就知道"对方还没好",乖乖等着;等从设备把数据备齐、松开 SCL,通信才接着走。

这机制平时很省心,但有两个坑要记住。一是有些主控的硬件 I2C 外设不支持或支持得不干净(ESP32 早期版本就有这毛病),碰到会拉伸时钟的从设备就读错数,解决办法是换支持拉伸的驱动、或者干脆用软件模拟 I2C。二是如果某个从设备程序卡死、一直按着 SCL 不撒手,整条总线就被它拖死了——这和下面"总线卡死"是同一回事。

读一个寄存器,其实分两步

你以为"读传感器"就是主控直接读一串数据?其实绝大多数 I2C 器件内部是一排寄存器,你得先告诉它"我要读哪一个"。所以一次读操作是这样的:

  1. 主控先发:点名地址 + 要读的寄存器编号(比如 0x00)——这一步是在"拨台"。
  2. 主控发一个重复起始(Repeated Start):不松总线、直接再来一次 Start,紧接着还点这个地址,但这次标
  3. 从设备把那个寄存器的内容一字节一字节吐出来,主控每收一个回一个 ACK,收够了回 NACK 加 Stop 收尾。

关键是第 2 步的重复起始:它不先 Stop 再 Start,就是为了中途不放开总线,防止多主场景里别的主控插队抢走。你抓逻辑分析仪,会看到一个 S … Sr … P 的结构,就是这么回事。这些驱动都替你封好了,但当你读出来"全是 0xFF"时,八成是第 1 步的寄存器编号没发对。

实战三个坑

  • 地址冲突:两个相同地址的设备挂一条线就打架,主控点名时俩一起应答,数据全乱。很多模块板留了焊盘或跳线让你改地址(比如 OLED 在 0x3C/0x3D 之间切)。
  • 上拉缺失:如上,裸芯片忘了加上拉,扫描全空。
  • 总线卡死:某个从设备在传输中途死了、还占着把 SDA 拉低不放,整条总线就锁住了。硬办法是给 SCL 手动打几个时钟脉冲把它"敲醒",软件复位往往救不回来。
  • 长线掉速:线拉长、挂的设备多,总线电容变大,波形上升沿变慢。表现是 100k 好好的、提到 400k 就误码。补救是减小上拉电阻或缩短走线,别硬提速。
💡 提示

不知道挂上去的设备地址是多少?跑一个 "I2C Scanner" 程序,它会把总线上所有响应的地址打印出来。这是接 I2C 设备的第一步——扫得到地址,说明接线和上拉都对了;扫不到,先查上拉。

ESP32-S3 上怎么用

ESP-IDF 5.x 用 i2c_master 驱动:先 i2c_new_master_bus 建总线(指定 SDA/SCL 引脚、是否启用内部上拉),再 i2c_master_bus_add_device 把设备的 7 位地址挂上去,之后收发直接调设备句柄。注意内部上拉很弱(几十 kΩ),正式项目仍建议板上加实体 4.7k。

一句话口诀

I2C = 两根线(SDA 数据、SCL 时钟)+ 主从 + 7 位地址点名,一条总线挂一串。三条铁律记牢:开漏必须外接上拉(典型 4.7k)、速度先跑 100k、接不通先跑 Scanner 查地址和上拉

什么时候用 I2C

设备多、速度要求不极致(传感器、小屏)时,I2C 最省线。要更快(大彩屏、SD 卡)就看 SPI。两者到底怎么选,看 通信协议横评 的对比表。

内容有错、看不懂、或想看下一期?告诉我们 →

本文为公开资料的学习整理,非亲测。涉接线/花钱/合规的步骤请结合实物与官方最新资料验证,风险自负。见免责声明