问题现象与背景
在嵌入式开发中,使用STM32定时器的输入捕获功能测量PWM信号的频率和占空比是常见需求。典型做法是:一个通道捕获上升沿,另一个通道捕获下降沿,通过两次捕获值的差值计算高电平时间。然而,不少开发者会遇到一个奇怪现象:当PWM频率改变时,测得的高电平宽度(脉宽)会随之漂移,导致占空比计算错误。例如,固定占空比50%的PWM,在1kHz时测得高电平500us,在10kHz时却变成480us或520us。
这种漂移并非随机误差,而是由定时器的预分频器(PSC) 和捕获边沿配置不当引起的系统性偏差。本文将逐层剖析原因,并给出正确的配置方法。
输入捕获原理回顾
STM32定时器的输入捕获单元(IC)通过边沿检测器监视输入引脚,当检测到指定边沿(上升沿/下降沿/双边沿)时,将当前计数器(CNT)的值锁存到捕获/比较寄存器(CCR)中,并可触发中断或DMA。测量PWM占空比通常需要两个捕获事件:
- 上升沿捕获得到周期起点(CCR1)
- 下降沿捕获得到高电平结束点(CCR2)
- 高电平时间 = CCR2 - CCR1(需处理计数器溢出)
- 周期 = 两次上升沿的时间差
- 占空比 = 高电平时间 / 周期
关键点:捕获值的分辨率由定时器计数频率决定,而计数频率 = 定时器时钟 / (PSC + 1)。
漂移的根因分析
1. 预分频器设置过大导致量化误差
假设定时器时钟为72MHz,PSC设置为71,则计数频率为1MHz,计数周期1us。若PWM高电平时间为500us,捕获值差为500,看似精确。但当PWM频率升高至10kHz(周期100us),高电平时间50us,捕获值差为50,此时若存在±1个计数的误差,相对误差为2%。若PSC更大(如计数频率100kHz,周期10us),50us高电平仅对应5个计数,±1误差导致20%的偏差。预分频越大,计数分辨率越低,高频PWM的脉宽测量误差越显著,表现为高电平宽度随频率变化而漂移。
2. 捕获边沿配置错误引入额外延迟
部分开发者误将两个通道都配置为上升沿捕获,或未正确设置从模式复位,导致捕获值并非预期边沿。更隐蔽的是,输入滤波器和边沿检测器的延迟会随信号频率变化:高频信号通过滤波器时,边沿可能被延迟或丢失,造成捕获值偏移。若滤波器采样频率与信号频率不匹配,延迟量不同,也会导致脉宽测量值漂移。
3. 中断响应延迟与计数器溢出处理不当
在高频PWM下,两次捕获间隔很短,若中断服务程序(ISR)响应不及时,可能错过第二次捕获或计数器已溢出。尤其是当PSC设置较大时,计数器溢出周期短,若未正确处理溢出,计算出的差值会出错。
4. 从模式复位(Reset Mode)配置问题
使用从模式复位时,上升沿会将CNT清零,此时下降沿捕获值直接对应高电平时间。但若复位信号与捕获边沿的时序配合不当(如复位延迟),会导致高电平测量值偏小,且该偏差与频率相关。
正确配置步骤
步骤1:合理选择预分频器
根据被测PWM的最低频率和所需分辨率选择PSC。原则:计数频率应足够高,使最小高电平时间对应至少100个计数以上,以降低量化误差。例如,被测PWM频率范围1kHz~100kHz,最小高电平时间约5us(100kHz、50%占空比),若要求1%精度,计数周期应≤50ns,即计数频率≥20MHz。72MHz时钟下,PSC设为0或1即可。
步骤2:正确配置捕获边沿与通道
- 通道1配置为上升沿捕获(捕获周期起点)
- 通道2配置为下降沿捕获(捕获高电平结束)
- 若使用从模式复位,将通道1的上升沿同时作为触发输入(TI1FP1),从模式选择Reset Mode,这样CNT在上升沿自动清零,通道2捕获值即为高电平时间。
步骤3:配置输入滤波器
根据信号频率设置IC Filter。滤波器采样频率 = fCK_INT / (PSC+1)(部分系列有独立分频),采样数N由滤波器位决定。滤波器会引入延迟,延迟时间 ≈ N / 采样频率。高频信号应减小滤波或关闭,避免延迟影响。
步骤4:中断与溢出处理
使能捕获中断和更新中断(溢出)。在ISR中记录溢出次数,计算差值时加上溢出补偿。对于高频PWM,建议使用DMA传输捕获值,减少CPU干预。
完整代码示例(基于STM32F1 HAL库)
// 定时器2输入捕获配置:CH1上升沿,CH2下降沿,从模式复位
TIM_HandleTypeDef htim2;
void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0; // 72MHz计数,分辨率13.9ns
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFF; // 最大计数值
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_IC_Init(&htim2);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);
// 从模式复位:TI1FP1触发复位
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;
sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;
sSlaveConfig.TriggerFilter = 0;
HAL_TIM_SlaveConfigSynchro(&htim2, &sSlaveConfig);
// 通道1:上升沿捕获,直接模式
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0; // 关闭滤波,避免延迟
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);
// 通道2:下降沿捕获,间接模式(映射到TI1)
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
}
// 捕获回调:计算频率与占空比
volatile uint32_t period = 0, high_time = 0;
volatile float duty = 0.0f;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
// 上升沿捕获,CNT已被复位,读取周期值(上一次周期)
period = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
} else if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
// 下降沿捕获,CNT从上升沿开始计数,直接为高电平时间
high_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
if (period > 0) {
duty = (float)high_time / period * 100.0f;
}
}
}
注意:上述代码利用从模式复位,上升沿将CNT清零,因此通道2捕获值即为高电平时间,通道1捕获值为周期(需在下一个上升沿读取)。若不用复位模式,则需分别捕获上升沿和下降沿并做差值,同时处理溢出。
注意事项与排查清单
- 预分频器宁小勿大:在满足计数器不溢出的前提下,尽量提高计数频率,降低量化误差。
- 滤波器谨慎使用:高频PWM下关闭或减小滤波器,避免边沿延迟导致脉宽测量偏小。
- 边沿配置必须成对:一个上升沿、一个下降沿,且注意直接/间接模式映射关系。
- 从模式复位时,确保触发源与捕获通道一致(如TI1FP1),否则CNT不会按预期复位。
- 中断优先级:捕获中断优先级应高于其他低速中断,防止丢失捕获事件。
- 溢出处理:若PWM周期大于计数器最大计数值,必须记录溢出次数,否则周期计算错误。
- 验证方法:用信号发生器输出固定占空比、不同频率的PWM,观察测量值是否稳定;若漂移,优先检查PSC和滤波器设置。
通过以上分析与配置,可彻底消除高电平宽度随频率漂移的现象,实现高精度的PWM占空比测量。
暂无评论,来抢沙发~