STM32定时器启动方式
前言
事情的起因本来是探究为什么在中断模式下的回调中函数中,我不小心加了延时函数为什么会导致崩溃,很遗憾啊,没看出来,不过需要在中断事件中延时的话,倒是可以用轮询模式下的配置。本文探究HAL库函数定时器的两种启动方式,注释分别写着是:轮询模式,中断模式。在我们配置好一个定时器的参数后,我们在主函数中往往会选取下述一个函数来开启定时器。
- HAL_TIM_Base_Start(&htim2); //轮询模式
- HAL_TIM_Base_Start_IT(&htim2); //中断模式
环境
- STM32F103C6T6核心板
- STM32CubeMX生成的HAL库文件
- 在STM32CubeMX的配置:
- 周期为1S的定时器2(TIM2)
- 启动PC13的LED
模式
轮询模式:是使能定时器的连续模式。它只是启动定时器的计数,在定时器的计数达到自动重装载值(ARR)时,不会产生中断事件。连续模式启动定时器适用于不需要使用中断,而是在主循环中轮询定时器的计数值,来确定是否触发特定操作的情况。例如,在每个周期结束后执行特定操作,然后重新启动定时器计数。
中断模式:是使能定时器的中断模式。它会启动定时器并设置为产生中断事件。当定时器的计数达到自动重装载值(ARR)时,会触发Update事件,并生成Update中断。使用中断模式启动定时器时,可以通过编写定时器的中断回调函数来实现在每次Update事件中执行特定操作的功能。
上述两种模式总的来说是,都打开了定时器的开始计数的功能,只是轮询模式下达到自动重装载值(ARR)时不会触发中断事件,但是在中断模式下达到时,会触发中断事件。
使用
根据上述两种启动模式的情况,下面举例出两种模式下常用的代码流程,代码省略了其它无关函数,仅为表达本文相关代码。
-
轮询模式
轮询模式的应用是在启动后,是要在主函数或主循环中,编写程序用于捕获指定标志位是否被触发,或者计数值是否达到指定数据等来判断,要触发的事件。而且如果是捕获指定标志位,在程序结束时,记得还有清除标志,不然的话会一直处于函数中出不去。常用的标志位:
TIM_FLAG_UPDATE
更新标志位,当定时器计数溢出并重新开始计数时,该标志位被置位。int Num; int main(void) { /****************** 省略其它的初始化函数 ******************/ //以轮询模式启动 HAL_TIM_Base_Start(&htim2); while(1) { //方法一:判断事件标志位 if(__HAL_TIM_GET_FLAG(&htim2,TIM_FLAG_UPDATE) == 1) { //GPIO电平反转 HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); //清除标志位 __HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_UPDATE); } //方法二:判断计数值 Num=__HAL_TIM_GET_COUNTER(&htim2); if(Num>5000) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); } } }
-
中断模式
中断模式的应用是在启动后,直接重写中断事件,然后就会周期性的执行了。这里不用手动清除标志位,事件更新时会自动清除的。
//重写中断回调事件 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { //判断信号是否来自TIM2 if(htim->Instance==TIM2) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); } } int main() { /****************** 省略其它的初始化函数 ******************/ //以中断模式启动 HAL_TIM_Base_Start_IT(&htim2); while(1) { } }
差异
其实通过对比器,也能看出这两个代码相差不大,只是在中断模式下使能定时器的更新中断,一旦定时器的更新事件发生,即定时器计数溢出并重新开始计数,将会产生更新中断,要处理这个中断我们在上面可知,重写回调事件即可。