概述
主要用途
- 有刷/无刷电机驱动
- 开关电源
- DAC
- 脉冲宽度计算,测距/测速
- FOC驱动
PWM基本输出配置
关键函数
主要包括IO设置、分辨率设置和MCPWM初始化,分辨率设置值决定了输出PWM的频率,定时器周期寄存器只有16bit,因此分辨率不宜过大或过小,过大有可能计数值超范围,过小则有可能不够计数,需根据实际输出pwm频率范围确定,mcpwm_init()函数执行后会自动启动PWM输出。
#include "driver/mcpwm.h"
esp_err_t mcpwm_gpio_init(
mcpwm_unit_t mcpwm_num,
mcpwm_io_signals_t io_signal,
int gpio_num);
esp_err_t mcpwm_set_pin(
mcpwm_unit_t mcpwm_num,
const mcpwm_pin_config_t *mcpwm_pin)
mcpwm_pin_config_t mcpwm_pin= {
.mcpwm0a_out_num = 1,
.mcpwm0b_out_num = 2,
.mcpwm1a_out_num = 3,
.mcpwm1b_out_num = 4,
.mcpwm2a_out_num = 5,
.mcpwm2b_out_num = 6,
.mcpwm_cap0_in_num = 7,
.mcpwm_cap1_in_num = 8,
.mcpwm_cap2_in_num = 9,
.mcpwm_sync0_in_num = -1,
.mcpwm_sync1_in_num = -1,
.mcpwm_sync2_in_num = -1,
.mcpwm_fault0_in_num = 10,
.mcpwm_fault1_in_num = -1,
.mcpwm_fault2_in_num = -1
};
esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, unsigned long int resolution);
esp_err_t mcpwm_timer_set_resolution(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, unsigned long int resolution)
esp_err_t mcpwm_init(
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num,
const mcpwm_config_t *mcpwm_conf);
mcpwm_config_t mcpwm_conf = {
.frequency = 1000,
.cmpr_a = 22.3,
.cmpr_b = 42.8,
.duty_mode = MCPWM_DUTY_MODE_0,
.counter_mode = MCPWM_UP_DOWN_COUNTER};
动态控制函数
esp_err_t mcpwm_set_signal_high or mcpwm_set_signal_low (
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num,
mcpwm_generator_t gen)
esp_err_t mcpwm_start(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
esp_err_t mcpwm_stop(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
esp_err_t mcpwm_set_duty_type(
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num,
mcpwm_generator_t gen,
mcpwm_duty_type_t duty_type)
esp_err_t mcpwm_set_duty(
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num,
mcpwm_generator_t gen,
float duty)
esp_err_t mcpwm_set_duty_in_us(
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num,
mcpwm_generator_t gen,
uint32_t duty_in_us)
float mcpwm_get_duty(
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num,
mcpwm_operator_t gen)
esp_err_t mcpwm_set_frequency(
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num,
uint32_t frequency)
uint32_t mcpwm_get_frequency(
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num)
示例程序
本示例程序配置MCPWM0的定时器0输出5KHz的PWM,并每5ms动态调整占空比,需要注意的是系统默认tick速率位100Hz(10ms),不能延迟小于10ms,需进行以下修改,改为1ms(1000Hz)即可。
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "string.h"
#include "driver/mcpwm.h"
void app_main(void)
{
mcpwm_pin_config_t mcpwm_pin = {
.mcpwm0a_out_num = 14,
.mcpwm0b_out_num = 15,
.mcpwm1a_out_num = -1,
.mcpwm1b_out_num = -1,
.mcpwm2a_out_num = -1,
.mcpwm2b_out_num = -1,
.mcpwm_cap0_in_num = -1,
.mcpwm_cap1_in_num = -1,
.mcpwm_cap2_in_num = -1,
.mcpwm_sync0_in_num = -1,
.mcpwm_sync1_in_num = -1,
.mcpwm_sync2_in_num = -1,
.mcpwm_fault0_in_num = -1,
.mcpwm_fault1_in_num = -1,
.mcpwm_fault2_in_num = -1
};
ESP_ERROR_CHECK(mcpwm_set_pin(MCPWM_UNIT_0, &mcpwm_pin));
ESP_ERROR_CHECK(mcpwm_group_set_resolution(MCPWM_UNIT_0, 10000000));
ESP_ERROR_CHECK(mcpwm_timer_set_resolution(MCPWM_UNIT_0, MCPWM_TIMER_0, 1000000));
mcpwm_config_t mcpwm_conf = {
.frequency = 10000,
.cmpr_a = 0,
.cmpr_b = 0,
.duty_mode = MCPWM_DUTY_MODE_0,
.counter_mode = MCPWM_UP_DOWN_COUNTER};
ESP_ERROR_CHECK(mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &mcpwm_conf));
float j;
while(1)
{
for (j = 0.1; j < 100; j = j + 0.1)
{
vTaskDelay(pdMS_TO_TICKS(5));
ESP_ERROR_CHECK(mcpwm_set_duty(
MCPWM_UNIT_0,
MCPWM_TIMER_0,
MCPWM_GEN_A,
j));
ESP_ERROR_CHECK(mcpwm_set_duty(
MCPWM_UNIT_0,
MCPWM_TIMER_0,
MCPWM_GEN_B,
j));
}
for (j = 99.9; j > 0; j = j - 0.1)
{
vTaskDelay(pdMS_TO_TICKS(5));
ESP_ERROR_CHECK(mcpwm_set_duty(
MCPWM_UNIT_0,
MCPWM_TIMER_0,
MCPWM_GEN_A,
j));
ESP_ERROR_CHECK(mcpwm_set_duty(
MCPWM_UNIT_0,
MCPWM_TIMER_0,
MCPWM_GEN_B,
j));
}
}
}
效果展示: 示波器1通道—MCPWM0_TIMER0_A; 示波器2通道—MCPWM0_TIMER0_B;
死区时间设置
原理说明
死区时间 : MOS管都存在结电容,存在开关延迟,死区时间是为了保证上下桥臂的MOS管不会同时导通的时间,一般在us级 ESP32死区时间控制原理如下图所示,控制S1 to S7 开关可选择不同的死区时间配置模式。
设置开关不容易理解且繁琐,下面列出几种常用的工作模式:
MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE(高有效互补): 输出A与输入同相,不考虑死区时间时输出A与B互补(A=!B),死区时间内A=B。 MCPWM_ACTIVE_LOW_COMPLIMENT_MODE(低有效互补): 输出A与输入反相,不考虑死区时间时输出A与B互补(A=!B),死区时间内A=B。 MCPWM_ACTIVE_HIGH_MODE(高有效模式): 输出A与输入同相,不考虑死区时间时输出A与B相等(A=B),死区时间内A=!B。 MCPWM_ACTIVE_LOW_MODE(低有效模式): 输出A与输入反相,不考虑死区时间时输出A与B相等(A=B),死区时间内A=!B。
函数说明
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)
示例程序
该程序展示死区时间配置,死区模块配置为高有效互补模式,输出只与A相关,因此只需要调整A的占空比即可。上升沿延迟和下降沿延迟均为10us,需注意mcpwm_deadtime_enable()函数需在mcpwm_init()函数之后执行,否则无效。
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "string.h"
#include "driver/mcpwm.h"
void app_main(void)
{
float j;
mcpwm_pin_config_t mcpwm_pin = {
.mcpwm0a_out_num = 14,
.mcpwm0b_out_num = 15,
.mcpwm1a_out_num = -1,
.mcpwm1b_out_num = -1,
.mcpwm2a_out_num = -1,
.mcpwm2b_out_num = -1,
.mcpwm_cap0_in_num = -1,
.mcpwm_cap1_in_num = -1,
.mcpwm_cap2_in_num = -1,
.mcpwm_sync0_in_num = -1,
.mcpwm_sync1_in_num = -1,
.mcpwm_sync2_in_num = -1,
.mcpwm_fault0_in_num = -1,
.mcpwm_fault1_in_num = -1,
.mcpwm_fault2_in_num = -1
};
ESP_ERROR_CHECK(mcpwm_set_pin(MCPWM_UNIT_0, &mcpwm_pin));
ESP_ERROR_CHECK(mcpwm_group_set_resolution(MCPWM_UNIT_0, 10000000));
ESP_ERROR_CHECK(mcpwm_timer_set_resolution(MCPWM_UNIT_0, MCPWM_TIMER_0, 1000000));
mcpwm_config_t mcpwm_conf = {
.frequency = 10000,
.cmpr_a = 0,
.cmpr_b = 0,
.duty_mode = MCPWM_DUTY_MODE_0,
.counter_mode = MCPWM_UP_DOWN_COUNTER};
ESP_ERROR_CHECK(mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &mcpwm_conf));
ESP_ERROR_CHECK(mcpwm_deadtime_enable(
MCPWM_UNIT_0,
MCPWM_TIMER_0,
MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE,
100,
100));
while (1)
{
for (j = 20; j < 80; j = j + 0.1)
{
vTaskDelay(pdMS_TO_TICKS(5));
ESP_ERROR_CHECK(mcpwm_set_duty(
MCPWM_UNIT_0,
MCPWM_TIMER_0,
MCPWM_GEN_A,
j));
}
for (j = 80; j > 20; j = j - 0.1)
{
vTaskDelay(pdMS_TO_TICKS(5));
ESP_ERROR_CHECK(mcpwm_set_duty(
MCPWM_UNIT_0,
MCPWM_TIMER_0,
MCPWM_GEN_A,
j));
}
}
}
效果: 示波器1通道—MCPWM0_TIMER0_A; 示波器2通道—MCPWM0_TIMER0_B;
定时器同步
定时器同步用于对不同定时器之间计数值的同步,输入同步信号支持GPIO或来自其他定时器的同步输出信号。
关键函数说明
esp_err_t mcpwm_sync_configure(
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num,
const mcpwm_sync_config_t *sync_conf)
esp_err_t mcpwm_sync_disable(
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num)
mcpwm_sync_config_t sync_cfg = {
.sync_sig = MCPWM_SELECT_GPIO_SYNC0,
.timer_val = 0,
.count_direction = MCPWM_TIMER_DIRECTION_UP};
示例程序
该程序启动MCPWM0中的Timer0和Timer1两个定时器,分别输出两个异步的PWM波,然后采用GPIO同步的方式,设置IO输出同步脉冲,进行软件同步。 注意: 该程序复用IO2即作为2个定时器的同步输入信号,又作为双向IO可进行软件置位/清零,IO复位后需先配置 mcpwm_set_pin() ,再配置IO方向,否则后面设置IO2高低电平函数不起作用。
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "string.h"
#include "driver/mcpwm.h"
#include "driver/gpio.h"
#define io_num(x) x
void app_main(void)
{
float j;
mcpwm_pin_config_t mcpwm_pin = {
.mcpwm0a_out_num = io_num(14),
.mcpwm0b_out_num = io_num(15),
.mcpwm1a_out_num = io_num(4),
.mcpwm1b_out_num = io_num(9),
.mcpwm2a_out_num = -1,
.mcpwm2b_out_num = -1,
.mcpwm_cap0_in_num = -1,
.mcpwm_cap1_in_num = -1,
.mcpwm_cap2_in_num = -1,
.mcpwm_sync0_in_num = io_num(2),
.mcpwm_sync1_in_num = -1,
.mcpwm_sync2_in_num = -1,
.mcpwm_fault0_in_num = -1,
.mcpwm_fault1_in_num = -1,
.mcpwm_fault2_in_num = -1
};
gpio_reset_pin(io_num(2));
ESP_ERROR_CHECK(mcpwm_set_pin(MCPWM_UNIT_0, &mcpwm_pin));
gpio_set_direction(io_num(2), GPIO_MODE_INPUT_OUTPUT);
ESP_ERROR_CHECK(mcpwm_group_set_resolution(MCPWM_UNIT_0, 10000000));
ESP_ERROR_CHECK(mcpwm_timer_set_resolution(MCPWM_UNIT_0, MCPWM_TIMER_0, 1000000));
ESP_ERROR_CHECK(mcpwm_timer_set_resolution(MCPWM_UNIT_0, MCPWM_TIMER_1, 1000000));
mcpwm_config_t mcpwm_conf = {
.frequency = 10000,
.cmpr_a = 0,
.cmpr_b = 0,
.duty_mode = MCPWM_DUTY_MODE_0,
.counter_mode = MCPWM_UP_DOWN_COUNTER};
ESP_ERROR_CHECK(mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &mcpwm_conf));
vTaskDelay(pdMS_TO_TICKS(50));
ESP_ERROR_CHECK(mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &mcpwm_conf));
mcpwm_sync_config_t sync_cfg = {
.sync_sig = MCPWM_SELECT_GPIO_SYNC0,
.timer_val = 0,
.count_direction = MCPWM_TIMER_DIRECTION_UP};
ESP_ERROR_CHECK(mcpwm_sync_configure(
MCPWM_UNIT_0,
MCPWM_TIMER_0,
&sync_cfg));
ESP_ERROR_CHECK(mcpwm_sync_configure(
MCPWM_UNIT_0,
MCPWM_TIMER_1,
&sync_cfg));
gpio_set_level(io_num(2), 0);
vTaskDelay(pdMS_TO_TICKS(5));
gpio_set_level(io_num(2), 1);
vTaskDelay(pdMS_TO_TICKS(5));
gpio_set_level(io_num(2), 0);
vTaskDelay(pdMS_TO_TICKS(5));
while (1)
{
for (j = 20; j < 80; j = j + 0.1)
{
vTaskDelay(pdMS_TO_TICKS(5));
ESP_ERROR_CHECK(mcpwm_set_duty(
MCPWM_UNIT_0,
MCPWM_TIMER_0,
MCPWM_GEN_A,
j));
ESP_ERROR_CHECK(mcpwm_set_duty(
MCPWM_UNIT_0,
MCPWM_TIMER_1,
MCPWM_GEN_A,
j));
}
for (j = 80; j > 20; j = j - 0.1)
{
vTaskDelay(pdMS_TO_TICKS(5));
ESP_ERROR_CHECK(mcpwm_set_duty(
MCPWM_UNIT_0,
MCPWM_TIMER_0,
MCPWM_GEN_A,
j));
ESP_ERROR_CHECK(mcpwm_set_duty(
MCPWM_UNIT_0,
MCPWM_TIMER_1,
MCPWM_GEN_A,
j));
}
}
}
效果: 不同步,示波器1通道—MCPWM0_TIMER0_A; 示波器2通道—MCPWM0_TIMER1_A; 同步之后:
参考
https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/peripherals/mcpwm.html
|