使用cubeMx 生成systick及周期调整
在cubeMx中生成的代码工程是自动配置systick时钟的,因为HAL库中的一些函数需要systick时钟来判断操作是否超时,下面要进入重点:如何配置systick,从cubeMX中生成的systick的周期时1ms一次的。
在main函数中找到其初始化代码:
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
从SystemClock_Config();进入找到
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
HAL_RCC_OscConfig(&RCC_OscInitStruct) 这个函数里面包含了配置systick的代码,进来后找到HAL_InitTick(uwTickPrio) ,HAL_InitTick(uwTickPrio) 就是配置systick的函数。
/* Adapt Systick interrupt period */
if (HAL_InitTick(uwTickPrio) != HAL_OK)
{
return HAL_ERROR;
}
下面就是定义systick的函数,其中uwTickFreq定义为1,可以去看其定义的地方。
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
HAL_StatusTypeDef status = HAL_OK;
if (uwTickFreq != 0U)
{
/*Configure the SysTick to have interrupt in 1ms time basis*/
if (HAL_SYSTICK_Config(SystemCoreClock / (1000U /uwTickFreq)) == 0U)
{
/* Configure the SysTick IRQ priority */
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
uwTickPrio = TickPriority;
}
else
{
status = HAL_ERROR;
}
}
else
{
status = HAL_ERROR;
}
}
else
{
status = HAL_ERROR;
}
/* Return function status */
return status;
}
那么这个周期时如何计算的呢?关键在于SystemCoreClock / (1000U /uwTickFreq),这里是得到的数值是传入到设置systick定时器的。因为uwTickFreq为1,所以周期的数值就是SystemCoreClock/1000,这里我们先假设SystemCoreClock是72MHz,那么systick的周期值就是72000,systick进入中断的频率就是72000000/72000=1000Hz,也就是1s进入systick中断1000次,所以每次中断就是1ms。如果要调整周期,只需要调整 (1000U /uwTickFreq)这个数值即可, (1000U /uwTickFreq)计算的结果就是systick的频率值,由于uwTickFreq为1,所以systick的频率就是1000U,如果想改变systick的周期,只要1000U改为想要的频率值即可(周期=1/频率)。
改变了周期之后会对HAL库的一些函数有影响,因为有些函数是要判断操作是否超时的,所以会以systick为计时器,通过回调__weak uint32_t HAL_GetTick(void)这个函数来判断操作是否超时,具体操作可以去看相应的函数。既然有影响我们就要消除影响,因为HAL_GetTick()这个函数主要是return uwTick;而影响uwTick的函数是__weak void HAL_IncTick(void)
__weak void HAL_IncTick(void)
{
uwTick += uwTickFreq;
}
uwTickFreq为1,这个函数有__weak 关键字标识,是可以重写的,我们只要在我们自己的.c文件中重写void HAL_IncTick(void)函数即可,我们这里仍然希望是1ms( uwTick +1),那么就根据自己设置的systick的频率来计算systick的周期值,每个周期systick会回调一次HAL_IncTick()函数,只要在HAL_IncTick()函数中计算好回调多少次该函数uwTick再+1即可。