esp32外设使用-MCPWM捕获模块使用

  • 概述
  • 关键函数说明
  • 示例代码


概述

捕获模块包含3 个完整的捕获通道,通道输入信号CAP0,CAP1 和CAP2 来自于GPIO 矩阵。由于GPIO 矩阵
的灵活性,CAP0,CAP1 和CAP2 可以通过任一管脚输入配置。多个捕获通道可同时采集同一个管脚,每个
通道可设置独立的分频系数。因此,可以通过后台硬件用多种方式处理捕获信号,而不直接由CPU 处理。
每个模块都有以下独立资源:

  • 一个32 位计数器(用于产生时间戳),可以被同步(重载相位寄存器的配置值)。
  • 每个通道支持:上升、下降、上升或下降三种模式
  • 输入捕获信号分频系数可配置(1 –256),输入为APB_CLK(默认:80MHz)。
  • 三个捕获事件都有中断功能。

捕获模块采集外部IO上升/下降沿,并记录当前边沿的时间戳,以此来计算脉冲宽度等信息。

关键函数说明

//捕获模块及中断配置
mcpwm_capture_config_t cap_cfg = {
    .cap_edge = MCPWM_BOTH_EDGE, // MCPWM_NEG_EDGE / MCPWM_POS_EDGE / MCPWM_BOTH_EDGE
    .cap_prescale = 1,           // 1-256 数值约小采集精度越高 1-最高精度
    .capture_cb = cap0_isr,      //中断回调函数
    .user_data = myTastHandle1}; //回调函数传输数据
//使能捕获通道
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(
    MCPWM_UNIT_0,      // MCPWM_UNIT_0 / MCPWM_UNIT_1
    MCPWM_SELECT_CAP0, // MCPWM_SELECT_CAP0 / MCPWM_SELECT_CAP1 / MCPWM_SELECT_CAP2
    &cap_cfg));        // 捕获配置
    
//捕获事件回调函数,返回值为true/false,表示在回调函数返回后是否需要任务切换,这通常是由于回调函数中唤醒了一些高优先级的任务,需要回调函数返回时立即调用。
typedef bool (*cap_isr_cb_t)(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_channel, const cap_event_data_t *edata, void *user_data)
//关闭捕获通道
esp_err_t mcpwm_capture_disable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_channel_id_t cap_channel)
//获取上次事件的时间戳,返回值为时间戳
uint32_t mcpwm_capture_signal_get_value(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig)
//获取上次事件的边沿类型,返回值为边沿类型
uint32_t mcpwm_capture_signal_get_edge(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig)

示例代码

该程序需要将io14和io4断接,程序从14脚输出可调整脉冲宽度的pwm信号,4脚作为捕获管脚,采集并计算实际输出pwm脉冲宽度,并打印出来。

#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"

#define io_num(x) x

mcpwm_capture_signal_t g_cap_edge = 0;
mcpwm_capture_signal_t g_cap_edge_old = 0;

uint32_t g_cap_value = 0;

static bool IRAM_ATTR cap0_isr(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_channel, const cap_event_data_t *edata, void *user_data)
{
    TaskHandle_t task_to_notify = (TaskHandle_t)user_data;
    BaseType_t high_task_wakeup = pdFALSE;
    g_cap_edge = edata->cap_edge;
    g_cap_value = edata->cap_value;
    //xTaskNotifyGive(task_to_notify);
    vTaskNotifyGiveFromISR(task_to_notify, &high_task_wakeup);
    return 0;
}

void mytask1(void *pvParameter)
{
    float t;
    while (1)
    {
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        if (g_cap_edge == 2)
            g_cap_edge_old = g_cap_value;
        if (g_cap_edge == 1)
        {
            t = (g_cap_value - g_cap_edge_old) * 12.5 / 1000000;
            printf("task1: positive pulse width is %f ms g_cap_value = %d \n", t , g_cap_value);
        }
    }
    vTaskDelete(NULL);
}

void app_main(void)
{
    //输出任务配置
    TaskHandle_t myTastHandle1 = NULL;
    xTaskCreate(mytask1, "mytask1", 1024 * 5, NULL, 1, &myTastHandle1);

    // mcpwm IO配置
    mcpwm_pin_config_t mcpwm_pin = {
        .mcpwm0a_out_num = io_num(14), //实际IO号
        .mcpwm0b_out_num = io_num(15),
        .mcpwm1a_out_num = -1,
        .mcpwm1b_out_num = -1,
        .mcpwm2a_out_num = -1,
        .mcpwm2b_out_num = -1,
        .mcpwm_cap0_in_num = io_num(4),
        .mcpwm_cap1_in_num = -1,
        .mcpwm_cap2_in_num = -1,
        .mcpwm_sync0_in_num = -1, // Not used
        .mcpwm_sync1_in_num = -1, // Not used
        .mcpwm_sync2_in_num = -1, // Not used
        .mcpwm_fault0_in_num = -1,
        .mcpwm_fault1_in_num = -1, // Not used
        .mcpwm_fault2_in_num = -1  // Not used
    };
    ESP_ERROR_CHECK(mcpwm_set_pin(MCPWM_UNIT_0, &mcpwm_pin));
    //设置PWM定时器分辨率
    ESP_ERROR_CHECK(mcpwm_group_set_resolution(MCPWM_UNIT_0, 10000000));               // MCPWM号(0/1)、分辨率(默认:10,000,000)
    ESP_ERROR_CHECK(mcpwm_timer_set_resolution(MCPWM_UNIT_0, MCPWM_TIMER_0, 1000000)); //定时器号(0/1/2)、分辨率(默认:1,000,000)
    mcpwm_config_t mcpwm_conf = {
        .frequency = 100, //输出pwm波形频率 Hz
        .cmpr_a = 0,      //操作器A输出占空比, i.e duty_a = 62.3
        .cmpr_b = 0,      //操作器B输出占空比, i.e duty_a = 42.8
        /*******************************************
         *duty_mode (占空比类型):
         *	MCPWM_DUTY_MODE_0: 高有效,例如:%20占空比 == 高电平20%
         *	MCPWM_DUTY_MODE_1: 低有效,例如:%20占空比 == 低电平20%
         *	MCPWM_HAL_GENERATOR_MODE_FORCE_LOW: 输出强制为低
         *	MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH:输出强制为高
         *	MCPWM_DUTY_MODE_MAX:Num of duty cycle modes
         ********************************************/
        .duty_mode = MCPWM_DUTY_MODE_0,
        /****************************************
         * counter_mode (计数模式):
         * 	MCPWM_FREEZE_COUNTER: 计数器冻结
         * 	MCPWM_UP_COUNTER:  计数器递增,左对齐,频率不变
         * 	MCPWM_DOWN_COUNTER: 计数器递减,右对齐,频率不变
         * 	MCPWM_UP_DOWN_COUNTER:计数器递增递减,中间对齐,频率减半
         ********************************************/
        .counter_mode = MCPWM_UP_COUNTER};
    ESP_ERROR_CHECK(mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &mcpwm_conf)); //启动定时器0

    //捕获模块及中断配置
    mcpwm_capture_config_t cap_cfg = {
        .cap_edge = MCPWM_BOTH_EDGE, // MCPWM_NEG_EDGE / MCPWM_POS_EDGE / MCPWM_BOTH_EDGE
        .cap_prescale = 1,           // 1-256 数值约小采集精度越高 1-最高精度
        .capture_cb = cap0_isr,      //中断回调函数
        .user_data = myTastHandle1}; //回调函数传输数据
    ESP_ERROR_CHECK(mcpwm_capture_enable_channel(
        MCPWM_UNIT_0,      // MCPWM_UNIT_0 / MCPWM_UNIT_1
        MCPWM_SELECT_CAP0, // MCPWM_SELECT_CAP0 / MCPWM_SELECT_CAP1 / MCPWM_SELECT_CAP2
        &cap_cfg));        // 捕获配置

    // 100ms钟30%占空比
    ESP_ERROR_CHECK(mcpwm_set_duty(
        MCPWM_UNIT_0,  // MCPWM_UNIT_0 / MCPWM_UNIT_1
        MCPWM_TIMER_0, // MCPWM_TIMER_0 / MCPWM_TIMER_1 / MCPWM_TIMER_2
        MCPWM_GEN_A,   // MCPWM_GEN_A / MCPWM_GEN_B
        30));          // 0.0 to 100.0,精度为小数点后1位,设置0和100等效于强制输出高、低
    vTaskDelay(pdMS_TO_TICKS(100));
    // 100ms钟80%占空比
    ESP_ERROR_CHECK(mcpwm_set_duty(
        MCPWM_UNIT_0,  // MCPWM_UNIT_0 / MCPWM_UNIT_1
        MCPWM_TIMER_0, // MCPWM_TIMER_0 / MCPWM_TIMER_1 / MCPWM_TIMER_2
        MCPWM_GEN_A,   // MCPWM_GEN_A / MCPWM_GEN_B
        80));          // 0.0 to 100.0,精度为小数点后1位,设置0和100等效于强制输出高、低
    vTaskDelay(pdMS_TO_TICKS(100));
    //输出低电平
    ESP_ERROR_CHECK(mcpwm_set_duty(
        MCPWM_UNIT_0,  // MCPWM_UNIT_0 / MCPWM_UNIT_1
        MCPWM_TIMER_0, // MCPWM_TIMER_0 / MCPWM_TIMER_1 / MCPWM_TIMER_2
        MCPWM_GEN_A,   // MCPWM_GEN_A / MCPWM_GEN_B
        0));           // 0.0 to 100.0,精度为小数点后1位,设置0和100等效于强制输出高、低
}

效果

task1: positive pulse width is 3.000000 ms g_cap_value = 1836843
task1: positive pulse width is 3.000000 ms g_cap_value = 2636843
task1: positive pulse width is 3.000000 ms g_cap_value = 3436843
task1: positive pulse width is 3.000000 ms g_cap_value = 4236843
task1: positive pulse width is 3.000000 ms g_cap_value = 5036843
task1: positive pulse width is 3.000000 ms g_cap_value = 5836843
task1: positive pulse width is 3.000000 ms g_cap_value = 6636843
task1: positive pulse width is 3.000000 ms g_cap_value = 7436843
task1: positive pulse width is 8.000000 ms g_cap_value = 8636843
task1: positive pulse width is 8.000000 ms g_cap_value = 9436843
task1: positive pulse width is 8.000000 ms g_cap_value = 10236843
task1: positive pulse width is 8.000000 ms g_cap_value = 11036843
task1: positive pulse width is 8.000000 ms g_cap_value = 11836843
task1: positive pulse width is 8.000000 ms g_cap_value = 12636843
task1: positive pulse width is 8.000000 ms g_cap_value = 13436843
task1: positive pulse width is 8.000000 ms g_cap_value = 14236843
task1: positive pulse width is 8.000000 ms g_cap_value = 15036843
task1: positive pulse width is 8.000000 ms g_cap_value = 15836843
task1: positive pulse width is 10.000100 ms g_cap_value = 15996851