使用ESP32的MCPWM外设输出两路互补PWM波控制驱动电路
写在前面
本文分享使用MCPWM的基本操作,最后的程序可用于输出双路互补PMW波以控制H桥电路。
本文只讨论了实现该PWM输出的必备模块,若需深入了解MCPWM,建议在学习MCPWM模块时多参考ESP32的技术参考手册和头文件。
MCPWM简单介绍
MCPWM外设提供了6个PWM输出,可用于控制H桥驱动电路等电路结构。使用MCPWM模块可以使ESP32在控制电机输出同时执行其他程序。
每个 MCPWM 外设(单元)都有一个时钟分频器(预分频器),三个 PWM 定时器,三个 PWM 操作器和一个捕获模块。
一些ESP32芯片包含两个MCPWM单元,如ESP32-S3。
MCPWM编程必备配置
开发平台:VS code PlatformIO扩展
以下配置均为mcpwm.h头文件中的声明,编程时使用#include <driver/mcpwm.h>导入。
MCPWM模块
某些ESP32芯片有多个MCPWM外设,如ESP32-S3,在使用时应当选择要使用的模块。
typedef enum {
MCPWM_UNIT_0, /*!<选择MCPWM unit0*/
MCPWM_UNIT_1, /*!<选择MCPWM unit1*/
MCPWM_UNIT_MAX, /*!<MCPWM 单元最大数量*/
} mcpwm_unit_t;
// 可以通过定义变量方式使用
mcpwm_unit_t unit = MCPWM_UNIT_0;
计时器
每一个MCPWM外设均包括三个定时器,用来控制PWM波形的频率。
typedef enum {
MCPWM_TIMER_0, /*!<选择MCPWM timer0*/
MCPWM_TIMER_1, /*!<选择MCPWM timer1*/
MCPWM_TIMER_2, /*!<选择MCPWM timer2*/
MCPWM_TIMER_MAX, /*!<一个MCPWM单元中定时器最大数量*/
} mcpwm_timer_t;
MCPWM输出信号
包括6路独立输出PWM通道,3路同步信号,3路故障检测信号,3路捕获通道。
typedef enum {
MCPWM0A = 0, /*!<PWM0A output pin*/
MCPWM0B, /*!<PWM0B output pin*/
MCPWM1A, /*!<PWM1A output pin*/
MCPWM1B, /*!<PWM1B output pin*/
MCPWM2A, /*!<PWM2A output pin*/
MCPWM2B, /*!<PWM2B output pin*/
MCPWM_SYNC_0, /*!<SYNC0 input pin*/
MCPWM_SYNC_1, /*!<SYNC1 input pin*/
MCPWM_SYNC_2, /*!<SYNC2 input pin*/
MCPWM_FAULT_0, /*!<FAULT0 input pin*/
MCPWM_FAULT_1, /*!<FAULT1 input pin*/
MCPWM_FAULT_2, /*!<FAULT2 input pin*/
MCPWM_CAP_0 = 84, /*!<CAP0 input pin*/
MCPWM_CAP_1, /*!<CAP1 input pin*/
MCPWM_CAP_2, /*!<CAP2 input pin*/
} mcpwm_io_signals_t;
MCPWM参数配置
对MCPWM其中一个操作器的基本参数进行配置,包括频率、占空比、占空比计算方式和计数方式。
typedef struct {
uint32_t frequency; /*!<以Hz为单位设置MCPWM的输出频率*/
float cmpr_a; /*!<设置操作器A(MCPWMXA)的占空比百分数, 要设置A路占空比为62.3%时,令 cmpr_a = 62.3*/
float cmpr_b; /*!<设置操作器B(MCPWMXB)的占空比百分数, 要设置B路占空比为48%时,令cmpr_b = 48.0*/
mcpwm_duty_type_t duty_mode; /*!<设置占空比计算方式,常用MCPWM_DUTY_MODE_0,即在异步控制时,占空比与高电平持续时间成正比*/
mcpwm_counter_type_t counter_mode; /*!<设置MCPWM计数器工作方式,如*/
} mcpwm_config_t;
//设置范例:
mcpwm_config_t pwm_config = {
.frequency = 20000, // 频率为20kHz
.cmpr_a = 70.0, // A通道占空比
.cmpr_b = 30.0, // B通道占空比
.duty_mode = MCPWM_DUTY_MODE_0, // duty cycle proportional to high time
.counter_mode = MCPWM_FREEZE_COUNTER //不使用计数
};
引脚绑定
将MCPWM输出信号或其他输入信号与引脚绑定。可以使用下面的函数绑定一个管脚,也可以直接使用结构体一次性全部绑定。
/*
参数:
mcpwm_num:MCPWM单元选择(0-1)
io_signal:MCPWM的输入输出信号
gpio_num:外设引脚
*/
esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal, int gpio_num);
// 将MCPWM单元0中操作器0的A通道与10号引脚绑定
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, 10)
// 配置引脚的结构体
typedef struct {
int mcpwm0a_out_num; /*!<MCPWM0A out pin*/
int mcpwm0b_out_num; /*!<MCPWM0A out pin*/
int mcpwm1a_out_num; /*!<MCPWM0A out pin*/
int mcpwm1b_out_num; /*!<MCPWM0A out pin*/
int mcpwm2a_out_num; /*!<MCPWM0A out pin*/
int mcpwm2b_out_num; /*!<MCPWM0A out pin*/
int mcpwm_sync0_in_num; /*!<SYNC0 in pin*/
int mcpwm_sync1_in_num; /*!<SYNC1 in pin*/
int mcpwm_sync2_in_num; /*!<SYNC2 in pin*/
int mcpwm_fault0_in_num; /*!<FAULT0 in pin*/
int mcpwm_fault1_in_num; /*!<FAULT1 in pin*/
int mcpwm_fault2_in_num; /*!<FAULT2 in pin*/
int mcpwm_cap0_in_num; /*!<CAP0 in pin*/
int mcpwm_cap1_in_num; /*!<CAP1 in pin*/
int mcpwm_cap2_in_num; /*!<CAP2 in pin*/
} mcpwm_pin_config_t;
// 使用结构体绑定
esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_pin);
MCPWM初始化
/*
参数:
mcpwm_num:MCPWM单元选择(0-1)
timer_pwm:MCPWM单元的计时器
mcpwm_conf:参数配置结构体
*/
esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpwm_config_t *mcpwm_conf);
// 示例(pwm_config为上述MCPWM参数配置中的定义):
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config)
死区设定
MCPWM的死区生成器可以直接用来配置一个A、B信号对的波形,如互补波;还可以设置它们的死区时间,常用高电平有效互补(AHC)。
/*
参数:
mcpwm_num:MCPWM单元选择(0-1)
timer_pwm:MCPWM单元的计时器
mcpwm_deadtime_type_t:死区方式选择。如MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE表示高电平有效互补,MCPWM_ACTIVE_HIGH_MODE表示高电平有效。
red、fed:上升沿和下降沿的延迟,单位为100ns。
*/
esp_err_t mcpwm_deadtime_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_deadtime_type_t dt_mode, uint32_t red, uint32_t fed);
调用以下函数时,死区设置停用:
esp_err_t mcpwm_deadtime_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
配置好MCPWM参数后,调用以下函数启动MCPWM:
// 启动MCPWM单元0的计时器0
mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_0);
MCPWM在运行时,可以改变分辨率、频率、占空比等参数,同时也可以通过有关函数读取。进行修改的函数如下:
/*
参数:
mcpwm_num:MCPWM单元选择(0-1)
timer_pwm:MCPWM单元的计时器
frequency:改变PWM波的频率
*/
esp_err_t mcpwm_set_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, uint32_t frequency);
/*
参数:
mcpwm_num:MCPWM单元选择(0-1)
timer_pwm:MCPWM单元的计时器
gen:选择操作器(如:MCPWM0A)
frequency:改变PWM波的频率
*/
esp_err_t mcpwm_set_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen, float duty);
// 设置MCPWM0A输出的占空比为50%
mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_GEN_A, 50.0);
主程序
输出两路互补PWM波,并使用模拟输入改变PWM波的占空比。
开发板:ESP32-S3 DevKitC-1
#include <Arduino.h>
#include <driver/mcpwm.h>
#define GPIO_PWM0A_OUT 10
#define GPIO_PWM0B_OUT 48
mcpwm_unit_t unit = MCPWM_UNIT_0;
mcpwm_timer_t timer = MCPWM_TIMER_0;
mcpwm_deadtime_type_t deadtime_type = MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE; // 高电平有效互补
volatile float analog;
void setup() {
// put your setup code here, to run once:
pinMode(9, OUTPUT); // 9号引脚读取模拟量
mcpwm_config_t pwm_config = {
.frequency = 20000, // 频率为20kHz
.cmpr_a = 70.0, // 占空比
.cmpr_b = 30.0, // 实验发现,死区类型设置为高电平互补模式时该数无效
.duty_mode = MCPWM_DUTY_MODE_0, //占空比计算方式为高电平时间
.counter_mode = MCPWM_UP_COUNTER //计数模式为向上计数
};
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT); // 绑定10号引脚和48号引脚为
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT);
mcpwm_init(unit, timer, &pwm_config);
mcpwm_deadtime_enable(unit, timer, deadtime_type, 10, 10); //死区方式配置
mcpwm_start(unit, timer);
}
void loop() {
// put your main code here, to run repeatedly:
analog = analogRead(9);
mcpwm_set_duty(unit, timer, MCPWM_GEN_A, analog / 4095 * 100); // 根据读取到的模拟量设置占空比
}
程序运行时,输出频率为20kHz的一对互补PWM波,由引脚10和引脚48输出,且占空比可以通过引脚9的输入调节。