学习目标
- 理解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控制蜂鸣器