ESP32-S3-PCNT(脉冲计数控制器)

文章目录

  • 一、PCNT
    • [   1、PCNT](#   1、PCNT)
    • [   2、核心能力](#   2、核心能力)
    • [   3、ESP32_S3_PCNT组成结构](#   3、ESP32_S3_PCNT组成结构)
  • 二、PCNT原理
    • [   1、PCNT框图](#   1、PCNT框图)
    • [   2、硬件滤波模块 filter](#   2、硬件滤波模块 filter)
    • [   3、多路选择 + 增减逻辑单元 inc_dec](#   3、多路选择 + 增减逻辑单元 inc_dec)
    • [   4、加法器 adder 全局控制](#   4、加法器 adder 全局控制)
    • [   5、阈值比较与中断输出模块](#   5、阈值比较与中断输出模块)
    • [   6、工程设计注意点](#   6、工程设计注意点)
  • [三、PCNT API](#三、PCNT API)
    • [   1、头文件/组件](#   1、头文件/组件)
      • [     头文件:](#     头文件:)
      • [     组件:](#     组件:)
    • [   2、枚举类型](#   2、枚举类型)
      • [     1. pcunt_count_mode_t 信号边沿计数动作](#     1. pcunt_count_mode_t 信号边沿计数动作)
      • [     2. pcnt_ctrl_mode_t Ctrl 方向电平策略](#     2. pcnt_ctrl_mode_t Ctrl 方向电平策略)
      • [     3. pcnt_unit_id_t PCNT 单元编号](#     3. pcnt_unit_id_t PCNT 单元编号)
      • [     4. pcnt_event_type_t 中断事件类型](#     4. pcnt_event_type_t 中断事件类型)
    • [   3、配置结构体](#   3、配置结构体)
      • [     1. pcnt_unit_config_t 单元全局配置](#     1. pcnt_unit_config_t 单元全局配置)
      • [     2. pcnt_channel_config_t 单通道引脚与计数规则配置](#     2. pcnt_channel_config_t 单通道引脚与计数规则配置)
      • [     3. 回调事件数据 pcnt_event_data_t](#     3. 回调事件数据 pcnt_event_data_t)
      • [     4. 回调结构体 pcnt_event_callbacks_t](#     4. 回调结构体 pcnt_event_callbacks_t)
    • [   4、创建 / 销毁资源API](#   4、创建 / 销毁资源API)
    • [   5、运行控制类API](#   5、运行控制类API)
    • [   6、中断回调配置函数](#   6、中断回调配置函数)
    • [   7、动态阈值配置类](#   7、动态阈值配置类)
    • [   8、开发流程](#   8、开发流程)
  • 四、示例代码
    • [   1、示例代码](#   1、示例代码)
    • [   2、执行结果](#   2、执行结果)

一、PCNT

   1、PCNT

     PCNT(Pulse Counter,脉冲计数控制器)是ESP32-S3内置的专用硬件脉冲计数外设,专为高频脉冲采集、正交编码器测速、脉冲信号统计设计。

     ESP32-S3搭载4个独立PCNT单元,每个单元包含2路脉冲输入通道,支持正交解码、单边计数、双向增减计数,可同时采集多路脉冲设备信号。

   2、核心能力

     对外部 GPIO 脉冲上升 / 下降沿做硬件计数,不需要 CPU 干预。

     支持方向控制信号,自动加 / 减计数。

     设置阈值,到达阈值产生中断。

     计数可过滤输入噪声(输入滤波)。

     16 位计数器,范围:‑32768 ~ +32767。

   3、ESP32_S3_PCNT组成结构

     PCNT 有四个称为"单元"的独立脉冲计数控制器,这些单元拥有自己的寄存器。

     PCNT 模块仅有一个时钟,为 APB_CLK。

     每个单元有两个通道(ch0 和 ch1),可以独立配置为递增或递减计数。

     每个通道有两个输入信号:

       一个脉冲输入信号(如 sig_ch0_un 为单元 n ch0 的脉冲输入信号。

       一个控制信号(如 ctrl_ch0_un 为单元 n ch0 的控制信号。

    

二、PCNT原理

   1、PCNT框图

    

   2、硬件滤波模块 filter

     输入:sig脉冲信号、ctrl方向控制信号分别独立滤波。

     配置寄存器:PCNT_FILTER_EN_Un(滤波使能)、PCNT_FILTER_THRES_Un(滤波阈值)。

     作用:宽度小于阈值的高频毛刺直接过滤,硬件消抖,无需软件防抖,适配机械编码器抖动场景。

   3、多路选择 + 增减逻辑单元 inc_dec

     配置寄存器分组:

       边沿动作配置:

         PCNT_CHx_POS_MODE_Un(sig 上升沿动作:加 / 减 / 不计数)。

         PCNT_CHx_NEG_MODE_Un(sig 下降沿动作:加 / 减 / 不计数)。

       方向控制配置:

         PCNT_CHx_HCTRL_MODE_Un(ctrl 高电平时计数策略)。

         PCNT_CHx_LCTRL_MODE_Un(ctrl 低电平时计数策略)。

     工作逻辑:

       sig提供脉冲边沿触发时机,ctrl电平决定本次计数是+1、-1、忽略。

       正交编码器模式下,A 相接 sig、B 相接 ctrl,可天然实现正反转自动增减计数。

   4、加法器 adder 全局控制

     输入来源:

       CH0、CH1 两路inc_dec的计数增量共同送入加法器累加。

     全局控制信号:

       PCNT_CNT_PAUSE_Un:暂停计数冻结当前值。

       PCNT_PULSE_CNT_RST_Un:硬件清零计数器(CLR 端口)。

     关键优势:

       双通道同时接入编码器 AB 相可实现四倍频正交计数,单通道仅能二倍频。

   5、阈值比较与中断输出模块

     加法器输出的pulse_cnt同时送入 5 组比较器:

      

   6、工程设计注意点

     1.滤波优先开启:

       机械编码器务必配置filter阈值,从硬件层面抑制触点抖动;

     2.计数模式选型:

       普通单端脉冲计数:仅用 CH0,ctrl引脚悬空配置为无效;

       正交编码器测速:CH0+CH1 双通道接入 AB 相,实现四倍频提升测量精度;

     3.溢出防护:

       PCNT 原生 16 位计数范围-32768~+32767,利用高低限中断做软件累计值扩展,突破位数限制;

     4.低 CPU 占用:

       全链路计数、滤波、比较均为硬件逻辑,CPU 仅需定时读取数值或响应阈值中断,不占用运算资源。

三、PCNT API

   1、头文件/组件

     头文件:

       #include "driver/pulse_cnt.h"

     组件:

       REQUIRES esp_driver_pcnt

   2、枚举类型

     1. pcunt_count_mode_t 信号边沿计数动作

c 复制代码
			typedef enum {
			    PCNT_COUNT_DIS = 0,    // 该边沿不计数
			    PCNT_COUNT_INC,        // 触发边沿时计数值 +1
			    PCNT_COUNT_DEC         // 触发边沿时计数值 -1
			} pcnt_count_mode_t;

     2. pcnt_ctrl_mode_t Ctrl 方向电平策略

c 复制代码
			typedef enum {
			    PCNT_CTRL_MODE_KEEP = 0,     // 保持sig边沿预设的增减规则
			    PCNT_CTRL_MODE_REVERSE,      // 反转sig边沿的增减方向
			    PCNT_CTRL_MODE_INC,          // Ctrl当前电平强制本次+1
			    PCNT_CTRL_MODE_DEC           // Ctrl当前电平强制本次-1
			} pcnt_ctrl_mode_t;

     3. pcnt_unit_id_t PCNT 单元编号

c 复制代码
			typedef enum {
			    PCNT_UNIT_0, PCNT_UNIT_1, PCNT_UNIT_2, PCNT_UNIT_3,
			    PCNT_UNIT_4, PCNT_UNIT_5, PCNT_UNIT_6, PCNT_UNIT_7
			} pcnt_unit_id_t;

     4. pcnt_event_type_t 中断事件类型

c 复制代码
			typedef enum {
			    PCNT_EVT_H_LIM,    // 计数到达高上限阈值
			    PCNT_EVT_L_LIM,    // 计数到达低下限阈值
			    PCNT_EVT_THRES_0,  // 计数匹配阈值0
			    PCNT_EVT_THRES_1,  // 计数匹配阈值1
			    PCNT_EVT_ZERO      // 计数归零
			} pcnt_event_type_t;

   3、配置结构体

     1. pcnt_unit_config_t 单元全局配置

c 复制代码
			typedef struct {
			    pcnt_unit_id_t unit_id;  // 指定PCNT单元编号
			    int low_limit;           // 计数下限(-32768~32767),触发L_LIM事件
			    int high_limit;          // 计数上限(-32768~32767),触发H_LIM事件
			} pcnt_unit_config_t;

     2. pcnt_channel_config_t 单通道引脚与计数规则配置

c 复制代码
			typedef struct {
			    int sig_gpio_num;        // SIG脉冲输入GPIO编号
			    int ctrl_gpio_num;       // CTRL方向控制GPIO,填-1表示不使用方向脚
			    pcnt_count_mode_t pos_mode;  // SIG上升沿计数动作
			    pcnt_count_mode_t neg_mode;  // SIG下降沿计数动作
			    pcnt_ctrl_mode_t hctrl_mode; // CTRL引脚高电平时的计数策略
			    pcnt_ctrl_mode_t lctrl_mode; // CTRL引脚低电平时的计数策略
			    uint32_t filter_ns;      // 硬件滤波时间(单位ns),0=关闭滤波,过滤窄毛刺
			} pcnt_channel_config_t;

     3. 回调事件数据 pcnt_event_data_t

c 复制代码
			typedef struct {
			    pcnt_event_type_t type;  // 触发的具体事件类型
			} pcnt_event_data_t;

     4. 回调结构体 pcnt_event_callbacks_t

复制代码
			typedef struct {
			    // 阈值/上下限/零值事件回调,中断上下文执行
			    bool (*on_reach)(pcnt_unit_handle_t unit, const pcnt_event_data_t *event_data, void *user_data);
			} pcnt_event_callbacks_t;

   4、创建 / 销毁资源API

c 复制代码
		esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *ret_handle);
		//创建并初始化一个 PCNT 单元,返回句柄
		esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit);        
		//禁用单元、释放硬件资源
		esp_err_t pcnt_new_channel(pcnt_unit_handle_t unit, const pcnt_channel_config_t *config);        
		//为指定 Unit 配置 CH0/CH1 通道参数

   5、运行控制类API

c 复制代码
		esp_err_t pcnt_unit_enable(pcnt_unit_handle_t unit);        
		//使能单元,开始硬件计数
		esp_err_t pcnt_unit_disable(pcnt_unit_handle_t unit);        
		//暂停单元计数
		esp_err_t pcnt_unit_clear_count(pcnt_unit_handle_t unit);        
		//硬件清零当前计数值
		esp_err_t pcnt_unit_get_count(pcnt_unit_handle_t unit, int *count);
		//读取当前实时计数值

   6、中断回调配置函数

c 复制代码
		esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt_event_callbacks_t *cbs, void *user_data);        
		//注册事件中断回调函数,可传入自定义用户参数
		esp_err_t pcnt_set_event_watchpoint(pcnt_unit_handle_t unit, pcnt_event_type_t evt_type, bool enable);        
		//单独开启 / 关闭某一类事件的中断触发

   7、动态阈值配置类

c 复制代码
		esp_err_t pcnt_set_thres0(pcnt_unit_handle_t unit, int thres);        
		//动态修改阈值 0 数值
		esp_err_t pcnt_set_thres1(pcnt_unit_handle_t unit, int thres);        
		//动态修改阈值 1 数值

   8、开发流程

复制代码
	1.定义并填充 pcnt_unit_config_t,调用 pcnt_new_unit 创建单元句柄。
	2.填充 pcnt_channel_config_t,调用 pcnt_new_channel 配置 CH0/CH1。
	3.可选:pcnt_unit_register_event_callbacks 注册阈值中断回调。
	4.可选:pcnt_set_thres0/thres1 设置自定义触发阈值。
	5.pcnt_unit_enable 启动硬件计数。
	6.业务循环:pcnt_unit_get_count 读取数值做运算;溢出中断内做软件累计扩展。
	7.任务退出:pcnt_unit_disable → pcnt_del_unit 释放资源。

四、示例代码

   1、示例代码

c 复制代码
		#include <stdio.h>
		#include "freertos/FreeRTOS.h"
		#include "freertos/task.h"
		#include "driver/pulse_cnt.h"
		#include "esp_log.h"
		static const char *TAG = "PCNT_HALL";
		#define HALL_GPIO          4
		#define PCNT_HIGH_LIMIT    32767
		#define PCNT_LOW_LIMIT     -32768
		pcnt_unit_handle_t pcnt_hall_unit = NULL;
		void pcnt_hall_init(void)
		{
		    // PCNT单元配置
		    pcnt_unit_config_t unit_cfg = {
		        .high_limit = PCNT_HIGH_LIMIT,
		        .low_limit  = PCNT_LOW_LIMIT
		    };
		    ESP_ERROR_CHECK(pcnt_new_unit(&unit_cfg, &pcnt_hall_unit));
		    // 毛刺滤波,霍尔容易有抖动,设置滤波
		    pcnt_glitch_filter_config_t filter_cfg = {
		        .max_glitch_ns = 2000,
		    };
		    ESP_ERROR_CHECK(pcnt_unit_set_glitch_filter(pcnt_hall_unit, &filter_cfg));
		    // PCNT通道配置:edge引脚接霍尔信号,level不使用
		    pcnt_chan_config_t chan_cfg = {
		        .edge_gpio_num = HALL_GPIO,
		        .level_gpio_num = -1
		    };
		    pcnt_channel_handle_t pcnt_chan = NULL;
		    ESP_ERROR_CHECK(pcnt_new_channel(pcnt_hall_unit, &chan_cfg, &pcnt_chan));
		    // 动作配置:上升沿计数+1,下降沿无动作
		    ESP_ERROR_CHECK(pcnt_channel_set_edge_action(pcnt_chan,
		        PCNT_CHANNEL_EDGE_ACTION_INCREASE,   // 上升沿
		        PCNT_CHANNEL_EDGE_ACTION_HOLD   // 下降沿
		    ));
		    ESP_ERROR_CHECK(pcnt_channel_set_level_action(pcnt_chan,
		        PCNT_CHANNEL_LEVEL_ACTION_KEEP,
		        PCNT_CHANNEL_LEVEL_ACTION_KEEP
		    ));
		    // 启用PCNT
		    ESP_ERROR_CHECK(pcnt_unit_enable(pcnt_hall_unit));
		    ESP_ERROR_CHECK(pcnt_unit_clear_count(pcnt_hall_unit));
		    ESP_ERROR_CHECK(pcnt_unit_start(pcnt_hall_unit));
		}
		void hall_read_task(void *arg)
		{
		    int pulse_val;
		    static int last_pulse = 0;
		    while (1)
		    {
		        ESP_ERROR_CHECK(pcnt_unit_get_count(pcnt_hall_unit, &pulse_val));
		        int delta = pulse_val - last_pulse;
		        last_pulse = pulse_val;
		        ESP_LOGI(TAG, "Hall Pulse: %d, Delta:%d", pulse_val, delta);
		        vTaskDelay(pdMS_TO_TICKS(100));
		    }
		}
		void app_main(void)
		{
		    pcnt_hall_init();
		    xTaskCreate(hall_read_task, "hall_task", 2048, NULL, 5, NULL);
		}

   2、执行结果

    

相关推荐
咖丨喱2 小时前
【中断与收包】
单片机·嵌入式硬件
youshi66682 小时前
平衡车——PID算法优化
stm32·单片机·嵌入式硬件·算法·pid·平衡车
comyccccc3 小时前
高效降压电路布局与铺铜优化技巧学习笔记
单片机·嵌入式硬件
白搞电子3 小时前
ESP32-S31 WASM 应用开发实录:重力弹球从电脑预览到 ESP-Mosaico 实机测试
单片机·嵌入式硬件·物联网·电脑·wasm
尼喃3 小时前
集成输入反接保护的USB限流保护芯片IC反向电流阻断验证
嵌入式硬件
ye150127774553 小时前
220V降压24V700mA交转直芯片WT5110
stm32·单片机·嵌入式硬件·其他·硬件工程
BSD_HY4 小时前
薄膜开关矩阵扫描在低功耗 MCU 上的 GPIO 扩展
单片机·嵌入式硬件·矩阵
时代的凡人5 小时前
生活中的恒流源和恒压源
嵌入式硬件
恒锐丰科技林技术员6 小时前
EG2181 半桥驱动芯片原理与应用解析
经验分享·嵌入式硬件·硬件工程