今天我们来使用Timer的中断功能吧!
设定与昨天大致相同,只是我们现在需要开启中断。
另外要注意的是什麽时候会进中断
在不同的模式下进中断的时机不同,上数与下数都是在一个周期的最後进入,而中心对齐则是数到头尾都会进入中断。
我们来自己实作一个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当中已经被定义过了,而我们这边是重新定义这个函式,可以在以下的地方打开这个档案直接搜寻这个函式
函式内容如下
函式的开头有__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罗。
第二个小程序我们要来实作微秒级的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启用,而要启用中断的函式与一般的启动函式略有不同
>>: Day 17 | Flutter的常用 widgets - Container、Row、Column
阵列名称就是阵列第一个元素的记忆体位置,同理函数名称也是程序码在记忆体的第一个位置,既然有了记忆体位...
实作 按照之前 Rich Menu 的思路,我们可以让使用者在点选不同主选单位置的时候丢出不同的文...
以一个月发一篇的速度,怕是还发完就关赛了... 适用人员: 技术人员。 适用法规: 资通安全责任等级...
终於来到铁人赛最後一天,本来想回顾总结我实作 side project 的过程,但想到读者应该对於 ...
前文 两种围度的Lock Lock范围 Lock类型 Update Lock 存在的意义 Lock...