HAL_Delay详解

HAL_Delay详解

最近我在使用HAL_Delay时经常出现死机等情况,后来经过调试发现,HAL_Delay()中无法进入SysTick定时器的中断,所以导致程序卡死,今天就来分析一下HAL_Delay函数,并且来探讨一下为什么会无法进入SysTick定时器的中断。

一、HAL_Init()

/**
  * @brief  This function is used to initialize the HAL Library; it must be the first
  *         instruction to be executed in the main program (before to call any other
  *         HAL function), it performs the following:
  *           Configure the Flash prefetch.
  *           Configures the SysTick to generate an interrupt each 1 millisecond,
  *           which is clocked by the HSI (at this stage, the clock is not yet
  *           configured and thus the system is running from the internal HSI at 16 MHz).
  *           Set NVIC Group Priority to 4.
  *           Calls the HAL_MspInit() callback function defined in user file
  *           "stm32f1xx_hal_msp.c" to do the global low level hardware initialization
  *
  * @note   SysTick is used as time base for the HAL_Delay() function, the application
  *         need to ensure that the SysTick time base is always set to 1 millisecond
  *         to have correct HAL operation.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_Init(void)
{
  /* Configure Flash prefetch */
#if (PREFETCH_ENABLE != 0)
#if defined(STM32F101x6) || defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) || \
    defined(STM32F102x6) || defined(STM32F102xB) || \
    defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) || \
    defined(STM32F105xC) || defined(STM32F107xC)

  /* Prefetch buffer is not available on value line devices */
  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif
#endif /* PREFETCH_ENABLE */

  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
  HAL_InitTick(TICK_INT_PRIORITY);

  /* Init the low level hardware */
  HAL_MspInit();

  /* Return function status */
  return HAL_OK;
}

这里面和systick有关的就时 HAL_InitTick(TICK_INT_PRIORITY);这个函数主要是配置systick的参数,让滴答定时器实现计时1ms秒的功能,并且设置滴答定时器的中断优先级,一般滴答定时器的中断优先级分组为0,优先级是最低的。


/**
  * @brief This function configures the source of the time base.
  *        The time source is configured  to have 1ms time base with a dedicated
  *        Tick interrupt priority.
  * @note This function is called  automatically at the beginning of program after
  *       reset by HAL_Init() or at any time when clock is reconfigured  by HAL_RCC_ClockConfig().
  * @note In the default implementation, SysTick timer is the source of time base.
  *       It is used to generate interrupts at regular time intervals.
  *       Care must be taken if HAL_Delay() is called from a peripheral ISR process,
  *       The SysTick interrupt must have higher priority (numerically lower)
  *       than the peripheral interrupt. Otherwise the caller ISR process will be blocked.
  *       The function is declared as __weak  to be overwritten  in case of other
  *       implementation  in user file.
  * @param TickPriority Tick interrupt priority.
  * @retval HAL status
  */
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /* Configure the SysTick to have interrupt in 1ms time basis*/ 
  //    //配置滴答定时器为1s。
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  {                                                                                               
    return HAL_ERROR;
  }

  /* Configure the SysTick IRQ priority */
  //设置滴答定时器中断优先级
  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  {
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  {
    return HAL_ERROR;
  }

  /* Return function status */
  return HAL_OK;
}

二、HAL_Delay()

/**
  * @brief This function provides minimum delay (in milliseconds) based
  *        on variable incremented.
  * @note In the default implementation , SysTick timer is the source of time base.
  *       It is used to generate interrupts at regular time intervals where uwTick
  *       is incremented.
  * @note This function is declared as __weak to be overwritten in case of other
  *       implementations in user file.
  * @param Delay specifies the delay time length, in milliseconds.
  * @retval None
  */
__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);  //1
  }

  while ((HAL_GetTick() - tickstart) < wait)  //501 - 500 = 1 < 101
  {
  }
}

Hal_Delay的原理就是,进入时先获取当前程序的运行时间,也就时获取滴答定时器里的值(HAL_GetTick();)然后传入一个等待时间Delay,判断等待的时间是否超过最大等待时间HAL_MAX_DELAY。如果不超过,就加上1,然后每1ms获取一次滴答定时器的时间,当差值大于wait,说明延时结束。

如果HAl_Delay出现卡死在 while ((HAL_GetTick() - tickstart) < wait)这个里面的情况,一般就是
HAL_GetTick() 这个函数出问题了,无法获取滴答时钟的值了。

/**
  * @brief This function is called to increment  a global variable "uwTick"
  *        used as application time base.
  * @note In the default implementation, this variable is incremented each 1ms
  *       in SysTick ISR.
  * @note This function is declared as __weak to be overwritten in case of other
  *      implementations in user file.
  * @retval None
  */
__weak void HAL_IncTick(void)
{
  uwTick += uwTickFreq;
}

/**
  * @brief Provides a tick value in millisecond.
  * @note  This function is declared as __weak to be overwritten in case of other
  *       implementations in user file.
  * @retval tick value
  */
__weak uint32_t HAL_GetTick(void)
{
  return uwTick;
}

我们可以看到HAL_GetTick(void)这个函数很简单,就是返回uwTick的值,然后我们在systick的中断里调用void HAL_IncTick(void)这个函数,每次进入中断给 uwTick加1。

三、死机分析

我的使用HAL_Delay死机的原因就是我没有设置systick的中断函数,导致 uwTick无法自增,所以才会死机,所以,我们需要配置一下systick的中断函数,并在中断函数里调用HAL_IncTick(void)这个,来实现每1ms自增一次

/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  
	HAL_IncTick();	
}

这样死机的问题就解决了。如果不是这个问题,就很有可能是中断优先级的问题了,如果在比systick中断优先级高的中断函数里调用,HAL_Delay,就会出现一直无法进入systcik中断的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值