在不使用FreeRTOS的时候,SysTick是默认的HAL基础时钟源,但是在SYS模块中,也可以选择其他定时器作为基础时钟源,例如可以选择基础定时器TIM6作为HAL的基础时钟源。
图1 选用TIM6作为HAL的基础时钟
选择TIM6作为基础时钟源后,TIM6就不能在作为其他用途,在STM32CubeMX中不能再对TIM6做任何设置。在NVIC中,TIM6的中断被自动启用,优先级被设置为最高。可以修改TIM6的中断优先级,但是不能关闭TIM6的中断。同时,SysTick定时器的中断也还是被自动启用的,且不能关闭,如图2所示。
图2 使用TIM6作为HAL基础时钟源时的NVIC设置
1. 基础时钟的初始化
在使用定时器TIM6作为HAL的基础时钟源并用STM32CubeMX生成代码后,\Src目录下新增了一个文件stm32f4xx_hal_timebase_TIM.c,这个文件里重新实现了文件stm32f4xx_hal.c中的3个弱函数,用定时器TIM6替代了SysTick的功能。文件stm32f4xx_hal_timebase_TIM.c的完整代码如下:
/* 文件: stm32f4xx_hal_timebase_TIM.c -----------------------------------------*/
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_tim.h"
TIM_HandleTypeDef htim6;
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
RCC_ClkInitTypeDef clkconfig;
uint32_t uwTimclock = 0;
uint32_t uwPrescalerValue = 0;
uint32_t pFLatency;
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, TickPriority ,0); //设置TIM6的中断优先级
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn); //开启TIM6中断
__HAL_RCC_TIM6_CLK_ENABLE(); //开启TIM6的时钟
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency); //获取时钟配置
uwTimclock = 2*HAL_RCC_GetPCLK1Freq(); //计算TIM6的时钟频率,是PCLK1的2倍
/* 计算分频系数,使TIM计数器时钟信号为1MHz*/
uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000) - 1);
/* 初始化 TIM6,使其定时周期为 1ms */
htim6.Instance = TIM6;
htim6.Init.Period = (1000000 / 1000) - 1;
htim6.Init.Prescaler = uwPrescalerValue;
htim6.Init.ClockDivision = 0;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
if(HAL_TIM_Base_Init(&htim6) == HAL_OK)
{
return HAL_TIM_Base_Start_IT(&htim6); //以中断方式启动TIM6
}
return HAL_ERROR;
}
void HAL_SuspendTick(void)
{ /* 禁止 TIM6 的UEV中断 */
__HAL_TIM_DISABLE_IT(&htim6, TIM_IT_UPDATE);
}
void HAL_ResumeTick(void)
{
/* 卡其 TIM6 的UEV中断 */
__HAL_TIM_ENABLE_IT(&htim6, TIM_IT_UPDATE);
}
函数HAL_InitTick()是在HAL_Init()中被调用的,重新实现的这个函数对定时器TIM6进行了初始化配置,设置其中断优先级,配置其分频系数、计数周期等,使其定时器周期为1ms。
重新实现的函数HAL_ResumeTick()和HAL_SuspendTick()也是对TIM6的操作。
2. 基础时钟的中断处理
在使用定时器TIM6作为HAL的基础时钟源并用STM32CubeMX生成代码后,在文件stm32f4xx_it.c中没有了SysTick的ISR函数,有TIM6的ISR函数。TIM6的ISR函数代码如下:
void TIM6_DAC_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim6);
}
定时器的UEV事件的回调函数是HAL_TIM_PeriodElapsedCallback,在文件main.c中就重新实现了这个函数,其功能就是执行函数HAL_IncTick(),代码如下:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM6) {
HAL_IncTick();
}
}
所以,在使用TIM6作为HAL的基础时钟时,TIM6完全替代了SysTick的功能。