STM32 HAL使用TIM6代替Systick作为时基

在使用STM32CubeMX生成对应的STM32工程时,很多时候在配置SYS的时候,会直接忽略掉时基源的选择,而STM32CubeMX默认选择的是Systick,作为HAL库的时基,用于一些超时操作,像I2C\USART等,都会用到。
在这里插入图片描述
而在实际的应用中,如果不跑裸机,就会用到Systick,作为RTOS的时基。许多人使用HAL库的时候,都会很习惯使用HAL_Delay作为毫秒级的延时(当然也可以作为us级别的,需要去改)。但上了RTOS,由于systick被HAL占用了,如果在Systick的中断中,继续添加RTOS的计数,不是不行,在使用STM32CubeMX 加上FreeRTOS的时候,就会有这样的提示:
在这里插入图片描述
其实你可以忽略掉这个,直接生成,得到的FreeRTOS的工程也是能用的,但是如果使用DWT作为时间戳进行时间测量(时间足够长),你会发现对比出来有时间差。并且官方也是极力不推荐的。

当然,面对这种尴尬的情况,也是有解决方案的

  • 1 、在杰杰的博客中有提到,使用Cortex-M内核中的一个调试追踪器----DWT,DWT有计数器寄存器,可以代替SYSTICK进行足够时间的计数。具体可看他的博客:https://blog.csdn.net/jiejiemcu/article/details/83932913

  • 2、使用一个TIM来代替systick进行延时。具体在使用STM32CubeMX生成的时候,将Systick换成一个自己不常用的基本定时器:在这里插入图片描述
    配置出来的工程中,会出现一个文件,
    在这里插入图片描述
    这里就已经将你的TIM6(或者别的,自己选择的)初始化并配置好了,基本上不需要自己配置,当然也可以自己配置初始化,将原本放在Systick中断中的

      HAL_IncTick()
    

这个函数,放在TIM6的中断服务函数中,也是可以的。

而也可以学官方的来改,

HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  RCC_ClkInitTypeDef    clkconfig;
  uint32_t              uwTimclock = 0;
  uint32_t              uwPrescalerValue = 0;
  uint32_t              pFLatency;
  
  /*Configure the TIM6 IRQ priority */
  HAL_NVIC_SetPriority(TIM6_DAC_IRQn, TickPriority ,0); 
  
  /* Enable the TIM6 global Interrupt */
  HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn); 
  
  /* Enable TIM6 clock */
  __HAL_RCC_TIM6_CLK_ENABLE();
  
  /* Get clock configuration */
  HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
  
  /* Compute TIM6 clock */
  uwTimclock = 2*HAL_RCC_GetPCLK1Freq();
   
  /* Compute the prescaler value to have TIM6 counter clock equal to 1MHz */
  uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000) - 1);
  
  /* Initialize TIM6 */
  htim6.Instance = TIM6;
  
  /* Initialize TIMx peripheral as follow:
  + Period = [(TIM6CLK/1000) - 1]. to have a (1/1000) s time base.
  + Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
  + ClockDivision = 0
  + Counter direction = Up
  */
  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)
  {
    /* Start the TIM time Base generation in interrupt mode */
    return HAL_TIM_Base_Start_IT(&htim6);
  }
  
  /* Return function status */
  return HAL_ERROR;
}

改好之后,在上RTOS的时候,记得在TIM6中断中,加入临界段保护(或进入中断保护),否则会出现意想不到的结果,反正我第一次这样做的时候,运行了5分钟左右就死机了,当时也不明白为啥。。。现在也不明白,后来发现中断那里写少了东西,加上之后就好了,嘿嘿。

发布了45 篇原创文章 · 获赞 52 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42312125/article/details/100169257