4. I2C总线协议进阶:7位地址和10位地址、读写操作、时钟 stretching
前面我们已经聊了I2C的基础时序,说白了就是Start、Stop和字节传输那套。但实际项目里,光懂这些是不够的。我调试过不下百种I2C设备,从几毛钱的温度传感器到复杂的摄像头模组,真正让你卡住的往往是地址冲突、时序不匹配这些进阶问题。这一章,咱们就深入进去,看看地址怎么玩、读写怎么区分,还有那个让人又爱又恨的时钟拉伸。
4.1 7位地址,你看到的可能只是表象
绝大多数I2C设备用的是7位地址。但很多人被数据手册里的“0x68”这种写法搞晕了。你想想看,这个“0x68”到底是不是总线上传输的那个字节?
不是。 数据手册给的通常是7位地址,但总线上你得左移一位,最后补上读写位。
| 概念 | 举例 | 说明 |
|---|---|---|
| 7位器件地址 | 0x34 | 数据手册给出的常用格式 |
| 写操作地址字节 | 0x68 | 左移一位,最低位为0 (0x34 << 1 | 0) |
| 读操作地址字节 | 0x69 | 左移一位,最低位为1 (0x34 << 1 | 1) |
#define I2C_ADDR 0x34,然后在读写函数里临时左移。这样代码可读性高,别人一看就知道你用的是哪个器件。
我曾经在一个项目中,接手别人的代码,发现宏定义写着 #define ADDR 0xD0。我查了半天数据手册,器件地址明明是0x68。后来才明白,他把写地址直接写死了。这种做法很危险,万一哪天要读寄存器,还得记着再或一个1,很容易出错。
4.2 10位地址:什么时候用?怎么用?
7位地址只能挂127个设备(0x00保留做通用呼叫),不够用了怎么办?这就轮到10位地址上场了。说实话,我在消费类电子产品里用到10位地址的场景不多,但在一些大型的工控背板上,挂几十个传感器时就会遇到。
10位地址的传输分两个阶段:
- 第一个字节: 高5位固定是
11110,接着是10位地址的高2位,最后是读写位。 - 第二个字节: 剩下的8位地址。
用逻辑分析仪抓出来的波形,你是能直接看出来的。第一个字节的前5位就是 0xF0 到 0xF7 的范围。你想想看,如果看到地址字节是 0xF0 或 0xF2,那肯定不是普通7位地址的设备。
4.3 读写操作,逻辑分析仪上的一目了然
I2C的读写其实非常直观。总线上读写操作的区别,不在于数据怎么传,而在于那个最低位的控制。
- 写操作: 主机发送地址字节(读写位=0),然后连续发送数据字节。每个字节后从机都会回复ACK。
- 读操作: 主机发送地址字节(读写位=1),然后主机变成接收者,从机开始发送数据。注意,这里的ACK/NACK是由主机控制的!
我刚开始学的时候,总有一个困惑:读操作时最后一拍到底怎么结束?
标准做法是: 读最后一个字节时,主机不要回复ACK,而是回复一个NACK,然后发Stop信号。这样从机就知道数据发送完了,停止驱动SCL和SDA。
你看这个表:
| 操作类型 | 主机角色 | 从机角色 | 最后一个字节应答 |
|---|---|---|---|
| 写 | 发送方 | 接收方 | 从机回复ACK |
| 读 | 接收方 | 发送方 | 主机回复NACK |
4.4 时钟拉伸(Clock Stretching):从机的“缓兵之计”
这是I2C协议里一个很特别的地方。标准I2C是主设备控制时钟,但时钟拉伸允许从机把SCL线拉低,强制主机等待。
为什么要干这事?你想想看,从机可能正在处理内部数据,比如刚刚完成一次AD转换,数据还没准备好。如果主机不管三七二十一地读,从机只能返回垃圾数据。这时从机就会拉低SCL,说:“等等,我还没准备好。”
逻辑分析仪上看时钟拉伸,最明显的就是:SCL的低电平时间被延长了,比正常的长很多。正常的SCL高低电平时间是对称的,拉伸时你会看到低电平占了很大一部分。
我遇到过一种情况:一个温湿度传感器在每次采样后,会拉伸时钟长达10ms。如果主机没有超时处理机制,就以为总线死锁了。其实不是,是传感器在忙。
时钟拉伸的两个关键点:
- 主机必须支持: 如果主机硬件不支持时钟拉伸,就会误判为总线错误。很多便宜的MCU的硬件I2C外设是不支持自动处理拉伸的,需要你用GPIO模拟。
- 必须有超时机制: 不能无限等下去。我个人的经验是,把超时设在10-20ms之间。超过这个时间还没释放,就认为从机挂死了,进行总线恢复。
4.5 一张图看懂本章核心
用逻辑分析仪抓波形时,我习惯开启协议解码功能。设置好是否支持时钟拉伸,很多时候你看到地址不对,其实是因为数据手册和逻辑分析仪的设置,一个用了7位格式,一个用了8位格式。统一一下就好了。
4.6 避坑指南
这一章讲的内容,在实际调试中会反复出现。我总结几个坑:
- 地址冲突: 同一个I2C总线上挂了两个相同地址的器件。解决办法:看器件有没有地址引脚,有的话改一个;没有的话,只能加I2C多路复用器。
- 读写位搞反: 我见过有人发送了读地址,但后续操作全是主机发数据。逻辑分析仪上一看,从机根本没响应,因为从机以为主机要读,自己正等着发数据呢。
- 忘记NACK: 读操作最后一拍回了ACK,总线卡死。这个前面说过了,一定注意。
- 时钟拉伸没超时: 一些从机启动时要几百ms,但正常工作后拉伸只有几ms。如果超时设得太短,上电时就会报错。
嗯,我个人经验是,调试I2C最忌讳“凭感觉”。用逻辑分析仪一帧一帧地看,地址对不对、ACK有没有、时序是否符合规格书上写的最小时序要求。这一章的内容,说白了就是让你拿到数据手册能看懂,抓到波形能分析。