Загрузка данных
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
// Экран (строго по нашему ряду)
#define TFT_SCL 13 // Подключен к SCK экрана
#define TFT_SDA 12 // Подключен к SDA экрана
#define TFT_DC 14 // Подключен к AO экрана
#define TFT_RST 27 // Подключен к RESET экрана
#define TFT_CS 26 // На твоей плате идет следующим в ряду
// Энкодер (идет следом по тому же ряду)
#define ENCODER_S1 25 // К контакту S1 крутилки
#define ENCODER_S2 33 // К контакту S2 крутилки
#define ENCODER_KEY 32 // К контакту Key (кнопка)
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_SDA, TFT_SCL, TFT_RST);
// Цветовая палитра вейпа
uint16_t COLOR_BG = 0x0000;
uint16_t COLOR_TEXT = 0xFFFF;
uint16_t COLOR_ACCENT = 0x07E0; // Неоновый зеленый под стиль
uint16_t COLOR_FRAME = 0x39E7;
int watts = 40;
int puff_count = 0;
float coil_ohm = 0.18;
long puff_timer = 0;
bool is_vaping = false;
int last_s1_state;
void drawStaticUI();
void updateWattsUI();
void drawVapingStatus(bool active);
void setup() {
tft.initR(INITR_BLACKTAB);
tft.setRotation(1);
tft.fillScreen(COLOR_BG);
// Подтягиваем пины крутилки к питанию внутренними резисторами
pinMode(ENCODER_S1, INPUT_PULLUP);
pinMode(ENCODER_S2, INPUT_PULLUP);
pinMode(ENCODER_KEY, INPUT_PULLUP);
last_s1_state = digitalRead(ENCODER_S1);
// Отрисовка интерфейса при старте
drawStaticUI();
updateWattsUI();
}
void loop() {
// 1. Считываем вращение крутилки
int current_s1_state = digitalRead(ENCODER_S1);
if (current_s1_state != last_s1_state && current_s1_state == LOW) {
if (digitalRead(ENCODER_S2) != current_s1_state) {
watts += 5;
if (watts > 80) watts = 80;
} else {
watts -= 5;
if (watts < 5) watts = 5;
}
updateWattsUI();
}
last_s1_state = current_s1_state;
// 2. Считываем нажатие кнопки затяжки
if (digitalRead(ENCODER_KEY) == LOW) {
if (!is_vaping) {
is_vaping = true;
puff_timer = millis();
drawVapingStatus(true);
} else {
// Пока держим — тикает таймер секунд
float duration = (millis() - puff_timer) / 1000.0;
tft.fillRect(15, 100, 70, 15, COLOR_BG);
tft.setCursor(15, 100);
tft.setTextColor(COLOR_TEXT);
tft.setTextSize(1);
tft.print(duration, 1);
tft.print(" sec");
}
delay(20);
} else {
// Отпустили кнопку — обновляем счетчик затяжек
if (is_vaping) {
is_vaping = false;
puff_count++;
drawStaticUI();
updateWattsUI();
}
}
}
void drawStaticUI() {
tft.fillScreen(COLOR_BG);
tft.drawRect(0, 0, tft.width(), tft.height(), COLOR_FRAME);
// Батарейка
tft.drawRect(125, 8, 20, 10, COLOR_TEXT);
tft.fillRect(145, 11, 2, 4, COLOR_TEXT);
tft.fillRect(127, 10, 16, 6, COLOR_ACCENT);
tft.setTextSize(1);
tft.setTextColor(COLOR_FRAME);
tft.setCursor(15, 65);
tft.print("COIL: ");
tft.setTextColor(COLOR_TEXT);
tft.print(coil_ohm); tft.print(" ohm");
tft.setCursor(15, 80);
tft.setTextColor(COLOR_FRAME);
tft.print("VOLT: ");
tft.setTextColor(COLOR_TEXT);
float fake_volt = sqrt(watts * coil_ohm);
tft.print(fake_volt, 2); tft.print(" V");
tft.setCursor(100, 65);
tft.setTextColor(COLOR_FRAME);
tft.print("PUFF");
tft.setCursor(100, 78);
tft.setTextColor(COLOR_ACCENT);
tft.setTextSize(2);
tft.print(puff_count);
}
void updateWattsUI() {
tft.fillRect(12, 22, 100, 35, COLOR_BG);
tft.fillRect(12, 55, 136, 5, COLOR_BG);
tft.setCursor(15, 25);
tft.setTextColor(COLOR_TEXT);
tft.setTextSize(4);
tft.print(watts);
tft.setTextSize(2);
tft.setTextColor(COLOR_ACCENT);
tft.print(" W");
tft.drawRect(12, 55, 136, 5, COLOR_FRAME);
int bar_w = map(watts, 5, 80, 0, 132);
tft.fillRect(14, 57, bar_w, 2, COLOR_ACCENT);
// Динамически пересчитываем Вольты на экране под новые Ватты
tft.fillRect(45, 78, 45, 12, COLOR_BG);
tft.setCursor(45, 80);
tft.setTextColor(COLOR_TEXT);
tft.setTextSize(1);
float fake_volt = sqrt(watts * coil_ohm);
tft.print(fake_volt, 2); tft.print(" V");
}
void drawVapingStatus(bool active) {
if (active) {
tft.fillRect(12, 22, 136, 38, COLOR_BG);
tft.setCursor(15, 30);
tft.setTextColor(COLOR_ACCENT);
tft.setTextSize(3);
tft.print("VAPING...");
}
}