简介
ESP-IDF版本:V5.1.2
ESP32的MCPWM外设是一个多功能的PWM生成器,集成多个子模块,在电力电子应用(如电机控制、数字电源等)中至关重要。常用于电极控制,H桥转换电路等。
如图,是MCPWM外设的主要子模块
ESP32编程指南中图片
ESP32技术手册中图片
从图中我们可以知道每个定时器都有对应的操作器,每个比较器要有对应的操作器,每个生成器要有对应的操作器,这些都可以从后面的代码得出。
程序导读(功能)
1.实现两个PWM之间有固定的间隔时间(也称作死区),如图所示。当然,想要实现不同定时器之间生成的PWM同步,也完全没问题,这其实也是同步的另一种方式。
2.实现低频控制,如生成1Hz的PWM波形。如用官方的程序是无法生成1Hz的PWM波的,需要改变MCPWM_TIMER_RESOLUTION_HZ,来变化每个tick的时间。(至于为什么在官方给的1MHz无法实现原理不明)
3.该程序通过改变端口电平来控制同步功能。
4.该程序能实现实时PWM的频率和占空比调节。
程序代码
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/mcpwm_prelude.h"
#include "driver/gpio.h"
#include "MCPWM_User.h"
const static char *TAG = "example";
uint32_t MCPWM_TIMER_RESOLUTION_HZ = 50000; // 50KHz, 20us per tick
uint32_t MCPWM_TIMER_PERIOD = 5000; // 5000 ticks, 100ms
uint32_t HB_duty;
#define EXAMPLE_GEN_GPIO1 GPIO_NUM_18 //输出PWM引脚
#define EXAMPLE_GEN_GPIO2 GPIO_NUM_19
#define EXAMPLE_SYNC_GPIO GPIO_NUM_4 //信号同步引脚
mcpwm_timer_handle_t timers[2]; // 创建定时器句柄
// 配置定时器结构体
mcpwm_timer_config_t timer_config = {
.group_id = 0, // 指定MCPWM的组ID
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT, // 设置定时器的时钟源
.resolution_hz = MCPWM_TIMER_RESOLUTION_HZ, // 设置定时器的预期分辨率
.count_mode = MCPWM_TIMER_COUNT_MODE_UP, // 向上计数
.period_ticks = MCPWM_TIMER_PERIOD, // 设置定时器的周期,以Tick为单位
};
mcpwm_cmpr_handle_t comparators[2]; // 创建比较器
mcpwm_comparator_config_t compare_config = {
.flags = {
.update_cmp_on_tez = true, // 当定时器计数值为0时更新比较阈值
}};
static void example_setup_sync_strategy(mcpwm_timer_handle_t timers[])
{
// +----GPIO----+
// | | |
// | | |
// v v v
// timer0 timer1 timer2
ESP_LOGI(TAG, "Create GPIO sync source");
mcpwm_sync_handle_t gpio_sync_source = NULL;
mcpwm_gpio_sync_src_config_t gpio_sync_config = {
.group_id = 0, // GPIO fault should be in the same group of the above timers
.gpio_num = EXAMPLE_SYNC_GPIO,
.flags = {
.active_neg = false, // by default, a posedge pulse can trigger a sync event
.io_loop_back = true, // then we can trigger a sync event using `gpio_set_level` on the same GPIO
.pull_down = true, // 拉低GPIO电平
}};
ESP_ERROR_CHECK(mcpwm_new_gpio_sync_src(&gpio_sync_config, &gpio_sync_source));
ESP_LOGI(TAG, "Set timers to sync on the GPIO");
mcpwm_timer_sync_phase_config_t sync_phase_config_timer0 = {
.sync_src = gpio_sync_source,
.count_value = 0, //定时器0从0开始计数
.direction = MCPWM_TIMER_DIRECTION_UP,
};
ESP_ERROR_CHECK(mcpwm_timer_set_phase_on_sync(timers[0], &sync_phase_config_timer0));
mcpwm_timer_sync_phase_config_t sync_phase_config_timer1 = {
.sync_src = gpio_sync_source,
.count_value = 2000, //定时器1从200开始计数,可调节,但不要小于占空比
.direction = MCPWM_TIMER_DIRECTION_UP,
};
ESP_ERROR_CHECK(mcpwm_timer_set_phase_on_sync(timers[1], &sync_phase_config_timer1));
ESP_LOGI(TAG, "Trigger a pulse on the GPIO as a sync event");
gpio_set_level(EXAMPLE_SYNC_GPIO, 0);
gpio_set_level(EXAMPLE_SYNC_GPIO, 1);
}
void MCPWM_TASK(void)
{
ESP_LOGI(TAG, "Create timers");
for (int i = 0; i < 2; i++)
{
ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config, &timers[i])); // 分配定时器
}
ESP_LOGI(TAG, "Create operators");
mcpwm_oper_handle_t operators[2]; // 创建操作器句柄
mcpwm_operator_config_t operator_config = {
// 操作器的组ID应与定时器的组ID对应
.group_id = 0, // operator should be in the same group of the above timers
};
for (int i = 0; i < 2; ++i)
{
ESP_ERROR_CHECK(mcpwm_new_operator(&operator_config, &operators[i])); // 分配操作器
}
ESP_LOGI(TAG, "Connect timers and operators with each other");
for (int i = 0; i < 2; i++)
{
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(operators[i], timers[i])); // 连接操作器和定时器
}
ESP_LOGI(TAG, "Create comparators");
for (int i = 0; i < 2; i++)
{
// 以MCPWM操作器句柄和配置结构体mcpwm_comparator_config_t为参数
ESP_ERROR_CHECK(mcpwm_new_comparator(operators[i], &compare_config, &comparators[i]));
// init compare for each comparator
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparators[i], 1000)); // 主要用于调节占空比
}
ESP_LOGI(TAG, "Create generators");
mcpwm_gen_handle_t generators[2]; // 创建生成器句柄
const int gen_gpios[2] = {EXAMPLE_GEN_GPIO1, EXAMPLE_GEN_GPIO2};
mcpwm_generator_config_t gen_config = {};
for (int i = 0; i < 2; i++)
{
gen_config.gen_gpio_num = gen_gpios[i]; // 设置生成器使用的GPIO编号
ESP_ERROR_CHECK(mcpwm_new_generator(operators[i], &gen_config, &generators[i])); // 分配生成器
}
ESP_LOGI(TAG, "Set generator actions on timer and compare event");
for (int i = 0; i < 2; i++)
{
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(
generators[i],
// when the timer value is zero, and is counting up, set output to high
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,
MCPWM_TIMER_EVENT_EMPTY,
MCPWM_GEN_ACTION_HIGH))); // 计数值为0时开始输出高电平
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(
generators[i],
// when compare event happens, and timer is counting up, set output to low
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,
comparators[i],
MCPWM_GEN_ACTION_LOW))); // 比较事件发生时,输出低电平
}
// 逐一启动定时器
ESP_LOGI(TAG, "Start timers one by one, so they are not synced");
for (int i = 0; i < 2; i++)
{
ESP_ERROR_CHECK(mcpwm_timer_enable(timers[i]));
// 控制定时器的启动,MCPWM_TIMER_START_NO_STOP是启动后不停止
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timers[i], MCPWM_TIMER_START_NO_STOP));
vTaskDelay(pdMS_TO_TICKS(10));
}
// 进行同步
ESP_LOGI(TAG, "Setup sync strategy");
example_setup_sync_strategy(timers);
vTaskDelay(pdMS_TO_TICKS(100));
}
//改变MCPWM频率
void MCPWM_Change_period(uint32_t period)
{
mcpwm_timer_set_period(timers[1], period);
mcpwm_timer_set_period(timers[0], period);
}
//改变MCPWM占空比
void MCPWM_Change_duty(uint32_t duty)
{
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparators[0], duty)); // 主要用于调节占空比
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparators[1], duty)); // 主要用于调节占空比
}