主题 | 内容 | 教学目的/扩展视频 |
---|---|---|
I2C总线 | 电路原理,跳线设置,I2C协议分析。驱动程序与调用。 | 熟悉I2C总线协议,熟练调用。 |
师从洋桃电子,杜洋老师
📑文章目录
- 引言
- 一、I2C驱动分层架构
- 二、I2C总线驱动代码精析
- 2.1 初始化配置(i2c.c)
- 2.2 数据发送函数(I2C_SAND_BUFFER)
- 2.3 数据接收函数(I2C_READ_BUFFER)
- 三、总线速度配置原理
- 四、用户应用实战(main.c)
- 五、器件驱动开发(LM75A示例)
- 5.1 温度读取函数
- 六、常见问题排查指南
- 七、进阶优化技巧
- 八、相关资源
- 总结
▲ 回顾上期🔍STM32入门之I2C总线应用详解(附LM75A温度传感器实战) | 零基础入门STM32第四十九步
引言
I2C总线是嵌入式系统中广泛使用的通信协议,具有接线简单、多设备共享总线等优点。本文将深入解析STM32的I2C驱动开发,通过分层架构设计、代码逐行分析和实战案例演示,帮助开发者快速掌握I2C通信的核心技术。
一、I2C驱动分层架构
- 硬件抽象层(HAL)
ST官方提供的固件库(如stm32f10x_i2c.c
),直接操作寄存器实现基础功能。 - 总线驱动层
封装I2C协议的核心操作(发送/接收数据),提供I2C_Configuration()
等接口。 - 器件驱动层
针对具体外设(如LM75A温度传感器)的驱动实现。 - 用户应用层
调用驱动函数实现业务逻辑,如温度显示。
二、I2C总线驱动代码精析
2.1 初始化配置(i2c.c)
void I2C_Configuration(void) {
// GPIO配置:SCL=PB6, SDA=PB7
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; // 复用开漏模式
GPIO_Init(GPIOB, &GPIO_InitStruct);
// I2C参数配置
I2C_InitStruct.I2C_ClockSpeed = 100000; // 100kHz标准模式
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 时钟占空比
I2C_Init(I2C1, &I2C_InitStruct);
I2C_Cmd(I2C1, ENABLE); // 使能I2C
}
- 关键点:
- GPIO必须配置为复用开漏模式(支持总线仲裁)
- 时钟速度需匹配从机设备(如LM75A支持400kHz)
2.2 数据发送函数(I2C_SAND_BUFFER)
void I2C_SAND_BUFFER(u8 SlaveAddr, u8 WriteAddr, u8* pBuffer, u16 NumByteToWrite) {
I2C_GenerateSTART(I2C1, ENABLE); // 发送起始信号
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); // 等待EV5
I2C_Send7bitAddress(I2C1, SlaveAddr, I2C_Direction_Transmitter); // 发送设备地址
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); // 等待EV6
I2C_SendData(I2C1, WriteAddr); // 发送寄存器地址
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // 等待EV8
while(NumByteToWrite--) { // 循环发送数据
I2C_SendData(I2C1, *pBuffer++);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
I2C_GenerateSTOP(I2C1, ENABLE); // 发送停止信号
}
- 协议流程:
- 起始信号 → 2. 发送地址+写方向 → 3. 发送寄存器地址 → 4. 发送数据 → 5. 停止信号
2.3 数据接收函数(I2C_READ_BUFFER)
三、总线速度配置原理
在i2c.h
中定义总线速率:
#define BusSpeed 200000 // 200kHz
- 计算公式:
SCL频率 = APB1时钟频率 2 × ( I2C_ClockSpeed + 1 ) \text{SCL频率} = \frac{\text{APB1时钟频率}}{2 \times (\text{I2C\_ClockSpeed} + 1)} SCL频率=2×(I2C_ClockSpeed+1)APB1时钟频率
- 注意事项:
- APB1时钟需在初始化时正确配置(默认为36MHz)
- 实际速率可通过示波器测量SCL引脚验证
四、用户应用实战(main.c)
int main(void) {
u8 tempData[3];
I2C_Configuration(); // 初始化I2C
TM1640_Init(); // 初始化显示模块
while(1) {
LM75A_GetTemp(tempData); // 读取温度
// 显示温度值(示例代码略)
delay_ms(200); // 控制采样频率
}
}
- 调用链:
main()
→LM75A_GetTemp()
→I2C_READ_BUFFER()
→ 硬件寄存器操作
五、器件驱动开发(LM75A示例)
5.1 温度读取函数
void LM75A_GetTemp(u8 *Tempbuffer) {
u8 rawData[2];
I2C_READ_BUFFER(LM75A_ADD, 0x00, rawData, 2); // 读取原始数据
// 数据解析(示例)
int16_t temp = (rawData[0] << 8) | rawData[1];
temp = temp >> 5; // 有效数据为11位
*Tempbuffer = temp * 0.125; // 转换为实际温度值
}
- 关键参数:
LM75A_ADD = 0x9E
(包含R/W位)- 温度数据为16位(高11位有效)
六、常见问题排查指南
现象 | 可能原因 | 解决方案 |
---|---|---|
总线无响应 | 1. 硬件连接错误 | 检查SCL/SDA上拉电阻(4.7kΩ) |
数据校验失败 | 2. 时序不匹配 | 降低时钟速度或调整延时 |
重复地址冲突 | 3. 从机地址配置错误 | 使用I2C扫描工具检测设备地址 |
七、进阶优化技巧
- DMA传输
使用DMA减少CPU占用:I2C_DMACmd(I2C1, I2C_DMAReq_Tx | I2C_DMAReq_Rx, ENABLE);
- 错误恢复机制
检测总线忙状态时自动复位:if(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)) { I2C_SoftwareResetCmd(I2C1, ENABLE); I2C_SoftwareResetCmd(I2C1, DISABLE); }
八、相关资源
[1] 洋桃电子B站课程-STM32入门100步
[2] STM32F103xx官方数据手册
[3] STM32F103X8-B数据手册(中文)
[4] STM32F103固件函数库用户手册(中文)
[5] I2C总线规范(中文)
[6] LM75(温度传感器)数据手册+编程说明+应用
[7] 温度传感器数码管显示程序
[8] I2C驱动程序分析.pptx
总结
本文从STM32的I2C驱动架构出发,详细解析了总线初始化、数据收发和速度配置的实现原理,并结合LM75A温度传感器展示了实际应用场景。掌握以下核心要点:
- 分层架构设计提升代码可维护性
- 严格遵循I2C协议时序
- 合理配置总线速率匹配外设
- 善用调试工具(如逻辑分析仪)验证通信波形
通过理论结合实践的方式,开发者能够快速构建稳定可靠的I2C通信系统。
💬 技术讨论(请在评论区留言~)
📌 下期预告:下一期将探讨LM75A驱动程序分析,欢迎持续关注!
点击查阅🔍往期【STM32专栏】文章
版权声明:本文采用[CC BY-NC-SA 4.0]协议,转载请注明来源
实测开发版:洋桃1号开发版(基于STM32F103C8T6)
更新日志:
- v1.0 初始版本(2025-03-07)