1. I2C协议基础:从物理层到通信时序
各位同学好,我是老周。做嵌入式这些年,调试过最多的总线就是I2C和SPI。今天咱们先聊聊I2C的基础——这部分要是没吃透,后面调试起来会非常痛苦。我见过太多工程师拿着逻辑分析仪对着波形发呆,其实就是起始条件没看明白。
1.1 I2C总线物理层:两根线打天下
I2C总线只用两根线:SCL(时钟线)和SDA(数据线)。但你别小看这两根线,它们的设计其实挺讲究的。
核心特点:
- 开漏输出:SCL和SDA都是开漏结构,只能拉低,不能主动拉高
- 上拉电阻:总线空闲时靠上拉电阻把电平拉到VDD
- 线与逻辑:多个设备可以同时拉低总线,谁先释放谁后释放由硬件仲裁
说白了,I2C的物理层就是一个"谁先拉低谁说话"的机制。我刚开始做驱动时,总觉得开漏结构很麻烦,后来才明白——正是这个设计让多主机通信成为可能。
我曾经踩过的坑:上拉电阻选型不当导致通信失败。电阻太小(比如1kΩ),总线拉低时电流过大,芯片可能驱动不了;电阻太大(比如10kΩ),上升沿太慢,高速模式下时序会出问题。一般4.7kΩ是个比较稳妥的起点,具体要看总线电容和通信速率。
1.2 SCL与SDA信号:谁控制谁?
SCL是时钟线,由主机控制。SDA是数据线,主机和从机都可以控制。但有个关键点:数据只能在SCL低电平时变化,高电平时采样。
| 信号 | 控制方 | 作用 | 注意事项 |
|---|---|---|---|
| SCL | 主机 | 提供时钟同步 | 从机可以拉低SCL进行时钟拉伸 |
| SDA | 主机/从机 | 传输数据 | 数据变化只能在SCL低电平期间 |
这里有个容易忽略的点:时钟拉伸。从机如果处理不过来,可以主动拉低SCL,让主机等一等。我调试一个温湿度传感器时就遇到过,从机每次发完地址都要拉伸时钟几百微秒,一开始我还以为是硬件坏了。
1.3 I2C通信时序:一个字节怎么传?
I2C传输一个字节(8位)的时序是这样的:
- SCL拉低,主机在SDA上设置第一位数据
- SCL拉高,从机采样SDA
- SCL再次拉低,主机设置下一位
- 重复8次,传完一个字节
- 第9个SCL周期:主机释放SDA,从机拉低SDA作为应答(ACK)
我的调试习惯:看I2C波形时,先找SCL的上升沿。在上升沿之前一点点看SDA的电平,那就是被采样的数据位。这个习惯帮我快速定位了很多数据错位的问题。
1.4 起始条件与停止条件:通信的开关
这两个条件是I2C通信的"开关",也是最容易出问题的地方。
起始条件(START):SCL高电平时,SDA从高电平跳变到低电平。
停止条件(STOP):SCL高电平时,SDA从低电平跳变到高电平。
关键区别:
- 起始条件:SDA下降沿,SCL保持高
- 停止条件:SDA上升沿,SCL保持高
- 数据位传输:SDA变化发生在SCL低电平
你想想看,如果SCL和SDA的时序搞反了,或者边沿不够陡峭,从机根本识别不到起始条件。我曾经在一个项目中,因为PCB走线太长导致SDA上升沿变缓,起始条件总是识别失败。后来在靠近从机端加了个施密特触发器才解决。
我曾经遇到的典型故障:主机发送起始条件后,从机没有响应。用示波器一看,起始条件确实发出了,但SDA的下降沿不够陡,从机没认出来。原因是上拉电阻太大加上总线电容太大,导致边沿变缓。解决办法:减小上拉电阻到2.2kΩ,或者降低通信速率。
1.5 知识结构总览
下面这张图把I2C协议基础的核心知识点串起来了,方便你对照理解。
1.6 常见故障排查清单
根据我多年的调试经验,I2C物理层和时序相关的故障,90%都可以归到下面这几类:
| 故障现象 | 可能原因 | 排查方法 |
|---|---|---|
| 总线一直为低 | 某个设备拉死了总线 | 逐个断开从机,看总线能否恢复 |
| 起始条件不识别 | SDA下降沿太缓 | 减小上拉电阻或降低速率 |
| 从机无应答 | 地址错误或从机未上电 | 核对地址位(7位还是10位) |
| 数据错位 | SCL抖动或干扰 | 加滤波电容或降低速率 |
| 时钟拉伸异常 | 从机处理超时 | 检查从机初始化时序 |
我的调试三板斧:
- 先用逻辑分析仪抓波形,看起始条件和停止条件是否完整
- 核对地址字节:7位地址左移1位,加上读写位
- 检查ACK位:第9个SCL周期SDA是否被从机拉低