1. 系统滴答时钟
stm32配置完外部晶振时钟源后会有一个默认的时钟中断用于记录tick,这个时钟是固定的1ms(暂时没找到不修改代码调整的方式)。HAL库中systick的配置
// Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
/**
* @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*/
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;
}
可以看到时钟被调整为1ms,传入HAL_SYSTICK_Config
的是计数器的值,计数到达这个值触发中断。算一下
- SystemCoreClock是核心时钟的频率,也就是计数器计数频率,如果什么都不除,这里就会造成1s的中断计数(8MHz计数8M,就是1s一次)
- 除以1000就是代表搞1ms中断
- uwTickFreq定义如下,代表真实想要的中断频率,默认就是1KHZ也就是除以1,还是1000,对应的正好是1ms中断
// Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal.h
/** @defgroup HAL_TICK_FREQ Tick Frequency
* @{
*/
typedef enum
{
HAL_TICK_FREQ_10HZ = 100U,
HAL_TICK_FREQ_100HZ = 10U,
HAL_TICK_FREQ_1KHZ = 1U,
HAL_TICK_FREQ_DEFAULT = HAL_TICK_FREQ_1KHZ
} HAL_TickFreqTypeDef;
// Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT; /* 1KHz */
- 系统时钟中断触发函数定义为
SysTick_Handler
// Core/Src/stm32f1xx_it.c
/**
* @brief This function handles System tick timer.
*/
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 */
}
// Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
/**
* @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;
}
这个HAL_IncTick
是个__weak
定义的,说明可以用户自定义,从里面的定义可以看出,这个uwTick保持ms级别计数。
- uwTickFreq = 1,1ms,uwTick+1
- uwTickFreq = 10,10ms,uwTick+10
uwTick和uwTickFreq对外暴露了,定义在这里
// Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal.h
/* Exported types ------------------------------------------------------------*/
extern __IO uint32_t uwTick;
extern uint32_t uwTickPrio;
extern HAL_TickFreqTypeDef uwTickFreq;
我们可以重写这个HAL_IncTick
作为我们自己的定时器处理函数,可以从一个1ms定时器搞出很多个定时器。
volatile unsigned long jiffies = 0;
static void timer_handler(void) {
++jiffies;
}
/**
* @brief Period elapsed callback in non-blocking mode
* @param htim TIM handle
* @retval None
*/
void HAL_IncTick() {
// 还原原始调用
uwTick += uwTickFreq;
// 调用定时器处理函数
timer_handler();
}
虽然uwTick作为ms计数很不错,这里搞个好玩的,把linux的jiffies搞进来使用,单独记录一个。主要是想要应用层代码和HAL完全隔离,不想要太多依赖HAL库,这样好移植