定时器和PWM
前言本实验基于 STM32F103 最小系统板围绕通用定时器与 PWM 脉宽调制展开实践。实验分为两部分第一部分利用定时器输出比较Toggle 模式驱动 LED 以 2s 周期亮灭闪烁第二部分将定时器配置为 PWM 输出模式通过动态调节占空比实现 LED 呼吸灯效果并借助 Keil 虚拟示波器观测 PWM 波形。通过本次实验可以深入理解 STM32 定时器的时基配置、引脚复用以及 PWM 生成原理为后续电机控制、舵机驱动等应用打下基础。目录一、实验目的二、实验内容1. 定时器计数方式控制 LED 闪烁2. PWM 模式实现呼吸灯实验总结一、STM32 定时器 PWM 生成的关键步骤二、常见问题及排查方法三、实验心得一. 实验目的深入了解STM32定时器原理掌握脉宽调制pwm生成方法。二. 实验内容使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin与GPIOx管脚复用见下图连接一个LED用定时器计数方式控制LED以2s的频率周期性地亮-灭。工程的建立具体操作观看前几个博客具体文件如下在main.c中写入以下代码;#includestm32f10x.hvoidTIM2_OC_Init(void);intmain(void){SystemInit();TIM2_OC_Init();while(1){// 无软件操作硬件自动翻转PA0(TIM2_CH1)}}voidTIM2_OC_Init(void){GPIO_InitTypeDef GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;TIM_OCInitTypeDef TIM_OCInitStruct;// 1.开启时钟GPIOA TIM2RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);// PA0 复用推挽输出TIM2_CH1复用功能重点GPIO_InitStruct.GPIO_PinGPIO_Pin_0;GPIO_InitStruct.GPIO_ModeGPIO_Mode_AF_PP;// 复用推挽输出GPIO_InitStruct.GPIO_SpeedGPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStruct);// 2.定时器时基配置 72M - 10kHz计数1s溢出TIM_TimeBaseStruct.TIM_Prescaler7199;TIM_TimeBaseStruct.TIM_Period9999;TIM_TimeBaseStruct.TIM_ClockDivisionTIM_CKD_DIV1;TIM_TimeBaseStruct.TIM_CounterModeTIM_CounterMode_Up;TIM_TimeBaseInit(TIM2,TIM_TimeBaseStruct);//3.输出比较配置匹配时电平翻转 Toggle模式TIM_OCInitStruct.TIM_OCModeTIM_OCMode_Toggle;TIM_OCInitStruct.TIM_OutputStateTIM_OutputState_Enable;TIM_OCInitStruct.TIM_Pulse9999;// 计到该值触发翻转TIM_OCInitStruct.TIM_OCPolarityTIM_OCPolarity_High;TIM_OC1Init(TIM2,TIM_OCInitStruct);TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Disable);TIM_Cmd(TIM2,ENABLE);}在stm32f10x_conf.h中写入#ifndef__STM32F10x_CONF_H#define__STM32F10x_CONF_H#includestm32f10x.h#includestm32f10x_rcc.h#includestm32f10x_gpio.h#includestm32f10x_usart.h#includemisc.h#includestm32f10x_tim.h#defineassert_param(expr)((void)0)#endif在本次实验中我使用的是pa0引脚将stm32最小板连接到面包板上烧录进去后将led灯正极连接到pa0引脚另一端接地通电后led灯闪烁。结果LED以2s的频率周期性地亮-灭。微信视频2026-10-20_131548_677接上采用定时器PWM模式让 LED 以呼吸灯方式渐亮渐灭周期为1~2秒自己调整占空比变化到一个满意效果使用Keil虚拟示波器观察 PWM输出波形。修改main.c的代码#includestm32f10x.hvoidTIM2_PWM_Init(void);voidDelay_ms(uint32_tms);intmain(void){uint16_tccr_val0;int8_tdir1;// 1:占空比增加-1:占空比减小SystemInit();TIM2_PWM_Init();while(1){TIM_SetCompare1(TIM2,ccr_val);// 修改TIM2 CH1的CCR改变占空比ccr_valdir;if(ccr_val199){dir-1;}elseif(ccr_val0){dir1;}Delay_ms(8);// 调整这个值修改呼吸快慢8ms 总呼吸周期约1.6s}}// TIM2_CH1 PA0 PWM初始化voidTIM2_PWM_Init(void){GPIO_InitTypeDef GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;TIM_OCInitTypeDef TIM_OCInitStruct;// 开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);// PA0 复用推挽输出 TIM2_CH1GPIO_InitStruct.GPIO_PinGPIO_Pin_0;GPIO_InitStruct.GPIO_ModeGPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_SpeedGPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStruct);// 时基TIM_TimeBaseStruct.TIM_Prescaler71;TIM_TimeBaseStruct.TIM_Period199;TIM_TimeBaseStruct.TIM_ClockDivisionTIM_CKD_DIV1;TIM_TimeBaseStruct.TIM_CounterModeTIM_CounterMode_Up;TIM_TimeBaseInit(TIM2,TIM_TimeBaseStruct);// PWM模式1CNTCCR时输出有效电平TIM_OCInitStruct.TIM_OCModeTIM_OCMode_PWM1;TIM_OCInitStruct.TIM_OutputStateTIM_OutputState_Enable;TIM_OCInitStruct.TIM_Pulse0;TIM_OCInitStruct.TIM_OCPolarityTIM_OCPolarity_High;TIM_OC1Init(TIM2,TIM_OCInitStruct);TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);TIM_ARRPreloadConfig(TIM2,ENABLE);TIM_Cmd(TIM2,ENABLE);}// 简单软件延时voidDelay_ms(uint32_tms){uint32_ti,j;for(i0;ims;i)for(j0;j7200;j);}使用Keil虚拟示波器观察 PWM输出波形。在Dialog DLL中输入 DARMSTM.DLL在Parameter中输入-pSTM32F103C8选用pa0引脚输入PORTA.0设置为bit.结果微信视频2026-10-20_131542_550微信视频2026-10-20_134332_185实验总结本次实验围绕 STM32F103 通用定时器与 PWM 脉宽调制展开完成了两项任务利用定时器定时中断实现 LED 周期 2s 亮灭闪烁配置定时器 PWM 输出模式实现 LED 呼吸灯渐亮渐灭效果并借助 Keil 虚拟示波器观测 PWM 波形达到熟悉定时器原理、掌握 PWM 生成方法的实验目的。实验第一部分选用 TIM2 定时器通道对应的复用 GPIO 引脚驱动 LED配置定时器预分频与自动重装载值配置更新中断每 2s 触发一次中断翻转 LED 电平实现 LED 周期性亮灭。该过程理解了通用定时器的计数、溢出中断工作机制掌握定时器时钟、分频、计数周期之间的计算关系区分普通定时中断和 PWM 输出的不同配置思路。实验第二部分将定时器通道配置为 PWM 输出模式在主循环中动态修改比较值连续改变 PWM 占空比控制 LED 亮度缓慢变化实现周期约 1.5s 的呼吸灯效果。同时打开 Keil 仿真虚拟示波器直观观察到 PWM 方波周期固定高电平宽度随程序动态变化对应占空比改变验证了 PWM 依靠调节占空比实现等效模拟输出、控制 LED 亮度的原理。实验中也遇到了一些问题一是定时器时钟参数计算错误导致闪烁 / 呼吸周期和预期不符二是 GPIO 没有正确配置为定时器复用推挽输出模式PWM 无波形输出三是占空比变化步长设置不当呼吸效果生硬或者变化速度过快。通过核对芯片手册复用引脚表、重新核算分频参数、调整比较值增减步长最终修正问题得到流畅的呼吸效果。通过本次实验我理解了 STM32 定时器的基础架构分清定时中断模式与 PWM 输出模式的寄存器配置差异理解 PWM 调光的本质人眼利用视觉暂留将高频方波的平均功率感知为亮度。同时学会使用 Keil 虚拟示波器在线观测波形建立 “代码配置 — 硬件输出 — 波形观测” 的嵌入式调试思路。本次实验也认识到定时器资源复用是 STM32 外设使用的重点GPIO 复用功能的选择、定时器模式的配置都需要严格对照参考手册。后续可以进一步优化代码调整呼吸灯变化曲线也可以利用 PWM 驱动电机等其他外设拓展 PWM 的应用场景。实验总结一、STM32 定时器 PWM 生成的关键步骤开启时钟分别使能 GPIO 端口时钟RCC_APB2PeriphClockCmd和定时器时钟RCC_APB1PeriphClockCmd注意 TIM2~TIM4 挂在 APB1 总线上而 GPIOA 挂在 APB2 总线上。配置引脚复用将目标引脚设置为复用推挽输出GPIO_Mode_AF_PP并确认该引脚对应的定时器通道如 PA0 对应 TIM2_CH1这是 PWM 信号能否正确输出的关键。配置定时器时基设置预分频器TIM_Prescaler和自动重载值TIM_Period确定 PWM 频率。例如 72MHz 时钟、预分频 71、重载值 199 时PWM 频率为 72M / (72 × 200) 5kHz。配置输出比较/PWM 模式选择TIM_OCMode_PWM1或TIM_OCMode_Toggle设置初始占空比TIM_Pulse和输出极性TIM_OCPolarity_High。使能预装载与定时器调用TIM_OC1PreloadConfig和TIM_ARRPreloadConfig使能预装载寄存器最后调用TIM_Cmd(TIM2, ENABLE)启动定时器。动态调节占空比在主循环中通过TIM_SetCompare1修改 CCR 值配合延时即可实现呼吸灯等渐变效果。二、常见问题及排查方法常见问题可能原因排查方法引脚复用配置错误未将引脚设置为GPIO_Mode_AF_PP或选错了复用通道如 PA0 不是 TIM2_CH1 而是其他功能对照芯片数据手册确认引脚与定时器通道的映射关系检查 GPIO 模式是否为复用推挽输出用 Keil 虚拟示波器观察引脚电平变化PWM 频率计算偏差预分频值或重载值计算错误未考虑 APB1 时钟分频系数确认定时器时钟源频率APB1 时钟可能被分频按公式f_PWM f_timer / ((PSC1) × (ARR1))复核用示波器实测波形频率与理论值对比输出无波形定时器未使能输出比较通道未使能引脚被其他外设占用检查是否调用TIM_Cmd使能定时器检查TIM_OutputState_Enable是否设置确认引脚未被 JTAG/SWD 或其他外设复用占空比无法调节未使能预装载寄存器CCR 值超出 ARR 范围调用TIM_OC1PreloadConfig和TIM_ARRPreloadConfig确保TIM_SetCompare1传入的值在 0~ARR 之间呼吸灯效果不流畅延时过短导致变化太快或 CCR 步进过大调整Delay_ms的延时时间减小 CCR 每次变化的步长如改为 1 或 2三、实验心得本次实验通过 STM32F103 的 TIM2 定时器成功实现了 LED 的周期性闪烁和呼吸灯效果加深了对定时器时基配置、输出比较/PWM 模式以及引脚复用功能的理解。实验中遇到的引脚复用配置问题提醒我们查阅芯片数据手册和参考手册是嵌入式开发中必不可少的环节。通过 Keil 虚拟示波器观察波形也直观验证了 PWM 频率和占空比的计算结果为后续更复杂的定时器应用如电机控制、舵机驱动打下了基础。