1. I2C协议基础:从一根线到两根线的故事

大家好,我是你们的嵌入式Linux驱动讲师。今天咱们聊聊I2C协议的基础。说实话,我最早接触I2C是在做一款传感器驱动的时候,那时候刚入行,被时序图搞得晕头转向。后来踩了不少坑,才慢慢摸透了它的脾气。

I2C,全称Inter-Integrated Circuit,是飞利浦公司在1982年搞出来的。你想想看,那时候的芯片之间通信,要么并口一大堆线,要么串口速率慢。I2C就聪明了——只用两根线,就能挂一堆设备。这个设计思路,到现在看都不过时。

核心要点:I2C是一种同步、半双工、多主从的串行通信总线。两根线:SDA(数据线)和SCL(时钟线)。

1.1 物理层特性:SDA和SCL到底怎么工作的?

SDA是数据线,SCL是时钟线。这两根线都是开漏输出,需要外部上拉电阻。什么叫开漏?说白了,就是芯片只能把线拉低,不能主动拉高。拉高的工作,交给上拉电阻来做。

我个人习惯把SDA想象成一条“公共汽车道”,SCL就是“红绿灯”。红绿灯(时钟)控制什么时候可以上下车(传输数据)。所有设备都挂在同一条道上,但同一时刻只能有一个设备在说话。

小技巧:我在调试I2C时,第一件事就是量SDA和SCL的静态电平。如果量出来是低电平,那八成是上拉电阻没焊,或者芯片把总线拉死了。这个坑我踩过不下三次。

1.2 电气特性与上拉电阻:选多大才合适?

上拉电阻的取值,其实是个平衡艺术。电阻太小,电流太大,功耗高;电阻太大,上升沿太慢,通信容易出错。

标准模式下,我一般用4.7kΩ。快速模式下,用2.2kΩ。高速模式下,可能要用到1kΩ甚至更小。当然,这跟总线电容也有关系。总线上的设备越多,电容越大,电阻就得选小一点。

模式 速率 推荐上拉电阻 总线电容
标准模式 100 kHz 4.7kΩ - 10kΩ < 400 pF
快速模式 400 kHz 2.2kΩ - 4.7kΩ < 200 pF
高速模式 3.4 MHz 1kΩ - 2.2kΩ < 100 pF

注意:我曾经在一个项目里,为了省电把上拉电阻换成了100kΩ。结果总线上升沿慢得像蜗牛,通信时好时坏。查了两天才发现是电阻的问题。嗯,从那以后我再也不敢乱改上拉电阻了。

1.3 I2C与SPI、UART对比:谁更适合你的项目?

很多初学者会问:I2C、SPI、UART,到底选哪个?我的回答是:看场景。

UART,最简单,三根线(TX、RX、GND)就能通信。但它是异步的,双方得约定好波特率。而且只能点对点,不能挂多个设备。我一般用它来做调试串口,或者跟蓝牙模块通信。

SPI,速度快,全双工,四根线(MOSI、MISO、SCLK、CS)。但每加一个设备,就得加一根片选线。设备多了,GPIO不够用。我做过一个项目挂了8个SPI设备,光片选线就占了8个GPIO,心疼得要命。

I2C,就两根线,能挂127个设备。但速度比SPI慢,而且是半双工。适合传感器、EEPROM、RTC这类对速率要求不高的设备。

特性 I2C SPI UART
线数 2(SDA + SCL) 4 + N(N为设备数) 2(TX + RX)
通信方式 半双工 全双工 全双工
速率 100 kHz - 3.4 MHz 可达几十MHz 通常 115200 bps - 几Mbps
多设备支持 是(地址寻址) 是(片选) 否(点对点)
典型应用 传感器、EEPROM ADC、LCD、Flash 调试串口、GPS模块

说白了,没有最好的协议,只有最合适的。我个人习惯是:需要挂多个低速设备,选I2C;需要高速传输,选SPI;简单点对点通信,选UART。

1.4 I2C协议的核心逻辑:一张图看懂

下面这张图,是我自己画的I2C通信流程。每次给新人培训,我都会先让他们看这张图。理解了它,I2C协议就掌握了一半。

I2C通信流程 起始条件 SCL高时SDA下降沿 发送设备地址 7位地址 + R/W位 等待从机应答 SDA被拉低 = ACK 传输数据 8位数据 + ACK 循环传输,直到所有数据发送完毕 停止条件 SCL高时SDA上升沿 关键时序说明 • 起始条件:SCL为高电平时,SDA从高电平切换到低电平 • 停止条件:SCL为高电平时,SDA从低电平切换到高电平 • 数据有效性:SCL为高电平时,SDA上的数据必须保持稳定 • 应答机制:每传输8位数据后,接收方必须拉低SDA表示应答 • 注意:没有应答(NACK)表示传输失败或传输结束

这张图把I2C通信拆成了五个步骤:起始条件、发地址、等应答、传数据、停止条件。其中“传数据”这一步可以循环多次,直到所有数据都传完。

我的经验:调试I2C时,用逻辑分析仪抓一下起始条件和停止条件,基本就能判断通信有没有跑通。如果起始条件都出不来,那肯定是硬件问题,别浪费时间调软件。

1.5 避坑指南:我踩过的那些坑

做I2C驱动这么多年,我总结了几条血泪教训:

  • 总线锁死:我曾经遇到过一次,从机在传输过程中突然复位了,结果SDA被拉低不放。主机等不到应答,一直卡死。解决办法是:在驱动里加超时机制,超时后强制产生9个时钟脉冲,让从机释放总线。
  • 地址冲突:两个设备用了同一个I2C地址。我查了两天,最后发现是芯片的地址引脚没接对。嗯,硬件原理图一定要仔细对。
  • 速率不匹配:从机只支持100kHz,主机却配成了400kHz。通信时好时坏。后来我习惯在驱动里先读从机的设备ID,确认通信正常后再切到高速模式。

重要提醒:I2C的时序要求很严格。SCL的上升沿时间、保持时间、数据建立时间,都有明确要求。如果你的I2C设备工作在恶劣环境(高温、强干扰),建议把速率降到标准模式,同时加上重试机制。

好了,这一章的内容就到这里。I2C协议基础是后面所有章节的基石,尤其是时序图和电气特性,建议大家多看几遍。下一章我们会深入I2C的时序细节,包括如何用逻辑分析仪抓波形、如何分析时序问题。


专注资料整理