I2C协议核心时序:起始、停止、数据位与应答

好,咱们正式进入协议层面。I2C的通信说到底就是四条规矩:起始条件怎么发、停止条件怎么收、数据位怎么摆、应答位怎么确认。把这四条记牢了,I2C就懂了七成。

我的习惯:刚开始学I2C时,我总把时序图和代码分开看,结果一调就翻车。后来我把时序节点直接注释在代码里,每个SCL边沿都标清楚该干什么。效果很明显。

起始条件(S)和停止条件(P)

先看起始条件。SCL在高电平的时候,SDA从高电平切换到低电平。注意,必须SCL先稳定在高电平,SDA才能跳变。为什么会这样?因为SCL高电平时总线是空闲状态,SDA不能随便动,只有起始条件才允许这个操作。

停止条件正好反过来:SCL高电平时,SDA从低电平切回高电平。这两个条件都是主设备控制的,从设备只能被动响应。

起始条件:SCL=1 → SDA 1→0
停止条件:SCL=1 → SDA 0→1

我曾经在项目里遇到一个坑:主设备发完起始条件后,SCL没保持够时间,从机没识别到。结果后续数据全对不上。查了两天才发现是起始条件的保持时间(tHD;STA)不满足规格书。所以说,别看时序图简单,参数一个都不能省。

数据位传输:SCL与SDA的配合

数据位的规则只有一句话:SCL低电平时SDA才能变化,SCL高电平时SDA必须保持稳定。你想想看,如果SCL高电平时SDA变了,那就会被解释成起始或停止条件。所以规范里严格规定了数据建立时间(tSU;DAT)和保持时间(tHD;DAT)。

一个字节有8位,从最高位(MSB)开始传。主设备每发一个位,都会拉低SCL,改变SDA,然后释放SCL让从机拉高(或主设备自己拉高),在SCL高电平中间采样。

时序参数含义标准模式(100kHz)快速模式(400kHz)
tSU;DAT数据建立时间≥250 ns≥100 ns
tHD;DAT数据保持时间≥0 ns≥0 ns
tHIGHSCL高电平时间≥4.0 μs≥0.6 μs
tLOWSCL低电平时间≥4.7 μs≥1.3 μs
注意:tHD;DAT虽然标称≥0 ns,但实际请留至少几十ns余量。我见过某些微控器的I2C外设在0 ns时抓不到数据。

应答位机制:ACK与NACK

每传完一个字节(8位),就会紧跟一个应答位(第9个SCL时钟)。规则很简单:

  • 发送方在第9个SCL时钟释放SDA(变为高阻输入)
  • 接收方如果想应答,就把SDA拉低
  • 如果接收方不想应答(比如错了、忙、或是最后一个字节),就保持SDA高电平

主设备怎么区分是应答还是非应答?很简单,主设备在第9个SCL高电平采样SDA。低电平就是ACK,高电平就是NACK。

避坑指南:我曾经调试一块温度传感器,读寄存器时总返回0xFF。示波器一看,从机在应答位发了NACK。原因是地址对了,但寄存器地址没发对。另一种情况:从机正在处理内部操作时,会主动拉低SCL(时钟拉伸),如果你没处理好,应答位会乱掉。

记住这个规律:
- 每个字节后必须有应答位(不管是主发还是从发)
- NACK通常用来表示传输结束或错误
- 从机时钟拉伸时,SCL被拉低,主设备必须等待

下面这张图把一次完整写事务的时序串起来,从起始到停止。你看,SCL和SDA的配合非常规矩。

I2C写事务完整时序流程图(主发数据到从机) 起始条件 S 设备地址 + R/W 从机应答 ACK 数据字节 (8位) 从机应答 ACK 停止条件 P 时序要点说明 • 每个数据字节(8位)后紧跟应答位(第9个SCL时钟) • 主设备在SCL高电平时采样SDA,确保数据稳定 • 从机可拉低SCL进行时钟拉伸,主设备必须等待 • 如果从机发NACK,主设备应发停止条件结束传输

说白了,I2C协议的本质就是主设备控制SCL的节奏,SDA在合适的时候变、合适的时候稳。起始和停止是帧头帧尾,数据位是内容,应答位是握手信号。把这套逻辑刻在脑子里,你写驱动时就能预判什么时候总线会卡住。

我的总结:I2C没有单独的片选线,全靠起始/停止条件来指定通信边界。所以这两个条件一定不能出错,否则整个总线就乱了。

好了,这一章就讲这些。你可以找一块示波器抓一下实际波形,对照着看,比只看书本深刻很多。