在不使用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的功能。