基于STM32的Free-RT-OS的两种时基的认识以及重写ms,us级延时

目录

两种时基

定时器重写ms和us级函数

Systick重写us ms级延时函数


两种时基

        在STM32的裸机开发中,没有操作系统这个概念,特别是在用CUBEMX配置生成项目时,默认都是选择了systick做为hal的时基。而当用了FREE RT OS时则强行绑定了systick做为其任务调度的时基。

        在操作系统中,时基被用做计数,systick是1ms一个脉冲,vTaskDelay使若任务挂起等若干内核级的函数用的就是这个。(内核封装了很多层,最终可以找到systick的中断回调就是为OS提供"心跳"

        在HAL库中,用到时基的地方,目前我在开发中还只知道在延时函数HAL_Delay() 有用到HAL库的时基。 HAL库时基的频率默认是1KHZ,1ms产生定时中断计数值加1。

在cubeMX配置TIM6作为HAL库时基时。默认生成的代码是预分频系数为系统时钟频率-1,装载为999,每1us计数值加1,1ms产生一次中断。全局维护一个u32类型的变量 utick。在中断函数中调用

 HAL_IncTick();使得utick自增1。

在以TIM6充当时基时:TIM6的初始化

HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  RCC_ClkInitTypeDef    clkconfig;
  uint32_t              uwTimclock, uwAPB1Prescaler = 0U;

  uint32_t              uwPrescalerValue = 0U;
  uint32_t              pFLatency;
  HAL_StatusTypeDef     status = HAL_OK;

  /* Enable TIM6 clock */
  __HAL_RCC_TIM6_CLK_ENABLE();

  /* Get clock configuration */
  HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);

  /* Get APB1 prescaler */
  uwAPB1Prescaler = clkconfig.APB1CLKDivider;
  /* Compute TIM6 clock */
  if (uwAPB1Prescaler == RCC_HCLK_DIV1)
  {
    uwTimclock = HAL_RCC_GetPCLK1Freq();
  }
  else
  {
    uwTimclock = 2UL * HAL_RCC_GetPCLK1Freq();
  }

  /* Compute the prescaler value to have TIM6 counter clock equal to 1MHz */
  uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000U) - 1U);

  /* 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 = (1000000U / 1000U) - 1U;
  htim6.Init.Prescaler = uwPrescalerValue;
  htim6.Init.ClockDivision = 0;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

  status = HAL_TIM_Base_Init(&htim6);
  if (status == HAL_OK)
  {
    /* Start the TIM time Base generation in interrupt mode */
    status = HAL_TIM_Base_Start_IT(&htim6);
    if (status == HAL_OK)
    {
    /* Enable the TIM6 global Interrupt */
        HAL_NVIC_EnableIRQ(TIM6_IRQn);
      /* Configure the SysTick IRQ priority */
      if (TickPriority < (1UL << __NVIC_PRIO_BITS))
      {
        /* Configure the TIM IRQ priority */
        HAL_NVIC_SetPriority(TIM6_IRQn, TickPriority, 0U);
        uwTickPrio = TickPriority;
      }
      else
      {
        status = HAL_ERROR;
      }
    }
  }

 /* Return function status */
  return status;
}

HAL_Delay会至少延时1个时钟周期。

                

__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;

  /* Add a freq to guarantee minimum wait */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }

  while ((HAL_GetTick() - tickstart) < wait)
  {
  }
}

定时器重写ms和us级函数

delay_ms

void delay_ms(u32 ms){

    __HAL_TIM_ENABLE(&htim6);
  HAL_Delay(ms);
   __HAL_TIM_DISABLE(&htim6);
    
}

delay_us

这里更为直接,CUBEMX配置后,默认就是1MHZ的时钟频率。也就是1us计数值加1。那么可以先将计数值CNT赋值为0等待计数则大功告成。这在日常用IIC,DHT温度传感器以及一些时序中经常使用。

void  delay_us(u32 nus)
{

 
	 
     uint32_t cnt=0;
	__HAL_TIM_ENABLE(&htim6);
    __HAL_TIM_SetCounter(&htim6,0);
	while( cnt < nus){
        
       cnt=__HAL_TIM_GetCounter(&htim6);
       
    }
   
	__HAL_TIM_DISABLE(&htim6);
    
}

Systick重写us ms级延时函数

通过滴答计数值tick结合hal_delay()实现软件延时.精度比不上用上面的定时器.


void delay_ms(uint32_t ms)
{
    
   
        HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
    
        HAL_Delay(ms-1);
 
 
   
          
}

void delay_us(uint32_t us)
{
    
        HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000000);
        HAL_Delay(us-1);
        HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
    
}

你可能感兴趣的:(STM32,stm32,单片机,arm)