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

以PA5对应的LED4为例,我们做一个呼吸灯的效果。
我们采用TIMER1进行实现:
开发流程
添加Timer依赖
- 初始化PWM
-
初始化PWM
static void PWM_config() {/*************** GPIO config **************/// 配置时钟rcu_periph_clock_enable(RCU_GPIOA);// 配置GPIO模式gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);// 配置GPIO输出gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);// 配置复用功能gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_5);/*************** Timer config *************/// 时钟配置rcu_periph_clock_enable(RCU_TIMER1);// 复位定时器timer_deinit(TIMER1);// 倍频配置rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL2);// 初始化定时器timer_parameter_struct tps;timer_struct_para_init(&tps);tps.prescaler = 10000 - 1; // 分频计数tps.period = SystemCoreClock / 10000 - 1; // 周期计数timer_init(TIMER1, &tps);// 配置输出通道timer_oc_parameter_struct tops;timer_channel_output_struct_para_init(&tops);tops.outputstate = TIMER_CCX_ENABLE;timer_channel_output_config(TIMER1, TIMER_CH_0, &tops);// 输出模式配置timer_channel_output_mode_config(TIMER1, TIMER_CH_0, TIMER_OC_MODE_PWM0);// 初始化timer_enable(TIMER1);}
PWM占空比控制
static void PWM_update(uint32_t pulse) {// 配置输出的占空比timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_0, pulse);}
输出通道
// 配置输出通道timer_oc_parameter_struct tops;timer_channel_output_struct_para_init(&tops);tops.outputstate = TIMER_CCX_ENABLE;timer_channel_output_config(TIMER1, TIMER_CH_0, &tops);
这里完整配置为多种:
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来控制输出通道的开启。关心的内容
static void PWM_config() {uint32_t timerx = TIMER1;uint32_t timerx_chn = TIMER_CH_0;uint32_t timerx_rcu = RCU_TIMER1;uint32_t timerx_psc = RCU_TIMER_PSC_MUL2;uint32_t timerx_prescaler = 10000 - 1; // 分频计数uint32_t timerx_period = SystemCoreClock / 10000 - 1; // 周期计数uint32_t timerx_port = GPIOA; // 哪个引脚和端口uint32_t timerx_port_rcu = RCU_GPIOA;uint32_t timerx_pin = GPIO_PIN_5;/*************** GPIO config **************/// 配置时钟rcu_periph_clock_enable(timerx_port_rcu);// 配置GPIO模式gpio_mode_set(timerx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, timerx_pin);// 配置GPIO输出gpio_output_options_set(timerx_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, timerx_pin);// 配置复用功能gpio_af_set(timerx_port, GPIO_AF_1, timerx_pin);/*************** Timer config *************/// 时钟配置rcu_periph_clock_enable(timerx_rcu);// 复位定时器timer_deinit(timerx);// 倍频配置rcu_timer_clock_prescaler_config(timerx_psc);// 初始化定时器timer_parameter_struct tps;timer_struct_para_init(&tps);tps.prescaler = timerx_prescaler; // 分频计数tps.period = timerx_period; // 周期计数timer_init(timerx, &tps);// 配置输出通道timer_oc_parameter_struct tops;timer_channel_output_struct_para_init(&tops);tops.outputstate = TIMER_CCX_ENABLE;timer_channel_output_config(timerx, timerx_chn, &tops);// 输出模式配置timer_channel_output_mode_config(timerx, timerx_chn, TIMER_OC_MODE_PWM0);// 初始化timer_enable(timerx);}
练习
- 实现pwm点灯
- 实现pwm控制震动马达
- 实现pwm控制蜂鸣器


