I²C(Inter-Integrated Circuit)通信协议简介
I²C(Inter-Integrated Circuit,简称IIC)是一种 串行通信协议,用于在短距离内连接低速设备,如传感器、EEPROM、显示屏(如OLED)、ADC/DAC、RTC等。它由 飞利浦(现NXP) 在1982年开发,具有占用引脚少、支持多个设备、硬件开销低等优点,在嵌入式系统中应用广泛。
1. I²C 的特点
- 主从结构:支持 一个或多个主机(Master) 控制多个从机(Slave)。
- 双线通信:使用两条信号线:
- SCL(Serial Clock,串行时钟线):由主设备提供时钟信号。
- SDA(Serial Data,串行数据线):用于主从设备之间的数据传输(双向)。
- 地址传输:每个从设备都有唯一的 7位或10位地址,主设备通过地址选择要通信的从设备。
- 支持多个设备:在同一条总线上,可以连接多个主机和多个从机。
- 半双工通信:数据传输为单向进行,每次只能有一个设备在发送数据。
- 支持不同速率:
- 标准模式(Standard Mode):最大传输速率 100kbps。
- 快速模式(Fast Mode):最大传输速率 400kbps。
- 高速模式(High-speed Mode, HSM):最大传输速率 3.4Mbps。
- 超高速模式(Ultra Fast Mode, UFm):最大传输速率 5Mbps。
2. I²C 总线的工作机制
2.1 I²C 设备连接
I²C 设备通过 SCL 和 SDA 连接到总线,所有设备共享这两条总线,由 主机 负责发送 时钟信号,并向从机发起通信请求。
2.2 I²C 数据传输格式
I²C 采用 主设备(Master) 发送 起始信号(Start Condition) 来通知从设备准备通信,然后通过 SDA 发送 从设备地址,如果有匹配的从机,它会发送应答信号(ACK)。数据传输完成后,主机发送 停止信号(Stop Condition) 结束通信。
I²C 传输步骤
- 起始条件(START):
- SDA 从高变低,SCL 维持高电平,表示开始通信。
- 发送从机地址(7位或10位)+ 读/写位(1位):
- 主机发送 从机地址,并设置最后 1 位(R/W):
0
:写(主机向从机发送数据)1
:读(主机从从机接收数据)
- 主机发送 从机地址,并设置最后 1 位(R/W):
- 从机应答(ACK):
- 如果地址匹配,从机会 拉低 SDA 发送 ACK 响应。
- 若没有匹配,从机保持 SDA 高电平(NACK)。
- 数据传输:
- 发送或接收 8 位数据,每发送 1 字节,从机需要发送 ACK。
- 停止条件(STOP):
- SDA 从低变高,SCL 维持高电平,表示数据传输完成。
2.3 I²C 数据帧
一个完整的 I²C 通信帧格式如下:
START | 7-bit 地址 | R/W | ACK | 数据字节 | ACK | ... | STOP
---------|-------------|-----|-----|-----------|-----|-----|------
| 从机地址 | 0/1 | 0 | 数据字节 | 0 | |
3. I²C 读写操作示例
3.1 通过 CubeMX 配置 I²C
- 设置 I2C1:
- SCL 口:PB8
- SDA 口:PB9
- 模式:主机模式(Master Mode)
- 时钟速度:400 kHz(快速模式 Fast Mode)
3.2 配置 PC13 作为 LED 控制引脚
- 模式:推挽输出(Output Push-Pull)
- 初始状态:高电平(LED1 熄灭)
3.3 配置 PB1 作为外部中断
- 引脚:PB1
- 模式:外部中断(EXTI)
- 触发方式:下降沿触发(Falling Edge)
3.4 启用 EXTI1 中断
- 中断控制器(NVIC)中启用 EXTI1
- 默认优先级
3.5 生成代码
- 生成代码后,开始编写应用逻辑。
3.6 在 EXTI1 的中断回调函数中切换 OLED 状态
目标:在中断触发时,通过 I²C 发送数据来切换 OLED 状态。
简要阅读SSD1306的数据手册,同时观察SSD1306的背面I2C地址指示,我们得知了OLED的I2C地址为0x78,以及点亮测试的基本流程,这样我们就能写控制驱动了。
uint8_t oled_on_cmd[]={0x00,0x8d,0x14,0xaf,0xa5};// {命令流,使能电荷泵,使能电荷泵,打开屏幕,屏幕全亮}
uint8_t oled_off_cmd[] = {0x00, 0xAE}; // 关闭显示
uint8_t DataRcvd;// 设置缓冲区存取读到的数据
uint8_t oled_state = 0; // 0: 关闭, 1: 打开
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_1) // 确保是 B1 按键的中断
{
oled_state = !oled_state; // 切换 OLED 状态
if (oled_state)
{
//uint8_t oled_on_cmd[] = {0x00, 0xAF}; // 0xAF = 打开 OLED 显示
HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDR, oled_on_cmd, sizeof(oled_on_cmd), HAL_MAX_DELAY);
}
else
{
uint8_t oled_off_cmd[] = {0x00, 0xAE}; // 0xAE = 关闭 OLED 显示
HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDR, oled_off_cmd, sizeof(oled_off_cmd), HAL_MAX_DELAY);
}
}
}
3.7 在主循环中轮询 OLED 状态,并控制 LED
目标:持续读取 OLED 的状态,并根据 OLED 是否点亮来控制 LED 开关。
while (1)
{
/* USER CODE END WHILE */
HAL_I2C_Master_Receive(&hi2c1,OLED_I2C_ADDR,&DataRcvd,1,HAL_MAX_DELAY);// 轮询读取oled的返回值,判断屏幕状况
if ((DataRcvd & (1 << 6)) == 0)
{ // 检查第6位
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); // 点亮LED
}
else
{
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); // 熄灭LED
}
HAL_Delay(100);// 每0.1秒检查一下LED的情况
}
3.8 实验现象
4. I²C 与 SPI 的对比
特性 | I²C | SPI |
---|---|---|
线数 | 2 条(SCL、SDA) | 4 条(SCK、MISO、MOSI、CS) |
速度 | 最高 3.4 Mbps | 最高几十 Mbps |
设备数量 | 可连接多个设备 | 需要独立 CS 选择设备 |
硬件开销 | 低 | 高 |
通信模式 | 半双工 | 全双工 |
5. I²C 在 STM32 开发中的使用
STM32 通过 I2C 外设 控制从设备,使用 HAL 库进行配置:
- 配置 I2C 引脚(如 SCL: PB6, SDA: PB7)
- 初始化 I2C
- 使用
HAL_I2C_Master_Transmit()
和HAL_I2C_Master_Receive()
进行数据传输
6. 结论
- I²C 是一种常用的低速串行总线,适用于短距离、多设备通信。
- 只需 2 根线即可连接多个设备,占用引脚少,硬件开销低。
- 支持多种传输速率(100kbps、400kbps、3.4Mbps等)。
- 适用于 OLED 屏幕、EEPROM、RTC、传感器等外设的通信。