ARM32开发--PWM高级定时器

发布于:2024-06-16 ⋅ 阅读:(26) ⋅ 点赞:(0)

目录

文章目录

前言

目标

学习内容

需求

高级定时器通道互补输出

开发流程

通道配置

打开互补保护电路

完整代码

练习题

总结


前言

在嵌入式软件开发中,PWM(脉冲宽度调制)技术被广泛应用于控制各种电子设备的亮度、速度等参数。理解PWM开发流程、定时器与通道的关系,掌握多通道配置策略和互补PWM配置策略,以及掌握定时器查询方式和代码抽取优化策略,对于提高嵌入式软件开发的效率和质量至关重要。

本次学习的目标是点亮2个LED灯,采用互补PWM的方式来控制互补LED效果。通过学习高级定时器通道互补输出,我们将逐步了解如何初始化PWM、配置通道的P极和N极、控制PWM占空比,以实现目标效果。


目标

  1. 加强掌握PWM开发流程
  2. 理解定时器与通道的关系
  3. 掌握多通道配置策略
  4. 掌握互补PWM配置策略
  5. 掌握定时器查询方式
  6. 掌握代码抽取优化策略
  7. 掌握PWM调试方式

学习内容

需求

点亮2个灯,采用互补pwm的方式

定时器

通道

引脚

AF

极性

LED序号

T0

ch0

PE8

AF1

ON

LED1

PE9

AF1

OP

LED2

将PE8短接至PD8,PE9短接至PD9,实现互补LED效果。

高级定时器通道互补输出

开发流程

  1. 添加Timer依赖
  2. 初始化PWM
  3. 配置通道的P极和N极
  4. PWM占空比控制

通道配置


void timer_channel_config(uint32_t timer_periph, uint16_t channel) {
  /* TIMER 通道输出配置 */
  timer_oc_parameter_struct ocpara;
  /* initialize TIMER channel output parameter struct */
  timer_channel_output_struct_para_init(&ocpara);
  ocpara.outputstate  = TIMER_CCX_ENABLE;        // OP Enable
  ocpara.outputnstate = TIMER_CCXN_ENABLE;       // ON Enable
  ocpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;   // OP Polarity
  ocpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;  // ON Polarity
  /* 配置输出参数 configure TIMER channel output function */
  timer_channel_output_config(timer_periph, channel, &ocpara);
  /* 配置通道输出输出比较模式 configure TIMER channel output compare mode */
  timer_channel_output_mode_config(timer_periph, channel, TIMER_OC_MODE_PWM0);
}
  • ocnpolarity:N极性电平
  • ocpolarity:P极性电平

打开互补保护电路

// break 只针对高级定时器TIMER0 & TIMER7,打开互补保护电路
/* TIMER通道互补保护电路 */
timer_break_parameter_struct breakpara;
/* 初始化TIMER break参数结构体 */
timer_break_struct_para_init(&breakpara);
/* break输入的极性 HIGH */
breakpara.breakpolarity   = TIMER_BREAK_POLARITY_HIGH;
/* 输出自动的启用 */
breakpara.outputautostate = TIMER_OUTAUTO_ENABLE;
/* break输入的启用*/
breakpara.breakstate      = TIMER_BREAK_ENABLE;
/* 配置TIMER0 break */
timer_break_config(TIMER0, &breakpara);
/* 启用TIMER0 break */
timer_break_enable(TIMER0);

完整代码

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "USART0.h"

void USART0_on_recv(uint8_t* data, uint32_t len) {
  printf("g_rx_buffer: %s g_rx_cnt:%d \n", data, len);
}

static void GPIO_config() {
  rcu_periph_clock_enable(RCU_GPIOC);
  gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
  gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);

  gpio_bit_reset(GPIOC, GPIO_PIN_6);
  
//  rcu_periph_clock_enable(RCU_GPIOD);
//  gpio_mode_set(GPIOD, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_8 | GPIO_PIN_9);
}

void timer_gpio_config(uint32_t gpio_rcu, uint32_t gpio_port, uint32_t gpio_pin, uint32_t gpio_af) {
  rcu_periph_clock_enable(gpio_rcu);
  /* 设置gpio模式 */
  gpio_mode_set(gpio_port, GPIO_MODE_AF, GPIO_PUPD_NONE, gpio_pin);
  gpio_output_options_set(gpio_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, gpio_pin);
  gpio_af_set(gpio_port, gpio_af, gpio_pin);
}

void timer_init_config(rcu_periph_enum rcu_periph, uint32_t timer_periph,
                       uint16_t t_prescaler, uint32_t t_period) {

  rcu_periph_clock_enable(rcu_periph);
  timer_deinit(timer_periph);
  /*初始化参数 */
  timer_parameter_struct initpara;
  /* initialize TIMER init parameter struct */
  timer_struct_para_init(&initpara);
  /* 根据需要配置值 分频系数 (可以实现更低的timer频率) */
  initpara.prescaler 	= t_prescaler - 1;
  /* 1个周期的计数(period Max: 65535) Freq > 3662  */
  initpara.period		= t_period - 1;
  /* initialize TIMER counter */
  timer_init(timer_periph, &initpara);
  /* enable a TIMER */
  timer_enable(timer_periph);

}

void timer_channel_config(uint32_t timer_periph, uint16_t channel) {
  /* TIMER 通道输出配置 */
  timer_oc_parameter_struct ocpara;
  /* initialize TIMER channel output parameter struct */
  timer_channel_output_struct_para_init(&ocpara);
  ocpara.outputstate  = TIMER_CCX_ENABLE;        // OP Enable
  ocpara.outputnstate = TIMER_CCXN_ENABLE;       // ON Enable
  ocpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;   // OP Polarity
  ocpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;  // ON Polarity
  /* 配置输出参数 configure TIMER channel output function */
  timer_channel_output_config(timer_periph, channel, &ocpara);
  /* 配置通道输出输出比较模式 configure TIMER channel output compare mode */
  timer_channel_output_mode_config(timer_periph, channel, TIMER_OC_MODE_PWM0);
}


// PWM
#define	PRESCALER		1
#define	FREQ			  10000
#define PERIOD			(SystemCoreClock / FREQ)

// LED1 TM0CH1 PE9  OP
// LED2 TM0CH0 PE8  ON
static void Timer_config() {
  // 定时器

  // GPIO ----------------------------------------
  timer_gpio_config(RCU_GPIOE, GPIOE, GPIO_PIN_9, GPIO_AF_1);
  timer_gpio_config(RCU_GPIOE, GPIOE, GPIO_PIN_8, GPIO_AF_1);

  // TIMER----------------------------------------
  /* 升级频率*/
  rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
  timer_init_config(RCU_TIMER0, TIMER0, PRESCALER, PERIOD); // 与通道无关

  // TIMER channel-------------------------------
  timer_channel_config(TIMER0, TIMER_CH_0);
  
  // Break --------------------------------------------------
  // break 只针对高级定时器TIMER0 & TIMER7,打开互补保护电路
  /* TIMER通道互补保护电路 */
  timer_break_parameter_struct breakpara;
  /* 初始化TIMER break参数结构体 */
  timer_break_struct_para_init(&breakpara);
  /* break输入的极性 HIGH */
  breakpara.breakpolarity   = TIMER_BREAK_POLARITY_HIGH;
  /* 输出自动的启用 */
  breakpara.outputautostate = TIMER_OUTAUTO_ENABLE;
  /* break输入的启用*/
  breakpara.breakstate      = TIMER_BREAK_ENABLE;
  
  /* 配置TIMER0 break */
  timer_break_config(TIMER0, &breakpara);
  /* 启用TIMER0 break */
  timer_break_enable(TIMER0);


}

/**********************************************************
 * @brief 更新pwm占空比
 * @param timer_periph 定时器
 * @param channel 通道
 * @param duty  占空比[0, 100]
 * @return 
 **********************************************************/
void PWM_update(uint32_t timer_periph, uint16_t channel, float duty) { // 0-100

  if(duty > 100) duty = 100;
  else if(duty < 0) duty = 0;

//	pulse / PERIOD == duty / 100
  uint32_t pulse = PERIOD * duty / 100.0f - 1;

  // 计数值 65535
  timer_channel_output_pulse_value_config(timer_periph, channel, pulse);
}

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

  // 拉低总开关
//  GPIO_config();

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

  float duty = 0;
  int8_t dir = 1;
  while(1) {
    PWM_update(TIMER0, TIMER_CH_0, duty);

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

    printf("duty: %.2f \n", duty);

    delay_1ms(10);
  }
}

练习题


总结

通过本次学习,我们深入了解了PWM技术在嵌入式软件开发中的应用。从添加Timer依赖开始,我们逐步完成了初始化PWM、配置通道的P极和N极、设定PWM占空比等步骤,最终实现了点亮2个LED灯的效果,并采用互补PWM的方式来控制LED的亮度。

在实现过程中,我们学习了定时器与通道的关系,掌握了多通道配置策略和互补PWM配置策略,同时了解了定时器查询方式和代码抽取优化策略,为日后更高效地进行PWM开发打下了坚实的基础。通过不断学习和实践,我们将能够提升自己在嵌入式软件开发领域的技能水平,开发出更加优秀和稳定的产品和应用。


网站公告

今日签到

点亮在社区的每一天
去签到