问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

嵌入式之常用通信协议-I²C

创作时间:
作者:
@小白创作中心

嵌入式之常用通信协议-I²C

引用
CSDN
1.
https://m.blog.csdn.net/weixin_65365693/article/details/145703188

I²C(Inter-Integrated Circuit,IIC)是一种广泛使用的同步、半双工、串行通信协议,由飞利浦(现恩智浦)在1980年代提出,主要用于连接低速外设。

物理层特性

  1. 信号线
  • SDA(Serial Data Line):双向数据线,通过开漏输出(Open-Drain)实现,需外接上拉电阻。
  • SCL(Serial Clock Line):单向时钟线,由主设备控制,同样需上拉电阻。
  • 总线空闲状态:SDA 和 SCL 均被上拉电阻拉高(高电平)。
  1. 电气特性
  • 开漏结构:允许多个设备共享总线,任一设备拉低总线即可实现“线与”逻辑。
  • 上拉电阻:典型值 4.7kΩ(具体值由总线电容和速度决定)。
  • 电压范围:支持 3.3V 或 5V 系统,不同电压设备需电平转换。
  1. 总线拓扑
  • 总线型结构:所有设备并联在总线上,通过地址寻址。
  • 设备数量限制:由总线电容决定(通常 <400pF,高速模式下更严格)。
  1. 硬件电路
  • 所有I2C设备的SCL连在一起,SDA连在一起
  • 设备的SCL和SDA均要配置成开漏输出模式
  • SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右
  • 避免总线没协调好导致电源短路问题--一个输出高一个输出低相连电源短路---->禁止所有设备输出强上拉的高电平,采用外置弱上拉电阻加开漏输出的电路结构

协议层详解

1. 数据帧格式

I²C 的通信以数据帧为单位,每帧包含以下部分:

  • 起始条件(Start Condition):SCL 为高电平时,SDA 由高→低跳变。
  • 从机地址(Slave Address):7位或10位地址 + 1位读写方向位(0: 主写,1: 主读)。
  • 应答位(ACK/NACK):每传输8位数据后,接收方需在第9个时钟周期拉低 SDA(ACK)或保持高(NACK)。
  • 数据段(Data Byte):每次传输1字节(8位),高位(MSB)先发。
  • 停止条件(Stop Condition):SCL 为高电平时,SDA 由低→高跳变。

完整帧示例(主设备向从设备写数据):

[Start] + [7位地址 + 0(写)] + [ACK] + [数据字节1] + [ACK] + ... + [数据字节N] + [ACK/NACK] + [Stop]

2. 地址机制

  • 7位地址模式
  • 支持 112 个设备(保留 16 个地址为特殊用途)。
  • 地址范围:0x08 ~ 0x77(部分地址已被标准设备占用,如 EEPROM 常用 0x50)。
  • 10位地址模式
  • 首字节前5位为11110,后2位为地址高位,次字节为地址低位。
  • 支持更多设备,但实际应用较少。

3. 传输模式

  • 主写模式(Master Transmitter):主设备向从设备发送数据。
  • 主读模式(Master Receiver):主设备从从设备读取数据。
  • 复合传输(Combined Format):在一次通信中切换读写方向(需重复起始条件)。

4. 时钟同步与仲裁

  • 时钟同步:多个主设备时,SCL 通过“线与”实现同步(低电平最长的设备主导)。
  • 仲裁机制
  • 主设备在发送数据时持续监测 SDA 线。
  • 若检测到总线状态与自身发送的数据不一致,则立即退出竞争(丢失仲裁)。
  • 仲裁失败的主设备转为从模式,等待总线空闲后重试。

5. 软件时序

I2C时序基本单元

  • 起始条件:SCL高电平期间,SDA从高电平切换到低电平
  • 终止条件:SCL高电平期间,SDA从低电平切换到高电平
  • 起始和终止都由主机产生
  • 发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
  • 流程:主机拉低SCL,把数据放在SDA上;主机松开SCL,从机读取SDA的数据;在SCL的同步下,依次进行主机发送和从机接收(松开,回弹高电平)
  • 接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
  • 发送应答:主机在接收完一个字节之后,在下一个时钟发送一 位数据,数据0表示应答,数据1表示非应答
  • 接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

I2C时序逻辑:

  1. 起始条件(Start Condition):
  • 起始条件是SCL为高电平时,SDA由高电平切换到低电平。
  • 在起始条件形成后,总线上的其他设备应该等待新的起始条件出现。
  1. 地址传递(Address Transmission):
  • 每个I2C通信开始时,主设备将目标从设备的地址发送到总线上。
  • 地址的最高位是起始位,接着是7位或10位的地址信息,最后是一个读/写位,指示是读操作还是写操作。
  1. 读/写位(Read/Write Bit):
  • 主设备发送一个位,指示接下来是读操作还是写操作。
  • 0表示写,1表示读。
  1. 应答位(Acknowledge Bit):
  • 在每个8位数据字节的传输后,接收方发送一个应答位。
  • 如果接收到的数据正确,应答位是低电平;如果出现错误或者接收方不准备接收下一个字节,应答位是高电平。
  1. 数据传输(Data Transmission):
  • 数据的传输在SCL的每个上升边沿完成。
  • 数据线的状态(高或低)在SCL上升边沿时被稳定。
  1. 停止条件(Stop Condition):
  • 停止条件是SCL为高电平时,SDA由低电平切换到高电平。
  • 在停止条件形成后,总线上的其他设备可以开始下一个通信过程。
  1. 重复起始条件(Repeated Start Condition):
  • 通过在没有形成停止条件的情况下再次发送起始条件,可以在不释放总线的情况下启动新的通信过程。

  • 指定地址写

  • 对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)

  • 当前地址读

  • 对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)

  • 指定地址读

  • 对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)

关键时序参数

I²C 的速度由主设备时钟频率决定,不同模式对应不同速率:

模式
最大速率
应用场景
标准模式
100 kHz
通用低速设备(传感器等)
快速模式
400 kHz
中速需求(如 OLED 屏)
高速模式
3.4 MHz
高速存储器
超快模式
5 MHz
特定设备(需硬件支持)

时序要求示例(标准模式):

  • 起始条件保持时间:>4.7 μs
  • 数据保持时间:>0 μs(需在 SCL 上升沿前稳定)
  • 停止条件建立时间:>4.0 μs

实际应用注意事项

1. 硬件设计要点

  • 上拉电阻选择:
  • 计算公式:
  • 典型值:3.3V 系统用 4.7kΩ,5V 系统用 2.2kΩ。
  • 总线电容控制:
  • 总电容过大导致上升沿变缓,需降低上拉电阻或使用缓冲器。

2. 软件实现关键

  • 起始/停止条件:需严格满足时序(尤其是在无硬件I²C控制器时用GPIO模拟)。
  • 超时处理:防止总线死锁(例如从设备故障未返回ACK)。
  • 多主竞争:主设备需实现仲裁逻辑(通常由硬件自动处理)。

3. 调试技巧

  • 逻辑分析仪:捕获 SDA/SCL 波形,检查起始/停止条件、地址和数据。
  • 示波器:观察总线电平上升时间是否合规。
  • 软件调试:打印 I²C 寄存器状态(如 NACK 错误标志)。

常见问题与解决方案

  1. 总线死锁
  • 现象:SDA 或 SCL 被意外拉低,总线无法恢复。
  • 解决
  • 发送额外时钟脉冲(手动切换SCL 9次)。
  • 硬件复位或重新上电。
  1. 地址冲突
  • 现象:多个从设备使用相同地址。
  • 解决
  • 选择支持地址配置的芯片(如 EEPROM 通过引脚设置地址)。
  • 使用 I²C 多路复用器(如 PCA9548)。
  1. 长距离通信不稳定
  • 现象:数据错误或丢失。
  • 解决
  • 降低总线速度(如从 400kHz 降至 100kHz)。
  • 使用 I²C 缓冲器(如 P82B715)增强驱动能力。

代码示例(Arduino)

// 主设备读取从设备(地址0x50)的1字节数据
#include <Wire.h>
void setup() {
  Wire.begin(); // 初始化I²C为主设备
  Serial.begin(9600);
}
void loop() {
  Wire.requestFrom(0x50, 1); // 向从设备0x50请求1字节数据
  while (Wire.available()) {
    byte data = Wire.read(); // 读取数据
    Serial.print("Received: ");
    Serial.println(data, HEX);
  }
  delay(1000);
}

I2C应用领域

  1. 传感器和芯片通信:用于连接微控制器和各种外围设备,如温度传感器、加速度计、EEPROM等。
  2. 总线连接:多个设备可以通过同一条I2C总线连接到主控制器。
  3. 显示屏:I2C也被用于连接一些小型显示屏。
  4. 存储器扩展:一些存储设备,如EEPROM,通过I2C进行通信。
  5. 实时时钟:RTC(Real-Time Clock)芯片通常使用I2C进行时间数据的传输。

总结

  • 优点:引脚少、支持多设备、协议简单。
  • 缺点:速度较低、总线电容限制扩展性。
  • 适用场景:板载低速外设(传感器、EEPROM、RTC等)。

学习参考:B站UP江协科技

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号