定时器介绍
软件定时
还记得以前在开发89C52的时候,经常使用stc助手生成的定时代码,形如:
以上这种定时方式就是软件定时,缺点是不够精准,且占用CPU资源
定时器工作原理
使用精准的时基,通过硬件的方式,实现定时功能。定时器核心就是计数器。
定时器分类
基本定时器(TIM6,TIM7)
通用定时器(TIM2~TIM5)
高级定时器(TIM1,TIM8)
可见,32的定时器资源是:一个高级定时器TIM1和三个通用定时器TIM2,3,4!
通用定时器介绍
可见,和51/52相比,32的定时器复杂多得多!
定时器计数模式
定时器时钟源
下图是手册P56,主要关注红圈部分
根据上图的原理,可以推出下面的公式,十分重要!!!
Tout = 设定时间 (单位秒s)
Tclk = 通过预分频后输出的TIMxCLK(上图右侧红线)
PSC = 预分频系数 (+1是因为计算机是从0开始的)
ARR = 自动重装载值(+1是因为计算机是从0开始的)
例如:要定时500ms,则可以在配置定时器时使用: PSC = 7199,ARR = 4999,TClk = 72M(72 000 000)(有多种组合)
使用定时器中断实现LED灯的状态反转
打开CubeMX,先进行惯例配置
注意,配置时钟(上图)最右侧一列的“APB1 Timer clocks”和“APB2 Timer clocks”就是刚刚提到的计算公式中的Tclk,单位是MHz,此处就是Tclk = 72MHz
然后由于要点灯,所以依然配置PB8(LED1)为GPIO_out模式且初始值为HIGH:
Timer 配置
1. 在左侧选择Timers选项,此处选择通用定时器Timer2
进行如下设置:(目前可以只关心 Clock Source),在设置为Internal Clock后,下方会自动弹出NVIC界面,选择打开中断。
再点击下方左边的“Parameter Settings”,并且暂时只关注上半部分“Counter settings”,其中第一个参数就是预分频器,第三个参数就是ARR:
回顾刚刚的计算公式:
例如:要定时500ms,则可以在配置定时器时使用: PSC = 7199,ARR = 4999,TClk = 72M(72 000 000)(有多种组合)
则,分频器PSC = 7199, ARR = 4999,同时打开第五个参数的自动重载!(因为希望LED连续不断的翻转状态,而不是翻转一次就结束)
生成工程
接下来又是一些惯例配置:
打开Keil
此时自动弹出Keil工程,记得先编译一下,养成良好编程习惯!
通过 stm32f1xx_it.c --> TIM2_IRQHandler() --> HAL_TIM_IRQHandler() --> 然后就和之前不大一样了,之前进行到这里就会出现一个 weak 类型的可重写中断处理函数,但此时是一个巨长无比的函数:
但是,我现在只关注:如果定时时间到了之后,定时器会做什么的函数
因此,可以找到这样一个函数:HAL_TIM_PeriodElapsedCallback(htim);
对于这个函数进行跳转,终于出现了可以重写的中断处理函数:
然后就可以在main.c中重写这个函数了:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2){ //注意,htim是一个结构体指针,所以对于结构体中成员变量的访问要用“->”
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
}
}
同时在main函数中添加一句,启动定时器:(当然,也是在生成的初始化之后)
HAL_TIM_Base_Start_IT(&htim2);
然后就是编译并烧写,在单片机上复位。
实现效果