本文参考江科大视频,侵删!
一、定时器整体框架
1、分类与总线

定时器核心作用:
定时中断:固定周期执行任务(流水灯、周期检测、计时);
计数功能:统计外部脉冲次数;
PWM输出:驱动电机、调光、调速;
2、核心内部模块
1)预分频器PSC:对定时器时钟分频,降低计数频率;
2)计数器CNT:16位寄存器,从0开始向上/向下计数;
3)自动重载寄存器ARR:计数最大值,CNT=ARR时触发溢出事件;
4)中断/事件输出:溢出可产生中断、触发信号(TRGO,用于定时器级联);
5)从模式控制器:选择时钟来源(内部时钟、其他定时器、外部引脚);
二、核心公式、参数计算
定时器基准时钟:CK_PSC:72MHz,经过预分频器后得到计数时钟。
1、计数器时钟频率,含义:1s内计数多少
CK_CNT=CK_PSC/PSC+1,PSC的取值范围0~65535;
2、单次溢出时间(定时周期)
计数器从0计数到ARR,共计数ARR+1次
计数器溢出频率CK_CNK_OV =CK_CNT/ARR+1 =CK_PSC/(PSC+1)/(ARR+1);
则周期是:T=(PSC+1)/CK_PSC *(ARR+1) =(PSC+1)*(ARR+1)/72*1000000(单位s);
举例1ms定时中断:
设:PSC+1 =72,ARR+1=1000。也就是以1us计数1000个。
3、常用定时器参数表
|-------|--------|-------|
| 定时时间 | PSC +1 | ARR+1 |
| 1ms | 72 | 1000 |
| 5ms | 72 | 5000 |
| 10ms | 72 | 10000 |
| 100ms | 720 | 10000 |
注:PSC、ARR都是16位无符号数,最大值65535,单定时器最长定时:
Tmax=65535*6555/72000000 =59.65s,超过这个时长,必须用定时器级联。
三、三种计数模式
配置定时器初始化函数,TIM_CounterMode,日常只用向上计数,另外2种较少使用。
1、向上计数(TIM_CounterMode_Up)
CNT从0到ARR,溢出后清零重新计数,最常用。
2、向下计数(TIM_CounterMode_Down)
CNT从ARR到0,溢出后重装;
3、中心对齐(TIM_CounterMode_CenterAligned)
0→ARR→0,往返计数,主要用于PWM波形对称场景。
四、时钟来源
1、内部时钟(CK_INT)--普通定时默认
芯片内部72MHz时钟,最常用;配置:不开启任何从模式,默认就是内部时钟。
2、内部触发ITRx(定时器级联)
一个定时器的溢出信号,作为另一个定时器的时钟。
3、外部引脚时钟(ETR)
外部引脚输入脉冲,定时器统计脉冲个数(脉冲计数功能)。
4、通道输入捕获时钟
多用于测速、测波形频率等。
五、定时中断完整配置流程

以TIM2,定时1ms为例
1、开启定时器总线时钟:TIM2~TIM7在APB1,TIM1/TIM8在APB2,不开时钟,外设不工作。
2、时基单元初始化(PSC、ARR、计数模式、分频),决定定时周期。
3、选择时钟源
普通定时:默认内部时钟;级联/计数:配置从模式+触发源
4、使能对应中断
溢出中断:TIM_IT_Update 。函数:TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
5、NVIC中断优先级配置
选择分组2,抢占优先级和子优先级按需配置。
6、使能定时器:TIM_Cmd(TIM2,ENABLE);
7、编写中断服务函数
1)判断中断标志;2)执行任务代码;3)必须清除中断标志,否则死循环进中断。
cpp
void TIM2_IRQHandler()
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
;//执行的代码,禁止长延时、复杂运算、大量函数调用
//手动清除中断挂起标志
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
8、注意事项
1)忘记清除中断标志→不停进中断,程序卡死;
2)中断内写延时/死循环→系统响应慢、中断可能丢失;
3)重复设置自动分组→优先级错乱、中断异常;
9、常用功能区分
1)单纯定时、周期执行任务:内部时钟+向上计数+更新中断;
2)超长定时:定时器级联(ITR内部触发);
3)统计外部脉冲个数:外部时钟模式;
4)电机调速、LED调光:PWM输出(通道比较模式);
5)测量外部高/低电平时间、频率:输入捕获;
10)中断源 TIM_ITConfig(TIM2,中断源,ENABLE);
PWM输出、输入捕获用TIM_IT_CCx;
定时器级联、外部触发同步:用TIM_IT_Trigger;
电机控制、刹车保护:TIM_IT_COM/TIM_IT_Break;
|-----------------|---------------|---------------------|--------------|
| 参数 | 含义 | 触发时机 | 适应场景 |
| TIM_IT_Update | 更新/溢出中断 | 计数器CNT溢出 (到ARR自动重装) | 普通定时中断、周期任务 |
| TIM_IT_CC1~CC4 | 捕获/比较通道1~4中断 | 输入捕获、PWM匹配事件 | 测量脉冲、PWM输出控制 |
| TIM_IT_COM | 换相中断 | 高级TIMER互补通道切换 | 电机控制、三相PWM |
| TIM_IT_Trigger | 触发中断 | 收到外部触发信号(ETR、ITR) | 定时器级联、外部同步 |
| TIM_IT_Break | 刹车中断 | 外部刹车信号触发 | 电机急停、安全保护 |
| | | | |
六、代码部分
练习:以周期1s为例,Num 1秒钟累加一次
1、Time初始化
cpp
#include "stm32f10x.h" // Device header
uint8_t IT_Flag;
void Timer1_Init()
{
//开启总线时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//使用内部时钟配置定时器内部计数时钟源(可以不写,默认就是内部时钟)
TIM_InternalClockConfig(TIM2);
//配置时基单元
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_InitStructure.TIM_ClockDivision =TIM_CKD_DIV1;
TIM_InitStructure.TIM_CounterMode =TIM_CounterMode_Up;
TIM_InitStructure.TIM_Period =7200-1;
TIM_InitStructure.TIM_Prescaler =10000-1;
TIM_InitStructure.TIM_RepetitionCounter =0x00;
TIM_TimeBaseInit(TIM2,&TIM_InitStructure);
//中断
TIM_ClearFlag(TIM2,TIM_IT_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//配置NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel =TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
//使能定时器
TIM_Cmd(TIM2,ENABLE);
}
//标志位复位
uint8_t GetITFlag()
{
if (IT_Flag ==1)
{
IT_Flag =0 ;
return 1;
}
return 0 ;
}
//中断服务函数
void TIM2_IRQHandler()
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
{
IT_Flag =1;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
注:时基单元中,TIM_InitStructure.TIM_ClockDivision =TIM_CKD_DIV1;是引脚采样分频,不影响CNT走数快慢。TIM_CKD_DIV1/TIM_CKD_DIV2/TIM_CKD_DIV4只针对输入捕获、ETR外部滤波采样时钟,用来抗干扰,不影响定时时间。
2、头文件
cpp
#ifndef __TIMER1_H
#define __TIMER1_H
void Timer1_Init();
uint8_t GetITFlag();
#endif
3、main函数
cpp
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer1.h"
uint16_t Num;
int main()
{
OLED_Init();
OLED_ShowString(1,1,"Num:");
Timer1_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
while(1)
{
if(GetITFlag() ==1)
{
Num++;
}
OLED_ShowNum(1,5,Num,5);
}
}
练习2:利用中断,实现1s钟
步骤1:初始化GPIOA,端口Pin_0
cpp
#include "stm32f10x.h"
void LED_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 ;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz ;
GPIO_Init(GPIOA,& GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);
}
步骤2:配置定时器及中断函数
cpp
#include "stm32f10x.h" // Device header
uint16_t Time_Cnt;
void Timer1_Init()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_InitStructure.TIM_ClockDivision =TIM_CKD_DIV1;
TIM_InitStructure.TIM_CounterMode =TIM_CounterMode_Up;
TIM_InitStructure.TIM_Period =72-1;
TIM_InitStructure.TIM_Prescaler =1000-1;
TIM_InitStructure.TIM_RepetitionCounter =0x00;
TIM_TimeBaseInit(TIM2,&TIM_InitStructure);
TIM_ClearFlag(TIM2,TIM_IT_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel =TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);
}
//中断服务函数
void TIM2_IRQHandler()
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
{
Time_Cnt ++;
if(Time_Cnt >=1000)
{
Time_Cnt =0;
GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_0)));
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
步骤3:main函数
cpp
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer1.h"
#include "LED.h"
extern uint16_t Time_Cnt;
int main()
{
OLED_Init();
Timer1_Init();
LED_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
OLED_ShowString(2,1,"Time_Cnt:");
while(1)
{
OLED_ShowNum(2,10,Time_Cnt,5);
}
}
七、与外部中断对比
|----------|----------|-----------|-------|
| 类型 | 触发方式 | 用途 | 优先级参考 |
| EXTI外部中断 | 引脚电平跳变触发 | 按键、红外遮挡检测 | 抢占1 |
| 定时器中断 | 固定时间自动触发 | 周期定时、定时控制 | 抢占2 |
本文完。