目录
一. 前言
二. 定时器的框图
三. 定时中断的根本结构
四. TIM定时器相关代码
五. 最终征象展示
一. 前言
什么是定时器? 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断。
TIM定时器不仅具备根本的定时中断功能,而且还包含表里时钟源选择,输入捕获,输出比较,编码器接口,主从触发模式等多种功能。
根据复杂度和应用场景分为了高级定时器,通用定时器,根本定时器。它们包含的编号以及分布总线和功能如下所示:
此中,我们可以看到高级定时器是毗连在APB2总线上的,所以前面介绍的APB2性能更高是没有问题的。
值得注意的是:不是所有的单片机芯片都拥有所有的定时器。比方我们的STM32F103C8T6就只拥有四个定时器资源:TIM1,TIM2,TIM3,TIM4。
二. 定时器的框图
根本定时器的根本框图如下所示:
如上所示,我们根本定时器主要就是通过预分频器对时钟进行预分频,然后计数器就自增计数。当计数值达到自动重装值时,计数值清零同时产生更新中断和更新事件。
通用定时器的根本框图如下所示:
我们可以看出,通用定时器比根本定时器的框图复杂了很多,主要是因为我们上面所介绍的它们的功能。 根本定时器只拥有定时中断,主模式触发DAC的功能。而我们的通用定时器不仅具备根本定时器的全部功能,并且还额外拥有表里时钟源选择,输入捕获,输出比较,编码器接口,主从触发模式等功能。比方上面框图中左下角的部门---输入滤波器和边沿检测器就是为我们通用定时器的输入捕获而设计的。
高级定时器的框图如下所示:
高级定时器主要就是在通用定时器的底子上新增了重复计数器(这里后面会涉及的,只有高级定时器才具备),死区天生,互补输出,刹车输入等功能。
三. 定时中断的根本结构
我们想要配置好定时器,并使用它,只需要根据它的根本结构来一个一个进行相关配置即可。定时中断的根本结构如下所示:
总结一下,就是:
1) 起首配置好时钟,选择内部时钟RCC还是外部时钟ETR等等。这里需要的库函数在tim.h当中探求。如果选择内部时钟,那么就需要使用TIM_InternalClockConfig()这个库函数。
2) 然后进行时基单位的配置。选择TIM_TimeBaseInit()函数。
对于此中的Period(重装载值ARR)和Prescaler(分频系数PSC)的取值都要在0~65536之间,因为它们都是16位的。这两个的取值不是唯一的,可以分频系数PSC给少点,自动重装给多点,如许就是以一个比较高的频率计比较多的数。
值得注意的是,为了方便更改此中一些具体的参数,如分频值等。ST公司提供了一些库函数,专门单独更改。比方TIM_PrescalerConfig()函数,就是用来单独写预分频值的。还有很多小的函数,这些大家看到都可以查询一下,很轻易就能查到。这里我就不过多逐一介绍了。
别的,在时基单位中的预分频器中,最紧张的其实是预分频缓冲器。它可以防止计数中途更改数值造成错误。
3)配置输出中断控制,允许更新中断输出到NVIC。这里使用库函数TIM_ITConfig()。
4)配置NVIC。这个之前讲过,根据之前的进行相关配置即可。
值得注意的是,定时器相关的GPIO配置,需要根据产品手册来查看,比方定时器2的GPIO配置就为浮空输入,这个地方在产品手册中的通用I/O(GPIO)位置查看,如下所示:
四. TIM定时器相关代码
上面已经讲过了TIM配置的流程,所以我们根据它来即可。我们只需要明确一点,那就是使用定时器根据它的根本结构来配置就行了。将它的结构都买通,不就可以运行定时器了吗。
起首就是开启对应的时钟,这里我们选择使用TIM2。如下所示:
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
复制代码 然后选择时钟源,这里选择内部时钟源。如下所示:
- TIM_InternalClockConfig(TIM2);
复制代码 值得注意的是,如果有小同伴对库函数参数配置不明确。可以在本身工程中找到该库函数,然后鼠标右键点击跳转到定义处,就可以查看库函数各个参数的作用了。
然后对时基单位进行初始化:
- TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
复制代码- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
- TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
- TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
- TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
- TIM_TimeBaseInitStructure.TIM_Prescaler= 7200 -1;
- TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //这里是高级定时器才具备的重复计数功能,所以我们置为0即可
- TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
复制代码 对于此中的Period和Prescaler值,我觉得还有须要讲下。这两个值就是ARR和PSC的值。由于我们单片机的主频率也就是72MHz。所以定时器的频率CK_CNT=72000000/(PSC+1)/(ARR+1)。
当我们的PSC为7200-1,ARR为10000-1时,那么最后CK_CNT的效果就为1Hz,也就是1s。
接着我们可以扫除下定时器更新标志:
- TIM_ClearFlag(TIM2, TIM_FLAG_Update);
复制代码 若是不扫除这个标志位,那么开启中断后,会立刻进入一次中断。比方我们点击复位按钮,理论上是从0开始计数的,但是如果不清晰这个标志位,那么它就会从1开始计数。这是不符合常理的。
开启更新中断输出使能中断:
- TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
复制代码 进行NVIC的相关配置:
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
-
- /*NVIC配置*/
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_InitStructure.NVIC_IRQChannerPreemptionPriority=2;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
- NVIC_Init(&NVIC_InitStructure);
复制代码 最后一步就是使能计数器,使它可以或许开始计数:
配置好定时器后,我们就可以使用它了。可以依托定时中断函数来使用。下面提供一个模板:
- //定时器中断函数,可以复制到使用它的地方
- void TIM2_IRQHandler(void)
- {
- if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
- {
-
- TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
- }
- }
复制代码 比方因为我们上面已经配置好了定时器为1s的计时。我们可以让它每次达到计数值的时间,进行数字的加1,最后显示在OLED上。如下所示,只需要加一行代码即可。至于显示到OLED上或者其他操纵,大家可以自由发挥尝试。
- void TIM2_IRQHandler(void)
- {
- if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) //判断是否是TIM2的更新事件触发的中断
- {
- Num ++; //Num变量自增,用于测试定时中断
- TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIM2更新事件的中断标志位
- //中断标志位必须清除
- //否则中断将连续不断地触发,导致主程序卡死
- }
- }
复制代码
五. 最终征象展示
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |