“ ESP32-S3 的 MCPWM 是多功能 PWM 生成器,含两个单元,支持 12 路独立 PWM 输出。通过定时器、操作器等模块实现高精度控制,具备死区、载波调制功能,可检测故障并制动保护。灵活配置 GPIO 输出,广泛用于电机控制、数字电源等场景,为电力电子应用提供高效解决方案。”

01 MCPWM 简介
ESP32-S3 的 MCPWM(电机控制脉宽调制器)是一种多功能 PWM 生成器,广泛应用于电机控制、数字电源、LED 调光等场景。它通过多个定时器、操作器、比较器和生成器模块,实现高精度、高效率的 PWM 信号输出,并支持故障检测、同步控制和脉宽捕获等高级功能。
1. 特性
- 功能丰富: 支持多种电机控制模式,如电机的向前 / 向后驱动、断电刹车等。
- 高精度控制: 支持死区控制和外部信号捕获。
- 多通道输出: 每个 MCPWM 外设可以输出 6 路 PWM 信号,两个 MCPWM 外设合计可以输出 12 路 PWM 信号。
- 高级功能: 支持载波调制、故障检测和制动控制。
- 灵活配置: 每个 PWM 操作器可以使用任一 PWM 定时器的定时参考,不同 PWM 操作器可使用相同或不同 PWM 定时器的值来生成 PWM 信号。
2. 数量
ESP32-S3 包含两个 MCPWM 单元,每个单元有三对 PWM 输出。每个 MCPWM 单元包含一个时钟分频器、三个 PWM 定时器、三个 PWM 操作器和一个捕获模块。因此,两个 MCPWM 单元合计可以提供 12 个占空比独立可调的 PWM 输出。
3.IO 口要求
MCPWM 模块包含两个子模块(MCPWM0 和 MCPWM1),每个子模块可以配置多个操作器(OP0、OP1、OP2),每个操作器可以输出到不同的 GPIO 引脚。每个操作器支持两种输出通道(A 和 B),并且每个通道可以映射到多个 GPIO 引脚。例如,MCPWM0 模块的 OP0 操作器的 A 通道可以输出到 GPIO0、GPIO10 或 GPIO16。所有可用 IO 口如下表所示:
MCPWM 模块 | 操作器 | 输出通道 | 可选 GPIO(示例) |
MCPWM0 | OP0 | A | GPIO0,GPIO10,GPIO16 |
OP0 | B | GPIO1,GPIO11,GPIO17 | |
OP1 | A | GPIO2,GPIO12,GPIO18 | |
OP1 | B | GPIO3,GPIO13,GPIO19 | |
OP2 | A | GPIO4,GPIO14,GPIO20 | |
OP2 | B | GPIO5,GPIO15,GPIO21 | |
MCPWM1 | OP0 | A | GPIO6,GPIO25,GPIO33 |
OP0 | B | GPIO7,GPIO26,GPIO34 | |
OP1 | A | GPIO8,GPIO27,GPIO35 | |
OP1 | B | GPIO9,GPIO28,GPIO36 | |
OP2 | A | GPIO22,GPIO29,GPIO37 | |
OP2 | B | GPIO23,GPIO30,GPIO38 |
02 功能框图

Esp32-s3 的 MCPWM 模块中,生成带死区和载波调制的 PWM 信号的工作流程如下:
①时钟预分频器(ClockPrescaler)将输入的 CLK_160M 时钟信号进行分频,为定时器提供适当的时钟频率。接着,三个定时器(Timer0、Timer1、Timer2)根据预分频后的时钟信号进行计数,生成 PWM 信号的基础周期。
②操作器(Operator0、Operator1、Operator2)根据定时器的输出和配置参数生成 PWM 信号。操作器可以配置死区时间,以在两个 PWM 信号之间插入一个固定的时间间隔,防止两个信号同时导通。
③操作器还可以通过载波调制技术,将 PWM 信号与高频载波信号结合,生成高频 PWM 信号,以提高电机控制的精度和效率。最后,生成的 PWM 信号通过 GPIO 矩阵输出到相应的 GPIO 引脚,驱动外部设备。
④故障检测(FaultDetect)模块监控 MCPWM 的运行状态,捕获(Capture)模块用于捕获外部信号的上升沿或下降沿,以实现更复杂的控制逻辑。在下图的无刷直流电机 (BLDC) 方案中,可以使用捕获子模块来确认来自霍尔传感器的转子位置。

死区:
在电机控制中,死区是功率电路(如 H 桥、三相逆变器)设计中为防止上下桥臂功率器件同时导通而设置的安全时间间隔。当控制信号从一个桥臂切换到另一个桥臂时,由于器件的开关延迟特性,若没有死区,可能出现短暂的上下管同时导通状态,导致电源短路。死区通过在原始控制信号的上升沿和下降沿分别插入延迟时间(正边沿延迟和负边沿延迟),确保上管完全关断后下管才导通,或下管完全关断后上管才导通,从而避免桥臂短路风险,保护功率器件和电路系统的安全稳定运行。

MCPWM 模块有以下外设:
时钟预分器频(ClockPrescaler):
时钟预分频器用于将输入的时钟频率(CLK_160M)降低,以适应 PWM 生成的需求。它通过分频系数来调整时钟频率,为后续的定时器提供合适的时钟信号。
定时器(Timer):
定时器是 MCPWM 的核心部分,用于生成定时信号。每个定时器可以独立配置,包括周期、比较值等。
操作器(Operator):
操作器接收来自定时器的定时信号,并根据配置生成 PWM 信号。每个操作器可以配置为不同的 PWM 模式,如互补、桥接等。
故障检测(FaultDetect):
故障检测模块用于监控 MCPWM 的运行状态,检测可能的故障情况,如过流、过压等。
捕获(Capture):
捕获模块用于捕获外部信号的上升沿或下降沿,通常用于测量外部信号的周期或频率。
GPIO 矩阵:
GPIO 矩阵用于将 MCPWM 生成的 PWM 信号输出到指定的 GPIO 引脚。
03 MCPWM 各种模式使用方法
1. 经典 PWM 波形生成
编程流程 :
创建定时器组,配置定时器的时钟源、分辨率、周期、计数模式等参数。
创建操作器,并将其与定时器绑定。
创建比较器,设置比较器的比较值。
创建生成器,配置生成器的 GPIO 引脚。
设置生成器在定时器事件和比较器事件上的动作,以生成所需的 PWM 波形。
#include"driver/mcpwm.h"
#include"esp_log.h"
#defineMCPWM_GROUP_ID0
#defineMCPWM_TIMER_ID0
#defineMCPWM_GEN_A_GPIO21
#defineMCPWM_GEN_B_GPIO22
voidapp_main(void){
// 创建定时器
mcpwm_timer_handle_ttimer=NULL;
mcpwm_timer_config_ttimer_config={
.group_id=MCPWM_GROUP_ID,
.clk_src=MCPWM_TIMER_CLK_SRC_DEFAULT,
.resolution_hz=1000000,//1MHz
.period_ticks=1000,//1ms 周期
.count_mode=MCPWM_TIMER_COUNT_MODE_UP,
};
ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config,&timer));
// 创建操作器
mcpwm_oper_handle_toper=NULL;
mcpwm_operator_config_toper_config={.group_id=MCPWM_GROUP_ID,};
ESP_ERROR_CHECK(mcpwm_new_operator(&oper_config,&oper));
// 绑定定时器和操作器
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper,timer));
// 创建比较器 mcpwm_cmpr_handle_tcmpr_a=NULL;
mcpwm_comparator_config_tcmpr_config={.flags.update_cmp_on_tez=true,};
ESP_ERROR_CHECK(mcpwm_new_comparator(oper,&cmpr_config,&cmpr_a));
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(cmpr_a,500));//50% 占空比
// 创建生成器
mcpwm_gen_handle_tgen_a=NULL;
mcpwm_generator_config_tgen_config={.gen_gpio_num=MCPWM_GEN_A_GPIO,};
ESP_ERROR_CHECK(mcpwm_new_generator(oper,&gen_config,&gen_a));
// 设置生成器动作 ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gen_a,MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,MCPWM_TIMER_EVENT_EMPTY,MCPWM_GEN_ACTION_HIGH)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gen_a,MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,cmpr_a,MCPWM_GEN_ACTION_LOW)));
// 启动定时器
ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer,MCPWM_TIMER_START_NO_STOP));
}
2. 死区生成
编程流程:
创建死区模块,并将其与操作器绑定。
配置死区时间,包括上升沿死区时间和下降沿死区时间。
设置生成器在定时器事件和比较器事件上的动作,以生成带有死区的 PWM 波形。
#include"driver/mcpwm.h"
#include"esp_log.h"
#defineMCPWM_GROUP_ID0
#defineMCPWM_TIMER_ID0
#defineMCPWM_GEN_A_GPIO21
#defineMCPWM_GEN_B_GPIO22
voidapp_main(void){
// 创建定时器
mcpwm_timer_handle_ttimer=NULL;
mcpwm_timer_config_ttimer_config={
.group_id=MCPWM_GROUP_ID,
.clk_src=MCPWM_TIMER_CLK_SRC_DEFAULT,
.resolution_hz=1000000,//1MHz
.period_ticks=1000,//1ms 周期
.count_mode=MCPWM_TIMER_COUNT_MODE_UP,
};
ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config,&timer));
// 创建操作器
mcpwm_oper_handle_toper=NULL;
mcpwm_operator_config_toper_config={.group_id=MCPWM_GROUP_ID,};
ESP_ERROR_CHECK(mcpwm_new_operator(&oper_config,&oper));
// 绑定定时器和操作器
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper,timer));
// 创建死区模块
mcpwm_deadtime_handle_tdeadtime=NULL;
mcpwm_deadtime_config_tdeadtime_config={
.update_on_tez=true,
.update_on_tep=true,
.update_on_sync=true,
.deadtime_ticks=10,//10us 死区时间
};
ESP_ERROR_CHECK(mcpwm_new_deadtime(oper,&deadtime_config,&deadtime));
// 创建比较器
mcpwm_cmpr_handle_tcmpr_a=NULL;
mcpwm_comparator_config_tcmpr_config={.flags.update_cmp_on_tez=true,};
ESP_ERROR_CHECK(mcpwm_new_comparator(oper,&cmpr_config,&cmpr_a));
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(cmpr_a,500));//50% 占空比
// 创建生成器
mcpwm_gen_handle_tgen_a=NULL;
mcpwm_generator_config_tgen_config={.gen_gpio_num=MCPWM_GEN_A_GPIO,};
ESP_ERROR_CHECK(mcpwm_new_generator(oper,&gen_config,&gen_a));
// 设置生成器动作 ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gen_a,MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,MCPWM_TIMER_EVENT_EMPTY,MCPWM_GEN_ACTION_HIGH)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gen_a,MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,cmpr_a,MCPWM_GEN_ACTION_LOW)));
// 启动定时器 ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer,MCPWM_TIMER_START_NO_STOP));
}
3. 载波调制
编程流程:
创建载波模块,并将其与操作器绑定。
配置载波频率、占空比等参数。
设置生成器在定时器事件和比较器事件上的动作,以生成载波调制的 PWM 波形。
#include"driver/mcpwm.h"
#include"esp_log.h"
#defineMCPWM_GROUP_ID0
#defineMCPWM_TIMER_ID0
#defineMCPWM_GEN_A_GPIO21
#defineMCPWM_GEN_B_GPIO22
voidapp_main(void){
// 创建定时器
mcpwm_timer_handle_ttimer=NULL;
mcpwm_timer_config_ttimer_config={
.group_id=MCPWM_GROUP_ID,
.clk_src=MCPWM_TIMER_CLK_SRC_DEFAULT,
.resolution_hz=1000000,//1MHz
.period_ticks=1000,//1ms 周期
.count_mode=MCPWM_TIMER_COUNT_MODE_UP,
};
ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config,&timer));
// 创建操作器
mcpwm_oper_handle_toper=NULL;
mcpwm_operator_config_toper_config={.group_id=MCPWM_GROUP_ID,};
ESP_ERROR_CHECK(mcpwm_new_operator(&oper_config,&oper));
// 绑定定时器和操作器
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper,timer));
// 创建载波模块
mcpwm_carrier_handle_tcarrier=NULL;
mcpwm_carrier_config_tcarrier_config={
.carrier_freq_hz=20000,//20kHz 载波频率
.duty_cycle=50,//50% 载波占空比
.update_on_tez=true,
.update_on_tep=true,
.update_on_sync=true,
};
ESP_ERROR_CHECK(mcpwm_new_carrier(oper,&carrier_config,&carrier));
// 创建比较器
mcpwm_cmpr_handle_tcmpr_a=NULL;
mcpwm_comparator_config_tcmpr_config={.flags.update_cmp_on_tez=true,};
ESP_ERROR_CHECK(mcpwm_new_comparator(oper,&cmpr_config,&cmpr_a));
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(cmpr_a,500));//50% 占空比
// 创建生成器
mcpwm_gen_handle_tgen_a=NULL;
mcpwm_generator_config_tgen_config={.gen_gpio_num=MCPWM_GEN_A_GPIO,};
ESP_ERROR_CHECK(mcpwm_new_generator(oper,&gen_config,&gen_a));
// 设置生成器动作 ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gen_a,MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,MCPWM_TIMER_EVENT_EMPTY,MCPWM_GEN_ACTION_HIGH)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gen_a,MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,cmpr_a,MCPWM_GEN_ACTION_LOW)));
// 启动定时器
ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer,MCPWM_TIMER_START_NO_STOP));
}
4. 故障检测
编程流程:
创建故障检测模块,并将其与操作器绑定。
配置故障检测的 GPIO 引脚和故障信号极性。
设置生成器在故障事件上的动作,以实现故障保护。
#include"driver/mcpwm.h"
#include"esp_log.h"
#defineMCPWM_GROUP_ID0
#defineMCPWM_TIMER_ID0
#defineMCPWM_GEN_A_GPIO21
#defineMCPWM_GEN_B_GPIO22
#defineMCPWM_FAULT_GPIO23
voidapp_main(void){
// 创建定时器
mcpwm_timer_handle_ttimer=NULL;
mcpwm_timer_config_ttimer_config={
.group_id=MCPWM_GROUP_ID,
.clk_src=MCPWM_TIMER_CLK_SRC_DEFAULT,
.resolution_hz=1000000,//1MHz
.period_ticks=1000,//1ms 周期
.count_mode=MCPWM_TIMER_COUNT_MODE_UP,
};
ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config,&timer));
// 创建操作器
mcpwm_oper_handle_toper=NULL;
mcpwm_operator_config_toper_config={.group_id=MCPWM_GROUP_ID,};
ESP_ERROR_CHECK(mcpwm_new_operator(&oper_config,&oper));
// 绑定定时器和操作器
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper,timer));
// 创建故障检测模块
mcpwm_fault_handle_tfault=NULL;
mcpwm_fault_config_tfault_config={
.fault_gpio_num=MCPWM_FAULT_GPIO,
.fault_signal_polarity=MCPWM_FAULT_SIGNAL_POLARITY_LOW,
.fault_debounce_ticks=10,//10us 消抖时间
};
ESP_ERROR_CHECK(mcpwm_new_fault(oper,&fault_config,&fault));
// 创建比较器
mcpwm_cmpr_handle_tcmpr_a=NULL;
mcpwm_comparator_config_tcmpr_config={.flags.update_cmp_on_tez=true,};
ESP_ERROR_CHECK(mcpwm_new_comparator(oper,&cmpr_config,&cmpr_a));
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(cmpr_a,500));//50% 占空比
// 创建生成器
mcpwm_gen_handle_tgen_a=NULL;
mcpwm_generator_config_tgen_config={.gen_gpio_num=MCPWM_GEN_A_GPIO,};
ESP_ERROR_CHECK(mcpwm_new_generator(oper,&gen_config,&gen_a));
// 设置生成器动作 ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gen_a,MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,MCPWM_TIMER_EVENT_EMPTY,MCPWM_GEN_ACTION_HIGH)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gen_a,MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,cmpr_a,MCPWM_GEN_ACTION_LOW)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_fault_event(gen_a,MCPWM_GEN_FAULT_EVENT_ACTION(fault,MCPWM_GEN_ACTION_LOW)));
// 启动定时器
ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer,MCPWM_TIMER_START_NO_STOP));
}
5. 同步模块
编程流程:
创建同步模块,并将其与操作器绑定。
配置同步信号的来源和同步事件的触发条件。
设置生成器在同步事件上的动作,以实现多 PWM 信号的同步。
#include"driver/mcpwm.h"
#include"esp_log.h"
#defineMCPWM_GROUP_ID0
#defineMCPWM_TIMER_ID0
#defineMCPWM_GEN_A_GPIO21
#defineMCPWM_GEN_B_GPIO22
voidapp_main(void){
// 创建定时器
mcpwm_timer_handle_ttimer=NULL;
mcpwm_timer_config_ttimer_config={
.group_id=MCPWM_GROUP_ID,
.clk_src=MCPWM_TIMER_CLK_SRC_DEFAULT,
.resolution_hz=1000000,//1MHz
.period_ticks=1000,//1ms 周期
.count_mode=MCPWM_TIMER_COUNT_MODE_UP,
};
ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config,&timer));
// 创建操作器
mcpwm_oper_handle_toper=NULL;
mcpwm_operator_config_toper_config={.group_id=MCPWM_GROUP_ID,};
ESP_ERROR_CHECK(mcpwm_new_operator(&oper_config,&oper));
// 绑定定时器和操作器
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper,timer));
// 创建同步模块
mcpwm_sync_handle_tsync=NULL;
mcpwm_sync_config_tsync_config={.sync_src=MCPWM_SYNC_SRC_TEZ,// 同步信号来源为定时器溢出事件};
ESP_ERROR_CHECK(mcpwm_new_sync(oper,&sync_config,&sync));
// 创建比较器
mcpwm_cmpr_handle_tcmpr_a=NULL;
mcpwm_comparator_config_tcmpr_config={.flags.update_cmp_on_tez=true,};
ESP_ERROR_CHECK(mcpwm_new_comparator(oper,&cmpr_config,&cmpr_a));
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(cmpr_a,500));//50% 占空比
// 创建生成器
mcpwm_gen_handle_tgen_a=NULL;
mcpwm_generator_config_tgen_config={.gen_gpio_num=MCPWM_GEN_A_GPIO,};
ESP_ERROR_CHECK(mcpwm_new_generator(oper,&gen_config,&gen_a));
// 设置生成器动作 ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gen_a,MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,MCPWM_TIMER_EVENT_EMPTY,MCPWM_GEN_ACTION_HIGH)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gen_a,MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,cmpr_a,MCPWM_GEN_ACTION_LOW)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_sync_event(gen_a,MCPWM_GEN_SYNC_EVENT_ACTION(sync,MCPWM_GEN_ACTION_HIGH)));
// 启动定时器
ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer,MCPWM_TIMER_START_NO_STOP));
}
6. 制动控制
编程流程:
配置生成器在故障事件上的制动动作,例如立即关闭或逐周期调节。
设置故障检测模块的故障信号来源和极性。
启动定时器并运行 PWM 信号,故障发生时生成器将执行制动动作。
#include"driver/mcpwm.h"
#include"esp_log.h"
#defineMCPWM_GROUP_ID0
#defineMCPWM_TIMER_ID0
#defineMCPWM_GEN_A_GPIO21
#defineMCPWM_GEN_B_GPIO22
#defineMCPWM_FAULT_GPIO23
voidapp_main(void){
// 创建定时器
mcpwm_timer_handle_ttimer=NULL;
mcpwm_timer_config_ttimer_config={
.group_id=MCPWM_GROUP_ID,
.clk_src=MCPWM_TIMER_CLK_SRC_DEFAULT,
.resolution_hz=1000000,//1MHz
.period_ticks=1000,//1ms 周期
.count_mode=MCPWM_TIMER_COUNT_MODE_UP,
};
ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config,&timer));
// 创建操作器
mcpwm_oper_handle_toper=NULL;
mcpwm_operator_config_toper_config={.group_id=MCPWM_GROUP_ID,};
ESP_ERROR_CHECK(mcpwm_new_operator(&oper_config,&oper));
// 绑定定时器和操作器
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper,timer));
// 创建故障检测模块
mcpwm_fault_handle_tfault=NULL;
mcpwm_fault_config_tfault_config={
.fault_gpio_num=MCPWM_FAULT_GPIO,
.fault_signal_polarity=MCPWM_FAULT_SIGNAL_POLARITY_LOW,
.fault_debounce_ticks=10,//10us 消抖时间
};
ESP_ERROR_CHECK(mcpwm_new_fault(oper,&fault_config,&fault));
// 创建比较器
mcpwm_cmpr_handle_tcmpr_a=NULL;
mcpwm_comparator_config_tcmpr_config={.flags.update_cmp_on_tez=true,};
ESP_ERROR_CHECK(mcpwm_new_comparator(oper,&cmpr_config,&cmpr_a));
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(cmpr_a,500));//50% 占空比
// 创建生成器
mcpwm_gen_handle_tgen_a=NULL;
mcpwm_generator_config_tgen_config={.gen_gpio_num=MCPWM_GEN_A_GPIO,};
ESP_ERROR_CHECK(mcpwm_new_generator(oper,&gen_config,&gen_a));
// 设置生成器动作 ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(gen_a,MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,MCPWM_TIMER_EVENT_EMPTY,MCPWM_GEN_ACTION_HIGH)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(gen_a,MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,cmpr_a,MCPWM_GEN_ACTION_LOW)));
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_fault_event(gen_a,MCPWM_GEN_FAULT_EVENT_ACTION(fault,MCPWM_GEN_ACTION_LOW)));
// 配置制动控制 ESP_ERROR_CHECK(mcpwm_generator_set_brake_action(gen_a,MCPWM_GEN_BRAKE_ACTION_LOW));
// 启动定时器 ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer,MCPWM_TIMER_START_NO_STOP));
}
7. 捕获模块
编程流程:
创建捕获模块,并配置捕获通道的 GPIO 引脚。
配置捕获事件的触发条件,例如上升沿或下降沿。
启用捕获中断,并在中断处理函数中读取捕获到的脉宽值。
#include"driver/mcpwm.h"
#include"esp_log.h"
#include"driver/gpio.h"
#defineMCPWM_GROUP_ID0
#defineMCPWM_CAPTURE_GPIO21
staticvoidIRAM_ATTRmcpwm_capture_intr_handler(void*arg){mcpwm_capture_handle_tcapture=(mcpwm_capture_handle_t)arg;
uint32_tcap_val=0;
mcpwm_capture_get_input_signal_value(capture,&cap_val);
ESP_LOGI("MCPWM","Capturedvalue:%u",cap_val);
}
voidapp_main(void){
// 创建捕获模块
mcpwm_capture_handle_tcapture=NULL;
mcpwm_capture_config_tcapture_config={
.group_id=MCPWM_GROUP_ID,
.capture_signal=MCPWM_CAPTURE_SIGNAL_A,
.input_signal=MCPWM_CAPTURE_INPUT_SIG_GPIO,
.input_gpio_num=MCPWM_CAPTURE_GPIO,
.capture_edge=MCPWM_CAPTURE_EDGE_RISING,
};
ESP_ERROR_CHECK(mcpwm_new_capture(&capture_config,&capture));
// 启用捕获中断
mcpwm_capture_enable_intr(capture);
mcpwm_capture_register_intr_handler(capture,mcpwm_capture_intr_handler,capture);
// 启动捕获模块
ESP_ERROR_CHECK(mcpwm_capture_enable(capture));
}
04 MCPWM 常用的 API 函数
mcpwm_new_timer()
用于创建并初始化 MCPWM 定时器句柄,作为所有 MCPWM 功能的时间基准。关键参数包括 MCPWM 组 ID(group_id)、时钟源(clk_src)、定时器分辨率(resolution_hz)、计数模式(count_mode)和周期计数值(period_ticks)。它是生成 PWM 信号的基础,为后续子模块提供统一的周期时基,适用于所有需要 PWM 输出的场景。
mcpwm_new_operator()
用于创建 MCPWM 操作器句柄,作为协调定时器、比较器、生成器等子模块的逻辑控制中枢。参数需指定组 ID(group_id)、定时器归零是否更新生成器动作(update_gen_action_on_tez)及中断优先级(intr_priority)。操作器需与定时器绑定后才能工作,是实现 PWM 波形生成的核心控制单元。
mcpwm_operator_connect_timer()
用于将操作器与定时器绑定,确保操作器能以定时器为时间基准调度子模块。参数为操作器句柄(oper)和定时器句柄(timer),且两者必须属于同一组。这是操作器正常工作的必要步骤,否则无法生成 PWM 信号。
mcpwm_new_comparator()
用于创建比较器句柄,用于设置 PWM 占空比的翻转阈值。需传入所属操作器句柄(oper)及比较值更新时机配置(如 update_cmp_on_tez 表示定时器归零时更新)。比较器通过对比定时器计数值与阈值触发电平翻转,是定义 PWM 占空比的关键模块。
mcpwm_new_generator()
用于创建生成器句柄,负责将 PWM 信号输出到指定 GPIO 引脚。参数包括所属操作器句柄(oper)、输出 GPIO 号(gen_gpio_num)、信号是否反相(invert_pwm)及上下拉配置(pull_up/pull_down)。生成器接收定时器和比较器事件并执行电平动作,是 PWM 信号的最终输出单元。
mcpwm_del_timer()
用于释放定时器资源,参数为定时器句柄。需按“生成器→比较器→操作器→定时器”的逆序释放,避免资源冲突,确保系统资源正确回收。
mcpwm_del_operator()
用于释放操作器资源,参数为操作器句柄。作为资源清理步骤之一,需在释放定时器前执行,防止资源占用导致的冲突。
mcpwm_del_comparator()
用于释放比较器资源,参数为比较器句柄。需在释放操作器前执行,确保比较器占用的硬件资源被正确回收。
mcpwm_del_generator()
用于释放生成器资源,参数为生成器句柄。作为资源清理的第一步,需优先释放,避免影响其他模块的资源回收流程。
mcpwm_comparator_set_compare_value()
设置比较器的阈值,动态调整 PWM 占空比。参数为比较器句柄(cmpr)和阈值(value),且阈值需≤定时器周期值。占空比计算公式为“阈值 / 周期值”,适用于电机调速等需要实时调整占空比的场景。
mcpwm_generator_set_action_on_timer_event()
配置生成器在定时器事件(如计数归零、达峰值)时的电平动作。参数包括生成器句柄(gen)及事件 – 动作配置(含计数方向、事件类型、动作如置高 / 置低 / 翻转)。例如可设置定时器归零时输出置高,定义 PWM 周期起点的电平状态。
mcpwm_generator_set_action_on_compare_event()
定义生成器在比较器事件(计数值 = 阈值)时的动作。需传入生成器句柄(gen)及包含计数方向、比较器句柄、动作的配置。通过该函数可设置比较值匹配时电平翻转,从而定义 PWM 占空比的结束点,实现特定占空比的 PWM 波形。
mcpwm_generator_set_dead_time()
为 PWM 信号配置死区时间,防止 H 桥、三相逆变器等功率电路中同一桥臂上下管同时导通。参数包括原始生成器(in_gen)、输出生成器(out_gen)、上升沿延迟(posedge_delay_ticks)、下降沿延迟(negedge_delay_ticks)及输出是否反相(invert_output)。适用于需要互补 PWM 信号的功率控制场景。
mcpwm_timer_enable()
启用定时器,使其开始计数并为子模块提供时基。参数为定时器句柄,启用后定时器按配置模式运行,触发后续比较器、生成器等模块的事件响应,是激活 MCPWM 功能的关键步骤。
mcpwm_timer_start_stop()
控制定时器计数的启动或停止,参数为定时器句柄和命令(MCPWM_TIMER_START 启动,MCPWM_TIMER_STOP 停止)。可用于临时暂停 PWM 输出,如电机急停等需要快速启停控制的场景。
mcpwm_new_gpio_fault()
创建 GPIO 故障检测句柄,监测外部故障信号(如过流、过压)。参数包括故障 GPIO 号(gpio_num)和有效电平(active_level)。通过检测指定 GPIO 的有效电平触发保护动作,适用于需要硬件故障保护的系统。
mcpwm_operator_set_brake_on_fault()
配置操作器在故障发生时的制动模式,参数为操作器句柄(oper)、故障句柄及制动模式(CBC 逐周期保护或 OST 一次性停机)。CBC 模式在故障消失后自动恢复,OST 需手动恢复,用于故障时保护系统安全。
mcpwm_timer_register_event_callbacks()
注册定时器事件回调函数,响应周期结束、计数归零等事件。参数为定时器句柄、回调结构体(含 on_full/on_empty 等回调)及用户数据(user_data)。可用于周期结束时更新参数(如动态调占空比)或记录运行状态,增强系统的实时控制能力。
FAQ
1、ESP32 的 MCPWM 模块支持多少路 PWM 输出?
ESP32 包含两个 MCPWM 单元,每个单元有三对 PWM 输出,共 12 路独立 PWM 信号,可用于电机控制和电力电子应用。
2、MCPWM 的死区控制有什么作用?
死区用于防止功率器件上下桥臂同时导通,避免电源短路,确保电机控制电路安全稳定运行。
3、如何在 ESP32 上实现 PWM 载波调制?
通过 MCPWM 的载波模块配置载波频率和占空比,并与操作器绑定,即可生成载波调制的 PWM 波形,提高电机控制的精度。
4、MCPWM 的 GPIO 引脚可以自由映射吗?
是的,ESP32 的 MCPWM 输入输出引脚支持 GPIO 矩阵配置,用户可以将 PWM 输出、捕获输入、故障信号等映射到任意可用的 GPIO 引脚上。
5、MCPWM 的故障检测和制动功能怎么用?
MCPWM 支持通过 GPIO 输入故障信号,在检测到过流或过压时自动关闭 PWM 输出,实现紧急制动,保障电机与电路的安全。
6、ESP32 MCPWM 适合哪些应用场景?
MCPWM 常用于无刷直流电机(BLDC)控制、步进电机驱动、逆变器、开关电源以及电力电子控制等需要高精度 PWM 的场景。
7、如何通过 ESP-IDF 配置 MCPWM 输出 PWM 信号?
开发者可以使用 ESP-IDF 的 mcpwm_new_timer()、mcpwm_new_operator()、mcpwm_new_comparator() 等 API 创建定时器、操作器和比较器,并绑定输出通道,即可生成所需的 PWM 信号。