1. STM32定时器输出比较功能解析
1.1 输出比较基础原理
输出比较(Output Compare)是STM32定时器模块中的核心功能之一,它通过比较计数器(CNT)和捕获/比较寄存器(CCR)的值来精确控制输出引脚的电平状态。这个功能在电机控制、LED调光、PWM波形生成等场景中应用广泛。
工作原理可以这样理解:定时器就像一个不断计数的秒表,CCR寄存器相当于我们预设的一个目标值。当计数器的值达到这个目标值时,硬件会自动触发预设的动作(比如改变引脚电平)。这种硬件级的比较操作不占用CPU资源,响应速度极快。
1.2 通用定时器输出比较通道
在STM32的通用定时器(如TIM2-TIM5)中,每个定时器通常有4个独立的输出比较通道。以TIM2为例:
-
寄存器配置:
- TIMx_CCMR1:配置输出比较模式
- TIMx_CCER:配置输出极性和使能
- TIMx_CCRx:设置比较值
-
工作流程:
- 计数器CNT从0开始递增
- 硬件实时比较CNT和CCR的值
- 当CNT=CCR时,根据配置的模式改变输出电平
- 计数器达到ARR值后自动重置
-
典型配置代码:
c复制TIM_OCInitTypeDef ocInit;
ocInit.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
ocInit.TIM_OutputState = TIM_OutputState_Enable; // 使能输出
ocInit.TIM_Pulse = 50; // 初始比较值
ocInit.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性
TIM_OC1Init(TIM2, &ocInit); // 初始化通道1
1.3 高级定时器输出比较特性
高级定时器(如TIM1、TIM8)在通用定时器功能基础上增加了:
- 互补输出:可同时输出两路相位相反的PWM信号
- 死区插入:防止H桥电路上下管直通
- 刹车功能:紧急情况下快速关断输出
死区时间计算公式:
code复制Td = (DTG[7:0] + 1) × Tdtg
其中Tdtg = Tck_int × 2^DTG[7:5]
注意:使用高级定时器时,必须配置BDTR寄存器的MOE位才能使能输出。
2. PWM原理与实现
2.1 PWM基础概念
脉冲宽度调制(PWM)通过调节脉冲的占空比来等效实现模拟量输出。关键参数:
- 频率(f):f = 1/T,T为周期
- 占空比(D):D = Ton/T
- 分辨率:最小可调占空比步长
2.2 STM32 PWM生成原理
STM32使用定时器的输出比较功能生成PWM:
-
时基配置:
- 预分频器(PSC):决定计数频率
- 自动重载寄存器(ARR):决定PWM周期
-
占空比控制:
- 通过CCR寄存器设置高电平时间
- 占空比 = CCR/(ARR+1)
-
模式选择:
- PWM模式1:CNT<CCR时输出有效电平
- PWM模式2:CNT<CCR时输出无效电平
2.3 PWM参数计算实例
假设系统时钟72MHz,需要生成1kHz PWM:
-
选择预分频值:
若PSC=71,则计数器时钟=72MHz/(71+1)=1MHz -
计算ARR值:
周期T=1/1kHz=1ms
计数次数=1ms/(1/1MHz)=1000
ARR=1000-1=999 -
占空比设置:
50%占空比 → CCR=500
25%占空比 → CCR=250
代码实现:
c复制void PWM_Init(void)
{
TIM_TimeBaseInitTypeDef tbInit;
tbInit.TIM_Period = 999; // ARR
tbInit.TIM_Prescaler = 71; // PSC
tbInit.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &tbInit);
TIM_OCInitTypeDef ocInit;
ocInit.TIM_OCMode = TIM_OCMode_PWM1;
ocInit.TIM_OutputState = TIM_OutputState_Enable;
ocInit.TIM_Pulse = 500; // 初始占空比50%
TIM_OC1Init(TIM2, &ocInit);
TIM_Cmd(TIM2, ENABLE);
}
3. 外设驱动实现
3.1 LED呼吸灯实现
呼吸灯通过PWM占空比渐变实现亮度变化:
-
硬件连接:
- LED阳极接PA0(TIM2_CH1)
- 阴极接GND(加限流电阻)
-
软件实现:
c复制void Breath_LED(void)
{
uint8_t i;
PWM_Init(); // 初始化PWM
while(1) {
// 渐亮
for(i=0; i<=100; i++) {
PWM_SetCompare1(i);
Delay_ms(10);
}
// 渐暗
for(i=100; i>0; i--) {
PWM_SetCompare1(i);
Delay_ms(10);
}
}
}
提示:实际应用中可加入非线性变换使亮度变化更符合人眼感知。
3.2 舵机控制
常见舵机控制参数:
- 周期:20ms(50Hz)
- 脉宽:0.5ms(0°) ~ 2.5ms(180°)
实现代码:
c复制void Servo_SetAngle(float angle)
{
uint16_t pulse = 500 + angle * (2000/180); // 0.5ms-2.5ms
TIM_SetCompare2(TIM2, pulse);
}
3.3 直流电机驱动
使用TB6612驱动直流电机:
-
接线方式:
- PWMA接TIM2_CH3(PA2)
- AIN1接PA4, AIN2接PA5
- VM接电机电源(4.5-10V)
-
驱动逻辑:
c复制void Motor_SetSpeed(int8_t speed)
{
if(speed >= 0) { // 正转
GPIO_SetBits(GPIOA, GPIO_Pin_4);
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
} else { // 反转
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
GPIO_SetBits(GPIOA, GPIO_Pin_5);
}
PWM_SetCompare3(abs(speed));
}
4. 常见问题与调试技巧
4.1 PWM输出异常排查
-
无输出:
- 检查定时器时钟是否使能
- 确认GPIO模式设置为复用推挽输出
- 验证CCER寄存器的输出使能位
-
频率不正确:
- 重新计算PSC和ARR值
- 检查时钟树配置,确认定时器时钟源频率
-
占空比不稳定:
- 避免在中断中频繁修改CCR值
- 使用DMA传输CCR值可实现平滑变化
4.2 电机驱动注意事项
-
电源处理:
- 电机电源与MCU电源隔离
- 添加大容量滤波电容(100uF以上)
-
保护措施:
- 电机两端并联续流二极管
- 驱动芯片散热处理
-
调试建议:
- 先测试固定占空比
- 逐步增加变化速度
- 使用示波器观察PWM波形
4.3 进阶优化技巧
-
使用DMA更新CCR:
可实现PWM波形表播放,适合复杂波形生成 -
定时器同步:
多个定时器主从同步,实现多路精确同步PWM -
互补PWM优化:
调整死区时间适应不同功率器件
通过实际项目验证,这些PWM应用技巧在机器人控制、智能家居和工业自动化等领域都有广泛应用。掌握定时器的输出比较功能,可以大大扩展STM32的应用场景。
