欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32学习笔记(8)定时器相关之通用定时器

程序员文章站 2022-03-04 22:43:41
...

简介

STM32中有三种定时器,包括高级定时器,通用定时器,基本定时器。以STM32F103ZET6为例,有高级定时器(TIM1,TIM8),通用定时器(TIM2~TIM5),基本定时器(TIM6,TIM7)。(三种定时器功能区别)本篇主要讲解通用定时器。

STM32F1 的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。

工作框图

STM32学习笔记(8)定时器相关之通用定时器
时钟来源:
1) 内部时钟(CK_INT)
2) 外部时钟模式 1:外部输入脚(TIx)
3) 外部时钟模式 2:外部触发输入(ETR)
4) 内部触发输入(ITRx):使用 A 定时器作为 B 定时器的预分频器(A 为 B 提供时钟)。

预分频器:将计数器的时钟频率按1到65536之间的任意值分频。它是基于一个(在TIMx_PSC寄存器中的)16位寄存器控制的16位计数器。这个控制寄存器带有缓冲器,它能够在工作时被改变。预分频器参数在下一次更新事件到来时被采用。

计数器模式:
1.向上计数模式 :计数器从0计数到自动加载值(TIMx_ARR计数器的内容),然后重新从0开始计数并且产生一个计数器溢出事件;
2. 向下计数模式 :计数器从自动装入的值(TIMx_ARR计数器的值)开始向下计数到0,然后从自动装入的值重新开始并且产生一个计数器向下溢出事件;
3.*对齐模式(向上/向下计数) :计数器从0开始计数到自动加载的值(TIMx_ARR寄存器)-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器下溢事件;然后再从0开始重新计数。
每次计数器溢出时可以产生更新事件,在TIMx_EGR寄存器中(通过软件方式或者使用从模式控制器)设置UG位也同样可以产生一个更新事件。

定时时间计算

以RCC的TIMxCLK作为时钟来源为例子,其频率为72MHz,则TimeOut=(ARR+1)(PSC+1)/Tclk。即溢出时间=(自动装载值+1)(预分频系数+1)/频率。此时一般使得预分频系数为71或7199等,便于计算。

初始化相关参数

typedef struct
{
  uint16_t TIM_Prescaler;//预分频系数
  uint16_t TIM_CounterMode;//计数模式     
  uint16_t TIM_Period;   //自动装入值
  uint16_t TIM_ClockDivision;//设置时钟分频因子    
  uint8_t TIM_RepetitionCounter;  //重复计数器
} TIM_TimeBaseInitTypeDef;

使用步骤

1.使能定时器时钟;RCC_APB1PeriphClockCmd();
2.初始化定时器,配置ARR,PSC;TIM_TimeBaseInit();
3.开启定时器中断,配置NVIC;TIM_ITConfig(); NVIC_Init();
4.使能定时器;TIM_Cmd();
5.编写相应中断服务函数。TIM3_IRQHandler();

设置一个500ms的定时器中断为例:

void TIM3_Int_Init(u16 arr,u16 psc)
{
 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitSrtue;//初始化相应结构体
 NVIC_InitTypeDef NVIC_InitStructure;
  
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能定时器时钟
 
 TIM_TimeBaseInitSrtue.TIM_Prescaler=psc;//预分频系数
 TIM_TimeBaseInitSrtue.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
 TIM_TimeBaseInitSrtue.TIM_Period=arr;//自动装载值
 TIM_TimeBaseInitSrtue.TIM_ClockDivision=TIM_CKD_DIV1;//设置时钟分割:TDTS = Tck_tim
 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitSrtue);//初始化TIMx的时间基数单位
   
 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//使能定时器的更新中断
 
  //中断优先级NVIC设置
 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
 NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器
 
 TIM_Cmd(TIM3,ENABLE);//使能定时器
}

void TIM3_IRQHandler(void)//中断服务函数
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
 {
  LED1=!LED1;
  TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除相应标志位

}

之后,在主函数里使用该函数并使用相应参数即可

 TIM3_Int_Init(4999,7199);//500ms