【Day15】:STM32辗压Arduino的功能—TIM(下)

TIMER+NVIC中断

今天我们来使用Timer的中断功能吧!
设定与昨天大致相同,只是我们现在需要开启中断。
https://ithelp.ithome.com.tw/upload/images/20210907/2014152519H82QVcKI.jpg
另外要注意的是什麽时候会进中断
https://ithelp.ithome.com.tw/upload/images/20210907/201415259JfLcZbMDZ.png
在不同的模式下进中断的时机不同,上数与下数都是在一个周期的最後进入,而中心对齐则是数到头尾都会进入中断。

小程序1-实作Counter

我们来自己实作一个counter来计时,利用中断的方式,设置PSC=15,ARR=1000,当这个counter数到1000的时候就会进入中断,稍微计算一下就可以知道每1ms会进入一次中断(PSC将时钟讯号降低1/16,变成1MHz,1000次会进入中断,又变为1kHz)。我们宣告两个变数,ms与sec,分别为毫秒与秒。当每次进入中断就把ms++,只要ms=1000代表经过1s了,我们就将ms归零,sec加一。实际程序码如下

程序码

HAL_TIM_Base_Start_IT(&htim2);

这一行程序码是不是与上次很相似啊,只是这次尾端加上了"IT",意思为interrupt,

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim){
	if(htim->Instance == TIM2){
		ms++;
		if(ms==1000){
			ms = 0;
			sec++;
		}

	}
}

这一段函式其实在tim.c当中已经被定义过了,而我们这边是重新定义这个函式,可以在以下的地方打开这个档案直接搜寻这个函式
https://ithelp.ithome.com.tw/upload/images/20210907/201415256fHcaCWEKd.jpg
函式内容如下
https://ithelp.ithome.com.tw/upload/images/20210907/20141525V8RhmAvmzX.jpg
函式的开头有__weak,用在函式前,代表这个函式是弱定义,当你的程序码其他地方有对这个函式就其他地方做定义,就会以新的定义为主,那有人可能会问,这样他定义这个有什麽用呢?
就是给你复制的...通常不熟悉的人很难记住函式的API,照着打出来,因此你可以先到tim.c当中找到这些程序码,直接复制到main.c当中,就可以直接使用了。

由於上述两段程序码分别在程序的不同地方,直接附上整段程序码看起来会非常的乱,读者可能也难以理解,因此以下会直接说明这两段程序码的位置

第一段程序码放在main里面不需要放在回圈当中,他不需要被重复的执行,只要start一次就可以了。
第二段程序码就是放在一般函式定义的地方,因此在main以外的任何地方都可以,我通常习惯放在底下的Begin和End之间,接近程序码尾端的位置。
记得要新增sec与ms两个全域变数,才能使用现场表达式监看喔

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

了解程序码的原理就写好完整的程序码执行看吧,应该可以利用现场表达式的功能看到ms与sec两个变数,看会不会如预期的一样sec会每秒增加1罗。

小程序2-实作HAL_Delay微秒级版本

第二个小程序我们要来实作微秒级的delay,函式库里的HAL_Delay()只能实现毫秒级的delay。
这个实作不会用到中断,只会需要再介绍一个新的函式!

昨天我们讲过底下这个函式可以获得现在counter数到的值,

__HAL_TIM_GET_COUNTER()

另一个函式可以设定counter的值,这个函式一样是用#define的方式定义的,我们可以在tim.h的文件中找到。

__HAL_TIM_SET_COUNTER()

实作delay的思路是,每次呼叫这个函式我们就将counter的值归零,然後让程序进到一个while的回圈当中,只要counter的值小於传进来的参数,就继续在回圈执行,大於等於时则跳出回圈,这样就可以让程序卡在这个地方不继续持行下去,达到delay的效果。底下为这个函式的设计:

void microDelay(int t){
	__HAL_TIM_SET_COUNTER(&htim2,0);
	while(__HAL_TIM_GET_COUNTER(&htim2) < t){
	}
}

我们再另外设计一个小程序来检测我们的microDelay(),到底有没有成功delay
在while回圈当中,每次延迟1000微秒,再把ms加一,而当ms等於1000,sec加1,这部分的思路与第一个实作很类似。

/* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  microDelay(1000);
	  ms++;
	  if(ms==1000){
		  sec++;
		  ms=0;
	  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

一样记得在全域宣告ms与sec两个变数
执行後的结果应该要与小实作一相同,不过我们一个是利用中断,一个是利用实作微秒级的delay来达成。

小结

这两天介绍了TIM最最最基本的功能以及几个函式。我们再来复习一次吧!程序开始都一定要让TIMER启用,而要启用中断的函式与一般的启动函式略有不同

  1. HAL_TIM_Base_Start();
  2. HLA_TIM_Base_Start_IT();
    另外我们也介绍了两个利用define来定义的函式
  3. __HAL_TIM_GET_COUNTER()
  4. __HAL_TIM_SET_COUNTER()
    这两个函式可以获得CNT的值

<<:  Day17:【技术篇】SQL之其它常用语法

>>:  Day 17 | Flutter的常用 widgets - Container、Row、Column

Day22

阵列名称就是阵列第一个元素的记忆体位置,同理函数名称也是程序码在记忆体的第一个位置,既然有了记忆体位...

Nutrition Helper

实作 按照之前 Rich Menu 的思路,我们可以让使用者在点选不同主选单位置的时候丢出不同的文...

盘点清查与检测扫描 - 安全性检测

以一个月发一篇的速度,怕是还发完就关赛了... 适用人员: 技术人员。 适用法规: 资通安全责任等级...

[Day 30] Ktor Q&A 与 Side Project Roadmap

终於来到铁人赛最後一天,本来想回顾总结我实作 side project 的过程,但想到读者应该对於 ...

浅谈SqlServer Lock(一)

前文 两种围度的Lock Lock范围 Lock类型 Update Lock 存在的意义 Lock...