ESP32——PCNT 驱动EC11

芯片:esp32s3

开发环境:espidfv4.4

一、官网源码

1、readme:ec11旋转脉冲样式 GPIO14 gpio15

```

A +-----+ +-----+ +-----+

| | | |

| | | |

+-----+ +-----+

B +-----+ +-----+ +-----+

| | | |

| | | |

+-----+ +-----+

 

+--------------------------------------->

CW direction

```

嘛意思:一会来看

该示例使4X模式能够解析旋转信号,这意味着,根据旋转方向,每个完整的旋转步骤将导致PCNT计数器增加/减少4。

2)这是有编码器的库,先编译看看结果,代码倒是非常少;乐鑫放在component里

头文件:#include "rotary_encoder.h"

3)修改了下,改为旋转一格加1,原本的为旋转一个变化4,代码放下面,加注释了,还是很容易看懂的,配合ec11的时序图更容易理解哦。.h没改。还是有很多不妥的地方,容易误判,后面再改

ESP32S3学习——pcnt_rotarty_encoder

芯片:esp32s3

开发环境:espidfv4.4

一、官网源码

1、readme:ec11旋转脉冲样式 GPIO14 gpio15

```

A +-----+ +-----+ +-----+

| | | |

| | | |

+-----+ +-----+

B +-----+ +-----+ +-----+

| | | |

| | | |

+-----+ +-----+

 

+--------------------------------------->

CW direction

```

嘛意思:一会来看

该示例使4X模式能够解析旋转信号,这意味着,根据旋转方向,每个完整的旋转步骤将导致PCNT计数器增加/减少4。

2)这是有编码器的库,先编译看看结果,代码倒是非常少;乐鑫放在component里

头文件:#include "rotary_encoder.h"

3)修改了下,改为旋转一格加1,原本的为旋转一个变化4,代码放下面,加注释了,还是很容易看懂的,配合ec11的时序图更容易理解哦。.h没改。还是有很多不妥的地方,容易误判,后面再改

 

 

1eccb48367d94a8bba51fbafc8bfae32.png

 

 

 

// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include "esp_compiler.h"
#include "esp_log.h"
#include "driver/pcnt.h"
#include "sys/lock.h"
#include "hal/pcnt_hal.h"
#include "rotary_encoder.h"

static const char *TAG = "rotary_encoder";

#define ROTARY_CHECK(a, msg, tag, ret, ...)                                       \
    do {                                                                          \
        if (unlikely(!(a))) {                                                     \
            ESP_LOGE(TAG, "%s(%d): " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
            ret_code = ret;                                                       \
            goto tag;                                                             \
        }                                                                         \
    } while (0)

#define EC11_PCNT_DEFAULT_HIGH_LIMIT (100)
#define EC11_PCNT_DEFAULT_LOW_LIMIT  (-100)

// A flag to identify if pcnt isr service has been installed.
//中断服务是否安装标志位
static bool is_pcnt_isr_service_installed = false;
// A lock to avoid pcnt isr service being installed twice in multiple threads.
// 防止中断服务被多次安装
static _lock_t isr_service_install_lock;
#define LOCK_ACQUIRE() _lock_acquire(&isr_service_install_lock)
#define LOCK_RELEASE() _lock_release(&isr_service_install_lock)
// ec11结构体,计数数目,父对象,pcnt单元
typedef struct {
    int accumu_count;
    rotary_encoder_t parent;
    pcnt_unit_t pcnt_unit;
} ec11_t;
// 滤波
static esp_err_t ec11_set_glitch_filter(rotary_encoder_t *encoder, uint32_t max_glitch_us)
{
    esp_err_t ret_code = ESP_OK;
    ec11_t *ec11 = __containerof(encoder, ec11_t, parent);

    /* Configure and enable the input filter */
    // 配置使能pcnt滤波
    ROTARY_CHECK(pcnt_set_filter_value(ec11->pcnt_unit, max_glitch_us * 80) == ESP_OK, "set glitch filter failed", err, ESP_FAIL);
    // 滤波时间有值,使能滤波
    if (max_glitch_us) {
        pcnt_filter_enable(ec11->pcnt_unit);
    } else {
        pcnt_filter_disable(ec11->pcnt_unit);
    }

    return ESP_OK;
err:
    return ret_code;
}
// 开启计数
static esp_err_t ec11_start(rotary_encoder_t *encoder)
{
    // 这个嘛意思,不造
    ec11_t *ec11 = __containerof(encoder, ec11_t, parent);
    // pcnt api
    pcnt_counter_resume(ec11->pcnt_unit);
    return ESP_OK;
}
// 停止计数
static esp_err_t ec11_stop(rotary_encoder_t *encoder)
{
    ec11_t *ec11 = __containerof(encoder, ec11_t, parent);
    pcnt_counter_pause(ec11->pcnt_unit);
    return ESP_OK;
}
// 获取计数值
static int ec11_get_counter_value(rotary_encoder_t *encoder)
{
    ec11_t *ec11 = __containerof(encoder, ec11_t, parent);
    int16_t val = 0;
    pcnt_get_counter_value(ec11->pcnt_unit, &val);
    return val + ec11->accumu_count;
}
// 删除ec11
static esp_err_t ec11_del(rotary_encoder_t *encoder)
{
    ec11_t *ec11 = __containerof(encoder, ec11_t, parent);
    free(ec11);
    return ESP_OK;
}
//pcnt移除处理函数
static void ec11_pcnt_overflow_handler(void *arg)
{
    ec11_t *ec11 = (ec11_t *)arg;
    uint32_t status = 0;
    //获取pcnt状态
    pcnt_get_event_status(ec11->pcnt_unit, &status);
//max:计数值累加
    if (status & PCNT_EVT_H_LIM) {
        ec11->accumu_count += EC11_PCNT_DEFAULT_HIGH_LIMIT;
    } else if (status & PCNT_EVT_L_LIM) {
        ec11->accumu_count += EC11_PCNT_DEFAULT_LOW_LIMIT;
    }
}
//创建ec11
esp_err_t rotary_encoder_new_ec11(const rotary_encoder_config_t *config, rotary_encoder_t **ret_encoder)
{
    esp_err_t ret_code = ESP_OK;
    ec11_t *ec11 = NULL;

    ROTARY_CHECK(config, "configuration can't be null", err, ESP_ERR_INVALID_ARG);
    ROTARY_CHECK(ret_encoder, "can't assign context to null", err, ESP_ERR_INVALID_ARG);
    //申请空间
    ec11 = calloc(1, sizeof(ec11_t));
    ROTARY_CHECK(ec11, "allocate context memory failed", err, ESP_ERR_NO_MEM);
    //pcnt单元
    ec11->pcnt_unit = (pcnt_unit_t)(config->dev);
    
    // Configure channel 0
    // 通道0配置,输入14,控制15
    pcnt_config_t dev_config = {
        .pulse_gpio_num = config->phase_a_gpio_num,
        .ctrl_gpio_num = config->phase_b_gpio_num,
        .channel = PCNT_CHANNEL_0,
        .unit = ec11->pcnt_unit,
        .pos_mode = PCNT_COUNT_DIS,//上升沿减少
        .neg_mode = PCNT_COUNT_INC,//下降沿增加
        .lctrl_mode = PCNT_MODE_REVERSE,//控制低电平反转
        .hctrl_mode = PCNT_MODE_KEEP,//高电平保持
        .counter_h_lim = EC11_PCNT_DEFAULT_HIGH_LIMIT,
        .counter_l_lim = EC11_PCNT_DEFAULT_LOW_LIMIT,
    };
    ROTARY_CHECK(pcnt_unit_config(&dev_config) == ESP_OK, "config pcnt channel 0 failed", err, ESP_FAIL);

    // Configure channel 1
    // dev_config.pulse_gpio_num = config->phase_b_gpio_num;
    // dev_config.ctrl_gpio_num = config->phase_a_gpio_num;
    // dev_config.channel = PCNT_CHANNEL_1;
    // dev_config.pos_mode = PCNT_COUNT_INC;
    // dev_config.neg_mode = PCNT_COUNT_DEC;
    // ROTARY_CHECK(pcnt_unit_config(&dev_config) == ESP_OK, "config pcnt channel 1 failed", err, ESP_FAIL);

    // PCNT pause and reset value
    // 清零计数值
    pcnt_counter_pause(ec11->pcnt_unit);
    pcnt_counter_clear(ec11->pcnt_unit);


    // register interrupt handler in a thread-safe way
    // 安装,添加中断回调
    LOCK_ACQUIRE();
    if (!is_pcnt_isr_service_installed) {
        ROTARY_CHECK(pcnt_isr_service_install(0) == ESP_OK, "install isr service failed", err, ESP_FAIL);
        // make sure pcnt isr service won't be installed more than one time
        is_pcnt_isr_service_installed = true;
    }
    LOCK_RELEASE();

    pcnt_isr_handler_add(ec11->pcnt_unit, ec11_pcnt_overflow_handler, ec11);
// 使能maxmin
    pcnt_event_enable(ec11->pcnt_unit, PCNT_EVT_H_LIM);
    pcnt_event_enable(ec11->pcnt_unit, PCNT_EVT_L_LIM);

    ec11->parent.del = ec11_del;
    ec11->parent.start = ec11_start;
    ec11->parent.stop = ec11_stop;
    ec11->parent.set_glitch_filter = ec11_set_glitch_filter;
    ec11->parent.get_counter_value = ec11_get_counter_value;

    *ret_encoder = &(ec11->parent);
    return ESP_OK;
err:
    if (ec11) {
        free(ec11);
    }
    return ret_code;
}

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 gpio-keyc的基础上改写的旋转按钮 ec11的驱动,已经经过了测试。可自定义左旋和右旋的键值。如果按键值输入是第三个引脚,也支持按键操作 补存的头文件: gpio_ec11.h #ifndef _GPIO_EC11_H #define _GPIO_EC11_H struct device; struct gpio_desc; /** * struct gpio_ec11_button - configuration parameters * @leftcode: ec11 left direction input event code (KEY_*, SW_*) * @rightcode: ec11 right direction input event code (KEY_*, SW_*) * @gpio: %-1 if this key does not support gpio * @gpio: %-1 if this key does not support gpio * @active_low: %true indicates that button is considered * depressed when gpio is low * @desc: label that will be attached to button's gpio * @type: input event type (%EV_KEY, %EV_SW, %EV_ABS) * @wakeup: configure the button as a wake-up source * @debounce_interval: debounce ticks interval in msecs * @can_disable: %true indicates that userspace is allowed to * disable button via sysfs * @value: axis value for %EV_ABS * @irq: Irq number in case of interrupt keys * @gpiod: GPIO descriptor */ struct gpio_ec11_button { unsigned int code; unsigned int leftcode; /*记录左旋键值*/ unsigned int rightcode; /*记录右旋键值*/ int gpio; /*旋转编码器A引脚的gpio号*/ int subgpio; /*旋转编码器B引脚的gpio号*/ int active_low; const char *desc; unsigned int type; int wakeup; int debounce_interval; bool can_disable; int value; unsigned int irq; unsigned int irq_flags; struct gpio_desc *gpiod; }; /** * struct gpio_ec11_platform_data - platform data for gpio_ec11 driver * @buttons: pointer to array of &gpio;_keys_button structures * describing buttons attached to the device * @nbuttons: number of elements in @buttons array * @poll_interval: polling interval in msecs - for polling driver only * @rep: enable input subsystem auto repeat * @enable: platform hook for enabling the device * @disable: platform hook for disabling the device * @name: input device name */ struct gpio_ec11_platform_data { struct gpio_ec11_button *buttons; int nbuttons; unsigned int poll_interval; unsigned int rep:1; int (*enable)(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值