I2C总线协议基础:物理层、起始条件、停止条件、数据传输格式

做嵌入式这些年,调试I2C可能是最频繁的活儿之一。两根线、一个时钟、一个数据,看似简单,坑却不少。今天我把I2C协议最核心的东西掰开讲——物理层怎么接、起始停止怎么抓、数据怎么传。这些都是逻辑分析仪抓I2C波形时绕不过的基本功。

I2C物理层:就两根线,别接错

I2C总线只有两条线:SCL(时钟)和SDA(数据)。所有设备都挂在这两条线上,谁都可以拉低,但谁都不能主动拉高。拉高靠的是上拉电阻。

我当年第一个项目,I2C通信死活时好时坏。逻辑分析仪一抓,SCL信号像锯齿一样。后来发现是忘了加上拉电阻,总线高电平全靠芯片内部弱上拉,根本带不动多个从机。嗯,这里要注意——外部上拉电阻省不得。

参数标准模式 (100kHz)快速模式 (400kHz)
上拉电阻推荐值4.7kΩ ~ 10kΩ1.5kΩ ~ 4.7kΩ
总线电容上限400pF400pF
SCL低电平时间≥4.7μs≥1.3μs
SCL高电平时间≥4.0μs≥0.6μs
经验值: 我习惯先按4.7kΩ起步。如果通信距离超过半米,改成2.2kΩ会更稳。总线电容大时,上拉电阻太小会导致上升沿变慢,波形畸变——逻辑分析仪上会看到“圆角”信号。

起始条件与停止条件:总线上的“举手”与“散会”

I2C总线上,所有传输都以起始条件开始,以停止条件结束。这是最基础的两个波形,也是逻辑分析仪解码的前提——你设置触发条件时,常用“起始条件”做触发。

起始条件:SCL高电平时,SDA从高电平跳变到低电平。
停止条件:SCL高电平时,SDA从低电平跳变到高电平。

说白了,就是在SCL高电平期间,SDA不能乱变。只有SCL为低电平时,SDA才能改变。这个规则保证了数据线的稳定性。

我曾经掉过的坑: 有一次用逻辑分析仪抓波形,死活抓不到起始条件。后来才发现是主控芯片的I2C外设初始化顺序搞反了——先拉高了SDA再拉高SCL,导致起始条件前有一段不确定电平。正确的初始化顺序应该是:先拉高SCL,再拉高SDA,然后等待。绝大多数芯片的I2C外设都会帮你处理,但如果你像我当时一样用GPIO模拟I2C,这个细节千万注意。

数据传输格式:每个字节都是9位

I2C数据传输的基本单位是字节,但每个字节在总线上实际上占9个SCL时钟周期。

  • 前8个周期:主机驱动SDA,按MSB-first发送8个数据位
  • 第9个周期:从机驱动SDA,发送一个ACK(低电平)或NACK(高电平)

你想想看,如果从机没来得及处理上一字节,它会在第9个时钟拉高SDA(NACK),主机收到NACK后就知道该停止或重发。这也是I2C通信的核心——每发一字节,必须等待对方确认。

关键点: 逻辑分析仪上查看ACK/NACK非常直观。在SCL第9个上升沿采样SDA,如果看到低电平就是ACK,高电平就是NACK。我通常用逻辑分析仪的“协议解码”功能自动标出ACK/NACK,但手动看波形时,重点关注第9个时钟沿前后的SDA电平变化。

完整数据帧的构成

一次典型的I2C写操作,波形是这样的:

起始条件 + 7位从机地址 + 1位R/W(0) + ACK + 
寄存器地址(1字节或2字节) + ACK +
数据字节0 + ACK + ... + 数据字节n + ACK/NACK + 
停止条件

读操作则复杂一些——主机先发写命令指定寄存器地址,然后重新发送起始条件(即重复起始条件,Repeated Start),再发读命令,从机才输出数据。

为什么要有重复起始?你可以避免释放总线后再重新仲裁,保持总线控制权。我见过不少初学者用停止条件+起始条件替代重复起始,结果导致总线竞争——逻辑分析仪上看到两个起始条件之间多了一个不确定的间隔。

快速判断: 逻辑分析仪上看到连续的START + ADDR + ACK + DATA + STOP,基本是一次完整写操作。如果看到START + ADDR + ACK + REG + ACK + START + ADDR + ACK,那就是读操作中的重复起始。记住这个波形模式,调试时一眼就能识别。

本章知识体系结构图

I2C总线协议基础框架 I2C协议基础 物理层 起始/停止条件 数据传输格式 帧结构 SCL时钟线 SDA数据线 上拉电阻 起始: SCL高时SDA↓ 停止: SCL高时SDA↑ MSB-first 8位数据 第9位ACK/NACK 地址+读/写位 重复起始条件 每个字节占9个SCL周期:8位数据 + 1位ACK/NACK 起始条件后,SCL高电平时SDA不能改变(除起始/停止)

用逻辑分析仪抓起始/停止条件的实操要点

我个人习惯在逻辑分析仪里设置触发条件为“起始条件”。大多数分析仪都内置这个选项,选上之后,按下“单次捕获”,它会等总线出现起始条件时才抓取波形。

为什么要用起始条件触发?因为I2C总线空闲时SDA和SCL都是高电平,如果你用边沿触发,随便一个噪声都会触发。而起始条件的下降沿在SCL高电平时出现,是一个“稳定且唯一”的事件,可以有效过滤噪声。

我曾经踩过的雷: 有一次在I2C总线上同时挂了三个从机,逻辑分析仪抓到的起始条件波形里,SDA下降沿并不陡峭,而是“先抖一下再下降”。后来查明是上拉电阻选太大(10kΩ)导致总线电容充放电太慢。换成4.7kΩ后波形立即干净了。所以,波形边沿不干净时,别急着怀疑协议,先看硬件。

再说一个技巧——用逻辑分析仪测量起始条件和停止条件之间的时间间隔。有时候调试从机响应慢,就可以用游标卡一下:起始条件到停止条件的总时长,减去所有数据字节和ACK的固定时间,剩下的就是从机的处理延迟。这个数值往往能帮我们定位到底是主机的时序参数不对,还是从机内部处理太慢。

数据传输格式的“第9位”陷阱

很多初学者以为I2C传8位数据就是8个时钟。错了,实际上是9个。第9个时钟是给从机应答的机会。如果从机不拉低SDA,主机就知道出了问题。

在逻辑分析仪上,我习惯这样解读:把SCL的上升沿作为采样点,一个字节结束后,在第9个SCL上升沿读SDA电平。如果SDA是低,OK;如果是高,NACK。这时候你可以判断:是地址不对(从机没应答)、还是寄存器地址越界、或者从机正忙?我遇到过一种情况:从机上电后需要几毫秒初始化,在此期间它对任何地址都回NACK。逻辑分析仪上看到第一个地址字节后就是NACK,我就知道需要加延时或重试。

一句话总结: I2C的物理层靠两根线上拉电阻实现“线与”,起始/停止条件是总线控制权的交接信号,数据传输严格遵循“8位数据+1位应答”的9位周期。这三个基础点,是你用逻辑分析仪看I2C波形的核心底子。