1. I2C协议基础:物理层特性与协议层规范

各位同学,咱们今天聊聊I2C。这个协议在嵌入式开发里太常见了——传感器、EEPROM、ADC、DAC,几乎每个板子上都能见到它的身影。我刚开始做MCU开发那会儿,总觉得I2C就是两根线的事儿,没啥好研究的。结果呢?一次项目里EEPROM死活读不对数据,折腾了两天才发现是上拉电阻选错了。从那以后,我再也不敢小看这两根线了。

说白了,I2C的成功秘诀就两个:物理层简单,协议层灵活。咱们一个一个拆开讲。

1.1 物理层特性:SDA/SCL开漏输出

I2C总线只有两根线:SDA(串行数据线)和SCL(串行时钟线)。但这两根线的驱动方式很特别——开漏输出。

什么叫开漏?你可以理解为:MOS管的漏极是“开”的,没有内部上拉。芯片只能把引脚拉低到GND,但拉不上去。要让它变成高电平,必须靠外部上拉电阻。

开漏输出的核心特点:

  • 芯片只能输出低电平(0)或高阻态(Z)
  • 高电平由外部上拉电阻提供
  • 多个设备可以“线与”——谁拉低谁说了算

为什么I2C要用开漏?我个人的理解是:为了多设备共用总线时不打架。你想啊,如果两个设备同时往一根线上输出,一个输出1一个输出0,那就短路了。开漏模式下,谁想拉低就拉低,谁想发高电平就释放总线,靠上拉电阻自动拉高。这就是“线与”逻辑——只要有一个设备拉低,总线就是低电平。

1.2 上拉电阻选择:不是随便焊一个就行

上拉电阻选多大?这个问题我面试过不少人,十个里有八个答不上来。其实就两个约束:

约束条件 说明 典型值
最小电阻 由灌电流能力决定。电阻太小,拉低时电流过大,会烧坏IO口 ≥ 1.6kΩ(VCC=3.3V,IO灌电流≤2mA)
最大电阻 由总线电容和上升时间决定。电阻太大,上升沿太慢,时序不满足 ≤ 10kΩ(100kHz,总线电容≤200pF)

实际项目中,我一般这么选:

  • 100kHz标准模式:4.7kΩ 或 10kΩ,通用
  • 400kHz快速模式:2.2kΩ 或 3.3kΩ,保证上升沿够陡
  • 1MHz快速+模式:1kΩ 左右,但要注意灌电流是否超限

我的经验:如果总线上挂的设备多(超过4个),或者走线比较长(超过10cm),建议用示波器实测一下上升时间。我曾经在一个项目里用了10kΩ电阻,总线电容太大,SCL上升沿拖到了1μs,100kHz都跑不稳。换成4.7kΩ后问题解决。

1.3 协议层规范:起始条件与停止条件

I2C的通信由主设备发起,以起始条件开始,以停止条件结束。这两个条件是总线上最关键的信号——所有设备都在盯着它们。

起始条件(S):

  • SCL为高电平时,SDA从高电平跳变到低电平
  • 只有主设备可以发出起始条件
  • 通信开始前,总线必须处于空闲状态(SDA和SCL都是高电平)

停止条件(P):

  • SCL为高电平时,SDA从低电平跳变到高电平
  • 停止条件发出后,总线释放,回到空闲状态

注意:起始条件和停止条件都是SCL高电平时SDA的跳变。而在数据传输过程中,SCL高电平时SDA必须保持稳定。这个区别很重要——我曾经见过有人把数据线上的跳变误判成起始条件,导致整个通信错乱。

1.4 数据有效性:SCL高电平时采样

I2C的数据传输规则很简单:

  • SCL低电平时:SDA可以变化(数据准备阶段)
  • SCL高电平时:SDA必须稳定(数据采样阶段)

每个时钟脉冲传输1位数据。先传高位(MSB),再传低位(LSB)。8个时钟脉冲传完一个字节后,第9个时钟脉冲用于应答。

你想想看,这个设计其实很巧妙。SCL低电平时改变数据,高电平时采样——这样只要保证SCL高电平期间SDA不变,就不会采错。抗干扰能力比UART那种异步采样强多了。

1.5 应答机制:ACK与NACK

应答是I2C协议里最容易被忽视、但又最容易出问题的地方。每个字节传输完成后,接收方必须在第9个时钟周期拉低SDA,表示“我收到了”。

应答规则:

  • ACK(应答):接收方在第9个时钟拉低SDA
  • NACK(非应答):接收方在第9个时钟释放SDA(保持高电平)

什么情况下会出现NACK?

  • 从设备地址不匹配
  • 从设备正忙,无法接收数据
  • 主设备读数据时,读完最后一个字节后发送NACK,通知从设备停止发送

避坑指南:我曾经在一个项目里发现,某个传感器在掉电重启后,第一次通信总是NACK。后来查手册才发现,这个传感器上电后需要5ms的稳定时间。如果在稳定时间内访问它,它根本不会应答。解决方案很简单——在每次通信前加一个10ms的延时。

1.6 知识结构总览

下面这张图把I2C协议基础的核心知识点串起来了。你可以把它当作本章的“思维导图”。

I2C协议基础知识结构图 I2C协议基础 物理层特性 SDA/SCL开漏输出 上拉电阻选择 线与逻辑(多设备共用) 协议层规范 起始条件 / 停止条件 数据有效性(SCL高采样) 应答机制(ACK/NACK) 核心:物理层决定“能不能通” 协议层决定“通得对不对”

1.7 本章小结

I2C协议基础,说白了就是两件事:物理层怎么接线,协议层怎么握手。物理层搞不定,上拉电阻选不对,通信根本起不来。协议层搞不清楚,起始条件、停止条件、应答机制弄混了,数据传过去也是错的。

我个人建议,初学者先别急着写代码。拿示波器或者逻辑分析仪,看看实际波形——起始条件长什么样?停止条件怎么跳变的?ACK时SDA是不是被拉低了?亲眼看过一次,比读十遍手册都管用。