stm32hal库II2C中断
时间: 2025-04-17 13:47:28 浏览: 29
### STM32 HAL库 I2C 中断 使用教程及问题解决
#### 初始化配置
为了正确使用I2C中断,在初始化阶段需设置好相应的参数。这包括定义I2C句柄结构体`I2C_HandleTypeDef`并调用`HAL_I2C_Init()`完成硬件资源分配和基本通信参数设定[^1]。
```c
// 定义I2C句柄实例
I2C_HandleTypeDef hi2c1;
void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x20909CEC; // 设置时序寄存器值
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
```
#### 启动传输过程中的注意事项
当启动数据发送或接收操作时,应采用非阻塞模式即通过回调机制来处理事件响应而非等待其结束。对于读写请求可以分别利用`HAL_I2C_Master_Transmit_IT()` 和 `HAL_I2C_Master_Receive_IT()` 函数实现异步的数据交换。
#### 处理错误情况下的恢复措施
如果遇到总线忙(`BUSY`)或其他异常情形,则可能需要执行特定的复位流程以恢复正常工作状态。一种常见做法是在检测到此类故障后立即停止当前事务并通过软件方式重置SCL/SDA引脚电平直到确认释放为止。
```c
if (__HAL_I2C_GET_FLAG(&hi2c1, I2C_FLAG_BUSY))
{
/* 清除 busy flag */
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_AF);
/* 执行物理层上的总线复位 */
while(__HAL_I2C_GET_FLAG(&hi2c1, I2C_FLAG_BUSY));
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_Delay(2); // 延迟一段时间
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET);
/* 恢复默认配置 */
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
```
#### 避免因延时造成的死锁现象
值得注意的是,在某些情况下直接在ISR内部调用像`HAL_Delay()`这样的延迟函数可能会引起系统挂起甚至崩溃的问题。这是因为该类API依赖于滴答定时器(Timer Tick),而在中断上下文中无法正常运作。因此建议改用其他形式的时间管理方案比如基于定时器的超时判断逻辑来替代简单的循环等待语句[^2]。
```c
uint32_t timeout = HAL_GetTick() + TimeoutDurationMs;
while((status == HAL_TIMEOUT || status == HAL_ERROR) && (HAL_GetTick() < timeout)){
// 循环检查条件满足与否...
}
if(HAL_GetTick() >= timeout){
// 超时处理..
}
```
阅读全文
相关推荐

















