嵌入式学习笔记:使用STM32G431(HAL库开发)中的Systick滴答定时器

系列文章目录

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记01:赛事介绍与硬件平台

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记02:开发环境安装

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记03:G4时钟结构

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记04:从零开始创建工程模板并开始点灯

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记05:Systick滴答定时器

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记06:按键输入

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记07:ADC模数转换

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记08:LCD液晶屏

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记09:EEPROM

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记10:USART串口通讯


目录

系列文章目录

前言

一、系统滴答定时器

1.Systick功能

2.Systick作用

2.1 精确延时

2.2 程序调度

二、程序设计

总结


前言

上一节我们讲了比赛时程序设计的流程,以及LED灯模块的设计,这一节我们学习一下Systick系统滴答定时器的一些功能。我们主要学习系统滴答定时是什么东西,有什么作用, 以及如何使用它来实现一些我们想要的功能,对于它的内部构造和原理就不在范围之内了。

一、系统滴答定时器

1.Systick功能

Systick是一个M4内核的系统级定时器,是所有M4内核芯片都有的一个定时器。它是一个24位向下递减的计数器,理论上可以计数2^24个值,当装载的寄存器的值减到0的时候就会产生一次中断,然后重新装载,重新计数。

我们用STM32CubeMX生成的工程会自动把Systick配置成一个1ms中断的定时器,并且在中断函数里,将全局变量uwTick每1ms增加1,这样我们就可以知道芯片的走时情况了,就可以知道从芯片上电到现在过了多少时间,利用这个也能实现一些功能。

2.Systick作用

2.1 精确延时

利用HAL_Delay()函数实现延时x毫秒。

我们来看一下这个函数的定义。

__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)
  {
  }
}

这个函数是定义了一个32位的变量Delay,然后HAL_GetTick()是一个记录上电时间的函数,它是实时变化的,每1ms会变化一次,然后我们记录一下函数开始时的时间,记录在tickstart里面,把我们需要延时的时间记录在wait里面,最后让HAL_GetTick()和tickstart作差,直到等于wait,也就是我们需要延时的时间。这样就可以实现延时的功能了。而中间那段if的作用是防止延时的设置超过Delay这个变量的上限,一般我们也不会需要那么长的延时。

这个功能我们在上一节里面已经示范过了,这里就不赘述了。这个程序有一个缺点,就是会让cpu在这里等待,阻塞程序,让cpu无法执行其他程序(除了中断)。所以我们要避免在While(1)里面长时间地使用Delay函数,最好控制在10ms以内,这样才不会影响cpu的实时性。那么我们要解决这个问题就可以将Systick用于程序调度。

2.2 程序调度

程序调度的主要目标是有效地分配和使用有限的处理器资源,确保多进程或程序能够并发执行,以最大限度地提高系统效率。

也就是说我们要想办法让cpu从计时这件事里跳出来,空出手去做其他的事情,而不是一直盯着定时器这一件事。考虑到我们有一个全局变量uwTick在全程记录时间,所以我们可以定义一个变量,记录一个时间点,然后用uwTick与之作差,计算出已经过去了的时间,然后判断这个时间是否在我们要求的范围内(也就是定时的时间),如果在,就说明还没到时间,就可以用return跳出循环做其他的事,一旦到达这个时间,就执行我们需要的程序(如点灯)。

这就是利用Systick做程序调度的思想,下面我们用程序来实例。

二、程序设计

我们把上一节的“LED间隔0.5秒循环闪烁”用程序调度的方法重新做一遍,之前的方法是执行LED_Control函数,然后HAL_Delay延时0.5秒。现在我们用新的方法,我们可以定义一个函数LED_Process,然后用if语句判断是否到了500ms,未到则return,到了则执行下面的指令。

如:

__IO uint32_t ledTick = 0;//定义一个32位变量初始化为0,__IO表示不能优化的宏定义
u8 led_ctrl = 0xff; //需要控制的LED灯
void LED_Process(void) //定义LED程序
{
	if(uwTick - ledTick < 500) return ; //判断是否到500ms,否则跳出,是则继续
	ledTick = uwTick; //把ledTick的值变成现在uwTick,这样下一次才能重新开始数500
	LED_Control (led_ctrl); //点亮led_ctrl指代的灯
	led_ctrl = ~led_ctrl; //led_ctrl取反,意思是下一次变成熄灭
}

这个函数的作用是每500ms执行一次LED_Control函数,由于加了一个led_ctrl取反的指令,所以实现起来就是开关开关的闪烁。

函数的核心内容是判断,因为uwTick是不断往上数的,所以定义一个ledTick为0,uwTick数到500之前,uwTick-ledTick都小于500,都是直接跳出函数,主函数去执行其他程序。当uwTick数到500时,执行LED_Control程序,与此同时,把ledTick写入uwTick现在的值,也就是500,这样下次uwTick数到1000时,uwTick-ledTick又变成500,又执行一次程序,然后ledTick变成1000,下次uwTick数到1500是,再执行……

我们把这段程序放在Private user code后面,在主循环中调用LED_Process(),可以看看效果,跟上一节的一样。

这个程序的好处是不占用CPU,而且非常模块化,也可以用在其他模块上,比如说KEY_Process()这样。

总结

本节的主要内容是将Systick用于程序调度的方法,一定要熟练掌握。本节的内容以后在实时操作系统RTOS中很重要。

下节课将学习KEY按键输入的内容。

作者:我不是板神

物联沃分享整理
物联沃-IOTWORD物联网 » 嵌入式学习笔记:使用STM32G431(HAL库开发)中的Systick滴答定时器

发表回复