文章目录
- STM32 定时器与 PWM 学习笔记
- 一、定时器分类
- STM32F103C8T6 定时器资源
- 系统时钟树要点
- 三个重要概念
- 定时时间计算公式
- 二、定时器中断配置流程
- 步骤
- 代码模板
- 三、PWM(脉冲宽度调制)
- 工作原理
- PWM 模式
- PWM 配置步骤
- PWM 代码模板
- 实时修改占空比
- 通道与引脚对应关系(F103C8T6 常用)
- 四、典型应用场景
- 1. LED 呼吸灯
- 2. 舵机控制
- 3. 直流电机调速
- 五、重要注意事项
- 六、小结
STM32 定时器与 PWM 学习笔记
基于 B站 江科大自化协 STM32 教程整理
一、定时器分类
STM32F103C8T6 定时器资源
| 类型 | 数量 | 位数 | 功能 |
|---|---|---|---|
| 高级定时器 (TIM1) | 1 | 16位 | PWM 互补输出、死区控制、刹车功能 |
| 通用定时器 (TIM2/3/4) | 3 | 16位 | 定时、PWM、输入捕获、输出比较、编码器 |
| 基本定时器 (TIM6/7) | 2 | 16位 | 仅定时功能(无外部 I/O) |
系统时钟树要点
- 系统时钟 SYSCLK = 72MHz(外部 8MHz 晶振 → PLL 倍频)
- APB2 总线:72MHz(TIM1 挂载在 APB2)
- APB1 总线:36MHz,但挂载在 APB1 上的定时器(TIM2/3/4/6/7)时钟 = 36MHz × 2 =72MHz(预分频器倍频)
三个重要概念
| 概念 | 缩写 | 作用 |
|---|---|---|
| 预分频器 | PSC | 对时钟分频,决定计数频率 |
| 自动重装载值 | ARR | 决定计数周期 |
| 计数器 | CNT | 当前计数值 |
定时时间计算公式
T = ( P S C + 1 ) × ( A R R + 1 ) T I M CLK T = \frac{(PSC + 1) \times (ARR + 1)}{TIM_{\text{CLK}}}T=TIMCLK(PSC+1)×(ARR+1)
例如:TIM_CLK = 72MHz,PSC = 7199,ARR = 9999 → T = 1s
二、定时器中断配置流程
步骤
- 开启定时器时钟(
RCC_APB1PeriphClockCmd或RCC_APB2PeriphClockCmd) - 配置时基单元(
TIM_TimeBaseInit) - 使能更新中断(
TIM_ITConfig) - 配置 NVIC(
NVIC_PriorityGroupConfig+NVIC_Init) - 使能定时器(
TIM_Cmd)
代码模板
voidTimer_Init(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_TimeBaseStructure.TIM_Prescaler=7199;// PSCTIM_TimeBaseStructure.TIM_Period=9999;// ARRTIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_RepetitionCounter=0;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStructure);TIM_Cmd(TIM2,ENABLE);}voidTIM2_IRQHandler(void){if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){TIM_ClearITPendingBit(TIM2,TIM_IT_Update);// 在这里写定时触发的操作}}三、PWM(脉冲宽度调制)
工作原理
通过改变占空比(Duty Cycle)来控制模拟量输出:
- 频率:由 ARR 决定,f P W M = T I M C L K ( P S C + 1 ) × ( A R R + 1 ) f_{PWM} = \frac{TIM_{CLK}}{(PSC + 1) \times (ARR + 1)}fPWM=(PSC+1)×(ARR+1)TIMCLK
- 占空比:由 CCR(捕获/比较寄存器)决定,D u t y = C C R A R R + 1 Duty = \frac{CCR}{ARR + 1}Duty=ARR+1CCR
- 分辨率:由 ARR 的位数决定,如 ARR = 999,分辨率为 0.1%
PWM 模式
| 模式 | 行为 | 极性 |
|---|---|---|
| PWM 模式 1 | CNT < CCR 时为有效电平 | 向上计数 |
| PWM 模式 2 | CNT > CCR 时为有效电平 | 向上计数 |
PWM 配置步骤
- 开启 GPIO 时钟和复用功能(
RCC_APB2PeriphClockCmd+ AFIO) - 配置 GPIO 为复用推挽输出(
GPIO_Init设置GPIO_Mode_AF_PP) - 开启定时器时钟
- 配置时基单元(
TIM_TimeBaseInit) - 配置输出比较单元(
TIM_OCInit) - 使能定时器(
TIM_Cmd)
PWM 代码模板
voidPWM_Init(void){// 1. GPIO 时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);// 2. GPIO 配置(以 PA0 → TIM2_CH1 为例)GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;// 复用推挽输出GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);// 3. 定时器时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);// 4. 时基单元TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_TimeBaseStructure.TIM_Prescaler=71;// 72MHz / 72 = 1MHzTIM_TimeBaseStructure.TIM_Period=999;// 1kHz PWMTIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);// 5. 输出比较配置TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse=0;// 初始占空比 0%TIM_OC1Init(TIM2,&TIM_OCInitStructure);// 6. 使能TIM_Cmd(TIM2,ENABLE);}实时修改占空比
voidPWM_SetCompare1(uint16_tCompare){// 注意:库函数 TIM_SetCompare1 没有检查参数上限// 如果传入值 > ARR,会一直输出高电平(100% 占空比)TIM_SetCompare1(TIM2,Compare);}通道与引脚对应关系(F103C8T6 常用)
| 定时器 | 通道 1 | 通道 2 | 通道 3 | 通道 4 |
|---|---|---|---|---|
| TIM1 | PA8 | PA9 | PA10 | PA11 |
| TIM2 | PA0 | PA1 | PA2 | PA3 |
| TIM3 | PA6 | PA7 | PB0 | PB1 |
| TIM4 | PB6 | PB7 | PB8 | PB9 |
四、典型应用场景
1. LED 呼吸灯
// 在主循环中渐变改变 CCRuint8_tdir=0;uint16_tpwm_val=0;while(1){PWM_SetCompare1(pwm_val);if(dir==0)pwm_val++;elsepwm_val--;if(pwm_val>=999)dir=1;if(pwm_val==0)dir=0;Delay_ms(1);// 控制呼吸速度}2. 舵机控制
| 脉宽 | 角度 |
|---|---|
| 0.5ms | 0° |
| 1.0ms | 45° |
| 1.5ms | 90° |
| 2.0ms | 135° |
| 2.5ms | 180° |
设置 PWM 频率 = 50Hz(周期 20ms),ARR = 19999(PSC = 71)
// SG90 舵机常用配置(50Hz)// ARR = 20000-1, PSC = 72-1// 0°: CCR = 500// 90°: CCR = 1500// 180°: CCR = 25003. 直流电机调速
使用 L298N 等驱动模块,通过 PWM 占空比控制电机转速:
// 0~100% 占空比对应 0~ARRPWM_SetCompare1((uint16_t)(speed/100.0*ARR));五、重要注意事项
- TIM_SetCompare 参数范围:库函数不检查传入值是否 ≤ ARR,超出会导致持续高电平而非 100% 占空比
- 重映射:部分引脚存在默认复用功能冲突时,需要通过 AFIO 重映射到备用引脚(如
GPIO_PinRemapConfig) - 高级定时器 TIM1 需要额外使能:
TIM_CtrlPWMOutputs(TIM1, ENABLE)才能使 PWM 输出 - PSC 和 ARR 是 16 位寄存器,最大值为 65535
- 影子寄存器:PSC 和 ARR 有影子寄存器,更新事件发生时才会真正生效;可设置
TIM_ARRPreloadConfig控制更新时机 - 时钟分割 (CKD):用于数字滤波器,不是定时器时钟的分频,配置死区时才起作用
六、小结
| 要实现 | 配置要点 |
|---|---|
| 定时中断 | 时基单元 + NVIC |
| PWM 输出 | 时基单元 + OC 通道 + AF_PP 引脚 |
| 占空比调节 | TIM_SetCompareX(TIMx, val) |
| 输入捕获 | 测量外部信号频率/脉宽 |
| 编码器模式 | 电机速度/位置采集 |
核心记忆口诀:时钟-引脚-时基-通道 四步走,PSC 决定单位时间,ARR 决定周期,CCR 决定占空比。
整理时间:2026-07-27