1. I2C协议基础:从物理层到时序解读
各位同学,咱们今天正式开讲I2C。说实话,做了这么多年嵌入式,I2C是我用得最多的总线之一。它简单、灵活,两根线就能搞定一堆外设。但越是简单的东西,出起问题来反而越让人头疼。我记得刚入行那会儿,一个温度传感器死活读不到数据,折腾了两天,最后发现是上拉电阻焊错了——嗯,这种坑咱们后面会细聊。
先搭个框架,让大家心里有数。这一章我们主要聊三块:
- 物理层——总线长什么样,电气特性如何
- 协议层——起始、停止、数据、应答,这些基本动作怎么玩
- 时序图解读——拿到一张时序图,怎么快速抓住关键信息
下面这张图,是我自己画的知识结构,建议你先扫一眼,有个整体印象。
1.1 物理层:两根线怎么撑起一片天?
I2C只有两根线:SCL(时钟线)和SDA(数据线)。所有设备都挂在这两根线上,主设备负责产生时钟,从设备听令行事。
这里有个关键点——开漏输出。说白了,设备只能把线拉低,不能主动拉高。那高电平谁来给?上拉电阻。我见过不少新手在这上面栽跟头,电阻选大了信号上升沿太慢,选小了功耗又高。标准模式下一般用4.7kΩ,快速模式用2.2kΩ左右,具体还得看总线电容。
地址方面,I2C支持7位和10位两种地址格式。7位地址最多挂127个设备,实际中够用了。每个设备有个唯一地址,主设备通过地址来选择跟谁说话。
1.2 协议层:四个基本动作,搞定一切通信
I2C的协议层其实不复杂,核心就四个动作。你把这四个搞明白了,剩下的都是组合拳。
起始条件(Start Condition)
SCL为高电平时,SDA从高切换到低。这个下降沿告诉所有从设备:注意,要开始通信了!
停止条件(Stop Condition)
SCL为高电平时,SDA从低切换到高。这个上升沿表示:本次传输结束,总线释放。
数据有效性
数据在SCL高电平时被采样,所以SDA必须在SCL高电平期间保持稳定。数据变化只能在SCL低电平时进行。这个规则很关键——你想想看,如果数据在SCL高电平时变了,那接收方就不知道你传的是啥了。
应答机制(ACK/NACK)
每传输完一个字节(8位),接收方需要在第9个时钟周期拉低SDA表示应答(ACK)。如果接收方不拉低(SDA保持高),那就是非应答(NACK),表示出问题了。
我曾经遇到一个坑:有个传感器偶尔不响应,查了半天发现是电源纹波太大,导致从设备内部复位,应答信号丢了。从那以后,我每次画板子都会在I2C设备旁边加个100nF去耦电容。
下面这个表格,把四个动作的关键点总结了一下,建议你收藏。
| 动作 | SCL状态 | SDA变化 | 说明 |
|---|---|---|---|
| 起始条件 | 高电平 | 高 → 低 | 下降沿,启动通信 |
| 停止条件 | 高电平 | 低 → 高 | 上升沿,结束通信 |
| 数据有效性 | 高电平 | 保持稳定 | SCL高时采样数据 |
| 应答(ACK) | 第9个时钟 | 被拉低 | 接收方确认收到 |
| 非应答(NACK) | 第9个时钟 | 保持高 | 接收方未确认 |
1.3 时序图解读:别怕,其实有套路
很多同学看到时序图就头大。其实没那么可怕,我教你一个方法:先找起始和停止,再看数据变化,最后盯应答位。
举个例子,主设备向从设备写一个字节的数据,流程是这样的:
- 主设备发出起始条件
- 主设备发送7位从设备地址 + 1位读写位(0表示写)
- 从设备在第9个时钟回复ACK
- 主设备发送8位数据
- 从设备回复ACK
- 主设备发出停止条件
读操作稍微复杂一点,需要先发地址再切换方向,但核心逻辑是一样的。
⚠️ 特别注意:时序图里的建立时间(tSU)和保持时间(tHD)是硬指标。我见过有人用GPIO模拟I2C,延时没算好,数据建立时间不够,从设备就是不认。标准模式下,数据建立时间至少需要250ns,保持时间至少0ns(但建议留点余量)。
我个人习惯,拿到一张时序图后,先用笔把起始条件和停止条件圈出来,然后数时钟个数,最后看数据位和应答位。多练几次,你就能一眼看出问题所在。
好了,这一章的基础知识就到这里。记住,I2C的精髓就是两根线加一个应答机制。后面我们会用这些知识去排查各种通信故障,到时候你就知道今天打的基础有多重要了。