AM2302 DHT22
Датчик працює від напруги 3,3 – 5,5 В. Його енергоспоживання залежить від режиму роботи:
У режимі вимірювання (активний стан): струм становить 1–1,5 мА. Розрахунок потужності при 5 В: 5 В × 0,0015 А = 0,0075 Вт (7,5 мВт).
У режимі очікування (сон): струм падає до 40–50 мкА (0,04–0,05 мА). Розрахунок потужності при 5 В: 5 В × 0,00005 А = 0,00025 Вт (0,25 мВт).
Середнє споживання під час роботи становить приблизно 0,2 мА (0,001 Вт), оскільки активні вимірювання відбуваються рідко (рекомендовано не частіше ніж раз на 2 секунди).
GY-GPS6MV2
Характеристики живлення та енергоспоживання:
Напруга живлення (VCC): від 3,3 В до 5 В.
Струм споживання у звичайному режимі (Tracking / Normal): близько 35 мА – 45 мА (піковий до 67 мА).
При 3,3 В: 33 мА × 3,3 В ≈ 0,11 Вт (або до 0,22 Вт при піку).
При 5 В: 45 мА × 5 В ≈ 0,225 Вт (або близько 0,335 Вт при максимальному навантаженні).
Струм у режимі енергозбереження (Power Save Mode): близько 11 мА (при 5 В це приблизно 0,055 Вт).
Ці піни не можна використовувати для кнопок чи датчиків:
LoRa SX1276 (SPI): SCK = GPIO 5, MISO = GPIO 19, MOSI = GPIO 27, CS = GPIO 18, RST = GPIO 23, DIO0 = GPIO 26
OLED-екран (I2C): SDA = GPIO 21, SCL = GPIO 22
Модуль / Периферія Пін модуля Пін LilyGO ESP32 Тип / Особливості підключення
MicroSD Картка (Шина HSPI) VCC / GND 3V3 / GND Живлення від 3.3 В
CS GPIO 13 Chip Select
MOSI / MISO / SCK GPIO 15 / 2 / 14
Шина HSPI
GPS GY-GPS6MV2
(UART2) VCC / GND 3V3 / GND
Живлення від 3.3 В (або 5V при USB)
TX GPIO 34 TX GPS → RX ESP32 (Input-Only)
RX GPIO 12 RX GPS ← TX ESP32
DHT22 (AM2302) (1-Wire) VCC / GND 3V3 / GND Живлення від 3.3 В
DATA GPIO 17
Зовнішній резистор 4.7k–10k Ом між DATA та 3.3V 5 Кнопок
(Замикання на GND) Кнопка 1 GPIO 35 Input-Only (потрібен зовн. резистор 10k до 3.3V)
Кнопка 2 GPIO 39 (VN) Input-Only (потрібен зовн. резистор 10k до 3.3V)
Кнопка 3 GPIO 36 (VP) Input-Only (потрібен зовн. резистор 10k до 3.3V)
Кнопка 4 GPIO 4 Підтяжка INPUT_PULLUP в коді
Кнопка 5 GPIO 0 Boot-пін (INPUT_PULLUP). Не тримати натиснутою при включенні!
Кнопки 1, 2, 3 (GPIO 35, 39, 36): Ці піни на ESP32 працюють тільки як входи і не мають внутрішньої програмної підтяжки. Для кожної з цих трьох кнопок обов'язково треба запаяти зовнішній резистор 10 кОм між піном та лінією 3.3V. Сама кнопка підключається між піном та GND.
Кнопка 5 (GPIO 0):GPIO 0 відповідає за перехід ESP32 у режим прошивки. Якщо її тримати натиснутою під час подачі живлення або скидання (Reset), плата не запуститься в нормальному режимі. Застосовуйте її для дій, що виконуються вже під час роботи системи.
Датчик DHT22 (AM2302): Для стабільного зчитування між виводом DATA та 3.3V обов'язково встановіть резистор підтяжки на 4.7 кОм – 10 кОм.
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/adc.h"
#include "esp_adc/adc_oneshot.h" // Або класичний adc1_get_raw залежно від версії IDF
#include "esp_log.h"
#define ADC_BUTTON_PIN ADC1_CHANNEL_7 // Відповідає GPIO 35
#define LONG_PRESS_TIME_MS 800
#define DEBOUNCE_TIME_MS 50
#define TASK_PERIOD_MS 20
static const char *TAG = "BTN_TASK";
// Перелік кнопок та подій
typedef enum {
BTN_NONE = 0,
BTN_1,
BTN_2,
BTN_3,
BTN_4,
BTN_5
} button_id_t;
typedef enum {
PRESS_SHORT = 0,
PRESS_LONG
} button_event_type_t;
typedef struct {
button_id_t id;
button_event_type_t event;
} button_message_t;
// Зовнішня черга для передачі подій в інші частини програми
extern QueueHandle_t xButtonEventQueue;
// Усереднення замірів АЦП для фільтрації шуму
static int read_stable_adc(void) {
long sum = 0;
const int samples = 10;
for (int i = 0; i < samples; i++) {
int raw_out = 0;
// Для ESP-IDF v5.x використовується adc_oneshot, для старших — adc1_get_raw()
sum += adc1_get_raw(ADC_BUTTON_PIN);
vTaskDelay(pdMS_TO_TICKS(1));
}
return sum / samples;
}
// Визначення кнопки за рівнем напруги (12-bit ADC: 0..4095)
static button_id_t get_pressed_button(void) {
int adc_val = read_stable_adc();
if (adc_val < 300) return BTN_1;
if (adc_val < 2300) return BTN_2;
if (adc_val < 2900) return BTN_3;
if (adc_val < 3250) return BTN_4;
if (adc_val < 3600) return BTN_5;
return BTN_NONE;
}
// FreeRTOS Task обробки клавіатури
void vKeyboardTask(void *pvParameters) {
button_id_t current_btn = BTN_NONE;
button_id_t active_btn = BTN_NONE;
TickType_t press_start_tick = 0;
bool is_pressed = false;
bool long_press_handled = false;
// Ініціалізація каналу АЦП
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC_BUTTON_PIN, ADC_ATTEN_DB_12); // Дійсно для 0..3.3V
ESP_LOGI(TAG, "Аналогова клавіатура запущена у FreeRTOS таску");
while (1) {
button_id_t read_btn = get_pressed_button();
TickType_t now = xTaskGetTickCount();
// 1. Зміна стану (початок тиску або відпускання)
if (read_btn != current_btn) {
current_btn = read_btn;
press_start_tick = now;
}
else {
// Перевірка антидребезгу
if ((now - press_start_tick) >= pdMS_TO_TICKS(DEBOUNCE_TIME_MS)) {
// Фіксація нового натискання
if (read_btn != BTN_NONE && !is_pressed) {
is_pressed = true;
active_btn = read_btn;
long_press_handled = false;
press_start_tick = now; // Скидаємо для довгого тиску
}
// Фіксація відпускання (Release)
if (read_btn == BTN_NONE && is_pressed) {
if (!long_press_handled) {
// Якщо довге натискання не спрацювало — це КОРОТКЕ
button_message_t msg = { .id = active_btn, .event = PRESS_SHORT };
xQueueSend(xButtonEventQueue, &msg, 0);
}
is_pressed = false;
active_btn = BTN_NONE;
}
// Перевірка на ДОВГЕ натискання під час утримання
if (is_pressed && !long_press_handled) {
if ((now - press_start_tick) >= pdMS_TO_TICKS(LONG_PRESS_TIME_MS)) {
button_message_t msg = { .id = active_btn, .event = PRESS_LONG };
xQueueSend(xButtonEventQueue, &msg, 0);
long_press_handled = true; // Запобігаємо повторним спрацьовуванням
}
}
}
}
// Періодичність опитування таску (не навантажує Core)
vTaskDelay(pdMS_TO_TICKS(TASK_PERIOD_MS));
}
}