STM32 定时器(PWM输入捕获)

发布于:2025-08-29 ⋅ 阅读:(20) ⋅ 点赞:(0)

以下是基于STM32标准库(以STM32F103为例)实现PWM输入模式(自动双沿捕获)的完整代码,通过配置定时器的PWM输入模式,可自动捕获外部PWM信号的周期(频率)​占空比,无需手动切换边沿。


🛠 ​完整代码实现

1. 硬件配置
  • 引脚​:PA6(TIM3_CH1,支持PWM输入模式)
  • 定时器​:TIM3(支持从模式复位)
  • 功能​:自动捕获上升沿(周期)和下降沿(占空比)
#include "stm32f10x.h"

// 全局变量存储PWM参数
volatile uint32_t PWM_Period = 0;    // 周期值(频率计算用)
volatile uint32_t PWM_Duty = 0;      // 占空比值

// 初始化函数
void PWM_Input_Init(void) 
{
    // 1. 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    // 2. 配置PA6为浮空输入(复用功能)
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;  // 浮空输入
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 3. 定时器基础配置(1MHz计数频率,72MHz主频分频后)
    TIM_TimeBaseInitTypeDef TIM_BaseStruct;
    TIM_BaseStruct.TIM_Period = 0xFFFF;                 // ARR = 65535(最大计数)
    TIM_BaseStruct.TIM_Prescaler = 72 - 1;              // 72分频 → 1MHz计数
    TIM_BaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_BaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_BaseStruct);

    // 4. 配置PWM输入模式(关键!)
    TIM_ICInitTypeDef TIM_ICStruct;
    TIM_ICStruct.TIM_Channel = TIM_Channel_1;            // 通道1(PA6)
    TIM_ICStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿触发
    TIM_ICStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; // 直接输入
    TIM_ICStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;       // 不分频
    TIM_ICStruct.TIM_ICFilter = 0x0;                     // 无滤波
    TIM_PWMIConfig(TIM3, &TIM_ICStruct);                // 自动配置双通道

    // 5. 从模式配置(复位模式)
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);       // TI1作为触发源
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);     // 触发时复位计数器

    // 6. 开启捕获中断
    TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2, ENABLE); // 使能通道1&2中断

    // 7. 配置NVIC
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    // 8. 启动定时器
    TIM_Cmd(TIM3, ENABLE);
}

// 中断服务函数
void TIM3_IRQHandler(void) 
{
    if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) {   // 通道1中断(周期捕获)
        PWM_Period = TIM_GetCapture1(TIM3);             // 读取周期值(上升沿时间)
        TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);        // 清除标志
    }
    if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET) {   // 通道2中断(占空比捕获)
        PWM_Duty = TIM_GetCapture2(TIM3);               // 读取占空比值(下降沿时间)
        TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
    }
}

// 计算频率(Hz)和占空比(%)
float PWM_Get_Frequency(void) 
{
    return 1000000.0f / (PWM_Period );  // 1MHz计数 → 单位:Hz
}

float PWM_Get_DutyCycle(void) 
{
    return (PWM_Duty + 0.0f) / (PWM_Period + 0.0f) * 100.0f; // 占空比百分比
}

⚙️ ​工作原理

  1. PWM输入模式

    • 使用 TIM_PWMIConfig() 自动配置两个通道:
      • 通道1(直接输入)​​:捕获上升沿 → ​周期值存入CCR1。
      • 通道2(间接输入)​​:捕获下降沿 → ​占空比值存入CCR2。
    • 无需手动切换极性,硬件自动完成双沿捕获。
  2. 从模式复位

    • 触发源设为 TI1FP1(通道1的滤波后信号)。
    • 从模式设为 Reset:上升沿时复位计数器,确保每次捕获的周期值准确。
  3. 参数计算

    • 频率​:Freq = 1MHz / (CCR1)
    • 占空比​:Duty = (CCR2) / (CCR1) * 100%

⚠️ ​关键注意事项

  1. 引脚复用
    • 确保PA6映射到TIM3_CH1(参考芯片手册)。
  2. 时钟配置
    • 默认使用72MHz系统时钟,需在 SystemInit() 中正确配置。
  3. 抗干扰设计
    • 若信号抖动大,增加 TIM_ICStruct.TIM_ICFilter(0-15)滤波。
  4. 测量范围
    • 最大频率受限于定时器计数频率(1MHz下最高约500kHz)。

🔍 ​扩展应用

  • 多通道捕获​:若需同时捕获多路PWM,使用不同定时器(如TIM2/TIM4)。
  • 高精度需求​:减少预分频值(如 TIM_Prescaler = 0)可提升计时分辨率。
  • 实时处理​:在中断中直接计算频率/占空比,避免全局变量延迟。

此代码通过STM32硬件自动完成双沿捕获,显著降低CPU负载,适用于电机控制、遥控信号解析等场景。实际使用时需根据信号特性调整滤波参数,并注意定时器溢出处理(如信号周期 > 65ms)