STM32使用HAL库I2C通信二次调试返回HAL_BUSY问题求助
STM32 HAL库I2C二次调试返回HAL_BUSY问题原因与解决方案
核心问题原因
该问题是STM32 I2C开发的常见问题,本质是软复位时仅重置MCU、未重置I2C从设备和总线状态导致的,具体触发原因分为两类:
- I2C总线死锁:调试/软复位MCU时,如果I2C通信刚好进行到一半,传感器(MAX30105)的I2C状态机停在等待SCL时钟的状态,会持续拉低SDA线,导致总线一直被标记为占用,HAL库检测到总线状态异常直接返回
HAL_BUSY。由于软复位不会给传感器断电,状态机一直卡在错误状态,只有全断电重置传感器才能恢复。 - HAL库I2C状态残留:STM32软复位时,I2C外设的部分寄存器、HAL库I2C句柄
hi2c1的State成员可能没有被重置,初始化完成后状态仍标记为HAL_I2C_STATE_BUSY,调用通信接口时会直接返回忙错误,无需总线真的被占用就会触发。
修复方案
1. 新增I2C总线复位流程(优先级最高,解决90%以上该类问题)
在MX_I2C1_Init函数开头的USER CODE I2C1_Init 0段加入模拟总线复位代码,强制重置从设备状态机,让其释放SDA总线:
/* USER CODE BEGIN I2C1_Init 0 */ GPIO_InitTypeDef GPIO_InitStruct = {0}; // 先把SCL、SDA引脚配置为开漏输出,端口根据你的实际硬件修改 __HAL_RCC_GPIOB_CLK_ENABLE(); // 引脚编号对应I2C1的SCL、SDA引脚,根据实际硬件修改 GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // 拉高SDA、SCL初始电平 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET); HAL_Delay(1); // 翻转SCL 9次,清除从设备待接收的位 for(int i=0; i<9; i++){ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); HAL_Delay(1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET); HAL_Delay(1); } // 发送停止位,复位从设备状态机 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); HAL_Delay(1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET); HAL_Delay(1); // 复位后引脚会在后续I2C初始化中自动复用为外设功能 /* USER CODE END I2C1_Init 0 */
2. 重置HAL I2C状态
调用HAL_I2C_Init之前先调用反初始化接口,清除寄存器和句柄的残留状态:
/* USER CODE BEGIN I2C1_Init 1 */ HAL_I2C_DeInit(&hi2c1); /* USER CODE END I2C1_Init 1 */
3. 增加运行时错误恢复逻辑
在调用HAL_I2C接口返回HAL_BUSY时,主动触发一次总线复位+I2C重新初始化流程,无需重启设备即可自动恢复通信。
内容的提问来源于stack exchange,提问作者Geisterfahrer
相关产品推荐
相关产品推荐

