一、STM32F407 PWM 捕获功能简介
STM32F407的定时器(TIM)模块支持输入捕获功能,用于测量外部PWM信号的频率和占空比。关键特性包括:
多通道支持:每个定时器最多4个独立捕获通道(如TIM2/TIM3/TIM4/TIM5)。
高精度测量:支持16位/32位计数器,最高计数频率84 MHz(APB1时钟)。
双边沿触发:可捕获上升沿和下降沿时间戳,计算脉冲宽度和周期。
硬件滤波:通过数字滤波器抑制输入噪声。
DMA支持:自动传输捕获值,减少CPU中断负载。
二、HAL库配置PWM捕获的关键步骤
- 初始化定时器(以TIM3通道1为例)
c
TIM_HandleTypeDef htim3;
// 定时器基础配置
htim3.Instance = TIM3;
htim3.Init.Prescaler = 84 - 1; // 分频系数(APB1时钟=84MHz → 定时器时钟=1MHz)
htim3.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
htim3.Init.Period = 0xFFFF; // 自动重载值设为最大(65535),防止溢出
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频(无分频)
HAL_TIM_IC_Init(&htim3); // 初始化输入捕获模式
// 配置输入捕获通道1(PA6复用为TIM3_CH1)
TIM_IC_InitTypeDef sConfigIC;
sConfigIC.ICPolarity = TIM_ICPOLARITY_BOTHEDGE; // 双边沿触发
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; // 直接连接到TI1输入
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; // 无分频,每个边沿都捕获
sConfigIC.ICFilter = 0x0; // 关闭输入滤波器
HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1);
- 配置GPIO为输入捕获模式
c
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_6; // PA6对应TIM3_CH1
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽模式
GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉电阻避免悬空
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3; // 复用功能为TIM3
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- 配置中断或DMA
中断模式(推荐用于实时性要求高的场景)
c
// 启用捕获中断
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
// 中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
static uint32_t first_edge = 0, second_edge = 0;
static uint32_t period = 0, pulse_width = 0;
if (first_edge == 0) {
first_edge = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
} else {
second_edge = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
// 计算周期和占空比(单位:微秒,假设定时器时钟1MHz)
period = second_edge - first_edge;
pulse_width = (htim->Instance->CCR2 - first_edge); // 假设使用通道2捕获下降沿
first_edge = 0; // 重置为下一次捕获
// 示例输出:周期和脉宽
printf("Period: %lu us, Pulse Width: %lu us\n", period, pulse_width);
}
}
}
DMA模式(适合高频信号,减少CPU中断)
c
// 配置DMA传输捕获值到内存
DMA_HandleTypeDef hdma_tim3_ch1;
hdma_tim3_ch1.Instance = DMA1_Stream4; // TIM3_CH1对应DMA1 Stream4
hdma_tim3_ch1.Init.Channel = DMA_CHANNEL_5; // 通道5
hdma_tim3_ch1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_tim3_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim3_ch1.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim3_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; // 32位对齐
hdma_tim3_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_tim3_ch1.Init.Mode = DMA_CIRCULAR; // 循环模式
hdma_tim3_ch1.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_tim3_ch1);
__HAL_LINKDMA(&htim3, hdma[TIM_DMA_ID_CC1], hdma_tim3_ch1);
// 启动DMA捕获
uint32_t capture_buffer[2]; // 存储两次捕获值
HAL_TIM_IC_Start_DMA(&htim3, TIM_CHANNEL_1, capture_buffer, 2);
- 处理捕获数据
频率计算:
占空比计算:
三、优缺点分析
优点:
高精度测量
硬件级时间戳捕获,分辨率可达1μs(1MHz定时器时钟),适合高精度应用(如电机转速检测)。
支持双边沿触发,单次捕获即可计算周期和占空比。
低CPU开销
DMA模式无需CPU干预,适合多通道或高频信号(如超声波测距)。
中断响应快,实时性强。
抗噪声能力
数字滤波器(ICFilter)可抑制短时脉冲干扰,提升信号稳定性。
缺点:
配置复杂度高
需协调定时器分频、捕获极性、DMA通道映射,配置错误易导致数据异常。
多通道同步捕获时,需处理数据对齐和溢出问题。
硬件资源限制
定时器通道有限,多路PWM捕获需分配多个定时器(如TIM2+TIM3+TIM4)。
高频信号(>1MHz)可能导致计数器溢出,需缩短自动重载值(ARR)。
中断延迟影响
高频率信号下,中断处理延迟可能导致数据丢失,需优化代码或使用DMA。
四、关键注意事项
定时器溢出处理
若信号周期超过ARR值,需启用溢出中断并计算总周期:
c
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
overflow_count++; // 溢出计数器
}
// 总周期 = (overflow_count * ARR) + captured_value
信号边沿抖动
启用输入滤波器(ICFilter)抑制噪声:
c
sConfigIC.ICFilter = 0x6; // 6个时钟周期的滤波
多通道协同工作
使用从模式(Slave Mode)同步多个定时器,实现多路信号精确对齐。
DMA缓冲区管理
循环DMA模式下,需双缓冲区切换防止数据覆盖:
c
uint32_t buffer1[2], buffer2[2];
HAL_TIM_IC_Start_DMA(&htim3, TIM_CHANNEL_1, buffer1, 2);
// 在DMA完成回调中切换缓冲区
五、适用场景
电机控制:测量编码器信号、转速反馈。
电源管理:监测开关电源的PWM调制信号。
通信解码:解析红外遥控器或无线模块的PWM编码。
传感器接口:超声波测距、舵机控制信号检测。
六、常见问题与解决方案
捕获值始终为0
原因:GPIO未正确配置或信号未到达。
解决:
检查GPIO复用功能和外部信号连接。
使用示波器验证信号是否输入到MCU引脚。
测量结果波动大
原因:输入信号噪声或未启用滤波。
解决:
增加ICFilter值(如0x6)。
在硬件端添加RC低通滤波器。
DMA传输不连续
原因:DMA缓冲区长度不足或未启用循环模式。
解决:
确保DMA配置为循环模式(DMA_CIRCULAR)。
增大缓冲区长度或使用双缓冲策略。
高频信号测量溢出
原因:ARR值过小导致频繁溢出。
解决:
降低定时器分频系数(如Prescaler=0,定时器时钟=84MHz)。
使用32位定时器(如TIM2/TIM5)扩展计数范围。
通过合理配置,PWM捕获功能能够高效实现信号参数测量,但在高频或多通道场景中需精细优化硬件和软件设计。