STM32HAL库之HAL_Delay()
- HAL_Init()
初始化hal库,其中有一个函数是初始化systick的,HAL_InitTick是用于初始化systick。systick 上电初始化(外部晶振还没开始工作,此时系统默认使用内部 HSI 提供时钟源)
main() -> HAL_Init() -> HAL_InitTick() -> HAL_SYSTICK_Config() ->
SysTick_Config(SystemCoreClock / (1000U / uwTickFreq)
其中SysTick_Config()这个函数传递值是初始化如下 LOAD的值
typedef struct
{
// 控制位
__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
//reload 也就是初始值,val需要要等与reload才会产生中断。
__IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
// 目前值,达到load产生一次中断。
__IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
__IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
} SysTick_Type;
- SystemClock_Config()
初始化系统时钟,初始化时钟树里面描述的所有信息。其中也包括了systick这个系统定时器。
AL_RCC_ClockConfig() -> HAL_InitTick() -> HAL_SYSTICK_Config() ->
SysTick_Config(SystemCoreClock / (1000U / uwTickFreq)
下面我们说一下 HAL_Delay()是如何实现的。
stm3214xx_hal.c
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick(); //最初为1
uint32_t wait = Delay; //延时的时间
/* Add a period to guaranty minimum wait */
if (wait < HAL_MAX_DELAY) //为了防止Delay延时时间为0,所以加一个1
{
wait += (uint32_t)uwTickFreq;
}
while ((HAL_GetTick() - tickstart) < wait))
{
}
}
HAL_GetTick()每一次中断加1,中断是由 val加到 reload产生一次中断,reload的值是(SystemCoreClock / (1000U / uwTickFreq)根据这个表达式来的,如果uwTickFreq的值越小,那么reload的值越大,当uwTickFreq等于1的时候,那么reload就是72MHZ,也就是延时最小是1s的了。上述的是uwTickFreq等于1000,那么reload就是72MHZ/1000,因为每秒产生72000 000个脉冲,如果除以1000,那么reload等于72000,因为72MHZ是1秒,那么72000就是1ms。所以while ((HAL_GetTick() - tickstart) < wait)),这个代表因为没产生一个中断HAL_GetTick()加1,也就是1ms加1,那么等到1000ms的时候HAL_GetTick()也等于1000,这个时候延时就停止。
stm3214xx_it.c
中断服务程序,每当val = 72000的时候,就产生一个中断,执行 SysTick_Handle()
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 */
}
HAL_IncTick()
HAL_GetTick(void)
__weak void HAL_IncTick(void)
{
uwTick += (uint32_t)uwTickFreq; //每次中断uwTick +1
}
__weak uint32_t HAL_GetTick(void)
{
return uwTick; //获取当前uwTick的值,当Delay(100)时候,就要让uwTick==100,即产生100次中断。
}