Initial commit
IMU and bubble level working
This commit is contained in:
200
main/keypad.c
Normal file
200
main/keypad.c
Normal file
@@ -0,0 +1,200 @@
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "keypad.h"
|
||||
|
||||
// ───────────── CONFIGURATION ─────────────
|
||||
|
||||
typedef enum {
|
||||
BUTTON1_GPIO = GPIO_NUM_36,
|
||||
BUTTON2_GPIO = GPIO_NUM_39,
|
||||
} button_gpio_t;
|
||||
|
||||
#define BUTTON_COUNT 2
|
||||
|
||||
// If your buttons are active‐low, set this to 0. If active‐high, set it to 1.
|
||||
#define KEYPAD_INACTIVE 1
|
||||
#define KEYPAD_ACTIVE 0
|
||||
|
||||
// Now we run the task every 50 ms and assume that is enough to debounce:
|
||||
#define DEBOUNCE_INTERVAL_MS 50 // Poll once every 50 ms
|
||||
// No more stable‐count logic—one sample/50 ms is considered “debounced.”
|
||||
|
||||
// Short vs. long press threshold (in ms):
|
||||
#define LONG_PRESS_MS 1000 // ≥1000 ms = “long press”
|
||||
|
||||
// Queue length for pending button events:
|
||||
#define BTN_EVT_QUEUE_LEN 10
|
||||
|
||||
// ───────────── EVENT ENUM & QUEUE HANDLE ─────────────
|
||||
|
||||
typedef struct
|
||||
{
|
||||
keycode_t key;
|
||||
gpio_num_t gpio;
|
||||
int prevState;
|
||||
int currentState;
|
||||
TickType_t activeTime;
|
||||
uint32_t event;
|
||||
} button_t;
|
||||
|
||||
static button_t _buttons[2];
|
||||
|
||||
// The queue handle that the debounce task will push events into:
|
||||
static QueueHandle_t s_btn_evt_queue = NULL;
|
||||
|
||||
// Call this to get the queue, so the main task can xQueueReceive():
|
||||
QueueHandle_t keypad_getQueue(void) {
|
||||
return s_btn_evt_queue;
|
||||
}
|
||||
|
||||
// ───────────── INTERNAL STATE ─────────────
|
||||
|
||||
// Current debounced state: 0 = released, 1 = pressed
|
||||
static int s_debounced[2] = { 0, 0 };
|
||||
|
||||
// Tick count when each button was debounced to “pressed”
|
||||
static TickType_t s_press_tick[2] = { 0, 0 };
|
||||
|
||||
// If we suppress an individual‐button event (because it was part of a “both” press), this is true
|
||||
static bool s_suppress_event[2] = { false, false };
|
||||
|
||||
// Tracks if we are currently in “both buttons pressed” phase:
|
||||
static bool s_was_both = false;
|
||||
|
||||
// Tick count when “both buttons” first became debounced‐pressed:
|
||||
static TickType_t s_both_press_tick = 0;
|
||||
|
||||
// ───────────── TAG FOR LOGGING ─────────────
|
||||
|
||||
static const char *TAG = "btn_debounce";
|
||||
|
||||
// ───────────── GPIO SETUP ─────────────
|
||||
|
||||
static void init_button_gpio(void)
|
||||
{
|
||||
// Configure both as inputs with pull‐up (assuming active‐low buttons)
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << BUTTON1_GPIO) | (1ULL << BUTTON2_GPIO),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
|
||||
_buttons[0].activeTime = 0;
|
||||
_buttons[0].gpio = BUTTON1_GPIO;
|
||||
_buttons[0].key = KEY0;
|
||||
_buttons[0].prevState = KEYPAD_INACTIVE;
|
||||
_buttons[0].currentState = KEYPAD_INACTIVE;
|
||||
|
||||
_buttons[1].activeTime = 0;
|
||||
_buttons[1].gpio = BUTTON2_GPIO;
|
||||
_buttons[1].key = KEY1;
|
||||
_buttons[1].prevState = KEYPAD_INACTIVE;
|
||||
_buttons[1].currentState = KEYPAD_INACTIVE;
|
||||
|
||||
}
|
||||
|
||||
// ───────────── BUTTON DEBOUNCE & PRESS‐TYPE TASK ─────────────
|
||||
|
||||
static void vButtonDebounceTask(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
TickType_t now = xTaskGetTickCount();
|
||||
TickType_t xLastWake = now;
|
||||
const TickType_t long_press_thresh = pdMS_TO_TICKS(LONG_PRESS_MS);
|
||||
|
||||
while (1) {
|
||||
|
||||
now = xTaskGetTickCount();
|
||||
|
||||
for (int i=0; i < BUTTON_COUNT; ++i)
|
||||
{
|
||||
button_t *button = &_buttons[i];
|
||||
|
||||
button->currentState = gpio_get_level(button->gpio);
|
||||
|
||||
if (button->currentState == KEYPAD_ACTIVE)
|
||||
{
|
||||
// just pressed
|
||||
if (button->prevState == KEYPAD_INACTIVE)
|
||||
{
|
||||
button->activeTime = now;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((now - button->activeTime) >= long_press_thresh)
|
||||
{
|
||||
if (button->event == 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "%d LONG", button->key);
|
||||
button->event = (button->key << KEY_LONG_PRESS);
|
||||
xQueueSend(s_btn_evt_queue, &button->event, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (button->currentState == KEYPAD_INACTIVE)
|
||||
{
|
||||
// just released
|
||||
if (button->prevState == KEYPAD_ACTIVE)
|
||||
{
|
||||
if (button->event == 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "%d SHORT", button->key);
|
||||
button->event = (button->key << KEY_SHORT_PRESS);
|
||||
xQueueSend(s_btn_evt_queue, &button->event, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "%d LONG RELEASE", button->key);
|
||||
}
|
||||
button->event = 0;
|
||||
|
||||
}
|
||||
button->activeTime = 0;
|
||||
}
|
||||
|
||||
button->prevState = button->currentState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 7) Wait 50 ms and repeat
|
||||
vTaskDelayUntil(&xLastWake, pdMS_TO_TICKS(DEBOUNCE_INTERVAL_MS));
|
||||
xLastWake = now;
|
||||
}
|
||||
}
|
||||
|
||||
// ───────────── PUBLIC “START” FUNCTION ─────────────
|
||||
|
||||
void keypad_start(void)
|
||||
{
|
||||
// 1) Create the queue for button events
|
||||
s_btn_evt_queue = xQueueCreate(BTN_EVT_QUEUE_LEN, sizeof(uint32_t));
|
||||
if (s_btn_evt_queue == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create button event queue");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) Initialize GPIOs & initial state
|
||||
init_button_gpio();
|
||||
|
||||
// 3) Launch the FreeRTOS task (low priority)
|
||||
xTaskCreate(vButtonDebounceTask,
|
||||
"btn_debounce",
|
||||
2048,
|
||||
NULL,
|
||||
tskIDLE_PRIORITY + 1,
|
||||
NULL);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user