中国DevOps平台技术适配力全景报告:2025年企业选型关键指标深度解析
2026/5/6 16:16:30
定时器是单片机开发中最核心的外设之一,广泛应用于定时控制、脉冲宽度调制(PWM)、外部脉冲计数等场景。本文基于STM32F103系列单片机,结合Keil MDK-ARM开发环境,从底层配置到实战调试,手把手讲解定时器定时中断、PWM输出、脉冲计数三大核心功能的编程方法,同时详细说明如何通过Keil调试功能观察变量、验证程序逻辑,零基础也能快速上手。
STM32F103的通用定时器(TIM2~TIM4)具备定时中断、PWM输出、脉冲计数功能,核心参数:
定时中断是定时器最基础的应用,例如实现1秒触发一次中断,控制LED灯闪烁。
系统时钟为72MHz(STM32F103常用配置),要实现1秒中断:
#include"stm32f10x.h"// 全局变量:记录中断次数u32 timer_count=0;// 定时器2初始化函数voidTIM2_Init(void){TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;// 使能TIM2时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);// 定时器基础配置TIM_TimeBaseStructure.TIM_Period=9999;// ARR值TIM_TimeBaseStructure.TIM_Prescaler=7199;// PSC值TIM_TimeBaseStructure.TIM_ClockDivision=0;// 时钟分频因子TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;// 向上计数TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);// 开启定时器更新中断TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);// NVIC配置:中断优先级NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStructure);// 使能定时器2TIM_Cmd(TIM2,ENABLE);}// LED初始化(PA0)voidLED_Init(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_0);// 初始熄灭}// TIM2中断服务函数voidTIM2_IRQHandler(void){if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET){timer_count++;// 中断次数+1if(timer_count%1==0)// 1秒触发{GPIO_WriteBit(GPIOA,GPIO_Pin_0,!GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_0));// LED翻转}TIM_ClearITPendingBit(TIM2,TIM_IT_Update);// 清除中断标志位}}intmain(void){LED_Init();TIM2_Init();while(1){// 主循环无需操作,中断中处理LED}}timer_count,按回车;timer_count每1秒增加1,LED同步闪烁;PWM通过调节高低电平占空比控制外设,例如调节LED亮度、电机转速。本文以TIM3_CH1(PA6)输出PWM为例。
#include"stm32f10x.h"// TIM3 PWM初始化voidTIM3_PWM_Init(u16 arr,u16 psc){GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;// 使能时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);// GPIO配置(PA6=TIM3_CH1)GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;// 复用推挽输出GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);// 定时器基础配置TIM_TimeBaseStructure.TIM_Period=arr;TIM_TimeBaseStructure.TIM_Prescaler=psc;TIM_TimeBaseStructure.TIM_ClockDivision=0;TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);// PWM模式配置TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;// PWM模式1TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;// 输出使能TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;// 高电平有效TIM_OC1Init(TIM3,&TIM_OCInitStructure);// 配置CH1TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);// 使能预装载寄存器TIM_ARRPreloadConfig(TIM3,ENABLE);// 使能ARR预装载TIM_Cmd(TIM3,ENABLE);// 使能TIM3}intmain(void){u16 pwm_val=0;u8 dir=1;// 占空比增减方向// 初始化:ARR=999,PSC=71 → 1kHz PWMTIM3_PWM_Init(999,71);while(1){// 模拟占空比渐变if(dir)pwm_val++;elsepwm_val--;if(pwm_val>999)dir=0;if(pwm_val==0)dir=1;TIM_SetCompare1(TIM3,pwm_val);// 设置CCR1值,调整占空比// 延时for(u32 i=0;i<10000;i++);}}pwm_val,启动调试;pwm_val从0递增到999,再递减到0,循环变化;pwm_val渐变。定时器支持外部时钟模式,可检测外部引脚的脉冲信号并计数,例如统计按键按下次数、编码器脉冲数。本文以TIM2_CH1(PA0)检测外部脉冲为例。
#include"stm32f10x.h"// 脉冲计数初始化voidTIM2_Count_Init(void){GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_ICInitTypeDef TIM_ICInitStructure;// 使能时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);// GPIO配置(PA0=TIM2_CH1,上拉输入)GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;// 上拉输入GPIO_Init(GPIOA,&GPIO_InitStructure);// 定时器基础配置TIM_TimeBaseStructure.TIM_Period=0xFFFF;// 最大计数范围TIM_TimeBaseStructure.TIM_Prescaler=0;// 不分频TIM_TimeBaseStructure.TIM_ClockDivision=0;TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);// 外部时钟模式配置TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;// 上升沿计数TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;// 不分频TIM_ICInitStructure.TIM_ICFilter=0x00;// 无滤波TIM_ICInit(TIM2,&TIM_ICInitStructure);// 选择外部时钟模式2:TI1FP1作为时钟源TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0);TIM_SetCounter(TIM2,0);// 计数器清零TIM_Cmd(TIM2,ENABLE);// 使能定时器}intmain(void){u16 pulse_count=0;TIM2_Count_Init();while(1){pulse_count=TIM_GetCounter(TIM2);// 读取脉冲计数// 每计数10个脉冲,做一次标记(可替换为业务逻辑)if(pulse_count%10==0&&pulse_count!=0){pulse_count=0;TIM_SetCounter(TIM2,0);// 清零重新计数}}}pulse_count;pulse_count随外部脉冲数递增,每累计10个脉冲自动清零,验证计数功能正常;pulse_count一致,确认计数准确。