单片机(8)定时器相关之通用定时器

310 阅读3分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

简介

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

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

工作框图

在这里插入图片描述

       时钟来源:

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等,便于计算,相对的,频率f=1/Timeout

初始化相关参数

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