Loading...

文章背景图

GD32F307ZGT6简易PWM封装

2026-07-14
1
-
- 分钟

使用PE5,根据数据手册说明,可以重映射为TIMER8_CH0。

cf3e7607-a986-4b9b-b04b-c9fd06f8116b.png

代码实现:

#define PWM_TIMER              TIMER8
#define PWM_TIMER_RCU          RCU_TIMER8
#define PWM_GPIO_RCU           RCU_GPIOE
#define PWM_GPIO_PORT          GPIOE
#define PWM_GPIO_PIN           GPIO_PIN_5
#define PWM_CHANNEL            TIMER_CH_0

#define PWM_DUTY_MAX           10000U     // 10000 = 100.00%
#define PWM_MAX_COUNTS         65535U     // ARR+1, 留出 CCR=65535 支持 100%

static uint16_t s_pwm_arr;
static uint16_t s_pwm_duty_10000;
static uint8_t s_pwm_output_enabled = 0U;

static uint32_t timer8_clock_get(void)
{
    uint32_t pclk2 = rcu_clock_freq_get(CK_APB2);

    if ((RCU_CFG0 & RCU_CFG0_APB2PSC) == RCU_APB2_CKAHB_DIV1)
    {
        return pclk2;
    }
    else
    {
        return pclk2 * 2U;
    }
}

static void pwm_calc_millihz(uint64_t freq_millihz, uint16_t *psc, uint16_t *arr)
{
    uint32_t timer_clk;
    uint64_t total_counts_64;
    uint32_t total_counts;
    uint32_t psc_div;
    uint32_t arr_counts;

    timer_clk = timer8_clock_get();

    total_counts_64 = ((uint64_t)timer_clk * 1000ULL + freq_millihz / 2ULL) / freq_millihz;

    if (total_counts_64 < 2ULL)
    {
        total_counts_64 = 2ULL;
    }

    if (total_counts_64 > (65536ULL * 65535ULL))
    {
        total_counts_64 = 65536ULL * 65535ULL;
    }

    total_counts = (uint32_t)total_counts_64;

    psc_div = (total_counts + 65535U - 1U) / 65535U;

    if (psc_div < 1U)
    {
        psc_div = 1U;
    }
    if (psc_div > 65536U)
    {
        psc_div = 65536U;
    }

    arr_counts = (total_counts + psc_div / 2U) / psc_div;

    if (arr_counts < 2U)
    {
        arr_counts = 2U;
    }
    if (arr_counts > 65535U)
    {
        arr_counts = 65535U;
    }

    *psc = (uint16_t)(psc_div - 1U);
    *arr = (uint16_t)(arr_counts - 1U);
}

static uint16_t pwm_duty_to_ccr(uint16_t arr, uint16_t duty_10000)
{
    uint32_t counts = (uint32_t)arr + 1U;

    if (duty_10000 > PWM_DUTY_MAX)
    {
        duty_10000 = PWM_DUTY_MAX;
    }

    return (uint16_t)(((uint64_t)counts * duty_10000) / PWM_DUTY_MAX);
}

void pe5_pwm_set_millihz(uint64_t freq_millihz, uint16_t duty_10000)
{
    uint16_t psc;
    uint16_t arr;
    uint16_t ccr;

    if (duty_10000 > PWM_DUTY_MAX)
    {
        duty_10000 = PWM_DUTY_MAX;
    }

    pwm_calc_millihz(freq_millihz, &psc, &arr);
    ccr = pwm_duty_to_ccr(arr, duty_10000);

    s_pwm_arr = arr;
    s_pwm_duty_10000 = duty_10000;

    timer_prescaler_config(PWM_TIMER, psc, TIMER_PSC_RELOAD_UPDATE);
    timer_autoreload_value_config(PWM_TIMER, arr);
    timer_channel_output_pulse_value_config(PWM_TIMER, PWM_CHANNEL, ccr);

    // 立即装载 PSC/ARR/CCR 的影子寄存器
    timer_event_software_generate(PWM_TIMER, TIMER_EVENT_SRC_UPG);
}

void pe5_pwm_set_duty(uint16_t duty_10000)
{
    if (duty_10000 > PWM_DUTY_MAX)
    {
        duty_10000 = PWM_DUTY_MAX;
    }

    s_pwm_duty_10000 = duty_10000;
    timer_channel_output_pulse_value_config(PWM_TIMER, PWM_CHANNEL, pwm_duty_to_ccr(s_pwm_arr, duty_10000));
    timer_event_software_generate(PWM_TIMER, TIMER_EVENT_SRC_UPG);
}

void pe5_on(void)
{
    uint16_t ccr = pwm_duty_to_ccr(s_pwm_arr, s_pwm_duty_10000);

    s_pwm_output_enabled = 1U;

    timer_channel_output_pulse_value_config(PWM_TIMER, PWM_CHANNEL, ccr);
    timer_channel_output_state_config(PWM_TIMER, PWM_CHANNEL, TIMER_CCX_ENABLE);
    timer_primary_output_config(PWM_TIMER, ENABLE);
    timer_enable(PWM_TIMER);

    timer_event_software_generate(PWM_TIMER, TIMER_EVENT_SRC_UPG);
}

void pe5_off(void)
{
    s_pwm_output_enabled = 0U;

    // PWM0 + high polarity 下,CCR=0 等效为 0% 占空比,PE5 保持低电平
    timer_channel_output_pulse_value_config(PWM_TIMER, PWM_CHANNEL, 0U);

    timer_event_software_generate(PWM_TIMER, TIMER_EVENT_SRC_UPG);
}

void pe5_pwm_init(uint64_t freq_millihz, uint16_t duty_10000)
{
    static uint8_t once_flag = 0;
    
    if (once_flag)
    {
        return;
    }

    timer_parameter_struct timer_initpara;
    timer_oc_parameter_struct oc_initpara;

    rcu_periph_clock_enable(PWM_GPIO_RCU);
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(PWM_TIMER_RCU);

    gpio_pin_remap_config(GPIO_TIMER8_REMAP, ENABLE);
    gpio_init(PWM_GPIO_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, PWM_GPIO_PIN);

    timer_deinit(PWM_TIMER);

    timer_struct_para_init(&timer_initpara);
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection = TIMER_COUNTER_UP;
    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0U;
    timer_init(PWM_TIMER, &timer_initpara);

    timer_channel_output_struct_para_init(&oc_initpara);
    oc_initpara.outputstate = TIMER_CCX_ENABLE;
    oc_initpara.outputnstate = TIMER_CCXN_DISABLE;
    oc_initpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
    oc_initpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
    oc_initpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
    oc_initpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;

    timer_channel_output_config(PWM_TIMER, PWM_CHANNEL, &oc_initpara);
    timer_channel_output_mode_config(PWM_TIMER, PWM_CHANNEL, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(PWM_TIMER, PWM_CHANNEL, TIMER_OC_SHADOW_ENABLE);
    timer_auto_reload_shadow_enable(PWM_TIMER);

    pe5_pwm_set_millihz(freq_millihz, duty_10000);

    timer_primary_output_config(PWM_TIMER, ENABLE);
    timer_enable(PWM_TIMER);
}

原创

GD32F307ZGT6简易PWM封装

本文链接: GD32F307ZGT6简易PWM封装

本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

评论交流

文章目录