目录
前言
目录
配置
操作
例程1
例程1解析
本篇为乐鑫官方文档,地址:Motor Control Pulse Width Modulator (MCPWM) - ESP32 - — ESP-IDF 编程指南 latest 文档
看下图可以非常清楚的看到ESP32 有两个 MCPWM 单元,分别是MCPWM_UNIT_0和MCPWM_UNIT_1。
每个 MCPWM 单元有三个定时器,分别是下图中的数字标号0,1,2。
每个定时器可以产生2路pwm,分别是下图中的A和B。
也就是说通过mcpwm最多可以产生2*3*2=12路(6对)pwm信号。可用于控制不同的电机。每个单元有三对 PWM 输出 。(从下图可以非常清晰的看到)
此外,在文章中,每个MCPWM单元的单个信号的输出标记为PWMxA/PWMxB。
例如MCPWM_UNIT_0的六路pwm输出,从上到下可以标记为PWM0A/PWM0B,PWM1A/PWM1B,PWM2A/PWM2B。MCPWM_UNIT_1同理。
MCPWM单元的更详细框图如下所示。每个A/B对可由三个定时器0、1和2中的任意一个定时器计时。同一定时器可用于对多对PWM输出进行计时。每个单元还能够收集同步信号等输入,检测电机过流或过压等故障信号,以及获取转子位置等捕捉信号的反馈。
本API的描述从配置MCPWM的定时器和发电机子模块开始,以提供基本的电机控制功能。然后讨论了故障处理器、信号捕获和载波的更高级子模块和功能。
配置输出的基本功能
操作输出以驱动电机
调整电机的驱动方式
同步同步计时器以协同工作
捕获外部信号以提供对输出的额外控制
使用故障处理程序检测和管理故障
如果输出信号通过隔离变压器,则添加更高频率的载波
额外的分辨率配置
配置范围取决于电机类型,特别是需要多少输出和输入,以及驱动电机的信号顺序。
在这种情况下,我们将描述一种简单的配置,用于控制仅使用部分可用MCPWM资源的有刷直流电机。下面显示了一个示例电路。它包括一个H桥,用于切换施加在电机(M)上的电压的极化,并提供足够的电流来驱动电机。
1.选择用于驱动电机的MCPWM装置。ESP32板上有两个可用单元,并在mcpwm_单元中列出。
2.通过调用mcpwm_gpio_init()初始化两个gpio作为所选单元内的输出信号。这两个输出信号通常用于命令电机向右或向左旋转。mcpwm\u io\u signals\t中列出了所有可用的信号选项。要一次设置多个管脚,请将函数mcpwm_set_pin()与mcpwm_pin_config_t一起使用。
3.定时器的选择。该装置内有三个定时器。定时器在mcpwm\u timer\t中列出。
4.在mcpwm配置结构内设置定时器频率和初始占空比。
5.如有必要,通过调用mcpwm_group_set_resolution()和mcpwm_timer_set_resolution()设置计时器分辨率
6.调用函数mcpwm_init()和上述参数,使配置生效
#include "driver/mcpwm.h"
#include "soc/mcpwm_reg.h"
#include "soc/mcpwm_struct.h"
#define MOTO_GPIO1 18
#define MOTO_GPIO2 5
//步骤一:选择mcpwm_unit
#define MOTOR_MCPWM_UNIT MCPWM_UNIT_0
//初始化需要的四个gpio口
void setup(){
//步骤二:用选定的mcpwm_unit来初始化gpio口
mcpwm_gpio_init(MOTOR_MCPWM_UNIT, MCPWM0A, MOTO_GPIO1);
mcpwm_gpio_init(MOTOR_MCPWM_UNIT, MCPWM0B, MOTO_GPIO2);
//步骤三:用mcpwm_init()这个函数为这个mcpwm_unit选定一个定时器,
#define MOTO_TIMER MCPWM_TIMER_0
mcpwm_config_t pwm_config;
//步骤四:通过mcpwm_config_t结构体为定时器设置频率和初始值
pwm_config.frequency = 1000; //frequency = 500Hz,
pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0
pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
//步骤五:调用mcpwm_init()函数使得配置生效
mcpwm_init(MOTOR_MCPWM_UNIT, MOTO_TIMER, &pwm_config); //Configure PWM0A & PWM0B with above settings
}
void loop(){
mcpwm_set_signal_low(MOTOR_MCPWM_UNIT, MOTO_TIMER, MCPWM_OPR_A);
mcpwm_set_duty(MOTOR_MCPWM_UNIT, MOTO_TIMER, MCPWM_OPR_B, 30);
mcpwm_set_duty_type(MOTOR_MCPWM_UNIT, MOTO_TIMER, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //call this each time, if operator was previously in low/high state
}
通过mcpwm_config_t结构体,我们可以新建一个mcpwm设置的结构体,进行相关设置,例如mcpwm的频率(frequency),
/**
* @brief MCPWM config structure
*/
typedef struct {
uint32_t frequency; /*!
接下来,就可以通过接口函数,设置对应的通道引脚为高、为低、或是有PWM波形。
通过调用 mcpwm _ set _ duty _ type ()可以改变 PWM 信号的相位,最后一个参数是表示mcpwm相位的,通过查看下面源码,我们可以看到这是个枚举类型。
typedef enum {
MCPWM_DUTY_MODE_0 = 0, /*!
所以,需要注意的是mcpwm_set_duty和mcpwm_set_duty_type 这两个函数必须要同时调用来控制一个通道引脚上产生pwm波形 。毕竟想要控制波形不光要有占空比,还需要相位。
我们看上述例程中最后一行代码,其中MCPWM_DUTY_MODE_1代表高电平占空比,MCPWM_DUTY_MODE_0代表低电平占空比。
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);
我们来看看不同代码的效果:
mcpwm_set_duty(MOTOR_MCPWM_UNIT, MOTO_TIMER, MCPWM_OPR_B, 30);
mcpwm_set_duty_type(MOTOR_MCPWM_UNIT, MOTO_TIMER, MCPWM_OPR_B, MCPWM_DUTY_MODE_0);
效果
mcpwm_set_duty(MOTOR_MCPWM_UNIT, MOTO_TIMER, MCPWM_OPR_B, 30);
mcpwm_set_duty_type(MOTOR_MCPWM_UNIT, MOTO_TIMER, MCPWM_OPR_B, MCPWM_DUTY_MODE_1);
效果
MCPWM.h
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/soc_caps.h"
#if SOC_MCPWM_SUPPORTED
#include "esp_err.h"
#include "soc/soc.h"
#include "driver/gpio.h"
#include "esp_intr_alloc.h"
#include "hal/mcpwm_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief IO signals for the MCPWM
*
* - 6 MCPWM output pins that generate PWM signals
* - 3 MCPWM fault input pins to detect faults like overcurrent, overvoltage, etc.
* - 3 MCPWM sync input pins to synchronize MCPWM outputs signals
* - 3 MCPWM capture input pins to gather feedback from controlled motors, using e.g. hall sensors
*/
typedef enum {
MCPWM0A = 0, /*!