HAL延时中断调试报告

- **调试日期**: 2026-04-21 - **调试人员**: 系统调试团队

2026-07-04
HAL库中断延时嵌入式调试

HAL_Delay函数死循环问题调试报告 - 中断优先级问题

文档信息


1. 问题描述

现象:

可能原因:

  1. 中断优先级问题
  2. 函数调用上下文不同
  3. 系统状态差异

2. 问题分析

2.1 代码分析

调用路径分析:

中断优先级设置:

HAL_Delay函数实现:


__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;

  /* Add a freq to guarantee minimum wait */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }

  while((HAL_GetTick() - tickstart) < wait)
  {
  }
}

HAL_IncTick函数实现:


__weak void HAL_IncTick(void)
{
  uwTick += uwTickFreq;
}

SysTick_Handler函数实现:


void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

2.2 问题原因

主要原因:

次要原因:


3. 解决方案

3.1 使用忙等待替代HAL_Delay

修改前:


HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
HAL_Delay(50); // 增加延时至50ms,符合蓝牙模块启动时序

// 使用非阻塞方式发送数据,避免卡住
HAL_StatusTypeDef status = HAL_UART_Transmit(&huart2, pch->TxBuf, pch->TxBufByteCtr, 100);
if (status != HAL_OK)
{
  // 发送失败,记录错误但继续执行
}

HAL_Delay(10); // 增加发送完成后的延时
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
HAL_Delay(10); // 增加拉高后的延时

修改后:


HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
// 不使用HAL_Delay,改为使用忙等待
for (uint32_t i = 0; i < 800000; i++) { __NOP(); }

// 使用非阻塞方式发送数据,避免卡住
HAL_StatusTypeDef status = HAL_UART_Transmit(&huart2, pch->TxBuf, pch->TxBufByteCtr, 100);
if (status != HAL_OK)
{
  // 发送失败,记录错误但继续执行
}

// 不使用HAL_Delay,改为使用忙等待
for (uint32_t i = 0; i < 160000; i++) { __NOP(); }
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
// 不使用HAL_Delay,改为使用忙等待
for (uint32_t i = 0; i < 160000; i++) { __NOP(); }

说明:

3.2 其他优化措施

  1. 调整中断优先级:
  1. 使用非阻塞方式:
  1. 使用定时器:

4. 测试验证

4.1 测试步骤

  1. 硬件连接:
  1. 软件设置:
  1. 测试执行:

4.2 预期结果

测试项目 预期结果
RS485_Send执行 正常完成,无死循环
PA15控制 正确拉低和拉高
蓝牙通信 正常建立连接
系统运行 稳定,无阻塞

5. 结论

通过分析和修改,解决了mb.C中HAL_Delay函数进入死循环的问题。主要修改包括:

  1. 使用忙等待替代HALDelay:在RS485Send函数中,将HALDelay替换为忙等待(_NOP()循环),避免依赖Systick中断
  2. 调整循环次数:根据系统时钟频率(16MHz)设置合适的循环次数,确保延时时间准确
  3. 保持功能完整性:确保PA15引脚控制时序符合蓝牙模块的要求

这些修改确保了RS485_Send函数在UART中断回调中能够正常执行,不会因为中断优先级问题而进入死循环。


文档结束

本文档提供了详细的HAL_Delay函数死循环问题的调试方案和解决方案,可作为系统维护的参考