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