1. I2C协议基础:从一根线到一套生态
各位同学,咱们今天聊聊I2C总线。说实话,这玩意儿在嵌入式领域太常见了。我刚开始做驱动时,总觉得I2C就是两根线拉一拉,没什么技术含量。后来被坑了几次才明白——越是基础的协议,越容易在细节上翻车。
1.1 I2C总线的起源
I2C是Philips(现在的NXP)在1982年搞出来的。当时他们想解决一个很实际的问题:板子上芯片越来越多,每个芯片都要一堆控制线,PCB都快被线占满了。于是他们设计了一种只需要两根线的总线——一根时钟线(SCL),一根数据线(SDA)。
你想想看,如果不用I2C,一个传感器可能就要5根线:VCC、GND、CS、SCLK、MISO、MOSI……嗯,SPI至少4根。而I2C不管接多少个设备,永远只需要两根线加电源。这就是它的核心价值——引脚复用,连线极简。
I2C名字的由来:Inter-Integrated Circuit,芯片间集成电路总线。中文常读作"I方C"或"IIC"。我个人习惯叫"I方C",老工程师都这么叫。
1.2 物理层特性
I2C的物理层其实很朴素。两根线都是开漏输出,加上拉电阻到VCC。什么叫开漏?说白了就是管子只能拉低电平,不能主动拉高。高电平靠上拉电阻来实现。
| 参数 | 标准模式 | 快速模式 | 高速模式 |
|---|---|---|---|
| 最大速率 | 100 kbit/s | 400 kbit/s | 3.4 Mbit/s |
| 上拉电阻典型值 | 4.7 kΩ | 2.2 kΩ | 1.0 kΩ |
| 总线电容上限 | 400 pF | 400 pF | 100 pF |
| 最大从机数量 | 127(7位地址) | 127 | 127 |
这里有个坑,我必须要说。上拉电阻不是随便选的。电阻太大,信号上升沿太慢,高速通信会出错;电阻太小,功耗大,而且可能拉不动。我在一个项目里遇到过——选了10kΩ上拉,400kHz通信时波形都变成正弦波了。后来换成2.2kΩ,问题解决。
注意:I2C总线上的设备必须共地。不同电压域的设备通信时,需要电平转换芯片,不能直接连。我曾经见过有人把3.3V和5V设备直接怼一起,结果烧了从机——嗯,血的教训。
1.3 主从机角色定义
I2C总线上的设备分为两种角色:主机(Master)和从机(Slave)。这个定义很清晰:
- 主机:产生时钟信号,发起通信,决定何时开始、何时结束。一个总线上可以有多个主机,但同一时刻只能有一个主机控制总线。
- 从机:被主机寻址,响应主机的读写请求。从机不能主动发起通信,但可以通过时钟拉伸(Clock Stretching)让主机等一下。
咱们这门课的重点就是从机模式。为什么?因为大部分MCU做主机很容易,但做从机时,要处理中断、DMA、RTOS任务同步,坑特别多。我后面会详细讲。
1.4 总线拓扑结构
I2C的拓扑结构很简单——总线型。所有设备都挂在同两根线上,每个设备有一个唯一的地址。主机通过地址来选择跟谁通信。
下面这张图,是我手绘的总线结构示意:
从这张图你能看到:
- 所有设备都挂在SDA和SCL两根线上
- 两端各有一个上拉电阻
- 主机只有一个(多主机情况咱们后面再聊)
- 从机可以有多个,每个有唯一地址
经验之谈:实际项目中,I2C总线上不建议挂超过8个设备。虽然理论上可以挂127个,但总线电容会变大,信号质量下降。我做过一个项目挂了6个设备,400kHz跑得很勉强,后来降到了100kHz才稳定。
1.5 地址与寻址
I2C的地址分两种:7位地址和10位地址。7位地址最常用,范围0x00~0x7F,但0x00是通用呼叫地址,0x01~0x07保留,实际可用地址大约112个。
每个I2C设备出厂时都有一个默认地址,但很多设备允许通过引脚配置。比如AT24C02 EEPROM,它的地址是0x50,但A0/A1/A2引脚可以改。我习惯在原理图阶段就把地址规划好,避免后期冲突。
地址冲突是I2C最常见的故障之一。两个从机地址一样,主机就不知道该跟谁说话。我曾经排查过一个系统,传感器和RTC地址都是0x68,折腾了两天才发现——嗯,从此以后我画原理图第一件事就是核对所有I2C地址。
1.6 本章小结
这一章咱们把I2C的底子打好了。你记住几个关键点:
- 两根线:SDA(数据)和SCL(时钟),开漏输出加上拉
- 主从架构:主机管时钟,从机管响应
- 总线拓扑:所有设备挂一起,地址区分
- 地址7位为主,注意别冲突