STM32源码阅读记录之HAL库(SystemTick)

问题

  1. HAL_Delay是怎么做到可以延迟控制的?

分析记录

步骤01:看函数本身

void HAL_Delay(uint32_t Delay);

/**
  * @brief 此函数根据变量递增提供最小延迟(以毫秒为单位)。
  * @note 在默认的实现中,SysTick计时器是时基的来源。它用于以固定的时间间隔生成中断,其中 uwTick 递增
  * @note 此函数声明为__weak在用户文件中出现其他实现时要覆盖。
  * @param Delay 指定延迟时间长度(以毫秒为单位)。
  * @retval None
  */
__weak void HAL_Delay(uint32_t Delay)
{
  // 获取一个计数值,简单来说就是一个记录当前时刻的记录值
  uint32_t tickstart = HAL_GetTick();
 
  uint32_t wait = Delay;

  /* 添加频率以保证最短的等待时间 */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }
  //  死循环,直到不满足要求时结束
  while ((HAL_GetTick() - tickstart) < wait)
  {
  }
}

uint32_t HAL_GetTick(void)

/**
  * @brief 提供以毫秒为单位的刻度值。
  * @note  此函数声明为__weak在用户文件中出现其他实现时要覆盖。
  * @retval tick value
  */
__weak uint32_t HAL_GetTick(void)
{
  return uwTick;
}

void HAL_IncTick(void)

/**
  * @brief 调用此函数以递增用作应用程序时基的全局变量“uwTick”。
  * @note 在默认实现中,此变量在 SysTick ISR 中每 1 毫秒递增一次。
  * @note 此函数声明为__weak在用户文件中出现其他实现时要覆盖。
  * @retval None
  */
__weak void HAL_IncTick(void)
{
  uwTick += uwTickFreq;
}

步骤02:观察相关联的变量

STM32源码阅读记录之HAL库(SystemTick)_第1张图片

步骤03:观察变化的地方

STM32源码阅读记录之HAL库(SystemTick)_第2张图片1. 在SysTick_Handler中被调用
STM32源码阅读记录之HAL库(SystemTick)_第3张图片

步骤04:中断要执行是需要开启的

  1. 在程序的开头HAL_Init();
    在这里插入图片描述STM32源码阅读记录之HAL库(SystemTick)_第4张图片
/**
  * @brief  此函数用于初始化 HAL 库;它必须是在主程序中执行的第一个指令(在调用任何其他 HAL 函数之前), 它执行以下操作:
  *           1. 配置闪存预取。
  *           2. 将 SysTick 配置为每 1 毫秒生成一次中断,
  *           3. 由 HSI 计时(在此阶段,时钟尚未配置,因此系统从内部 HSI 以 16 MHz 运行).
  *           4. 将 NVIC 组优先级设置为 4
  *           5. 调用用户文件 “stm32f1xx_hal_msp.c” 中定义的 HAL_MspInit() 回调函数来执行全局低级硬件初始化
  *
  * @note   SysTick 用作 HAL_Delay() 函数的时基,应用程序需要确保 SysTick 时基始终设置为 1 毫秒,以便具有正确的 HAL 操作
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_Init(void) {
    /* 配置闪存预取 */
#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)

    /* 预取缓冲区在超值行设备上不可用 */
    __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif
#endif /* PREFETCH_ENABLE */

    /* NVIC 组优先级设置 */
    HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

    /*将 SysTick 配置为每 1 毫秒生成一次中断(重置后的默认时钟为 HSI) */
    HAL_InitTick(TICK_INT_PRIORITY);

    /* 初始化低级硬件 */
    HAL_MspInit();

    /* 返回函数状态 */
    return HAL_OK;
}

步骤04:查看HAL_InitTick执行函数

STM32源码阅读记录之HAL库(SystemTick)_第5张图片

/**
  * @brief 此函数配置时基源。时间源配置为具有 1ms 时基,具有专用的 Tick 中断优先级
  * @note 此函数在程序开始时由 HAL_Init() 重置后或在时钟由 HAL_RCC_ClockConfig() 重新配置时自动调用。
  * @note 在默认实现中,SysTick 计时器是时基的来源。它用于以固定的时间间隔生成中断。
  *       如果从外设 ISR 进程调用 HAL_Delay(),则必须小心,SysTick 中断的优先级必须高于外设中断(数值较低)。否则,调用方 ISR 进程将被阻止。
  * @param TickPriority Tick interrupt priority.
  * @retval HAL status
  */
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) {
    /* 将系统滴答配置为在 1ms 时间内中断*/
    if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U) {
        return HAL_ERROR;
    }

    /* 配置系统滴答 IRQ 优先级 */
    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;
}

步骤05: 查看HAL_SYSTICK_Config函数

  1. 这一步就是对外再包装了一层
    STM32源码阅读记录之HAL库(SystemTick)_第6张图片

步骤06: 查看SysTick_Config函数(实际执行的)

STM32源码阅读记录之HAL库(SystemTick)_第7张图片

步骤07: 重点记录SystemCoreClock的变化:

STM32源码阅读记录之HAL库(SystemTick)_第8张图片STM32源码阅读记录之HAL库(SystemTick)_第9张图片

第一次使用的地方

STM32源码阅读记录之HAL库(SystemTick)_第10张图片

第一次变化的地方

STM32源码阅读记录之HAL库(SystemTick)_第11张图片

查看HAL_RCC_ClockConfig执行函数

STM32源码阅读记录之HAL库(SystemTick)_第12张图片STM32源码阅读记录之HAL库(SystemTick)_第13张图片

你可能感兴趣的:(STM32之HAL源码记录,stm32,单片机,嵌入式硬件)