I²C总线通信原理详解
-
-
-
- [**1. I²C是什么?**](#1. I²C是什么?)
- [**2. 硬件连接**](#2. 硬件连接)
- [**3. 通信流程(以读取传感器数据为例)**](#3. 通信流程(以读取传感器数据为例))
-
- **步骤1:起始条件(START)**
- [**步骤2:发送从机地址 + 读写位**](#步骤2:发送从机地址 + 读写位)
- **步骤3:数据传输**
- **步骤4:停止条件(STOP)**
- [**4. 关键机制**](#4. 关键机制)
- [**5. 典型时序图**](#5. 典型时序图)
- [**6. 优缺点**](#6. 优缺点)
- [**7. 实际应用**](#7. 实际应用)
- [**8. 动手实验**](#8. 动手实验)
-
-
1. I²C是什么?
I²C(Inter-Integrated Circuit,读作"I-squared-C")是一种由飞利浦 (现恩智浦)设计的同步、串行、半双工通信协议,主要用于短距离、低速设备间的通信(如传感器、EEPROM、LCD驱动芯片等)。
核心特点:
- 两根线 :仅需SDA (数据线)和SCL(时钟线)。
- 多主多从:支持多个主设备(Master)和从设备(Slave)共享总线。
- 地址寻址:每个从设备有唯一地址(如0x68),主设备通过地址选择通信对象。
2. 硬件连接
- 开漏输出 :SDA和SCL均为开漏结构,需外接上拉电阻(通常4.7kΩ),避免信号冲突。
- 设备地址:7位或10位地址(如0x1A),支持广播寻址(所有从机响应)。
SCL SDA SCL SDA 上拉电阻 上拉电阻 Master Slave1 Slave2 SDA SCL VCC
3. 通信流程(以读取传感器数据为例)
步骤1:起始条件(START)
-
SCL为高电平 时,主设备将SDA从高拉低 ,表示通信开始。
waveform SCL: 1-1-1-1-1-1-1-1-1 SDA: 1-1-1-1-1-0-0-0-0 START: ^
步骤2:发送从机地址 + 读写位
- 7位地址 + 1位方向 (0=写,1=读)。例如:
- 写操作:地址0x68(二进制
1101000)→ 发送1101000 0 - 从机回应ACK(拉低SDA表示确认)。
- 写操作:地址0x68(二进制
步骤3:数据传输
- 主设备发送命令 (如寄存器地址
0x01),从机ACK。 - 主设备发送重复起始条件(Repeated START),切换为读模式。
- 从机返回数据 (如温度值
0x25),主设备ACK或NACK(结束读取)。
步骤4:停止条件(STOP)
-
SCL为高电平 时,主设备将SDA从低拉高 ,结束通信。
waveform SCL: 1-1-1-1-1-1-1-1-1 SDA: 0-0-0-0-0-1-1-1-1 STOP: ^
4. 关键机制
时钟同步(SCL)
- 多个主设备可通过"线与"逻辑协商时钟速率(慢速设备拉低SCL强制等待)。
仲裁(多主竞争)
- 若两个主设备同时发送数据,SDA先输出高电平的设备退出(无破坏性冲突)。
错误处理
- 无ACK:从机未响应(地址错误或设备故障)。
- 超时:SCL被长时间拉低(从机卡死)。
5. 典型时序图
Master Slave START + 地址(写) + ACK 寄存器地址 + ACK REPEATED START + 地址(读) + ACK 数据字节1 + ACK 数据字节2 + NACK STOP Master Slave
6. 优缺点
| 优点 | 缺点 |
|---|---|
| 硬件简单(两根线) | 速度较慢(标准模式100kbps) |
| 支持多主从 | 地址冲突需手动管理 |
| 无需片选信号(CS) | 长距离通信需加驱动 |
7. 实际应用
- 读取传感器 (如BMP280气压计):主设备读取从机地址
0x77的校准数据。 - 配置外设 (如OLED屏幕):主设备向地址
0x3C发送显示指令。
8. 动手实验
-
硬件连接 :
- Arduino(主) + MPU6050(从,地址0x68) + 4.7kΩ上拉电阻。
-
代码示例 (Arduino):
cpp#include <Wire.h> void setup() { Wire.begin(); // 主设备模式 Wire.beginTransmission(0x68); // 指定从机地址 Wire.write(0x3B); // 寄存器地址 Wire.endTransmission(false); // 保持连接 Wire.requestFrom(0x68, 6); // 请求6字节数据 while (Wire.available()) { byte data = Wire.read(); // 读取数据 } }