当前位置:   article > 正文

SysTick 定时器详细学习笔记并兼容FreeRTOS_rtos时标使用systick还是timer

rtos时标使用systick还是timer


一:基础知识

  1. SysTick 是什么?

    SysTick:系统定时器,是一个 24bit 的向下递减的计数器(计数器每计数一次的时间为 1/SYSCLK,SYSCLK 为系统的是时钟频率(72M、168M等))。属于 CM3 内核中的一个外设,并且内嵌在 NVIC 中。

  2. SysTick 的特点

    • SysTick 常常用作 延时 或 用于产生时基,维持操作系统的“心跳”。即该硬件定时器用来产生某些使用了时基的系统(FreeRTOS、UCOS 等)需要的“滴答”中断。
    • SysTick 是属于 CM3 内核的外设,所有基于 CM3 内核的单片机都具有这个系统定时器。使得操作系统和其它系统软件在 CM3 器件间可以很容易的移植。
    • 该定时器的时钟源可以是内部时钟(FCLK, CM3 上的自由运行时钟),或者是外部时钟( CM3 处理器上的 STCLK 信号)。 具体需要检视芯片的器件手册来决定选择什么作为时钟源。
    • 节省 MCU 外设资源(不浪费 MCU 内部集成的 TIMER),睡眠模式下也可以工作。

​ SysTick 定时器可以选择不同的时钟源,可以产生中断,并且 SysTick 定时器是一个倒计数的计数器,每隔一个时钟周期计数值减一,计数至 0 后重新从计数初值处开始倒计数。因此,SysTick 也可用作精准延时。 ​ SysTick 定时器在《STM32F10x- 参考手册》里一个屁都没放,只有在《ARM Cortex-M3 技术参考手册》和《ARM Cortex-M3 权威指南》才找到相关寄存器的介绍。

二:SysTick 的时钟频率

  • 在《STM32F10x- 参考手册》中查看有关 SysTick 时钟频率的时钟树。如下图
    在这里插入图片描述

从图中可以看出 SysTick 有两种模式:一种是 8 分频模式(AHB/8),一种是 FCLK 模式(AHB)。AHB 最大频率可为 SYSCLK (在 f1系列为 72M,f4 系列为 168M )。详细参看《STM32F10x 参考手册》。

三:SysTick 的配置

  • 《ARM Cortex-M3 权威指南》中 SysTick 包含四个寄存器,都是 24 位的寄存器,分别是:
    在这里插入图片描述
  • 从上图可以得知,Systick 寄存器 分别为:
    1. CTRL:控制和状态寄存器。主要用作 配置 SysTick 的时钟源、开启 SysTick 定时器中断以及开启 SysTick 定时器。
    2. LOAD:重装载数值寄存器。主要作用就是配置 SysTick 的重装载值(一般是配置为 1ms 或者1us 需要递减计数的数值。比如在频率为 72M 下,1us 就需要计数 72 下,1ms 需要递减 72000 下。)并且需要注意的是,SysTick 定时器是一个 24 位递减计数器,所以重装载数值寄存器 LOAD 仅仅用到低 24 位(bit0 ~ bit23),从而使得可以设置的最大值为 16777215。
    3. VAL:当前数值寄存器。主要作用就是用 延时函数中。(在后面的 us 延时函数中有用到)。
    4. CALIB:校准数值寄存器。我没怎么用过,就不怎么清楚。

​ 综上所述,SysTick 是一个 24 位的倒计数定时器,当技术到 0 时,会产生 “滴答” 并 将从 RELOAD 寄存器中自动重装载定时初值。只要 SysTick 控制及状态寄存器中的使能位没有清 0,SysTick 定时器就会一直运行。

  • 在 core_cm3.h 中声明了可使用的 SysTick 的结构体,声明如下:

    typedef struct
    {
      __IO uint32_t CTRL;                    /*控制和状态寄存器 */
      __IO uint32_t LOAD;                    /*重装载数值寄存器*/
      __IO uint32_t VAL;                     /*当前数值寄存器*/
      __I  uint32_t CALIB;                   /*校准数值寄存器*/
    } SysTick_Type;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 其次,在 core_cm3.h 中,将 (SysTick_Type *) 进行宏定义为 SysTick。方便后面直接访问结构体内相关成员。

SysTick 初始化编程步骤

  1. 配置 SysTick 时钟源

    固件库函数:SysTick_CLKSourceConfig( );

    头文件:misc.h

    参数: SysTick_CLKSource_HCLK_Div8 --> AHB 的8分频

    ​ SysTick_CLKSource_HCLK --> AHB

  2. 配置 SysTick 的重装载值

  3. 开 SysTick 中断 以及 开启 SysTick 定时器

四:SysTick 实现精准延时并兼容 FreeRTOS

SysTick 定时器初始化脑图

在这里插入图片描述

SysTick 进行初始化代码

void delay_init(u8 SYSCLK)
{
	u32 reload;
 	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); 
	fac_us=SYSCLK;							//不论是否使用 OS,fac_us 都需要使用,即 记录 1us 所需要的节拍数
	reload=SYSCLK;							//每 1us 的计数次数   
	reload*=1000000/configTICK_RATE_HZ;		//根据 FreeRTOS 中的 configTICK_RATE_HZ设定溢出时间,FreeRTOS 需要每 1ms 的定时器中断,因此设置的重装载数值为 SYSCLK*1000。 
	fac_ms=1000/configTICK_RATE_HZ;			//代表 OS 可以延时的最少单位,在 os 下,代表每个节拍的ms 数	   
	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启 SYSTICK 中断
	SysTick->LOAD=reload; 					//因为加 入FreeRTOS,所以设置为每 1ms 中断一次	
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启 SYSTICK     
}	
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 注释:假设系统频率为 72M HZ,那么 SysTick 定时器每 1s 的计数数值为 72000000。同理,SysTick 定时器节拍数为 72000,那么就是 1ms;为 72,就是 1us。

微妙延时函数的实现

void delay_us(u32 nus) 						// nus:要延时的 us 数
{		
	u32 ticks;								// 记录需要延时微妙时间的 节拍数
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;				//LOAD的值,重装载的数值	    	 
	ticks=nus*fac_us; 						//需要的节拍数 = 需要延时 us 数 * 1us 所需要的节拍数 
	told=SysTick->VAL;        				//通过 VAL 寄存器记录刚进入时的计数器值
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
		}  
	};										    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 延时函数的实现过程如下:
    在这里插入图片描述

毫秒延时函数的实现

// 延时 nms,会引起任务调度
void delay_ms(u32 nms)				//nms:要延时的ms数
{	
	if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
	{		
		if(nms>=fac_ms)						//延时的时间大于OS的最少时间周期,即大于1ms
		{ 
   			vTaskDelay(nms/fac_ms);	 		//FreeRTOS延时
		}
		nms%=fac_ms;						//OS已经无法提供这么小的延时了,采用普通方式延时    
	}
	delay_us((u32)(nms*1000));				//普通方式延时,毫秒延时 = 微妙延时 * 1000
}

//延时nms,不会引起任务调度
void delay_xms(u32 nms)				//nms:要延时的ms数
{
	u32 i;
	for(i=0;i<nms;i++) delay_us(1000);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

五:参考

【1】STM32: SysTick系统定时器–滴答定时器

【2】Systick定时器

【3】Stm32-SysTick详解

【4】单片机(四)Systick系统定时器

【5】SysTick定时器

【6】STM32F103 Systick配置

【7】《STM32F10x- 参考手册》

【8】《ARM Cortex-M3 技术参考手册》

【9】《ARM Cortex-M3 权威指南》

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/285172
推荐阅读
相关标签
  

闽ICP备14008679号