参考资料:
《开发指南》P206,定时器中断实验
《参考手册》P253,通用定时器

1. 定时器基本原理

STM32F103ZE(精英版、战舰版)有8个16位的定时器,其中有4个通用定时器,2个高级定时器,2个基本定时器。

1.1 三种定时器的区别

具体区别如下图:

在这里插入图片描述
在实际编程中通常使用“通用定时器”。

1.2 通用定时器的主要特点

STM32F103的通用定时器是TIM2、TIM3、TIM4、TIM5.
▶位于低速APB1总线上(时钟可以来源于APB1的时钟)
▶16位向上、向下、中心对齐 的计数模式,自动装载计数器(TIMx_CNT)。
▶16位可实时修改的预分频器(TIMx_PSC),计数器时钟频率的分频系数位1~65535之间的任意数值。(分频之后计数器的时钟频率变小,因此可以计数更长的周期)
▶每一个定时器都有4个独立通道(TIMx_CH1~4),这些道路可以用来作为:
①输入捕获
②输出比较
③PWM生成
④单脉冲模式输出

1.3 通用定时器的3种计数器模式

通用定时器可以向上计数、向下计数、向上向下双向计数模式。
①向上计数模式:
计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
在这里插入图片描述
②向下计数模式:
计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
在这里插入图片描述
③中央对齐模式(向上/向下计数):
计数器从0开始计数到自动装入的值,产生一个计数器溢出事件;然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
在这里插入图片描述

1.4 通用定时器工作过程

在这里插入图片描述
▶图中红圈内是对定时器的时钟选择配置;
▶蓝色圈内是定时器作为计时器、定时的相关配置;
▶左下绿色区域是用来“输入捕获”,也就是测量脉冲的宽度;
▶右下黄色区域是输出比较寄存器,例如,比某个设定的值大时输出为1,比它小时输出为0,可用作PWM

1.5 定时器的内部时钟配置

定时器的时钟可来自内部时钟(CK_INT)

定时器时钟由内部时钟的来由过程:
在这里插入图片描述
在这里插入图片描述
✦首先由AHB的时钟经过APB1时钟的预分频系数产生ABP1的时钟,如果ABP1的预分频为1,那么定时器的时钟(CK_INT)为ABP1的时钟乘以1;如果ABP1的预分频不为1,则为ABP1乘以2。

✦又由于定时器的时钟选择来源于内部时钟,因此CK_PSC等于CK_INT;之后CK_PSC再除以PSC寄存器的值N(预分频系数)则得到计数器的时钟CK_CNT。

例如在默认情况下SYSCLK=72M;AHB时钟=72M;APB1时钟=36M;所以APB1的分频系数为2;因此通用定时器的时CK_INT=2*36M=72M,也就是说CK_PSC=72M,之后再除以PSC寄存器的值,就得到CK_CNT的频率。
实际上走的是这一条路线:
在这里插入图片描述

2. 定时器中断实验

实现用定时器控制led在500ms闪烁一次

2.1 常见库函数

▶定时器参数初始化:
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
第二个参数的结构体定义如下:

typedef struct
{
  uint16_t TIM_Prescaler;       初始化预分频系数
  uint16_t TIM_CounterMode;      计数模式
  uint16_t TIM_Period;          自动装载值
  uint16_t TIM_ClockDivision;     在输入捕获模式才用
  uint8_t TIM_RepetitionCounter;    在高级定时器才使用
} TIM_TimeBaseInitTypeDef;

▶定时器使能函数:
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
第一个参数是哪个定时器;第二个参数是ENABLE/DISABLE

▶定时器中断使能函数:
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
第一个参数是哪个定时器;第二个参数是中断源;第三个参数是ENABLE/DISABLE

▶状态标志位获取和清楚函数:
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

2.2 定时器中断具体实现步骤

  1. 使能定时器时钟
    RCC_APB1PeriphClockCmd();

实例中为:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
  1. 初始化定时器,配置ARR(自动装载值),PSC (预分频系数)
    TIM_TimeBaseInt();

实例中为:

	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; 向上计数模式 
	TIM_TimeBaseInitStruct.TIM_Period=arr;   自动装载值
	TIM_TimeBaseInitStruct.TIM_Prescaler=psc;   预分频系数
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct); 
  1. 开启定时器中断,配置NVIC(配置中断分组,中断优先级)
    void TIM_ITConfig();
    NVIC_Init();

实例中:

	NVIC_InitTypeDef NVIC_InitStruct;

	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);     使能定时器中断3
	
	NVIC_InitStruct.NVIC_IRQChannel=TIM3_IRQn;    选择初始化定时器中断3
	NVIC_InitStruct.NVIC_IRQChannelCmd=	ENABLE;    使能
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;   抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=3;     响应优先级
	NVIC_Init(&NVIC_InitStruct);              
  1. 使能定时器
    TIM_Cmd();

实例中:

TIM_Cmd(TIM3,ENABLE);
  1. 编写handler函数
    TIMx_IRQHandler();

实例中:

void TIM3_IRQHandler()
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
	{
		LED1=!LED1;
		TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
	}	
}
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐