一、STM32通用定时器原理
STM32系列的CPU,有多达8个定时器,其间TIM1和TIM8是能够产生三对PWM互补输出的高档定时器,常用于三相电机的驱动,它们的时钟由APB2的输出产生。其它6个为一般定时器,时钟由APB1的输出产生。
下图是STM32参考手册上时钟分配图中,有关定时器时钟部分的截图:
从图中能够看出,定时器的时钟不是直接来自APB1或APB2,而是来自于输入为APB1或APB2的一个倍频器,图中的蓝色部分。
下面以通用定时器2的时钟阐明这个倍频器的效果:当APB1的预分频系数为1时,这个倍频器不起效果,定时器的时钟频率等于APB1的频率;当APB1的预分频系数为其它数值(即预分频系数为2、4、8或16)时,这个倍频器起效果,定时器的时钟频率等于APB1的频率两倍。
可能有同学仍是有点不理解,OK,咱们举一个比方阐明。假定AHB=36MHz,因为APB1答应的最大频率为36MHz,所以APB1的预分频系数能够取恣意数值;
当预分频系数=1时,APB1=36MHz,TIM2~7的时钟频率=36MHz(倍频器不起效果);
当预分频系数=2时,APB1=18MHz,在倍频器的效果下,TIM2~7的时钟频率=36MHz。
有人会问,已然需求TIM2~7的时钟频率=36MHz,为什么不直接取APB1的预分频系数=1?答案是:APB1不光要为TIM2~7供给时钟,并且还要为其它外设供给时钟;设置这个倍频器能够在确保其它外设运用较低时钟频率时。
Stm32外设用户手册,如图:
再举个比方:当AHB=72MHz时,APB1的预分频系数有必要大于2,因为APB1的最大频率只能为36MHz。假如APB1的预分频系数=2,则因为这个倍频器,TIM2~7依然能够得到72MHz的时钟频率。能够运用更高的时钟频率,无疑提高了定时器的分辨率,这也正是规划这个倍频器的初衷。
二、STM32通用定时器编程
定时器编程,便是中止的编程。因为运用定时器必定要运用到中止。
进程一:RCC_Configuration();//设置体系时钟,包含时钟RCC的装备,倍频到72MHZ。
进程二:GPIO的装备,运用函数为GPIO_cfg();,该函数的完成如下:
voidGPIO_cfg()
{
GPIO_InitTypeDefGPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//挑选引脚6
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//输出频率最大50MHz
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//带上拉电阻输出
GPIO_Init(GPIOC,&GPIO_InitStructure);
}
实际上定时器的解说,不需求装备GPIO的引脚,仅仅咱们在定时器试验中,
运用每隔一秒点亮一次LED灯来做试验,所以需求装备对应GPIO的引脚。
进程三:嵌套中止控制器的装备,咱们照样运用函数NVIC_Config();仅仅初始化的进程略有不同。这儿咱们也把函数完成列出来:
从以上函数完成来看,实际上仅仅改动了结构体成员NVIC_IRQChannel的值,现在需求的通道是TIM2的通道,因而初始化值为TIM2_IRQChannel。从这儿也能够看出,这个函数实际上能够看做一个模型,能够拿去其他程序中改动后直接运用。
voidNVIC_cfg()
{
NVIC_InitTypeDefNVIC_InitStructure;
//挑选中止分组1
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//挑选TIM2的中止通道
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQChannel;
//抢占式中止优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
//呼应式中止优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
//使能中止
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
进程四:定时器的初始化装备,运用Timer_Config();。OK,要害部分出来了。
咱们来看下完成进程:
TIMER_cfg();//定时器的装备
//敞开定时器2
TIM_Cmd(TIM2,ENABLE);
voidTimer_Config(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_Period=2000-1;//主动重装载寄存器的值
TIM_TimeBaseStructure.TIM_Prescaler=(36000-1);//时钟预分频数
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;//采样分频
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数形式
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//铲除溢出中止标志
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM2,ENABLE);/敞开时钟
}
咱们每个句子都来解释一下。首要咱们想运用定时器,就有必要使能定时器的时钟,这便是函数RCC_APB1PeriphClockCmd();,通过它敞开RCC_APB1Periph_TIM2。
TIM_DeInit(TIM2);该函数首要用于复位TIM2定时器,使之进入初始状况。
然后咱们对主动重装载寄存器赋值,TIM_Period的巨细实际上表明的是需求通过TIM_Period次计数后才会产生一次更新或中止。接下来需求设置时钟预分频数TIM_Prescaler,这儿有一个公式,咱们举例来阐明:例如时钟频率=72MHZ/(时钟预分频+1)。阐明当时设置的这个TIM_Prescaler,直接决议定时器的时钟频率。浅显点说,便是一秒钟能计数多少次。比方算出来的时钟频率是2000,也便是
一秒钟会计数2000次,而此刻假如TIM_Period设置为4000,即4000次计数后就会中止一次。因为时钟频率是一秒钟计数2000次,因而只需2秒钟,就会中止一次。
再往后的代码,还有一个需求留意的,TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;便是咱们一般选用向上计数形式,即每次计数就会加1,直到寄存器溢出产生中止停止。最终别忘了,需求使能定时器!!
产生中止时刻=(TIM_Prescaler+1)* (TIM_Period+1)/FLK
用上述公式可算出:产生中止时刻 (2000-1+1)*(36000-1+1)/72000000=1 秒
进程五:编写中止服务程序。相同需求留意的,一进入中止服务程序,第一步要做的,便是铲除去中止标志位。因为咱们运用的是向上溢出形式,因而运用
的函数应该是:TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);。
STM32开发板完成的中止服务程序如下:
每隔一秒,产生中止时,进入此中止函数履行程序,让LED闪一下,此中止程序地点文件stm32f10x_it.c
*FunctionName:TIM2_IRQHandler
*Description:ThisfunctionhandlesTIM2globalinterruptrequest.
*Input:None
* Output : None
来历;21ic