· I2C

I2C

1862 字
9 分钟
I2C
StarryLin/Geek · 摘要

I2C用SDA、SCL两根开漏线上拉实现同步半双工板级总线,靠地址帧、ACK、起始停止位与时钟拉伸完成一主多从通信,边界是短距低速。

一、两根线,各司其职#

I2C(Inter-Integrated Circuit,读作 “I 方 C”)是飞利浦(现 NXP)在 1982 年推出的。它的物理层极简:

表格

引脚名称作用
SDASerial Data数据线,双向传输
SCLSerial Clock时钟线,由主机驱动(从机可拉低”暂停”)

没有 TX/RX 之分,两根线都是开漏(Open-Drain)输出,必须外接上拉电阻到 VCC。正因为是开漏,多个设备可以直接把 SDA/SCL 并在一起——谁想说话,就把线拉低;不想说话,就松手(线被电阻拉回高电平)。

这就是 I2C 的**“线与”逻辑**:只要有一个设备拉低,整条线就是低电平。天然支持多设备仲裁。


二、同步通信:时钟说了算#

和 UART 的异步不同,I2C 是同步通信。主机通过 SCL 线发出时钟脉冲,SDA 上的数据必须在 SCL 高电平期间保持稳定,在 SCL 低电平期间翻转。

plain

┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐
SCL ───┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘─────┘ └─
┌───┐ ┌───────┐ ┌─────────┐
SDA ───┘ └───┘ └───────┘ └───
D7 D6 D5 D4 D3 D2 D1 D0
↑ SCL 高电平时 SDA 必须稳定 ↑

接收端不用猜”什么时候采样”,盯着 SCL 的上升沿或高电平中段读 SDA 就行。所以 I2C 的时钟可以慢到几 Hz,也可以根据从机能力动态调整——这是异步串口做不到的。


三、一帧数据的结构#

I2C 没有”起始位/停止位”的概念,它靠特殊的电平跳变来标记开始和结束。

1. 起始位(Start, S)#

SCL 为高电平时,SDA 从高变低。

2. 停止位(Stop, P)#

SCL 为高电平时,SDA 从低变高。

3. 数据帧格式#

plain

[ S ] [ 从机地址(7bit) + R/W(1bit) ] [ ACK ] [ 数据1(8bit) ] [ ACK ] ... [ 数据N ] [ ACK/NACK ] [ P ]
↑ ↑ ↑ ↑ ↑
起始 地址帧,第8位是方向位 从机应答 每8位数据 每字节应答
  • 地址帧:7 位地址(范围 0x00~0x7F,但 0x00 广播保留,部分地址保留给特殊用途)+ 1 位读写标志(0=写,1=读)。

  • ACK(应答):每传输完 8 位,接收方必须在第 9 个时钟把 SDA 拉低,表示”我收到了”。如果保持高电平,就是 NACK(没收好/没空/结束了)。

  • 数据帧:真正的 payload,每字节 8 位,MSB 先传(和 UART 的 LSB 先传相反)。


四、一次完整的读写对话#

写操作:主机给从机发数据#

假设主机(MCU)要给地址为 0x50 的 EEPROM 写入数据 0xAB 到寄存器 0x10:

plain

主机: [S] [0x50 + W(0)] [ACK] [0x10] [ACK] [0xAB] [ACK] [P]
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
起始 地址+写 从机应答 寄存器地址 应答 数据 应答 停止

读操作:主机从从机取数据#

假设主机要从地址 0x50 的 EEPROM 读取寄存器 0x10 的值:

plain

主机: [S] [0x50 + W(0)] [ACK] [0x10] [ACK] [Sr] [0x50 + R(1)] [ACK]
从机: [0xAB] [NACK] [P]
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
起始 地址+写 应答 寄存器 应答 重复起始 地址+读 应答 数据 主机NACK 停止

注意读操作通常需要两次起始:第一次告诉从机”我要读哪个寄存器”,第二次切换成读模式。中间的 Sr 是重复起始(Repeated Start),不释放总线,防止被其他主机抢走。


五、时钟拉伸:从机”喊暂停”#

I2C 里从机不是完全被动的。如果某个从机处理不过来(比如 EEPROM 正在写内部 Flash),它可以把 SCL 拉低,强制主机等待:

plain

SCL ─────┐ ┌─────┐ ┌───┐ ┌───┐
└─────┘ └─────┘ └────────┘ └───
↑_________↑
从机把SCL拉低,主机必须等

主机检测到 SCL 被自己释放后仍然为低,就进入等待状态,直到从机松手。这叫 Clock Stretching,是 I2C 优雅处理速度不匹配的关键机制。


六、速度等级#

I2C 不像 UART 那样随意设波特率,它有几个标准模式:

表格

模式速率典型应用
标准模式(Sm)100 kHz老传感器、EEPROM
快速模式(Fm)400 kHz主流 MEMS、触摸屏
快速模式+(Fm+)1 MHz较新的外设
高速模式(Hs)3.4 MHz需要高速吞吐的场景
超快速模式(UFm)5 MHz单向传输,较少见

实际开发中,如果总线挂的设备多、线缆长,往往需要把速率降到 100 kHz 甚至更低,保证信号完整性。


七、和 UART / RS-485 的对比#

表格

特性UARTRS-485I2C
线数2~3 根(TX/RX/GND)2 根(A/B,差分)2 根(SDA/SCL)
时钟异步,双方约定波特率异步同步,主机带时钟
设备数点对点一主多从(32~256)一主多从+多主仲裁
方向全双工半双工为主半双工
寻址无,靠物理接线区分无,靠轮询或上层协议内置 7/10 位地址
传输距离短(<15m)长(1200m)短(<1m 板级,<10m 低速)
速率常见 115200最高 10 Mbps最高 3.4 Mbps
应答机制无(硬件层)无(硬件层)每字节硬件 ACK
抗干扰弱强(差分)弱(单端开漏)

I2C 的设计哲学是**“板级互联”**——同一块电路板上,MCU 和周边芯片之间的短距通讯。如果要跨板、跨机柜、抗强干扰,请回 RS-485 的怀抱。


八、实际接线与上拉电阻#

plain

VCC (3.3V / 5V)
│
┌┴┐
│ │ Rp(典型 4.7kΩ,取决于总线电容和速率)
└┬┘
├──────────┬──────────┐
SDA SCL │
│ │ GND
┌────┴────┐ │
MCU 传感器A 传感器B
(主机) (从机) (从机)

上拉电阻选多大?

  • 电阻太小:功耗大,低电平时电流大,开漏管可能拉不动

  • 电阻太大:上升沿变缓,高速时信号变形

  • 经验值:4.7kΩ @ 100kHz,2.2kΩ @ 400kHz,1kΩ @ 1MHz

  • 多设备并联时,总线电容增大,电阻适当减小或降低速率


九、常见问题与排雷#

表格

现象可能原因
总线一直低,无法启动某个设备死锁,持续拉低 SDA 或 SCL;或上拉电阻虚焊
偶尔丢数据线缆太长、上拉电阻太大、速率太高;或缺少 ACK 处理
多设备冲突地址冲突(两个从机地址相同);或多主机场景没做仲裁
读数据全为 0xFF从机没应答(NACK),SDA 被电阻拉高了

十、总结#

表格

概念一句话理解
SDA / SCL数据线和时钟线,开漏输出,必须上拉
起始/停止SCL 高时,SDA 下降沿=开始,上升沿=结束
7 位地址 + R/W先喊门牌号,第 8 位告诉对方”我要读还是写”
ACK每传 8 位,接收方拉低 SDA 表示”收到”
时钟拉伸从机拉低 SCL 喊暂停,主机乖乖等着
重复起始不挂电话直接转读模式,防止总线被抢
上拉电阻开漏的命根子,决定信号质量和功耗

十一、一点延伸#

I2C 的地址只有 7 位(128 个),现代芯片越来越多,出现了地址冲突。解决方案:

  • 10 位地址扩展:用两个字节发地址,兼容老设备

  • I2C 开关/多路复用器(如 TCA9548A):一条总线分成多条,软件选通

  • SMBus / PMBus:基于 I2C 的工业/电源管理子集,增加了超时、PEC 校验等

如果你的项目只是在同一块 PCB 上连几个传感器、RTC、OLED,I2C 是最省引脚、最省 PCB 走线的选择。两根线,一排设备,优雅又简洁。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

I2C
https://mjzy.tech/posts/通信协议/06-i2c/
作者
JIA
发布于
2026-08-21
许可协议
CC BY-NC-SA 4.0

评论区

正在加载 GitHub 评论…

Tips · 随手记
仅自己可见 · 每篇文章单独保存

文章目录