第十四章 TIM基本定时器

目录

13.1 定时器的分类

13.2 TIM基本定时器简介

13.2.1 定时器的概念和作用

13.2.2 TIM基本定时器的工作原理和使用场景

13.3 TIM基本定时器功能框图

13.3.1 时钟源

13.3.2 控制器

13.3.3 时基(定时器的心脏)

13.3.4 影子寄存器

13.4 TIM基本定时器的初始化和配置方法

13.4.1 定时时间的计算

 13.4.2 时基初始化结构体

13.5 TIM基本定时器实验

13.5.1 实验要求

13.5.2 软件设计

13.5.3下载验证


13.1 定时器的分类

        STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部IO。通用定时器 TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部 IO。高级定时器 TIM1/8 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有 8 个外部 IO。

13.2 TIM基本定时器简介

13.2.1 定时器的概念和作用

        STM32的TIM定时器是一种硬件计时器,用于在嵌入式系统中生成精确的时间基准。TIM实际上是"Timer/Counter (计时器/计数器) Interface Module"(计时器/计数器接口模块)的缩写。

        STM32中的TIM定时器通常由一个或多个计数器、预分频器和比较器组成,并具有许多不同的工作模式。这些模式包括向上计数模式、向下计数模式、自动重载模式以及其他特殊模式。

        计数器是STM32 TIM定时器的核心组件之一。它可以递增或递减,每当计数器计数达到特定值时,就会触发中断或输出信号。计数器可以被设置为向上或向下模式,并且具有可配置的计数位数。

        预分频器是一个可编程的除法器,用于将外部时钟信号分频以产生所需的计数速度。预分频器的运作方式为:当计时器工作时,输入的时钟信号经过预分频器进行等分频处理,输出给计数器控制计数,从而实现了对计数器工作频率的控制。

        比较器是另一个重要的组件,用于将计数器的值与预设的比较值进行比较。当两者相等时,可以触发中断或输出信号。通过设置比较器的阈值,可以实现周期性任务等功能。

        除了以上基本组件,STM32 TIM定时器还提供了许多高级功能,例如输入捕获模式、PWM波形生成模式、编码器模式等。这些功能使得TIM定时器变得更加灵活和功能强大,可适应不同的应用场景。

        总之,STM32 TIM定时器是一种非常重要的硬件计时器,在嵌入式系统中具有广泛的应用前景。通过配置它的各种参数和模式,我们可以实现各种功能,如延时、频率计数、PWM波形生成等,并提供高精度和可靠性的时间基准。

13.2.2 TIM基本定时器的工作原理和使用场景

        TIM基本定时器的工作原理如下:当定时器启动时,计数器开始从0开始递增计数,并在计数器达到特定值时产生更新事件,可以触发中断或输出信号。通过设置预分频器的值,可以控制计时器的输入时钟频率,进而控制计数器的计数速度,从而实现所需的计时周期。

使用场景:

        延时操作:通过配置计数器的初始值和计数周期,可以实现不同长度的延时操作。

        脉冲计数:利用计数器递增的特性,可以将外部脉冲信号转化为可计数的低频信号,并通过比较器判断周期是否完成,实现对脉冲信号的计数和测量。

        频率计数:与脉冲计数类似,通过设置计数器的计数周期和预分频器的分频系数,可以将高频脉冲信号转化为可计数的低频信号,并通过比较器判断周期是否完成,实现对频率的计数和测量。

        PWM波形生成:通过设置计数器的计数周期和比较器的比较值,可以实现周期性的PWM波形输出,并通过比较器的占空比设置,调节PWM波形的占空比,从而控制电机、LED等设备的亮度或速度。

        周期性任务:通过定时器的中断功能,可以创建周期性任务,例如定时读取温度传感器数据、驱动显示屏幕刷新等操作。

        总之,STM32 TIM基本定时器是一种非常重要的硬件计时器,在嵌入式系统中具有广泛的应用前景。通过合理配置其参数和模式,可以实现各种延时、计数、PWM波形生成等功能,同时提供高精度、可靠性和稳定性的时间基准。

13.3 TIM基本定时器功能框图

13.3.1 时钟源

        定时器时钟 TIMxCLK,即内部时钟 CK_INT,经 APB1 预分频器后分频提供,如果 APB1 预分频系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系数是 2,即 PCLK1=36M,所以定时器时钟 TIMxCLK=36*2=72M。

13.3.2 控制器

        控制器用于控制定时器的:复位、使能、计数、触发DAC,涉及到的寄存器为:CR1/2、DIER、EGR、SR。

13.3.3 时基(定时器的心脏)

13.3.3.1 预分频器

        16bit的预分频器PSC对内部的时钟CKPSC进行分频之后得到计数器时钟CK_CNT=CK_PSC/(PSC+1),计数器在CNT的马区动下,开始计数,计数一数时间为/Ck_CNT

13.3.3.2 计数器、自动重装载寄存器

定时器使能(CEN置1)后,计数器CNT在CK_CNT驱动下计数当TCNT值与ARR的设定值相等时,就自动生成事件并CNT自动请零,然后自动重新计数。

13.3.4 影子寄存器

影子寄存器是一种常用的嵌入式系统技术,通常用于存储设备外部接口的状态信息。影子寄存器与设备实际寄存器一一对应,可以在设备实际寄存器发生改变时快速更新,从而提高系统的响应速度和稳定性。

在实际使用中,影子寄存器通常由两个寄存器组成,一个是设备实际寄存器,另一个是影子寄存器。在设备初始化时,将设备实际寄存器的值复制到影子寄存器中,并在后续代码中仅使用影子寄存器进行读写操作。当设备实际寄存器的值发生改变时,通过中断或轮询等方式及时更新影子寄存器的值,从而保持最新的状态信息。

使用影子寄存器有以下几个优点:

提高响应速度:由于直接读取影子寄存器,无需访问设备实际寄存器,因此能够更快地获取状态信息并进行相应的处理。

提高系统稳定性:影子寄存器能够及时反映设备实际寄存器的值,避免了由于读取过程中设备实际寄存器的值发生变化导致的不一致。

提高代码可读性:使用影子寄存器可以简化代码逻辑,使代码更加易读、易懂和易维护。

总之,影子寄存器是一种常用的嵌入式系统技术,在外部接口的状态信息存储、处理和控制等方面发挥着重要作用,能够提高系统的响应速度和稳定性,并使代码更加简洁、易读和易于维护。

13.4 TIM基本定时器的初始化和配置方法

13.4.1 定时时间的计算

        定时器的定时时间等于计数器的中断周期乘以中断的次数。计数器在 CK_CNT 的驱动下,计一个数的时间则是 CK_CLK 的倒数,等于: 1/(TIMxCLK/(PSC+1)),产生一次中断的时间则等于:1/(CK_CLK * ARR)。如果在中断服务程序里面设置一个变量 time,用来记录中断的次数,那么就可以计算出我们需要的定时时间等于: 1/CK_CLK* (ARR+1)*time。

        例如:实现1ms的定时

        PSC = 72–1 = 72M/(PSC+1) = 1MHz,1us

        ARR = 1000-1,即从0计数到999,则计了1000次

        中断周期 T = 100*1/1000000 = 1ms

 13.4.2 时基初始化结构体

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) TIM_Prescaler:定时器预分频器设置,时钟源经该预分频器才是定时器时钟,它设定 TIMx_PSC寄存器的值。可设置范围为 0 至 65535,实现 1 至 65536 分频。

        (2) TIM_CounterMode:定时器计数方式,可是在为向上计数、向下计数以及三种中心对齐模式。基本定时器只能是向上计数,即 TIMx_CNT 只能从 0 开始递增,并且无需初始化。

        (3) TIM_Period:定时器周期,实际就是设定自动重载寄存器的值,在事件生成时更新到影子寄存器。可设置范围为 0 至 65535。

        (4) TIM_ClockDivision:时钟分频,设置定时器时钟 CK_INT 频率与数字滤波器采样时钟频率分频比,基本定时器没有此功能,不用设置。

        (5) TIM_RepetitionCounter:重复计数器,属于高级控制寄存器专用寄存器位,利用它可以非常容易控制输出 PWM 的个数。这里不用设置。

13.5 TIM基本定时器实验

13.5.1 实验要求

        利用基本定时器TIM6/TIM7定时1s,1s时间到LED灯翻转一次,蜂鸣器鸣叫一声。

13.5.2 软件设计

13.5.2.1 设计思路

        首先配置时基初始化结构体,开启定时器更新中断(即定时器时间到了),配置中断优先级,使能定时器,编写中断服务函数,编写主函数。

13.5.2.2 代码分析

bsp_TimeBase.h

#ifndef _BSP_TIMEBASE_H
#define _BSP_TIMEBASE_H

#include "stm32f10x.h"
#define BASIC_TIM6	

#ifdef 	BASIC_TIM6	//使用基本定时器6
#define BASIC_TIM					TIM6
#define BASIC_TIM_APBxClock_FUN		RCC_APB1PeriphClockCmd
#define BASIC_TIM_CLK				RCC_APB1Periph_TIM6
#define BASIC_TIM_Period			(1000-1)
#define BASIC_TIM_Prescaler			71
#define BASIC_TIM_IRQ				TIM6_IRQn
#define BASIC_TIM_IRQHandler		TIM6_IRQHandler

#else				//使用基本定时器7
#define BASIC_TIM					TIM7
#define BASIC_TIM_APBxClock_FUN		RCC_APB1PeriphClockCmd
#define BASIC_TIM_CLK				RCC_APB1Periph_TIM7
#define BASIC_TIM_Period			(1000-1)
#define BASIC_TIM_Prescaler			71
#define BASIC_TIM_IRQ				TIM7_IRQn
#define BASIC_TIM_IRQHandler		TIM7_IRQHandler

#endif

void BASIC_TIM_Init(void);
 
#endif /*_BSP_TIMBASE_H*/

bsp_TimeBase.c

#include "bsp_TimeBase.h"

static void BASIC_TIM_Mode_Config(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	
	//开启定时器时钟,即内部CK_INT = 72M
	BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK,ENABLE);
	
	//自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
	TIM_TimeBaseStructure.TIM_Period = BASIC_TIM_Period;
	
	//时钟分频系数
	TIM_TimeBaseStructure.TIM_Prescaler = BASIC_TIM_Prescaler;
	
	//时钟分频因子,基本定时器没有不用管
	//TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	
	//计数器的计数模式,基本定时器只能向上计数,没有计数模式的设置
	//TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	
	//重复计数器的值,基本定时器没有,不用管
	//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
	
	//初始化定时器
	TIM_TimeBaseInit(BASIC_TIM,&TIM_TimeBaseStructure);
	
	//清除计数器的中断标志位 
	TIM_ClearFlag(BASIC_TIM,TIM_FLAG_Update);
	
	//开启计数器中断
	TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);
	
	//使能计数器
	TIM_Cmd(BASIC_TIM,ENABLE);
}

static void BASIC_TIM_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStruct;
	
	//设置中断优先级分组位0
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	
	//设置中断源
	NVIC_InitStruct.NVIC_IRQChannel = BASIC_TIM_IRQ;
	
	//设置主优先级为0
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	
	//设置抢占优先级为3
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
	
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	
	NVIC_Init(&NVIC_InitStruct);
}

void BASIC_TIM_Init(void)
{ 
	BASIC_TIM_NVIC_Config();
	BASIC_TIM_Mode_Config();
}

中断服务函数

#include "stm32f10x_it.h"
#include "bsp_BasicTim.h"
extern uint16_t time;

void BASIC_TIM_IRQHandler(void)
{
	if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET ) 
	{	
		time++;
		TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update);  		 
	}		 	
}

main.c

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_buzzer.h"
#include "bsp_TimeBase.h"
#include "bsp_systick.h"

volatile uint32_t time = 0;		//ms计时变量

int main(void)
{
	LED_GPIO_Config();
	 
	BASIC_TIM_Init();
	
	BUZZER_GPIO_Config();
	
	while(1)
	{
		//1000 * 1ms = 1s
		if(time == 1000)
		{
			time = 0;
			
			LED1_Toggle;
			BUZZER_Toggle;
		}
	}
}

13.5.3下载验证

        可以观察到开发板上的LED灯和蜂鸣器的状态1秒切换一次。

谢谢阅读!

猜你喜欢

转载自blog.csdn.net/weixin_68288412/article/details/129935853