☰
ESP32-S3-PCNT(脉冲计数控制器)
2026/10/11 6:52:01 网站建设 项目流程

文章目录

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

typedefenum{PCNT_COUNT_DIS=0,// 该边沿不计数PCNT_COUNT_INC,// 触发边沿时计数值 +1PCNT_COUNT_DEC// 触发边沿时计数值 -1}pcnt_count_mode_t;

2. pcnt_ctrl_mode_t Ctrl 方向电平策略

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

3. pcnt_unit_id_t PCNT 单元编号

typedefenum{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 中断事件类型

typedefenum{PCNT_EVT_H_LIM,// 计数到达高上限阈值PCNT_EVT_L_LIM,// 计数到达低下限阈值PCNT_EVT_THRES_0,// 计数匹配阈值0PCNT_EVT_THRES_1,// 计数匹配阈值1PCNT_EVT_ZERO// 计数归零}pcnt_event_type_t;

3、配置结构体

1. pcnt_unit_config_t 单元全局配置

typedefstruct{pcnt_unit_id_tunit_id;// 指定PCNT单元编号intlow_limit;// 计数下限(-32768~32767),触发L_LIM事件inthigh_limit;// 计数上限(-32768~32767),触发H_LIM事件}pcnt_unit_config_t;

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

typedefstruct{intsig_gpio_num;// SIG脉冲输入GPIO编号intctrl_gpio_num;// CTRL方向控制GPIO,填-1表示不使用方向脚pcnt_count_mode_tpos_mode;// SIG上升沿计数动作pcnt_count_mode_tneg_mode;// SIG下降沿计数动作pcnt_ctrl_mode_thctrl_mode;// CTRL引脚高电平时的计数策略pcnt_ctrl_mode_tlctrl_mode;// CTRL引脚低电平时的计数策略uint32_tfilter_ns;// 硬件滤波时间(单位ns),0=关闭滤波,过滤窄毛刺}pcnt_channel_config_t;

3. 回调事件数据 pcnt_event_data_t

typedefstruct{pcnt_event_type_ttype;// 触发的具体事件类型}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

esp_err_tpcnt_new_unit(constpcnt_unit_config_t*config,pcnt_unit_handle_t*ret_handle);//创建并初始化一个 PCNT 单元,返回句柄esp_err_tpcnt_del_unit(pcnt_unit_handle_tunit);//禁用单元、释放硬件资源esp_err_tpcnt_new_channel(pcnt_unit_handle_tunit,constpcnt_channel_config_t*config);//为指定 Unit 配置 CH0/CH1 通道参数

5、运行控制类API

esp_err_tpcnt_unit_enable(pcnt_unit_handle_tunit);//使能单元,开始硬件计数esp_err_tpcnt_unit_disable(pcnt_unit_handle_tunit);//暂停单元计数esp_err_tpcnt_unit_clear_count(pcnt_unit_handle_tunit);//硬件清零当前计数值esp_err_tpcnt_unit_get_count(pcnt_unit_handle_tunit,int*count);//读取当前实时计数值

6、中断回调配置函数

esp_err_tpcnt_unit_register_event_callbacks(pcnt_unit_handle_tunit,constpcnt_event_callbacks_t*cbs,void*user_data);//注册事件中断回调函数,可传入自定义用户参数esp_err_tpcnt_set_event_watchpoint(pcnt_unit_handle_tunit,pcnt_event_type_tevt_type,bool enable);//单独开启 / 关闭某一类事件的中断触发

7、动态阈值配置类

esp_err_tpcnt_set_thres0(pcnt_unit_handle_tunit,intthres);//动态修改阈值 0 数值esp_err_tpcnt_set_thres1(pcnt_unit_handle_tunit,intthres);//动态修改阈值 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、示例代码

#include<stdio.h>#include"freertos/FreeRTOS.h"#include"freertos/task.h"#include"driver/pulse_cnt.h"#include"esp_log.h"staticconstchar*TAG="PCNT_HALL";#defineHALL_GPIO4#definePCNT_HIGH_LIMIT32767#definePCNT_LOW_LIMIT-32768pcnt_unit_handle_tpcnt_hall_unit=NULL;voidpcnt_hall_init(void){// PCNT单元配置pcnt_unit_config_tunit_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_tfilter_cfg={.max_glitch_ns=2000,};ESP_ERROR_CHECK(pcnt_unit_set_glitch_filter(pcnt_hall_unit,&filter_cfg));// PCNT通道配置:edge引脚接霍尔信号,level不使用pcnt_chan_config_tchan_cfg={.edge_gpio_num=HALL_GPIO,.level_gpio_num=-1};pcnt_channel_handle_tpcnt_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));// 启用PCNTESP_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));}voidhall_read_task(void*arg){intpulse_val;staticintlast_pulse=0;while(1){ESP_ERROR_CHECK(pcnt_unit_get_count(pcnt_hall_unit,&pulse_val));intdelta=pulse_val-last_pulse;last_pulse=pulse_val;ESP_LOGI(TAG,"Hall Pulse: %d, Delta:%d",pulse_val,delta);vTaskDelay(pdMS_TO_TICKS(100));}}voidapp_main(void){pcnt_hall_init();xTaskCreate(hall_read_task,"hall_task",2048,NULL,5,NULL);}

2、执行结果

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询