本文参考江科大视频侵删一、定时器整体框架1、分类与总线定时器核心作用定时中断固定周期执行任务流水灯、周期检测、计时计数功能统计外部脉冲次数PWM输出驱动电机、调光、调速2、核心内部模块1预分频器PSC对定时器时钟分频降低计数频率2计数器CNT16位寄存器从0开始向上/向下计数3自动重载寄存器ARR计数最大值CNTARR时触发溢出事件4中断/事件输出溢出可产生中断、触发信号TRGO用于定时器级联5从模式控制器选择时钟来源内部时钟、其他定时器、外部引脚二、核心公式、参数计算定时器基准时钟CK_PSC72MHz经过预分频器后得到计数时钟。1、计数器时钟频率含义1s内计数多少CK_CNTCK_PSC/PSC1PSC的取值范围0~655352、单次溢出时间定时周期计数器从0计数到ARR共计数ARR1次计数器溢出频率CK_CNK_OV CK_CNT/ARR1 CK_PSC/(PSC1)/(ARR1)则周期是T(PSC1)/CK_PSC *(ARR1) (PSC1)*(ARR1)/72*1000000单位s举例1ms定时中断设PSC1 72ARR11000。也就是以1us计数1000个。3、常用定时器参数表定时时间PSC 1ARR11ms7210005ms72500010ms7210000100ms72010000注PSC、ARR都是16位无符号数最大值65535,单定时器最长定时Tmax65535*6555/72000000 59.65s超过这个时长必须用定时器级联。三、三种计数模式配置定时器初始化函数TIM_CounterMode日常只用向上计数另外2种较少使用。1、向上计数(TIM_CounterMode_Up)CNT从0到ARR溢出后清零重新计数最常用。2、向下计数TIM_CounterMode_DownCNT从ARR到0溢出后重装3、中心对齐TIM_CounterMode_CenterAligned0→ARR→0往返计数主要用于PWM波形对称场景。四、时钟来源1、内部时钟CK_INT--普通定时默认芯片内部72MHz时钟最常用配置不开启任何从模式默认就是内部时钟。2、内部触发ITRx定时器级联一个定时器的溢出信号作为另一个定时器的时钟。3、外部引脚时钟ETR外部引脚输入脉冲定时器统计脉冲个数脉冲计数功能。4、通道输入捕获时钟多用于测速、测波形频率等。五、定时中断完整配置流程以TIM2定时1ms为例1、开启定时器总线时钟TIM2~TIM7在APB1TIM1/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必须清除中断标志否则死循环进中断。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互补通道切换电机控制、三相PWMTIM_IT_Trigger触发中断收到外部触发信号ETR、ITR定时器级联、外部同步TIM_IT_Break刹车中断外部刹车信号触发电机急停、安全保护六、代码部分练习以周期1s为例Num 1秒钟累加一次1、Time初始化#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、头文件#ifndef __TIMER1_H #define __TIMER1_H void Timer1_Init(); uint8_t GetITFlag(); #endif3、main函数#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#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_PinGPIO_Pin_0 ; GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz ; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2); }步骤2配置定时器及中断函数#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); } }步骤3main函数#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本文完。