Bootstrap

ARM32开发——PWM与通用定时器

🎬 秋野酱:《个人主页》
🔥 个人专栏:《Java专栏》《Python专栏》

⛺️心若有所向往,何惧道阻且长

PWM

PWM全称是脉宽调制(Pulse Width Modulation),是一种通过改变信号的脉冲宽度来控制电路输出的技术。PWM技术在工业自动化、电机控制、LED调光等领域广泛应用。
PWM是一种将数字信号转换为模拟信号的技术,它通过改变信号的占空比来控制输出的电平。
在ARM32系列芯片中,PWM输出的频率和占空比可以由程序控制,因此可以用来控制各种电机、灯光和其他设备的亮度、速度等参。
在ARM32系列芯片中,PWM的调制是通过Timer来实现的。PWM与引脚相关,除了基本定时器以外,其他类型的Timer都可以作为PWM来进行使用。
在这里插入图片描述

pwm原理

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以PD14对应的LED4为例,我们做一个呼吸灯的效果。
我们采用TIMER3CH2进行实现:
在这里插入图片描述

开发流程

  1. 添加Timer依赖
  2. 初始化PWM
  3. PWM占空比控制
    初始化PWM

#define	PRESCALER	10		    // [1, 65536]
#define	FREQ		1000		// 1000Hz

// 保证分母 (FREQ * PRESCALER) >= 2564
#define PERIOD 				SystemCoreClock / (FREQ * PRESCALER)

// TIMER3_CH2
static void Timer_config() {
    // 通用定时器

    // GPIO PD14 =================================================================
    rcu_periph_clock_enable(RCU_GPIOD);
    gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_14);
    gpio_af_set(GPIOD, GPIO_AF_2, GPIO_PIN_14);

    // TIMER3C0 =================================================================
    // 初始化定时器配置
    rcu_periph_clock_enable(RCU_PERIPH);

    timer_deinit(TIMER_PERIPH);
    // 升级频率
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
    // 初始化参数
    timer_parameter_struct initpara;
    /* initialize TIMER init parameter struct */
    timer_struct_para_init(&initpara);
    /* 根据需要配置值 */
    initpara.prescaler = PRESCALER - 1;	// 分频系数 (可以实现更低的timer频率)
    // 1个周期的计数(period Max: 65535) Freq > 2564
    initpara.period		 = PERIOD - 1;
    /* initialize TIMER counter */
    timer_init(TIMER_PERIPH, &initpara);

    // TIMER通道输出配置
    timer_oc_parameter_struct ocpara;
    /* 初始化结构体参数 initialize TIMER channel output parameter struct */
    timer_channel_output_struct_para_init(&ocpara);
    /* 启用TM1 CH0的OP极(正极) */
    ocpara.outputstate  = (uint16_t)TIMER_CCX_ENABLE;
    /* 配置输出参数configure TIMER channel output function */
    timer_channel_output_config(TIMER_PERIPH, TIMER_CH, &ocpara);
    /* 配置通达输出比较模式 configure TIMER channel output compare mode */
    timer_channel_output_mode_config(TIMER_PERIPH, TIMER_CH, TIMER_OC_MODE_PWM0);
    /* 设置通道输出脉冲值 (修改占空比) configure TIMER channel output pulse value */
    timer_channel_output_pulse_value_config(TIMER_PERIPH, TIMER_CH, (PERIOD - 1) * 1.0f);

    /* enable a TIMER */
    timer_enable(TIMER_PERIPH);
}

PWM占空比控制

void PWM_update(float duty) { // 0 -> 100

    if(duty > 100) {
        duty = 100;
    } else if (duty < 0) {
        duty = 0;
    }
    // pulse / (PERIOD - 1) == duty / 100;
    uint32_t pulse = (PERIOD - 1) * duty / 100.0f;
    /* 设置通道输出脉冲值 (修改占空比) configure TIMER channel output pulse value */
    timer_channel_output_pulse_value_config(TIMER_PERIPH, TIMER_CH, pulse);

}

main函数修改duty

int main(void)
{
    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
    systick_config();
    USART0_init();

    Timer_config();
    printf("Init Complete!\n");

    PWM_update(0);

    float duty = 0;
    int dir = 1;
    while(1) {

        // printf发送字符串
        // 0 -> (PERIOD - 1) -> 0 -> ....

        if(duty >= 100) {
            dir = -1;
        } else if(duty <= 0) {
            dir = 1;
        }

        duty += dir;

        PWM_update(duty);

        delay_1ms(10);
    }
}

输出通道

这里完整配置为多种:

void timer_channel_output_struct_para_init(timer_oc_parameter_struct *ocpara)
{
    /* initialize the channel output parameter struct member with the default value */
    ocpara->outputstate  = (uint16_t)TIMER_CCX_DISABLE;
    ocpara->outputnstate = TIMER_CCXN_DISABLE;
    ocpara->ocpolarity   = TIMER_OC_POLARITY_HIGH;
    ocpara->ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    ocpara->ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    ocpara->ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
}

我们具体的可以分为两类:

ocpara->outputstate  = (uint16_t)TIMER_CCX_DISABLE;
ocpara->ocpolarity   = TIMER_OC_POLARITY_HIGH;
ocpara->ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
ocpara->outputnstate = TIMER_CCXN_DISABLE;
ocpara->ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
ocpara->ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;

特别观察API,带N的为反向,带P的为正向。赋值的结果常量也是需要注意是否带N。
P和N的配置主要出现在互补PWM中,如果当前的Timer不是高级定时器,那么就不具备互补的功能,那么我们一律认为他是P类型,也就是设置P才有用。
通过设置outputstate 的 ENABLE来控制输出通道的开启。

关心的内容

● 哪个定时器
● 哪个引脚输出pwm
● 周期和分频系数

重要的关键词

周期

在这里插入图片描述
pwm中,一个周期就是一次高低电平的变化。

分频

将原来的活增加几倍时间干完。

占空比

在这里插入图片描述

;