[研电赛技术支持] GD32F470的PWM呼吸灯

[复制链接]
513|0
观海 发表于 2025-10-11 07:47 | 显示全部楼层 |阅读模式
1. PWM 是什么?
PWM(Pulse Width Modulation,脉宽调制):通过控制“高电平的时间占比”,来调节负载获得的平均能量。

应用:LED 调光、直流电机调速、蜂鸣器音调控制等。

波形特征:

周期 固定(由频率决定)

高电平持续时间 可变(由占空比决定)


2. PWM 频率公式

9602868e8886b04410.png

3. 占空比与平均电压

220668e888580073a.png

6151868e8884f4d8da.png

代码


#include "pwm.h"

/* -------- 硬件相关宏定义 -------- */
#define PWM_GPIO_PORT      GPIOA           // 使用的 GPIO 端口:A 组
#define PWM_GPIO_PIN       GPIO_PIN_6      // 使用的引脚:PA6
#define PWM_GPIO_AF        GPIO_AF_2       // 复用功能号:PA6 → TIM2_CH0,选择 AF2

#define PWM_TIMER          TIMER2          // 绑定的定时器:TIM2
#define PWM_TIMER_CHANNEL  TIMER_CH_0      // 使用的定时器通道:CH0

/* 定时器时钟频率:84 MHz
* 注:APB1 总线如果分频不为 1,定时器时钟=2×APB1。这里假设算下来就是 84 MHz。
*/
#define TIM_CLK            84000000UL

/* ================= GPIO 初始化 ================= */
void pwm_gpio_init(void) {
    // 打开 GPIOA 时钟
    rcu_periph_clock_enable(RCU_GPIOA);

    // 打开定时器 TIM2 的时钟
    rcu_periph_clock_enable(RCU_TIMER2);

    // 设置 PA6 为复用模式 (AF),不使用上下拉
    // 参数1:端口
    // 参数2:模式(AF = 复用功能)
    // 参数3:上拉/下拉
    // 参数4:引脚
    gpio_mode_set(PWM_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, PWM_GPIO_PIN);

    // 设置 PA6 的输出属性:推挽输出,速度 50MHz
    // 参数1:端口
    // 参数2:输出类型(推挽/开漏)
    // 参数3:速度等级
    // 参数4:引脚
    gpio_output_options_set(PWM_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, PWM_GPIO_PIN);

    // 把 PA6 绑定到 TIM2_CH0 的复用功能 AF2
    // 参数1:端口
    // 参数2:复用功能号
    // 参数3:引脚
    gpio_af_set(PWM_GPIO_PORT, PWM_GPIO_AF, PWM_GPIO_PIN);
}

/* ================= 定时器 PWM 初始化 ================= */
void pwm_timer_init(uint32_t freq_hz) {
    timer_parameter_struct timer_initpara;

    /* --- 1. 计算预分频器 PSC 和 自动重装载值 ARR --- */
    uint32_t psc = 83;   // PSC=83 → 定时器时钟=84MHz/(83+1)=1MHz → 1us计数一次
    uint32_t arr = (TIM_CLK / (psc + 1)) / freq_hz - 1;
                        // ARR = (定时器时钟/psc)/(目标频率) - 1
                        // 举例 freq_hz=1000 → arr=999 → 周期1ms → 1kHz PWM

    if (arr > 0xFFFF) {
        arr = 0xFFFF;   // 限制 ARR 不超过 16 位定时器的最大值
    }

    /* --- 2. 配置定时器基本参数 --- */
    timer_struct_para_init(&timer_initpara);   // 初始化结构体为默认值

    timer_initpara.prescaler         = psc;                 // 设置预分频器
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;  // 边沿对齐模式(常用)
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;    // 向上计数
    timer_initpara.period            = arr;                 // 设置 ARR 值
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;    // 时钟不再分频
    timer_initpara.repetitioncounter = 0;                   // 重复计数器(一般 0)

    timer_deinit(PWM_TIMER);               // 清空定时器配置(复位)
    timer_init(PWM_TIMER, &timer_initpara);// 应用新配置

    /* --- 3. 配置通道输出参数 --- */
    timer_oc_parameter_struct ocpara;
    timer_channel_output_struct_para_init(&ocpara); // 初始化输出比较结构体

    ocpara.outputstate = TIMER_CCX_ENABLE;         // 打开通道输出
    ocpara.ocpolarity  = TIMER_OC_POLARITY_HIGH;   // 有效电平为高电平

    // 应用到指定定时器和通道
    // 参数1:定时器
    // 参数2:通道号
    // 参数3:OC配置结构体指针
    timer_channel_output_config(PWM_TIMER, PWM_TIMER_CHANNEL, &ocpara);

    /* --- 4. 设置通道为 PWM 模式 --- */
    // PWM0 模式:计数器 < CCR → 输出高电平;否则低电平
    timer_channel_output_mode_config(PWM_TIMER, PWM_TIMER_CHANNEL, TIMER_OC_MODE_PWM0);

    // 禁用影子寄存器(写CCR立即生效)
    timer_channel_output_shadow_config(PWM_TIMER, PWM_TIMER_CHANNEL, TIMER_OC_SHADOW_DISABLE);

    /* --- 5. 设置初始占空比 --- */
    // CCR = (ARR+1)/2 → 50% 占空比
    timer_channel_output_pulse_value_config(PWM_TIMER, PWM_TIMER_CHANNEL, (arr + 1) / 2);

    /* --- 6. 启动定时器 --- */
    timer_auto_reload_shadow_enable(PWM_TIMER); // 允许ARR影子更新
    timer_enable(PWM_TIMER);                    // 启动定时器
}

/* ================= 设置占空比函数 ================= */
void pwm_set_duty(uint16_t ccr_val) {
    // 参数1:定时器
    // 参数2:通道
    // 参数3:比较值 CCR(范围 0~ARR)
    timer_channel_output_pulse_value_config(PWM_TIMER, PWM_TIMER_CHANNEL, ccr_val);
}




/************************************************************
* 版权:2025CIMC Copyright。
* 文件:Function.c
* 作者: Lingyu Meng
* 平台: 2025CIMC IHD-V04
* 版本: Lingyu Meng     2025/2/16     V0.01    original
************************************************************/


/************************* 头文件 *************************/

#include "Function.h"

/************************* 宏定义 *************************/


/************************ 变量定义 ************************/


/************************ 函数定义 ************************/


void System_Init(void)
{
        systick_config();     // 时钟配置
        pwm_gpio_init();     // 配置 PA6 为 PWM 输出引脚
    pwm_timer_init(1000);    // 启动定时器 PWM 输出,初始占空比 50%
       
}

void UsrFunction(void)
{
        int ccr = 0;         // 当前占空比对应的 CCR 值
    int step = 1;        // 步进值,决定每次加/减多少
       
        while(1)
        {
               
                pwm_set_duty(ccr);   // 设置当前占空比(CCR)

        // 粗略延时 ≈ 2ms,决定“呼吸速度”
        for (volatile int i = 0; i < 16000; ++i);

        // 改变占空比,呼吸渐变
        ccr += step;
        if (ccr >= 1000) { ccr = 1000; step = -1; }  // 达上限后开始减
        if (ccr <= 0)    { ccr = 0;    step = +1; }  // 达下限后开始加
       
        }
}







————————————————
版权声明:本文为CSDN博主「lanhua1304403542」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lanhua1304403542/article/details/151936334

您需要登录后才可以回帖 登录 | 注册

本版积分规则

153

主题

4385

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部