🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习 🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发 ❄️作者主页:一个平凡而乐于分享的小比特的个人主页 ✨收录专栏:通信协议,本专栏为记录项目中用到的知识点,以及一些硬件常识总结 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

I²C(Inter-Integrated Circuit,集成电路总线)是一种简单、双向、同步的串行通信总线,由飞利浦公司在1980年代开发。它只需要两根线就能在多个设备间进行通信。
主设备1 主设备2
│ │
└─────┬─────┘
│
┌──┴──┐
│总线 │
└──┬──┘
│
┌─────┼─────┐
从设备1 从设备2 从设备3每个I²C从设备都有一个7位或10位的硬件地址。主设备通过发送这个地址来选择要通信的从设备。
┌─────┬─────────────────────────────────────┐
│ 位 │ 7 6 5 4 3 2 1 0 │
├─────┼─────────────────────────────────────┤
│ 含义 │ A6 A5 A4 A3 A2 A1 A0 R/W │
└─────┴─────────────────────────────────────┘设备类型 | 典型地址(十六进制) | 地址(二进制) |
|---|---|---|
EEPROM | 0x50 | 1010000 |
温度传感器 | 0x48 | 1001000 |
实时时钟 | 0x68 | 1101000 |
OLED显示屏 | 0x3C | 0111100 |
地址范围 用途
0000 000 广播地址
0000 001 起始字节
0000 010 CBUS地址
0000 011 保留
0000 1XX 高速模式
1111 0XX 保留
1111 1XX 10位地址标识
0001 000-1110 111 7位设备地址(可用112个)
I2C的读写地址除了 7bit 物理地址以外,还有 1bit 用来标识读/写方向位。这样I2C的从设备读写地址通常是一个字节,其中高 7bit 是上面描述的物理地址,最低位用来表示读写方向(0 为写操作,1为读操作)。

每个字节传输后,接收方必须发送一个应答位:


I²C支持多种速度模式:
模式 | 速率 | 用途 |
|---|---|---|
标准模式 | 100 kbps | 通用低速设备 |
快速模式 | 400 kbps | 大多数传感器 |
快速模式+ | 1 Mbps | 高速需求 |
高速模式 | 3.4 Mbps | 特殊高速设备 |
速率 (kbps)
3500 ┤ ╭─高速模式
3000 ┤ │
2500 ┤ │
2000 ┤ │
1500 ┤ │
1000 ┤ ╭─快速模式+ │
500 ┤ │ │
400 ┤ ╭─快速模式│ │
200 ┤ │ │ │
100 ┤╭─标准模式 │ │
0 └┴──────┴─────────┴───────────────────┘主设备(发送数据到从设备)
步骤1:发送起始条件
步骤2:发送从设备地址 + 写标志(0)
步骤3:等待从设备应答(ACK)
步骤4:发送数据字节1
步骤5:等待从设备应答
步骤6:发送数据字节2
步骤7:等待从设备应答
...
步骤N:发送停止条件
主设备(从从设备读取数据)
步骤1:发送起始条件
步骤2:发送从设备地址 + 读标志(1)
步骤3:等待从设备应答(ACK)
步骤4:接收数据字节1
步骤5:发送应答(ACK)
步骤6:接收数据字节2
步骤7:发送应答(ACK)
...
步骤N:接收最后一个字节
步骤N+1:发送非应答(NACK)
步骤N+2:发送停止条件
假设我们有一个智能气象站,包含以下I²C设备:
┌─────────────────┐
│ 主控制器 │
│ (STM32) │
└────────┬────────┘
│
SDA ──┼────┬────────┬────────┬────────┐
SCL ──┼────┼────────┼────────┼────────┘
│ │ │ │
┌────────┴┐ ┌─┴─────┐ ┌─┴─────┐ ┌─┴─────┐
│温度传感器│ │湿度传感器│ │气压传感器│ │OLED屏│
│ 0x48 │ │ 0x5C │ │ 0x77 │ │ 0x3C │
└─────────┘ └───────┘ └───────┘ └───────┘// 1. 发送起始信号
i2c_start();
// 2. 发送温度传感器地址 + 写位
i2c_send_byte(0x48 << 1 | 0); // 0x48左移1位,最后一位0表示写
// 3. 检查ACK
if (i2c_check_ack()) {
// 4. 发送要读取的寄存器地址
i2c_send_byte(TEMP_REGISTER);
// 5. 发送重新开始信号
i2c_restart();
// 6. 发送温度传感器地址 + 读位
i2c_send_byte(0x48 << 1 | 1); // 最后一位1表示读
// 7. 读取温度数据(2字节)
uint8_t temp_high = i2c_read_byte();
i2c_send_ack(); // 发送ACK,继续读取
uint8_t temp_low = i2c_read_byte();
i2c_send_nack(); // 发送NACK,最后一个字节
// 8. 发送停止信号
i2c_stop();
// 9. 处理数据
float temperature = process_temp_data(temp_high, temp_low);
}现象 | 可能原因 | 解决方法 |
|---|---|---|
无应答 | 1. 地址错误 2. 设备未上电 3. 线路故障 | 1. 检查地址 2. 检查电源 3. 检查连接 |
数据错误 | 1. 总线竞争 2. 时钟太快 3. 干扰 | 1. 检查多主冲突 2. 降低速率 3. 添加滤波 |
总线锁死 | SCL被长期拉低 | 发送9个以上时钟脉冲 |
I²C协议以其简洁的两线设计和灵活的寻址机制,成为嵌入式系统中最常用的通信协议之一。通过掌握起始/停止条件、地址寻址、数据收发流程和应答机制,您可以轻松实现各种I²C设备的控制。
记住关键点:
通过实际项目的练习,您将能熟练运用I²C协议连接各种传感器、存储器和显示设备。