You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32蓝板(Bluepill) Timer1无法输出PWM至GPIO引脚问题排查

STM32F103 Bluepill Timer1 PWM输出异常排查(libopencm3)

问题描述

使用STM32F103蓝板(Bluepill)搭配libopencm3库,尝试通过Timer1在PA8引脚输出PWM信号,同时利用定时器比较中断触发板载LED(PC13)翻转。目前中断功能正常(LED按预期24Hz翻转,计数数值符合预期),但PA8的PWM信号未正常输出,附代码如下:

#include <stdlib.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h>
#include <libopencm3/stm32/timer.h>
#include <libopencm3/cm3/nvic.h>

void tim1_cc_isr(){
    timer_clear_flag(TIM1, TIM_SR_CC1IF);
    gpio_toggle(GPIOC, GPIO13);
}

int main(void)
{
    unsigned int i;

    // Initialize the master clock
    rcc_clock_setup_in_hse_8mhz_out_72mhz();

    rcc_periph_clock_enable(RCC_GPIOA);
    rcc_periph_clock_enable(RCC_GPIOC);

    gpio_set(GPIOC, GPIO13);
    gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
              GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);

    // Timer clocks
    rcc_periph_clock_enable(RCC_AFIO);
    rcc_periph_clock_enable(RCC_TIM1);

    timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_CENTER_1,
                TIM_CR1_DIR_UP);
    timer_enable_oc_output(TIM1, TIM_OC1);
    timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1);
    timer_set_oc_polarity_low(TIM1, TIM_OC1);
    gpio_set_mode(GPIO_BANK_TIM1_CH1, 
                GPIO_MODE_OUTPUT_2_MHZ, 
                GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_TIM1_CH1);

    // Set Period
    timer_set_prescaler(TIM1, 1000); 
    // Count to 750 for 24Hz
    timer_set_period(TIM1, 750);
    timer_clear_flag(TIM1, TIM_SR_CC1IF);
    timer_set_oc_value(TIM1, TIM_OC1, 350);
    timer_enable_counter(TIM1);
    
    nvic_enable_irq(NVIC_TIM1_CC_IRQ);
    timer_enable_irq(TIM1, TIM_DIER_CC1IE);
    while(1){}
}

问题排查与修复方案

  • 高级定时器主输出未使能:STM32F1的高级定时器(TIM1)默认关闭主输出,即使配置了通道OC输出,不开启主输出引脚不会有PWM信号。必须添加:
    timer_enable_break_main_output(TIM1);
    
  • GPIO速率不匹配:系统时钟为72MHz,PA8作为TIM1_CH1输出,建议将GPIO速率提升至GPIO_MODE_OUTPUT_10_MHZ,避免信号失真。
  • 定时器模式冲突:你同时设置了中心对齐模式(TIM_CR1_CMS_CENTER_1)和向上计数(TIM_CR1_DIR_UP),中心对齐模式下计数方向会自动切换,无需手动指定向上计数,可改为边沿对齐模式(TIM_CR1_CMS_EDGE)或保留中心对齐但移除TIM_CR1_DIR_UP参数。
  • 预分频器计算错误:当前预分频器设置为1000时,实际频率与预期24Hz不符。正确计算:72MHz / (PSC+1) / (ARR+1) =24Hz → (PSC+1)*(ARR+1)=3e6。若ARR设为749(周期750),则PSC需设为3999。

修改后的完整代码

#include <stdlib.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/timer.h>
#include <libopencm3/cm3/nvic.h>

void tim1_cc_isr(){
    timer_clear_flag(TIM1, TIM_SR_CC1IF);
    gpio_toggle(GPIOC, GPIO13);
}

int main(void)
{
    // Initialize the master clock
    rcc_clock_setup_in_hse_8mhz_out_72mhz();

    rcc_periph_clock_enable(RCC_GPIOA);
    rcc_periph_clock_enable(RCC_GPIOC);

    gpio_set(GPIOC, GPIO13);
    gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
              GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);

    // Timer clocks
    rcc_periph_clock_enable(RCC_AFIO);
    rcc_periph_clock_enable(RCC_TIM1);

    // 使用边沿对齐模式,避免方向设置冲突
    timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
    timer_enable_oc_output(TIM1, TIM_OC1);
    timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1);
    timer_set_oc_polarity_low(TIM1, TIM_OC1);
    // 提升GPIO输出速率
    gpio_set_mode(GPIO_BANK_TIM1_CH1, 
                GPIO_MODE_OUTPUT_10_MHZ, 
                GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_TIM1_CH1);

    // 修正预分频器与周期,确保24Hz频率
    timer_set_prescaler(TIM1, 3999); 
    timer_set_period(TIM1, 749);
    timer_clear_flag(TIM1, TIM_SR_CC1IF);
    timer_set_oc_value(TIM1, TIM_OC1, 350);
    // 开启TIM1主输出(高级定时器必需)
    timer_enable_break_main_output(TIM1);
    timer_enable_counter(TIM1);
    
    nvic_enable_irq(NVIC_TIM1_CC_IRQ);
    timer_enable_irq(TIM1, TIM_DIER_CC1IE);
    while(1){}
}

内容的提问来源于stack exchange,提问作者EdL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 15:42:27