Схема подключения (Пины для ESP32-WROOM-32)
Для матричной клавиатуры 4x4 требуется 8 пинов: 4 выхода для строк (Row) и 4 входа для столбцов (Column). [1]
Важно для ESP32: Избегайте пинов с ограничением по режиму (например, GPIO 34–39 работают только на вход и без подтяжки), а также пинов, влияющих на загрузку (0, 2, 5, 12, 15). [1, 2]
Пример безопасных пинов:
• Строки (Row 1–4): GPIO 16, 17, 18, 19 (настроить как выходы GPIO_MODE_OUTPUT)
• Столбцы (Column 1–4): GPIO 21, 22, 23, 25 (настроить как входы с подтяжкой к питанию GPIO_MODE_INPUT + включить GPIO_PULLUP_ENABLE)
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
static const char *TAG = "KEYPAD";
// Определение пинов строк и столбцов
#define ROW_COUNT 4
#define COL_COUNT 4
static const gpio_num_t row_pins[ROW_COUNT] = { GPIO_NUM_16, GPIO_NUM_17, GPIO_NUM_18, GPIO_NUM_19 };
static const gpio_num_t col_pins[COL_COUNT] = { GPIO_NUM_21, GPIO_NUM_22, GPIO_NUM_23, GPIO_NUM_25 };
// Раскладка клавиатуры 4x4
static const char key_map[ROW_COUNT][COL_COUNT] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
void keypad_init(void) {
// Настраиваем строки как выходы
for (int i = 0; i < ROW_COUNT; i++) {
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << row_pins[i]),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLDOWN_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&io_conf);
gpio_set_level(row_pins[i], 1); // Изначально высокий уровень
}
// Настраиваем столбцы как входы с подтяжкой вверх
for (int j = 0; j < COL_COUNT; j++) {
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << col_pins[j]),
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&io_conf);
}
}
char keypad_scan(void) {
char pressed_key = '\0';
for (int r = 0; r < ROW_COUNT; r++) {
// Устанавливаем текущую строку в LOW (0)
gpio_set_level(row_pins[r], 0);
for (int c = 0; c < COL_COUNT; c++) {
// Если на столбце LOW — кнопка нажата
if (gpio_get_level(col_pins[c]) == 0) {
pressed_key = key_map[r][c];
// Ждем отпускания клавиши (простейший антидребезг)
vTaskDelay(pdMS_TO_TICKS(50));
while (gpio_get_level(col_pins[c]) == 0) {
vTaskDelay(pdMS_TO_TICKS(10));
}
break;
}
}
// Возвращаем строку в HIGH (1)
gpio_set_level(row_pins[r], 1);
if (pressed_key != '\0') {
break;
}
}
return pressed_key;
}
void keypad_task(void *pvParameters) {
keypad_init();
char last_key = '\0';
while (1) {
char key = keypad_scan();
if (key != '\0') {
ESP_LOGI(TAG, "Pressed key: %c", key);
}
vTaskDelay(pdMS_TO_TICKS(50));
}
}
void app_main(void) {
xTaskCreate(keypad_task, "keypad_task", 2048, NULL, 5, NULL);
}