假期摆了几个月,一点没学(摆子是这样的),还有两天开学,打算这两天尽可能的把 stm32 标准库的内容给补完上传到博客,肝就完了。

# 一、TIM 简介

  • TIM(Timer)定时器
  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
  • 16 位计数器、预分频器、自动重装寄存器的时基单元,在 72MHz 计数时钟下可以实现最大 59.65s 的定时
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
  • 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型

# 二、定时器类型

类型编号总线功能
高级定时器TIM1、TIM8APB2拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能
通用定时器TIM2、TIM3、TIM4、TIM5APB1拥有基本定时器的全部功能、并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能
基本定时器TIM6、TIM7APB1拥有定时中断、主模式触发 DAC 的功能

1、基本定时器

image-20240513205136172

预分频器

若预分频器 PSC 寄存器写 0,就是不分频或叫作 1 分频,输出频率 = 输入频率 / 1=72MHz;

若寄存器写 1,就是 2 分频,输出频率 = 输入频率 / 2=36MHz;

若寄存器写 2,就是 3 分频,输出频率 = 输入频率 / 3=24MHz……

实际分频系数 = 预分频器的值 + 1

该预分频器为 16 位,所以最大值为 65535,也就是 65536 分频

计数器

计数器可以对预分频后的计数时钟进行计数,计数时钟每来一个上升沿,计数器的值 + 1,该预分频器为 16 位,所以值可以从 0 加到 65535,再加便回到 0 重新开始。

所以计数器的值在计时过程中不断自增运行,当自增运行到目标值时,产生中断,那就完成了定时的任务。

所以还需要一个存储目标值的寄存器,即自动重装寄存器。

自动重装寄存器

自动重装寄存器也是 16 位,存储我们需要的计数目标。

计数值 = 自动重装寄存器 产生的中断叫做 “更新中断”,通往 NVIC,再配置好 NVIC 的定时器通道,那么定时器的更新中断就能得到 CPU 的响应了。

更新事件” 不会触发中断,但可以触发内部其他电路的工作

2、通用定时器

通用定时器框图:

image-20240515022319373

基本定时器仅支持向上计数模式,通用定时器和高级定时器支持向上计数向下计数中央对齐计数三种模式,常用向上计数模式。

3、高级定时器

image-20240515022427412

高级定时器多一个重复计数器,当时基单元发生 update 事件时,重复计数器 + 1 计数

# 三、定时中断基本结构

image-20240515022624954

# 四、定时器中断程序实例:

#include "stm32f10x.h"                  // Device header
 
void Timer_Init(void)
{
	//①开启时钟,选择时钟源
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	TIM_InternalClockConfig(TIM2);
	//②时基单元初始化
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;	//ARR 自动重装寄存器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;	// 重复计数器
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	//③使能更新中断
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);	// 清除更新中断标志位
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	//④配置 NVIC
	NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	//⑤启动定时器
	TIM_Cmd(TIM2,ENABLE);
}
 
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		
		TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	}
}