目录
- I2C 总线介绍
- 1. I2C 的原理
- (1) 双线通信
- (2) 主从结构
- (3) 多设备通信
- (4) 硬件连接
- 2. I2C 的特性
- (1) 双向通信
- (2) 多主设备
- (3) 速度支持
- (4) 硬件简单
- (5) 地址区分
- 3. I2C 的协议
- (1) 起始条件(Start Condition)
- (2) 地址传输
- (3) 数据传输
- (4) 应答信号(ACK/NACK)
- (5) 停止条件(Stop Condition)
- 4. 配置与使用
- (1) 配置 I2C 外设
- 使能 I2C 外设时钟
- 配置 GPIO 为 I2C 功能
- 配置 I2C 参数
- (2) 发送数据
- (3) 接收数据
- 5. 实例代码
- 6. 常见问题
- (1) 总线冲突
- (2) 上拉电阻配置
- (3) 从设备应答丢失
- (4) 时钟速度设置
- 7. 应用场景
- (1) 传感器数据采集
- (2) EEPROM 存储
- (3) 显示屏控制
- (4) 电机控制
- (5) 无线模块
- 8. 总结
I2C 总线介绍
I2C(Inter-Integrated Circuit,集成电路总线) 是一种串行通信协议,广泛应用于嵌入式系统和电子设备中,用于在微控制器与外围设备(如传感器、EEPROM、显示屏等)之间进行低速数据通信。I2C 总线因其简单、高效和灵活的特点,成为许多设备的标配通信接口。
1. I2C 的原理
(1) 双线通信
I2C 总线由两根信号线组成:
- SCL(Serial Clock Line,时钟线):由主设备(Master)产生时钟信号,用于同步数据传输。
- SDA(Serial Data Line,数据线):用于主设备与从设备(Slave)之间的双向数据传输。
(2) 主从结构
- 主设备(Master):控制总线的时钟和启动/停止数据传输。
- 从设备(Slave):响应主设备的请求。
(3) 多设备通信
I2C 总线支持多个主设备和从设备连接到同一条总线,通过地址区分不同的从设备。
(4) 硬件连接
- I2C 总线通过上拉电阻(通常为 4.7 kΩ)连接到电源,确保空闲状态下 SDA 和 SCL 线为高电平。
- 所有设备的 SDA 和 SCL 线分别连接到同一条总线。
2. I2C 的特性
(1) 双向通信
- 数据线 SDA 支持双向数据传输,主设备和从设备都可以发送和接收数据。
(2) 多主设备
- I2C 总线支持多个主设备同时工作,但需要总线仲裁机制避免冲突。
(3) 速度支持
- 标准模式:<= 100 kbps。
- 快速模式:<= 400 kbps。
- 高速模式:<= 3.4 Mbps。
- 超快速模式:<= 5 Mbps(部分设备支持)。
(4) 硬件简单
- 只需两根信号线,降低了电路设计的复杂性。
(5) 地址区分
- 每个从设备都有唯一的 7 位或 10 位地址,主设备通过地址选择从设备。
3. I2C 的协议
(1) 起始条件(Start Condition)
- 主设备通过拉低 SDA 线,然后在 SCL 线拉低时发送起始信号。
(2) 地址传输
- 主设备发送 7 位或 10 位从设备地址,后面跟随读/写标志位(R/W):
- 0:写操作。
- 1:读操作。
(3) 数据传输
- 在 SCL 的高电平期间,SDA 上的数据必须保持稳定。
- 每个字节(8 位)传输后,接收方需要发送一个应答位(ACK)或非应答位(NACK)。
(4) 应答信号(ACK/NACK)
- ACK(应答):接收方在第 9 个时钟周期拉低 SDA 线,表示成功接收数据。
- NACK(非应答):接收方在第 9 个时钟周期保持 SDA 线高电平,表示接收失败或不需要更多数据。
(5) 停止条件(Stop Condition)
- 主设备在拉高 SCL 线后,再拉高 SDA 线,发送停止信号。
4. 配置与使用
(1) 配置 I2C 外设
在 STM32 微控制器中,I2C 外设的配置通常基于 HAL 库。
使能 I2C 外设时钟
__HAL_RCC_I2C1_CLK_ENABLE(); // 使能 I2C1 外设时钟
配置 GPIO 为 I2C 功能
GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9; // I2C1 的 SCL 和 SDA 引脚
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // 开漏输出
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; // 复用功能
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉/下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // GPIOB 配置
配置 I2C 参数
I2C_HandleTypeDef hi2c1;hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000; // 时钟频率 100 kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; // 时钟占空比
hi2c1.Init.OwnAddress1 = 0x00; // 主设备地址(不需要)
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7 位地址模式
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; // 禁用双地址模式
hi2c1.Init.OwnAddress2 = 0x00; // 从设备地址(不需要)
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; // 禁用广播模式
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // 禁用不拉伸模式HAL_I2C_Init(&hi2c1); // 初始化 I2C
(2) 发送数据
HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)0x50 << 1, data, sizeof(data), HAL_MAX_DELAY);
- 参数说明:
0x50
:从设备的 7 位地址。data
:要发送的数据。HAL_MAX_DELAY
:阻塞等待,直到传输完成。
(3) 接收数据
HAL_I2C_Master_Receive(&hi2c1, (uint16_t)0x50 << 1, data, sizeof(data), HAL_MAX_DELAY);
- 参数说明:
0x50
:从设备的 7 位地址。data
:接收数据的缓冲区。HAL_MAX_DELAY
:阻塞等待,直到接收完成。
5. 实例代码
以下是一个完整的示例,配置 I2C1 并与从设备 0x50 通信:
void I2C_Config(void)
{// 使能 I2C1 外设时钟__HAL_RCC_I2C1_CLK_ENABLE();// 配置 GPIO 为 I2C 功能GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9; // I2C1 的 SCL 和 SDA 引脚GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // 开漏输出GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; // 复用功能GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉/下拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // GPIOB 配置// 配置 I2C 参数I2C_HandleTypeDef hi2c1;hi2c1.Instance = I2C1;hi2c1.Init.ClockSpeed = 100000; // 时钟频率 100 kHzhi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; // 时钟占空比hi2c1.Init.OwnAddress1 = 0x00; // 主设备地址(不需要)hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7 位地址模式hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; // 禁用双地址模式hi2c1.Init.OwnAddress2 = 0x00; // 从设备地址(不需要)hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; // 禁用广播模式hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // 禁用不拉伸模式HAL_I2C_Init(&hi2c1); // 初始化 I2C// 发送数据到从设备 0x50uint8_t data[] = {0x01, 0x02, 0x03};HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)0x50 << 1, data, sizeof(data), HAL_MAX_DELAY);
}
6. 常见问题
(1) 总线冲突
- 如果多个主设备同时尝试控制总线,可能会导致总线冲突。
- 解决方法:硬件设计时避免多个主设备同时操作。
(2) 上拉电阻配置
- I2C 总线需要外部上拉电阻,通常为 4.7 kΩ。
- 检查电路设计是否正确接线。
(3) 从设备应答丢失
- 可能是从设备地址错误或设备未上电。
- 解决方法:检查从设备地址和供电情况。
(4) 时钟速度设置
- 根据设备的要求设置合适的时钟速度。
- 例如,EEPROM 通常支持 100 kHz,而某些传感器可能支持 400 kHz。
7. 应用场景
(1) 传感器数据采集
- 如温度传感器(LM75)、加速度传感器(MPU6050)等。
(2) EEPROM 存储
- 如 24C02 EEPROM,用于存储设备配置信息。
(3) 显示屏控制
- 如 OLED 显示屏(SSD1306)通过 I2C 接口进行通信。
(4) 电机控制
- 如步进电机驱动器(L298N)通过 I2C 总线进行控制。
(5) 无线模块
- 如蓝牙模块(HM-10)通过 I2C 与主控通信。
8. 总结
I2C 是一种简单高效的串行通信协议,适用于嵌入式系统中的多设备通信。通过配置 STM32 的 I2C 外设,可以实现与各种外围设备的低速数据传输。其主要特点包括:
- 双线通信:仅需 SCL 和 SDA 两根信号线。
- 主从结构:支持主设备与从设备通信。
- 多设备支持:通过地址区分不同的从设备。
- 硬件简单:仅需上拉电阻,设计成本低。
I2C 的应用场景广泛,从传感器数据采集到显示屏控制,再到电机驱动和无线通信,都可以通过 I2C 实现高效可靠的通信。