一、基本定时器概念内容
基本定时器(Basic Timer)是一种用于计时或产生周期性定时中断的硬件定时器。它通常由计数器和相关的控制寄存器组成。而在STM32F40x 中的基本定时器包括TIM6和TIM7,下面就以这两个定时器展开说明。
二、TIM6和TIM7简介
基本定时器TIM6和TIM7包含一个16位自动重载计数器,该计数器由可编程预分频器驱动。此类定时器不仅可用作通用定时器以生成时基,还可以专门用于驱动数模转换器(DAC)。实际上,此类定时器内部连接到DAC并能够通过其触发输出驱动DAC。
这些定时器彼此完全独立,不共享任何资源。
三、TIM6和TIM7的主要特性
1、16位自动重载递增计数器
2、16位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数介于1和65536之间
3、用于触发DAC的同步电路
4、发生如下更新事件时会生成中断/DMA请求:计数器上溢
其基本定时器框图如下所示:
由图进行分析可知:
设计时间:分频---给重装载写值---打开计数---开始递增计数---计数完成---触发中断
自动重装载和预分频有影子寄存器---影子相当于缓冲器---获得对应寄存器的值,所有预分频、自动重装载只是间接操作定时器,定时器得到的值是影子寄存器的值。
四、TIM6和TIM7功能说明
1、时基单元
时基单元是指可编程定时器的主要模块由一个16位递增计数器及其相关的自动重载寄存器组成。计数器的时钟可通过预分频进行分频。
计数器、自动重载寄存器和预分频器寄存器可通过软件进行读写。即使在计数器运行也可执行读写操作。
时基单元包括:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)和自动重载寄存器(TIMx_ARR)。其中,自动重载寄存器是预装载的。每次尝试对自动重载寄存器执行读写操作时,都会访问预装载寄存器。预装载寄存器的内容既可以直接传送到影子寄存器,也可以在每次发生更新事件UEV时传送到影子寄存器,这取决于TIMx_CR1寄存器中的自动重载预装载使能位(ARPE)。当计数器达到上溢值且TIMx_CR1寄存器中的UDIS位为0时,将发送更新事件。该更新事件也可以由软件产生。
计数器由预分频器输出CK_CNT提供时钟,仅当TIMx_CR1寄存器中的计数器启动位(CEN)置1时,才会启动计数器。
2、预分频器说明
预分频器可对计数器时钟频率进行分频,分频系数介于1和65536之间。该预分频器基于TIMx_PSC寄存器中的16位寄存器所控制的16位计数器。由于TIMx_PSC寄存器有缓冲,因此可对预分频器进行实时更改。而新的预分频比将在下一更新事件发生时被采用。图1和图2 给出了在预分频比实时发生变化时一些计数器行为:
图1:预分频器分频由1变化到2时的计数器时序图
图2:预分频器分频由1变化到2时的计数器时序图
3、计数器说明
计数器从0计数到自动重载值(TIMx_ARR寄存器的内容),然后重新从0开始计数并生成计数器上溢事件。每次发生计数器上溢时会生成更新事件,或将TIMx_EGR寄存器中的UG位置1(通过软件或使用从模式控制器)也可以生成更新事件。
通过软件将TIMx_CR1寄存器中的UDIS位置1可禁止UEV事件。这可避免向预装载寄存器写入新值时更新影子寄存器。这样,直到UDIS位中写入0前便不会生成任何更新事件,但计数器和预分频器计数器都会重新从0开始计数(而预分频比保持不变)。此外,如果TIMx_CR1寄存器中的URS位(更新请求选择)已置1,则将UG位置1会生成更新事件UEV,但不会将UIF标志置1(因此,不会发送任何中断或DMA请求)。
发生更新事件时,将更新所有寄存器且将更新标志(TIMx_SR寄存器中的UIF位)置1(取决于URS位):
(1)使用预装载值(TIMx_PSC寄存器的内容)重新装载预分频器的缓冲区
(2)使用预装载值(TIMx_ARR)更新自动重载影子寄存器
以下各图3~图8 显示了当TIMx_ARR=0x36时不同时钟频率下计数器行为的示例:
图3:计数器时序图,1分频内部时钟
图4:计数器时序图,2分频内部时钟
图5:计数器时序图,4分频内部时钟
图6:计数器时序图,N分频内部时钟
图7:计数器时序图,ARPE = 0时更新事件(TIMx_ARR未预装载)
图8:计数器时序图,ARPE=1时更新事件(TIMx_ARR未预装载)
4、时钟源
计数器时钟由内部时钟(CK_INT)源提供。CEN(TIMx_CR1寄存器中)和UG位(TIMx_EGR寄存器中)为实际控制位,并且只能通过软件进行更改(保持自动清零的UG除外)。当对CEN位写入1时,预分频器的时钟就由内部时钟CK_INT提供。图9显示了正常模式下控制电路与递增计数器的行为(没有预分频的情况下):
图9:正常模式下的控制电路,1分频内部时钟
五、计算频率的例子
问题:84M的频率怎么算得1S钟?
回答:通过分频系数得到一个数值,通过重装载得到倍率
先求出一个比较好算的数
PSC--65535
ARR--65535
84M/84=1M --84预分频 1M个数给到ARR ARR爆了
84M/8400=10000 --84预分频 10000个数给到ARR ARR计数1S
如果把10000换算成MS//10000/1000=10 计10个数是1mS
如果要设置定时器500MS进一次中断 10*500 ==ARR写入5000
要注意,写入PSC寄存器的除数是在寄存器中加1了,所以要减1
六、TIM6和TIM7定时器配置步骤
1、TIM6时钟使能
2、初始化定时器参数,设置自动重载值,分频系数,计数方式等
3、设置TIM6_DIER允许更新中断
4、TIM6中断优先级设置
5、允许TIM6工作,即使能TIM6
6、编写中断服务函数
七、TIM6和TIM7定时器初始化参数结构体说明
结构体中的五个参数分别为:TIM_Prescaler、TIM_CounterMode、TIM_Period、TIM_ClockDivision和TIM_RepetitionCounter。下面对这五个参数分别进行说明:
第一个参数TIM_Prescaler是用来设置分频系数,可根据自己的功能要求选择合适的分频系数;
第二个参数TIM_CounterMode是用来设置计数方式,可设置为向上计数、向下计数方式和中央对齐计数方式三种方式其中一种,而我们比较常用的是向上计数模式TIM_CounterMode_Up和向下计数模式TIM_CounterMode_Down这两种的其中一种;
第三个参数TIM_Period是设置自动重载计数周期值;
第四个参数TIM_ClockDivision是用来设置时钟分频因子;
第五个参数TIM_RepetitionCounter是高级定时器才有用,所以这里不需要用到,我们可以在写代码时将其注释或者不写。
八、代码示例
1、tim6.c
/************************************************************ 函数名称:基本定时器6中断初始化 参数说明:arr:自动重装值 psc:时钟预分频数 //定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us. //Ft=定时器工作频率,单位:Mhz //这里使用的是定时器6! ************************************************************/ void Tim6_Init(u16 arr,u16 psc){ TIM_TimeBaseInitTypeDef TIM_Time6_Init; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);//使能TIM6时钟 TIM_Time6_Init.TIM_Period = arr;//自动重装载值 TIM_Time6_Init.TIM_Prescaler = psc; //定时器分频 TIM_Time6_Init.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式 TIM_Time6_Init.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM6,&TIM_Time6_Init);//初始化定时器TIM6 TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE); //允许定时器6更新中断 NVIC_InitStructure.NVIC_IRQChannel = TIM6_DAC_IRQn; //定时器6中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; //抢占优先级1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //响应优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;使能 NVIC_Init(&NVIC_InitStructure);//初始化NVIC TIM_Cmd(TIM6,ENABLE); //使能定时器6 } //定时器6中断服务函数 void TIM6_DAC_IRQHandler(void){ //溢出中断 if(TIM_GetITStatus(TIM6,TIM_IT_Update)==SET) { LED1 = !LED1; } TIM_ClearITPendingBit(TIM6,TIM_IT_Update); //清除中断标志位 }
2、tim6.h
#ifndef _TIM6_H_ #define _TIM6_H_ #include "stm32f4xx.h" #include "stdio.h" #include "led.h" void Tim6_Init(int16_t psc,int16_t arr); #endif
3、main.c
#include "led.h" #include "systick.h" #include "tim6.h" int main(void){ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 SsyTick_Init(168); //初始化延时函数 LED_Init();//初始化LED端口 Tim6_Init(5000-1,8400-1);//定时器时钟84M,分频系数8400,所以84M/8400=10Khz//的计数频率,计数5000次为500ms while(1){ LED2 = !LED2; Delay_ms(200);//延时200ms }; }
九、下载验证结果
我们将将编译好的文件下载到硬件上进行验证。如果没有错误,我们将看LED2不停闪烁(每400ms闪烁一次),而LED1也是不停的闪烁,但是闪烁时间较LED2慢(1s一次)。
十、总结
1、基本定时器是微控制器中的常见定时器模块之一,用于生成定时中断、计时和触发特定事件。
2、基本定时器可以配置为定时器模式或计数器模式,用于定时中断或计数外部事件。
3、通过预分频和计数器值,可以设置定时器的定时或计数时间。
4、基本定时器通常具有中断功能,可以触发定时中断,并可以设置中断优先级。
5、使用特定的寄存器和控制位来配置和操作基本定时器。
6、初始化和配置基本定时器的相关寄存器和控制位,包括选择输入时钟源,配置预分频器和设置计数值或计时周期等。
7、编写中断处理程序来处理定时器中断,可以执行所需的操作,如更新计数值、触发其他事件和清除中断标志位等。
十一、其他说明
本文选择TIM6配置即可,如若需要配置TIM7,参考本文即可,将本文中TIM6用TIM7和代替,其余参数也可根据自己的需求进行修改,同时配置TIM7的过程与TIM6的过程一致,只是有个别参数不同而已。自己根据手册进行修改即可。
注意:本人所写文章内容均用于记录自己在学习嵌入式的成长过程!!!!!