7.STM32F40x 基本定时器(TIM6和TIM7)

一、基本定时器概念内容

       基本定时器(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的过程一致,只是有个别参数不同而已。自己根据手册进行修改即可。

注意:本人所写文章内容均用于记录自己在学习嵌入式的成长过程!!!!!