定时器工作原理
如图:
定时器分类
类型 | 实现 | 功能 |
基本定时器 | TIM6 、TIM7 | 常⽤作定时、中断、ADC转换 |
通⽤定时器 | TIM2-TIM5、TIM9-TIM14 | 具有多路独⽴通道,可用于输⼊捕获、输出⽐ 较,也可用作定时功能 |
⾼级定时器 | TIM1、TIM8 | 具备通用定时器的所有功能,还具有互补信号输 出,刹车输⼊(电机控制) |
基本定时器
概念:
STM32F407 基本定时器由时钟源、控制器、时基单元组成。 有两个基本定时器 TIM6 和 TIM7,它们的功能完全相同,资源是完全独立的,可以同时使用。
结构组成:
时钟源
定时器的核心是计算器,要实现计数功能,首先要给它一个时钟源。基本定时器时钟挂载在APB1总线,所以它的时钟来自于APB1总线,但是基本定时器时钟不是直接由APB总线直接提供,而是先经过一个倍频器。
当APB1的预分频器系数为1 时,这个倍频器系数为1,当APB1的预分频器系数≥2分频时,这个倍频器系数就为2 。
控制器
控制定时器复位、使能、计数等功能之外,还可以用于触发 DAC 转换。
时基单元
构成时基单元的三个组要部分PSC、CNT、ARR的具体功能在文章开篇的图中就已经给出了,这里不再说明。需要说明的概念是影子寄存器。
这里假设我们给ARR的值是5,也就是说CNT从0、1、2…..一直数到5算是一个周期(设定CNT的计数模式为递增计数);给PSC的分配大小是2,当CNT数到3(也就是一个周期没数完)时,我们将PSC的大小修改为3,此时CNT不会受到影响,而是等当前周期结束才会发生改变,这个就是影子寄存器的作用。同样,如果我们不改变PSC的大小,而是改变ARR的值,比如改为6,那么CNT也不会立即从数到5结束改为数到6结束,而是在当前周期数到5,下个周期才数到6,所以ARR同样也拥有影子寄存器。
也就是说,PSC和ARR都有两个寄存器,影子寄存器是实际起作用的寄存器,不可直接访问。当更新事件发生时(周期结束),值才写入影子寄存器。PSC的影子寄存器和ARR的影子寄存器有区别:前者不可配置,后者可配置。
CNT的计数模式和溢出条件
计数器模式 | 溢出条件 |
递增计数模式 | CNT == ARR |
递减计数模式 | CNT == 0 |
中心对齐模式 | CNT == ARR-1 && CNT == 1 |
溢出时间计算
我们需要定时500ms,该如何计算:
我们的基本定时器未分频之前的频率为:84MHZ,我们设置分频系数为8400, 即写入预分频寄存
器的值为 8399,那么 fCK_CNT=84MHz/8400=10KHz。这样就得到计数器的计数频率为10KHz,即计数器 1 秒钟可以计 10000 个数。我们需要 500ms的中断周期,所以我们让计数器计数 5000 个数就能满足要求,即需要设置自动重载寄存器的值为 4999。
对于定时器的预分频和重载值,通常是因为计数器是从 0 开始的,所以在设置寄存器时需要减1。
对于预分频器,如果设置为 N,则实际的预分频为 +1这是因为预分频器的作用是将输入频率分频为 N+1。所以,如果要实现 N 的预分频,就需要设置为 N−1。同样,对于重载寄存器,如果设置为 M,则实际的重载值为 M+1。这是因为计数器是从 0 开始的,所以为了达到 M 的计数,需要设置为 M−1。
实践
#include "stm32f4xx.h" // Device header
void TIM6_DAC_IRQHandler(void)
{
if (TIM_GetITStatus(TIM6,TIM_IT_Update) == SET)
{
GPIO_ToggleBits(GPIOF,GPIO_Pin_9);
GPIO_ToggleBits(GPIOF,GPIO_Pin_10);
/*清除中断标志*/
TIM_ClearITPendingBit(TIM6,TIM_IT_Update);
}
}
int main()
{
/*点灯使能*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
/*定时器使能*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
/*初始化定时器结构体*/
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = TIM6_DAC_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStruct);
/*初始化LED灯结构体*/
GPIO_InitTypeDef GPIO_InitTypeDefStruct;
GPIO_InitTypeDefStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitTypeDefStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitTypeDefStruct.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_9;
GPIO_InitTypeDefStruct.GPIO_Speed = GPIO_Fast_Speed;
GPIO_SetBits(GPIOF,GPIO_Pin_10);
GPIO_SetBits(GPIOF,GPIO_Pin_9);
GPIO_Init(GPIOF,&GPIO_InitTypeDefStruct);
/*时基单元*/
TIM_TimeBaseInitTypeDef TIM_InitStruct;
/*预分频系数*/
TIM_InitStruct.TIM_Prescaler = 8399;
/*重装载值*/
TIM_InitStruct.TIM_Period = 4999;
TIM_TimeBaseInit(TIM6,&TIM_InitStruct);
/*定时器中断配置*/
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);
/*定时器中断使能*/
TIM_Cmd(TIM6,ENABLE);
TIM6_DAC_IRQHandler();
while(1)
{
}
}
输出结果:STM32F407ZG开发板上的两个LED灯会规律性的亮灭。
注意事项
①我们必须在中断服务函数里把该位清零。如果中断到来后,不清除中断标志,那么系统就会⼀直进入中断服务函数。
②中断函数不要放入循环体中,因为CNT到达ARR设定的值后会自行重置,达到一直循环效果。
原文地址:https://blog.csdn.net/maderfaker/article/details/134665514
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_43778.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!