From 83b414dd0d369eabec95dbf4a0b2a0ce94e1ab49 Mon Sep 17 00:00:00 2001 From: yuanjiong Date: Wed, 20 Oct 2021 20:12:08 +0800 Subject: [PATCH] :sparkles: add gpio buttons and adc buttons --- components/modules/button/who_adc_button.c | 110 +++++++++++++++++++++ components/modules/button/who_adc_button.h | 30 ++++++ components/modules/button/who_button.c | 100 +++++++++++++++++++ components/modules/button/who_button.h | 29 ++++++ 4 files changed, 269 insertions(+) create mode 100644 components/modules/button/who_adc_button.c create mode 100644 components/modules/button/who_adc_button.h create mode 100644 components/modules/button/who_button.c create mode 100644 components/modules/button/who_button.h diff --git a/components/modules/button/who_adc_button.c b/components/modules/button/who_adc_button.c new file mode 100644 index 0000000..59a0a41 --- /dev/null +++ b/components/modules/button/who_adc_button.c @@ -0,0 +1,110 @@ +/* ADC1 Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/adc_common.h" +#include "esp_adc_cal.h" +#include "who_adc_button.h" + +//ADC Channels +#define ADC1_EXAMPLE_CHAN0 ADC1_CHANNEL_0 +//ADC Attenuation +#define ADC_EXAMPLE_ATTEN ADC_ATTEN_DB_11 +//ADC Calibration +#if CONFIG_IDF_TARGET_ESP32 +#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF +#elif CONFIG_IDF_TARGET_ESP32S2 +#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP +#elif CONFIG_IDF_TARGET_ESP32C3 +#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP +#elif CONFIG_IDF_TARGET_ESP32S3 +#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP_FIT +#endif + +#define PRESS_INTERVAL 500000 + +static uint32_t voltage = 0; + +static const char *TAG = "ADC SINGLE"; + +static esp_adc_cal_characteristics_t adc1_chars; + +button_adc_config_t *adc_buttons; +int adc_button_num; +static QueueHandle_t xQueueKeyStateO = NULL; + +static bool adc_calibration_init(void) +{ + esp_err_t ret; + bool cali_enable = false; + + ret = esp_adc_cal_check_efuse(ADC_EXAMPLE_CALI_SCHEME); + if (ret == ESP_ERR_NOT_SUPPORTED) + { + ESP_LOGW(TAG, "Calibration scheme not supported, skip software calibration"); + } + else if (ret == ESP_ERR_INVALID_VERSION) + { + ESP_LOGW(TAG, "eFuse not burnt, skip software calibration"); + } + else if (ret == ESP_OK) + { + cali_enable = true; + esp_adc_cal_characterize(ADC_UNIT_1, ADC_EXAMPLE_ATTEN, ADC_WIDTH_BIT_DEFAULT, 0, &adc1_chars); + } + else + { + ESP_LOGE(TAG, "Invalid arg"); + } + return cali_enable; +} + +void adc_button_task(void *arg) +{ + int last_button_pressed = -1; + int button_pressed = -1; + int64_t backup_time = esp_timer_get_time(); + int64_t last_time = esp_timer_get_time(); + + //ADC1 config + ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_DEFAULT)); + ESP_ERROR_CHECK(adc1_config_channel_atten(ADC1_EXAMPLE_CHAN0, ADC_EXAMPLE_ATTEN)); + + while (1) + { + voltage = adc1_get_raw(ADC1_EXAMPLE_CHAN0); + backup_time = esp_timer_get_time(); + for (int i = 0; i < adc_button_num; ++i) + { + if ((voltage >= adc_buttons[i].min) && (voltage <= adc_buttons[i].max)) + { + button_pressed = adc_buttons[i].button_index; + if ((button_pressed != last_button_pressed) || ((backup_time - last_time) > PRESS_INTERVAL)) + { + last_button_pressed = button_pressed; + last_time = backup_time; + xQueueOverwrite(xQueueKeyStateO, &button_pressed); + break; + } + } + } + vTaskDelay(pdMS_TO_TICKS(10)); + } +} + +void register_adc_button(button_adc_config_t *buttons_ptr, int button_num, const QueueHandle_t key_state_o) +{ + xQueueKeyStateO = key_state_o; + adc_buttons = buttons_ptr; + adc_button_num = button_num; + xTaskCreatePinnedToCore(adc_button_task, "adc_button_scan_task", 1024, NULL, 5, NULL, 0); +} \ No newline at end of file diff --git a/components/modules/button/who_adc_button.h b/components/modules/button/who_adc_button.h new file mode 100644 index 0000000..25fb0af --- /dev/null +++ b/components/modules/button/who_adc_button.h @@ -0,0 +1,30 @@ +#pragma once +#include "esp_event_loop.h" +#include "soc/system_reg.h" +#include "driver/gpio.h" +#include "esp_log.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct + { + int button_index; /**< button index on the channel */ + int min; /**< min voltage in mv corresponding to the button */ + int max; /**< max voltage in mv corresponding to the button */ + } button_adc_config_t; + + /** + * @brief initialize adc button + * + * @param buttons_ptr the pointer of adc button configuration + * @param button_num the numbers of adc buttons + * @param key_state_o the queue to send which button is pressed + */ + void register_adc_button(button_adc_config_t *buttons_ptr, int button_num, const QueueHandle_t key_state_o); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/modules/button/who_button.c b/components/modules/button/who_button.c new file mode 100644 index 0000000..1bf7f9f --- /dev/null +++ b/components/modules/button/who_button.c @@ -0,0 +1,100 @@ +#include +#include +#include "who_button.h" + +typedef struct +{ + gpio_num_t io_num; + key_state_t state; +} key_scan_state_t; + +#define LONG_PRESS_THRESH 700000 +#define DOUBLE_CLICK_THRESH 300000 + +static xQueueHandle gpio_evt_queue = NULL; +static QueueHandle_t xQueueKeyStateO = NULL; + +static void IRAM_ATTR gpio_isr_handler_key(void *arg) +{ + uint32_t gpio_num = (uint32_t)arg; + xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); +} + +int key_scan(TickType_t ticks_to_wait) +{ + gpio_num_t io_num; + BaseType_t press_key = pdFALSE; + BaseType_t lift_key = pdFALSE; + int64_t backup_time = 0; + int64_t interval_time = 0; + static int64_t last_time = 0; + + for (;;) + { + xQueueReceive(gpio_evt_queue, &io_num, ticks_to_wait); + + if (gpio_get_level(io_num) == 0) + { + press_key = pdTRUE; + backup_time = esp_timer_get_time(); + interval_time = backup_time - last_time; + } + else if (press_key) + { + lift_key = pdTRUE; + last_time = esp_timer_get_time(); + backup_time = last_time - backup_time; + } + + if (press_key & lift_key) + { + press_key = pdFALSE; + lift_key = pdFALSE; + + if (backup_time > LONG_PRESS_THRESH) + { + return KEY_LONG_PRESS; + } + else + { + if ((interval_time < DOUBLE_CLICK_THRESH) && (interval_time > 0)) + return KEY_DOUBLE_CLICK; + else + return KEY_SHORT_PRESS; + } + } + } +} + +void key_trigger(void *arg) +{ + int ret = 0; + + while (1) + { + ret = key_scan(portMAX_DELAY); + xQueueOverwrite(xQueueKeyStateO, &ret); + } + + vTaskDelete(NULL); +} + +void key_init(gpio_num_t gpio_num) +{ + gpio_config_t io_conf = {0}; + io_conf.mode = GPIO_MODE_INPUT; + io_conf.intr_type = GPIO_INTR_ANYEDGE; + io_conf.pin_bit_mask = 1LL << gpio_num; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + gpio_config(&io_conf); + gpio_evt_queue = xQueueCreate(5, sizeof(uint32_t)); + gpio_install_isr_service(0); + gpio_isr_handler_add(gpio_num, gpio_isr_handler_key, (void *)gpio_num); +} + +void register_button(const gpio_num_t key_io_num, const QueueHandle_t key_state_o) +{ + xQueueKeyStateO = key_state_o; + key_init(key_io_num); + xTaskCreatePinnedToCore(key_trigger, "key_scan_task", 1024, NULL, 5, NULL, 0); +} \ No newline at end of file diff --git a/components/modules/button/who_button.h b/components/modules/button/who_button.h new file mode 100644 index 0000000..e5989c0 --- /dev/null +++ b/components/modules/button/who_button.h @@ -0,0 +1,29 @@ +#pragma once +#include "esp_event_loop.h" +#include "soc/system_reg.h" +#include "driver/gpio.h" +#include "esp_log.h" + +typedef enum +{ + KEY_SHORT_PRESS = 1, + KEY_LONG_PRESS, + KEY_DOUBLE_CLICK, +} key_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief initialize gpio button + * + * @param key_io_num the gpio number of the button + * @param key_state_o the queue to send the button state + */ +void register_button(const gpio_num_t key_io_num, const QueueHandle_t key_state_o); + +#ifdef __cplusplus +} +#endif \ No newline at end of file