STM32 定时器输入捕获:频率与脉宽测量实战指南
👁 3 阅读 · 2026-08-15 · STM32 定时器
输入捕获是STM32定时器的重要功能,广泛应用于频率、周期、脉宽及占空比测量。本文从捕获原理出发,结合TIM时基与捕获通道配置,以STM32F103为例,详解使用PWM输入模式测量频率和占空比的方法,并给出基于寄存器级别的完整代码示例,帮助开发者深入理解并快速落地。
## 一、输入捕获原理概述
输入捕获模式通过定时器通道检测外部信号的边沿(上升沿或下降沿),并在边沿到来时将当前计数器值(CNT)锁存到捕获寄存器(CCR)中。通过连续两次捕获的计数值差值,结合定时器时钟频率,即可计算出信号的周期或高电平时间。
对于频率测量,通常捕获相邻两个上升沿的CNT值,其差值即为一个完整周期内的计数个数。若定时器分频后计数频率为`f_clk`,则信号频率为`f_clk / (capture2 - capture1)`。
对于脉宽(高电平时间)测量,则需捕获上升沿和下降沿的CNT值,两者之差对应高电平持续时间。
## 二、硬件资源与测量方案
以STM32F103系列为例,常用定时器TIM2、TIM3、TIM4、TIM5均支持输入捕获。每个定时器有4个独立通道,且每个通道可映射到不同的引脚。
测量方案有两种常用方式:
- **单通道捕获**:手动切换捕获边沿,先捕获上升沿,再捕获下降沿,计算脉宽。适合单通道实现,但需在中断中修改边沿极性。
- **PWM输入模式**:使用同一定时器的两个通道(CH1和CH2)分别捕获上升沿和下降沿,硬件自动完成,无需切换极性,配合主从模式可同时获得周期和脉宽。
本文重点讲解PWM输入模式,因其效率最高,尤其适合测量PWM信号的频率和占空比。
## 三、PWM输入模式原理
STM32的PWM输入模式是输入捕获的一种特殊用法,它将TIMx_CH1映射到IC1和IC2两个捕获单元:
- IC1捕获上升沿,记录周期计数值;
- IC2捕获下降沿,记录脉宽计数值。
通过配置触发选择(TS=TI1FP1)和从模式(复位模式),使计数器在上升沿清零,从而CCR1直接存储周期值,CCR2直接存储脉宽值。这样无需中断处理即可实时读取两个寄存器,频率和占空比可通过简单计算获得。
## 四、寄存器配置步骤
以TIM3为例,使用CH1(PA6)作为PWM输入引脚,具体配置步骤如下:
1. **开启时钟**:使能GPIOA和TIM3时钟。
2. **配置GPIO**:PA6设置为浮空输入(或上拉输入,根据外部信号电平)。
3. **设置时基**:配置PSC预分频器,使计数频率适合待测信号。例如,72MHz时钟,PSC=71,则计数频率为1MHz,分辨率1μs。
4. **配置捕获通道**:将CH1设置为输入捕获,映射到TI1(即直接连接),并选择上升沿触发IC1,同时通过CC1S选择IC1映射到TI1。
5. **设置捕获边沿**:IC1上升沿,IC2下降沿(通过CCER配置CC1P=0,CC2P=1)。
6. **配置触发和从模式**:设置TS=101(TI1FP1),SMS=100(复位模式)。
7. **使能捕获和定时器**:使能CC1E、CC2E,最后使能TIM3。
## 五、完整代码示例(寄存器版)
```c
// 使用TIM3_CH1 (PA6) 测量PWM频率和占空比
// 系统时钟72MHz,计数频率1MHz
void TIM3_PWM_Input_Init(void)
{
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // 使能TIM3时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // 使能GPIOA时钟
// PA6 浮空输入(外部信号驱动)
GPIOA->CRL &= ~(0xF << (6 * 4));
GPIOA->CRL |= (0x4 << (6 * 4)); // CNF=01, MODE=00 => 浮空输入
// 时基配置:PSC=71, ARR=0xFFFF(最大计数)
TIM3->PSC = 71; // 72MHz / 72 = 1MHz,每计数1次=1us
TIM3->ARR = 0xFFFF;
// 通道1映射到TI1,上升沿捕获(IC1)
TIM3->CCMR1 |= (0x1 << 0); // CC1S=01, IC1映射到TI1
TIM3->CCER &= ~(0x1 << 1); // CC1P=0, 上升沿捕获
// 通道2映射到TI1,下降沿捕获(IC2)
TIM3->CCMR1 |= (0x1 << 8); // CC2S=01, IC2映射到TI1
TIM3->CCER |= (0x1 << 5); // CC2P=1, 下降沿捕获
// 触发选择:TI1FP1作为触发输入
TIM3->SMCR |= (0x5 << 4); // TS=101
// 从模式:复位模式,上升沿清零计数器
TIM3->SMCR |= (0x4 << 0); // SMS=100
// 使能捕获通道
TIM3->CCER |= (0x1 << 0); // CC1E=1
TIM3->CCER |= (0x1 << 4); // CC2E=1
// 使能TIM3
TIM3->CR1 |= TIM_CR1_CEN;
}
typedef struct {
uint32_t frequency; // 单位Hz
uint32_t duty; // 占空比(百分比整数)
} PWM_Result;
void PWM_Measure(PWM_Result *result)
{
uint32_t period = TIM3->CCR1; // 周期计数值
uint32_t pulse = TIM3->CCR2; // 脉宽计数值
if (period == 0) {
result->frequency = 0;
result->duty = 0;
return;
}
// 频率 = 1MHz / period (单位Hz)
result->frequency = 1000000UL / period;
// 占空比 = pulse / period * 100%
result->duty = (uint32_t)((uint64_t)pulse * 100 / period);
}
int main(void)
{
PWM_Result result;
TIM3_PWM_Input_Init();
while (1) {
PWM_Measure(&result);
// 在此使用result.frequency和result.duty,如串口输出
// 注意调用间隔要大于一个输入周期,否则可能读到中间值
delay_ms(100);
}
}
```
## 六、注意事项
- **预分频与精度**:计数器频率越高,测量精度越高,但可测最大周期受ARR限制。若ARR=65535,计数频率1MHz时最大周期约65.5ms,即最小频率约15Hz。测量更高周期需降低计数频率或使用更高位定时器(如TIM2/TIM5为32位)。
- **信号质量**:输入信号应具有良好的边沿陡峭度,必要时使用外部施密特触发器整形,避免抖动引起误捕获。
- **溢出处理**:当信号周期大于定时器溢出周期时,需要在中断中处理计数器溢出(更新中断),累加溢出次数。若使用PWM输入模式,在复位模式下计数器不会自由溢出至ARR,因此适用于周期小于ARR的信号。
- **连续读取一致性**:在读取CCR1和CCR2时,两个寄存器并非原子更新,若在电机控制等实时性要求高的场景,建议先读取后验证或使用暂停计数器的方法,避免读到混合周期的新旧值。
- **通道映射**:PWM输入模式下,IC1和IC2的滤波(ICF)可配置以滤除高频毛刺,但会增加信号延迟,需权衡。
## 七、总结
利用STM32定时器的输入捕获功能,可以高效、精准地测量外部信号的频率和脉宽。PWM输入模式通过硬件自动捕获周期和脉宽,极大简化了软件逻辑。开发者只需正确配置时基、捕获通道和从模式,即可在主循环中直接读取结果,非常适合实时性要求高的嵌入式应用。掌握这一技术,也为后续实现编码器测速、红外解码等高级功能打下坚实基础。