关于嵌入式学习随笔->5《Systick定时器》

1、什么是Systick定时器?

---》Systick定时器是一个简单的滴答定时器,对于ST的M3、M4、M7内核芯片,都有滴答定时器。

---》Systick滴答定时器常常用来做延迟,或者时时操作系统的心跳时钟。这样可以节省MCU的资源,不用另外浪费一个定时器。比如UCOS系统中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick滴答定时器做UCOS的心跳时钟。

---》Systick定时器就是一个系统滴答定时器,一个24位的倒计数定时器,记到0时,将从RELOAD寄存器中自动装载定时器初值。只要不把它在Systick控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。

---》Systick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。

---》Systick中断的优先级也可以设置。

2、Systick相关寄存器

4个Systick寄存器在HAL库中(core_cm7.h//core_cm4.h)定义位:

  1 typedef struct
  2 {
  3   __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
  4   __IOM uint32_t LOAD;                   /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register */
  5   __IOM uint32_t VAL;                    /*!< Offset: 0x008 (R/W)  SysTick Current Value Register */
  6   __IM  uint32_t CALIB;                  /*!< Offset: 0x00C (R/ )  SysTick Calibration Register */
  7 } SysTick_Type;

CTRL-------------Systick控制和状态寄存器

LOAD-------------Systick自动重装载除值寄存器

VAL----------------Systick当前值寄存器

CALIB-------------Systick校准值寄存器

对于STM32,外部时钟源是HCLK(AHB总线时钟)的1/8,内核时钟是HCLK时钟。

3、Systick相关配置函数

配置函数为:

  1 HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource);//Sysick时钟源选择
  1 Systick_Config(uint32_t ticks);//初始化Systick时钟为HCLK并开启中断

Systick中断服务函数为:

  1 void SysTick_Handler(void);

SysTick_Config函数:

  1 __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
  2 {
  3   if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  4   {
  5     return (1UL);                                                   /* Reload value impossible */
  6   }
  7
  8   SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  9   NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
 10   SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
 11   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
 12                    SysTick_CTRL_TICKINT_Msk   |
 13                    SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
 14   return (0UL);                                                     /* Function successful */
 15 }

SysTick_Config(uint32_t ticks)

HAL_SYSTICK_CLKSourceConfig函数:

  1 void HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource)
  2 {
  3   /* Check the parameters */
  4   assert_param(IS_SYSTICK_CLK_SOURCE(CLKSource));
  5   if (CLKSource == SYSTICK_CLKSOURCE_HCLK)
  6   {
  7     SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
  8   }
  9   else
 10   {
 11     SysTick->CTRL &= ~SYSTICK_CLKSOURCE_HCLK;
 12   }
 13 }

HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource)

用滴答定时器制作的系统延迟函数(无需支持OS系统):

  1 void delay_init(u8 SYSCLK)
  2 {
  3     HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick频率为HCLK
  4 	fac_us=SYSCLK;						    //不论是否使用OS,fac_us都需要使用
  5 }

delay_init(u8 SYSCLK)

  1
  2 void delay_us(u32 nus)
  3 {
  4 	u32 ticks;
  5 	u32 told,tnow,tcnt=0;
  6 	u32 reload=SysTick->LOAD;				//LOAD的值
  7 	ticks=nus*fac_us; 						//需要的节拍数
  8 	told=SysTick->VAL;        				//刚进入时的计数器值
  9 	while(1)
 10 	{
 11 		tnow=SysTick->VAL;
 12 		if(tnow!=told)
 13 		{
 14 			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
 15 			else tcnt+=reload-tnow+told;
 16 			told=tnow;
 17 			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
 18 		}
 19 	};
 20 }

delay_us(u32 nus)

  1 void delay_ms(u16 nms)
  2 {
  3 	u32 i;
  4 	for(i=0;i<nms;i++) delay_us(1000);
  5 }

delay_ms(u16 nms)

当使用OS系统时:

  1 //初始化延迟函数
  2 //当使用ucos的时候,此函数会初始化ucos的时钟节拍
  3 //SYSTICK的时钟固定为AHB时钟的1/8
  4 //SYSCLK:系统时钟频率
  5 void delay_init(u8 SYSCLK)
  6 {
  7 #if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
  8 	u32 reload;
  9 #endif
 10     HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick频率为HCLK
 11 	fac_us=SYSCLK;						    //不论是否使用OS,fac_us都需要使用
 12 #if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
 13 	reload=SYSCLK;					        //每秒钟的计数次数 单位为K
 14 	reload*=1000000/delay_ostickspersec;	//根据delay_ostickspersec设定溢出时间
 15 											//reload为24位寄存器,最大值:16777216,在216M下,约合77.7ms左右
 16 	fac_ms=1000/delay_ostickspersec;		//代表OS可以延时的最少单位
 17 	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
 18 	SysTick->LOAD=reload; 					//每1/OS_TICKS_PER_SEC秒中断一次
 19 	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
 20 #endif
 21 }

delay_init(u8 SYSCLK)

  1 //延时nus
  2 //nus:要延时的us数.
  3 //nus:0~204522252(最大值即2^32/fac_us@fac_us=21)
  4 void delay_us(u32 nus)
  5 {
  6 	u32 ticks;
  7 	u32 told,tnow,tcnt=0;
  8 	u32 reload=SysTick->LOAD;				//LOAD的值
  9 	ticks=nus*fac_us; 						//需要的节拍数
 10 	delay_osschedlock();					//阻止OS调度,防止打断us延时
 11 	told=SysTick->VAL;        				//刚进入时的计数器值
 12 	while(1)
 13 	{
 14 		tnow=SysTick->VAL;
 15 		if(tnow!=told)
 16 		{
 17 			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
 18 			else tcnt+=reload-tnow+told;
 19 			told=tnow;
 20 			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
 21 		}
 22 	};
 23 	delay_osschedunlock();					//恢复OS调度
 24 }

delay_us(u32 nus)

  1 //延时nms
  2 //nms:要延时的ms数
  3 //nms:0~65535
  4 void delay_ms(u16 nms)
  5 {
  6 	if(delay_osrunning&&delay_osintnesting==0)//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)
  7 	{
  8 		if(nms>=fac_ms)						//延时的时间大于OS的最少时间周期
  9 		{
 10    			delay_ostimedly(nms/fac_ms);	//OS延时
 11 		}
 12 		nms%=fac_ms;						//OS已经无法提供这么小的延时了,采用普通方式延时
 13 	}
 14 	delay_us((u32)(nms*1000));				//普通方式延时
 15 }

delay_ms(u16 nms)

根据滴答定时器的递减技术计数特性,就可以很容易的理解编程的思路了。对于Contex-M系统中,Systick代码可以通用,如果使用时发现延时不一致,问题一般都是因为不同内核时钟不一样而已。修改ticks值即可。

原文地址:https://www.cnblogs.com/vcan123/p/10428760.html

时间: 2024-10-31 17:08:26

关于嵌入式学习随笔->5《Systick定时器》的相关文章

关于嵌入式学习随笔-&gt;4《F7系统时钟》

1.STM32有5个时钟源:HSI.HSE.LSI.LSE.PLL. -->HSI是高速内部时钟,RC振荡器,频率为16MHz,精度不高.可以直接作为系统时钟或者用作PLL时钟输入. -->HSE是告诉外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~26MHz. -->LSI是低速内部时钟,RC振荡器,频率为32KHz,提供低功耗时钟.LSI主要可以作为IWDG独立看门狗时钟,LPTimer低功耗定时器时钟以及RTC时钟. -->LSE是低速外部时钟,接频率为

关于嵌入式学习随笔-&gt;6《NVIC中断优先级管理》

1.中断技术概述 在单片机应用系统中,中断技术主要用于时时检测与控制,也就是要求单片机能感及时地响应中断请求源提出的服务请求,进行快速响应并及时处理,这些工作是由单片机片内的中断系统来实现的.当中断请求源发出中断请求时,如果中断请求得到允许,单片机暂时中止当前正在执行的主程序,转到中断服务处理程序处理中断请求,处理完中断服务请求后,再回到原来被中止的程序处(断点),继续执行被中断的主程序. 中断响应和处理过程如下图所示: 2.中断源 -->M4/M7内核支持256个中断,其中包含了16个内核中断

关于嵌入式学习随笔-&gt;8《UART串行通信原理》

1.什么是串口 串口是MCU(Microcontroller Unit:微控制单元)重要的外部接口,同时也是软件开发重要的调试手段,现如今基本上所有的MCU都会带有串口.以STM32F767为例,它的串口资源相当丰富,功能也十分强大,STM32F767IGT6最多可以提供8路串口,支持8/16倍过采样.支持自动波特率检测.支持Modbus通信.支持同步单线通信和半双工单线通信.支持LIN.支持调制解调器操作.智能卡协议和IrDA SIR ENDEC规范.具有DMA等. 处理器与外部设备通信的两种

关于嵌入式学习随笔-&gt;13《STM32CubeMX应用4-FreeRTOS的配置》

使用FreeRTOS配置led闪烁 设置创建任务的名字和对应的弱函数名字 生成代码,在弱函数中写入相应的函数,刚生成的函授都在main.c中.点add可以添加任务. 原文地址:https://www.cnblogs.com/vcan123/p/12249995.html

关于嵌入式学习随笔-&gt;14《STM32CubeMX应用5-CAN总线的配置》

STM32CubeMX-CAN总线的配置 配置好后生成代码 关于HAL库中相关文件代码 1.HAL库滤波器设置c文件 #include "bsp_can.h" #include "main.h" extern CAN_HandleTypeDef hcan1; extern CAN_HandleTypeDef hcan2; void can_filter_init(void) { CAN_FilterTypeDef can_filter_st; can_filter_

STM32学习及应用笔记一:SysTick定时器学习及应用

这几年一直使用STM32的MCU,对ARM内核的SysTick计时器也经常使用,但几乎没有仔细了解过.最近正好要在移植一个新的操作系统时接触到了这块,据比较深入的了解了一下. 1.SysTick究竟是什么? 关于SysTick在STM32的资料中并没有详细的介绍,这可能由于SysTick是ARM内核的东西.在<STM32F10xxx参考手册>.<STM32F4xx参考手册>以及<STM32F7xx参考手册>中,介绍时钟的时候仅仅是在使用树上简单的画出了HCLK时钟经过8

嵌入式学习笔记008-裸奔篇之串口

串口是个好东西,前几篇裸奔程序由于没有串口,自己调试都是有led等来表示的,比较"苦逼",终于可以用串口了~~~,这里主要采用上一篇博文(嵌入式学习笔记007-裸奔篇之定时器),也就是串口也是用中断实现的,而且也只是在前一篇博文增加串口的初始化uart0_init(),以及在中断处理函数增加对串口的处理.只要稍微改造前一篇博文就是一个通用的中断处理程序! 这里主要实现在串口输入一个字符,接受后+2再发送到串口,所以在串口输入a 会返回c---. 由于code都有相应的注释,读者自行查看

舵机的PWM控制学习随笔

舵机的控制信号,对于脉宽调制信号的脉宽变换,常用的一种方法是采用调制信号获取有源滤波后的直流电压,但是需要50Hz(周期是20ms)的信号,这对运放器件的选择有较高要求,从电路体积和功耗考虑也不易采用.5mV以上的控制电压的变化就会引起舵机的抖动,对于机载的测控系统而言,电源和其他器件的信号噪声都远大于5mV,所以滤波电路的精度难以达到舵机的控制精度要求. 可以用单片机作为舵机的控制单元,使PWM信号的脉冲宽度实现微秒级的变化,从而提高舵机的转角精度.单片机完成控制算法,再将计算结果转化为PWM

嵌入式学习笔记103-uboot_1.1.6移植(3)

经过之前对uboot的整体flow分析,现在开始针对2440移植,需要注意的是移植的code可能包含支持部分的2410code 不过并没有在s3c2410板子实测过. 主要概括:第一阶段的汇编code尽量短小,能用C实现的就用C,由于2440的board和头文件是从2410 copy过来的 里面会有很多信息或者宏关于2410,并且很多.c文件的头文件由于include的是2410,所以新增的一些关于2440的结构体也会一并放在2410.h,移植的思想与前文类似, 根据code的执行流程来移植.