Загрузка данных
#include <FastLED.h>
// --- НАСТРОЙКИ ---
#define LED_PIN 25 // Пин управления светодиодами (GPIO 25)
#define BUTTON_PIN 4 // Пин кнопки (вы можете изменить на любой свободный, например, 13 или 21)
#define NUM_LEDS 60 // Укажите количество светодиодов в вашей ленте/кольце
#define BRIGHTNESS 120 // Яркость (от 0 до 255), чтобы не слепило
CRGB leds[NUM_LEDS];
// --- ПАЛИТРА ИЗ 12 ПРИЯТНЫХ СТАТИЧНЫХ ЦВЕТОВ ---
const CRGB pleasantColors[12] = {
CRGB(255, 120, 50), // 0. Теплый янтарный (мягкий закатный)
CRGB(255, 150, 100), // 1. Пастельный персиковый
CRGB(255, 100, 150), // 2. Нежно-розовый
CRGB(180, 100, 255), // 3. Мягкий лавандовый
CRGB(100, 130, 255), // 4. Спокойный васильковый
CRGB(50, 180, 255), // 5. Небесно-голубой
CRGB(50, 220, 180), // 6. Бирюзово-мятный
CRGB(80, 240, 120), // 7. Светло-салатовый (пастельный)
CRGB(220, 220, 100), // 8. Теплый золотистый/песочный
CRGB(255, 180, 50), // 9. Медовый
CRGB(200, 150, 220), // 10. Сиреневая дымка
CRGB(220, 220, 220) // 11. Теплый белый (уютный)
};
// --- СОСТОЯНИЯ ---
int currentHueIndex = 0; // Индекс текущего цвета (0-11)
int currentMode = 0; // Текущий режим анимации (0-5)
const int totalModes = 6; // Всего модов анимации
// Переменные для обработки кнопки с антидребезгом и определением длинного нажатия
unsigned long buttonPressStartTime = 0;
bool buttonIsPressed = false;
bool longPressHandled = false;
const unsigned long longPressTime = 500; // Время длинного нажатия в миллисекундах (0.5 сек)
void setup() {
Serial.begin(115200);
// Инициализация ленты FastLED (используем WS2812B, порядок цветов GRB)
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
// Настройка пина кнопки (используем внутреннюю подтяжку к питанию,
// так как вы говорили, что хотите замыкать в минус / GND)
pinMode(BUTTON_PIN, INPUT_PULLUP);
}
void loop() {
handleButton();
runCurrentMode();
FastLED.delay(15); // Небольшая задержка для стабильности анимаций (~60 FPS)
}
// --- ЛОГИКА КНОПКИ (КОРОТКОЕ / ДОЛГОЕ НАЖАТИЕ) ---
void handleButton() {
// Кнопка подключена к GND, поэтому при нажатии читается LOW
bool reading = (digitalRead(BUTTON_PIN) == LOW);
if (reading && !buttonIsPressed) {
// Кнопка только что нажата
buttonIsPressed = true;
buttonPressStartTime = millis();
longPressHandled = false;
}
else if (reading && buttonIsPressed) {
// Кнопка удерживается, проверяем на длинное нажатие
if (!longPressHandled && (millis() - buttonPressStartTime >= longPressTime)) {
// Сработало ДОЛГОЕ нажатие -> меняем МОД анимации
currentMode = (currentMode + 1) % totalModes;
longPressHandled = true;
Serial.print("Смена мода анимации на: ");
Serial.println(currentMode);
}
}
else if (!reading && buttonIsPressed) {
// Кнопка отпущена
buttonIsPressed = false;
// Если долгое нажатие НЕ срабатывало, значит это было КОРОТКОЕ нажатие
if (!longPressHandled) {
// Сработало КОРОТКОЕ нажатие -> меняем ЦВЕТ
currentHueIndex = (currentHueIndex + 1) % 12;
Serial.print("Смена цвета на индекс: ");
Serial.println(currentHueIndex);
}
}
}
// --- ВЫПОЛНЕНИЕ ТЕКУЩЕГО МОДА АНИМАЦИИ ---
void runCurrentMode() {
CRGB baseColor = pleasantColors[currentHueIndex];
switch (currentMode) {
case 0:
// Мод 0: Статичное свечение выбранным цветом
fill_solid(leds, NUM_LEDS, baseColor);
break;
case 1:
// Мод 1: Мягкое «дыхание» (плавное затухание и проявление выбранного цвета)
{
float breath = (sin(millis() / 400.0) + 1.0) / 2.0; // от 0.0 до 1.0
CRGB breathColor = baseColor;
breathColor.nscale8(triangularScale(breath));
fill_solid(leds, NUM_LEDS, breathColor);
}
break;
case 2:
// Мод 2: Бегающая волна (плавный перелив яркости вдоль ленты)
for (int i = 0; i < NUM_LEDS; i++) {
float wave = (sin(millis() / 200.0 + i * 0.2) + 1.0) / 2.0;
CRGB waveColor = baseColor;
waveColor.nscale8(wave * 255);
leds[i] = waveColor;
}
break;
case 3:
// Мод 3: Бегающая точка-искра на фоне выбранного приглушенного цвета
{
fadeToBlackBy(leds, NUM_LEDS, 40);
int pos = (millis() / 50) % NUM_LEDS;
leds[pos] = CRGB::White; // Белая искра бегает по выбранному цвету
// Заполняем фон приглушенным цветом
for(int i=0; i<NUM_LEDS; i++) {
if(i != pos) {
CRGB dimColor = baseColor;
dimColor.nscale8(100);
leds[i] = dimColor;
}
}
}
break;
case 4:
// Мод 4: Переливающийся градиент (плавный переход оттенков вокруг выбранного цвета)
fill_gradient_rainbow(leds, NUM_LEDS, currentHueIndex * 21); // Сдвигаем палитру по кругу
break;
case 5:
// Мод 5: Плавное мерцание (эффект тлеющих угольков / мягких переливов)
{
fadeToBlackBy(leds, NUM_LEDS, 20);
if (random8() < 40) {
int idx = random16(NUM_LEDS);
leds[idx] = baseColor;
}
}
break;
}
}
// Вспомогательная функция для плавности дыхания
uint8_t triangularScale(float val) {
return (uint8_t)(val * 255);
}