W tym artykule podłączymy do mojego ulubionego *stukonoga* ESP32 S2 mini diody adresowe w postaci pierścienia NeoPixel 12 RGB LED WS2812 i będziemy sterować 10 prostymi efektami świetlnymi. Ten przykład kodu został wykorzystany w projekcie internetowego radia na esp32 w obudowie wydrukowanej na drukarce 3D.
Komponenty:
- ESP32-S2 Mini
- Pierścień LED 12 RGB WS2812 (NeoPixel)
- 3 przyciski (lub przyciski taktowe)
- Rezystory 10k (opcjonalnie do podciągania przycisków)
- Przewody
- Zasilanie 5V (np. z USB)
- Arduino IDE
| Przeznaczenie | Pin ESP32-S2 Mini |
|---|---|
| Pierścień LED (DIN) | GPIO16 |
| Przycisk "Następny" | GPIO18 |
| Przycisk "Poprzedni" | GPIO35 |
| Przycisk "Wł/Wył" | GPIO33 |
| Zasilanie pierścienia (5V) | 5V |
| GND pierścienia i przycisków | GND |
Zakładamy, że masz zainstalowane Arduino IDE (używam wersji 2.3.3). Dodaj w menedżerze bibliotek FastLED do sterowania diodami adresowymi. Jeśli nie masz:
Szkic → Dołącz bibliotekę → Zarządzaj bibliotekami
Znajdź i zainstaluj FastLED
Jak to będzie działać:
- Diody LED są podłączone do pinu 16 i sterowane przez bibliotekę FastLED.
- Przycisk na pinie 18 przełącza efekt do przodu.
- Przycisk na pinie 35 przełącza do tyłu.
- Przycisk na pinie 33 włącza i wyłącza animację.
#include <fastled.h>
#define LED_PIN 16
#define NUM_LEDS 12
#define BRIGHTNESS 100
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
// Кнопки
#define BTN_NEXT 18
#define BTN_PREV 35
#define BTN_TOGGLE 33
bool effectOn = true;
int currentEffect = 0;
const int totalEffects = 10;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 200; // защита от дребезга
void setup() {
FastLED.addLeds<led_type, led_pin,="" color_order="">(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(BRIGHTNESS);
pinMode(BTN_NEXT, INPUT_PULLUP);
pinMode(BTN_PREV, INPUT_PULLUP);
pinMode(BTN_TOGGLE, INPUT_PULLUP);
// Показать зелёный при старте
fill_solid(leds, NUM_LEDS, CRGB::Green);
FastLED.show();
delay(2000);
FastLED.clear();
FastLED.show();
}
void loop() {
handleButtons();
if (effectOn) {
switch (currentEffect) {
case 0: rainbowCycle(); break;
case 1: colorWipe(CRGB::Red); break;
case 2: theaterChase(CRGB::Blue); break;
case 3: setSolidColor(CRGB::White); break;
case 4: setSolidColor(CRGB::Blue); break;
case 5: setSolidColor(CRGB::Green); break;
case 6: setSolidColor(CRGB::Red); break;
case 7: fireEffect(); break;
case 8: rainbowFill(); break;
case 9: strobeEffect(); break;
}
FastLED.show();
delay(30);
} else {
FastLED.clear();
FastLED.show();
delay(100);
}
}
// === ЭФФЕКТЫ ===
void setSolidColor(CRGB color) {
fill_solid(leds, NUM_LEDS, color);
}
void rainbowFill() {
static uint8_t hue = 0;
fill_rainbow(leds, NUM_LEDS, hue, 7); // шаг изменения цвета
hue++;
}
void strobeEffect() {
static uint32_t lastBlinkTime = 0;
static bool ledOn = false;
if (millis() - lastBlinkTime >= 100) {
lastBlinkTime = millis();
ledOn = !ledOn;
setSolidColor(ledOn ? CRGB::White : CRGB::Black);
}
}
void fireEffect() {
static uint8_t heat[NUM_LEDS];
for (int i = 0; i < NUM_LEDS; i++) {
heat[i] = qsub8(heat[i], random(0, 50));
}
for (int i = NUM_LEDS - 1; i >= 2; i--) {
heat[i] = (heat[i - 1] + heat[i - 2] + heat[i - 2]) / 3;
}
if (random(0, 10) > 7) {
int sparkIndex = random(0, 3);
heat[sparkIndex] = qadd8(heat[sparkIndex], random(160, 255));
}
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = HeatColor(heat[i]);
}
}
void rainbowCycle() {
static uint8_t hue = 0;
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV((hue + (i * 256 / NUM_LEDS)) % 256, 255, 255);
}
hue++;
}
void colorWipe(CRGB color) {
static int pos = 0;
leds[pos] = color;
pos = (pos + 1) % NUM_LEDS;
}
void theaterChase(CRGB color) {
static int step = 0;
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = ((i + step) % 3 == 0) ? color : CRGB::Black;
}
step = (step + 1) % 3;
}
// === ОБРАБОТКА КНОПОК ===
void handleButtons() {
static bool lastStateNext = HIGH;
static bool lastStatePrev = HIGH;
static bool lastStateToggle = HIGH;
bool currentStateNext = digitalRead(BTN_NEXT);
bool currentStatePrev = digitalRead(BTN_PREV);
bool currentStateToggle = digitalRead(BTN_TOGGLE);
unsigned long currentTime = millis();
// Обработка кнопки "Следующий эффект"
if (currentStateNext == LOW && lastStateNext == HIGH && (currentTime - lastDebounceTime > debounceDelay)) {
currentEffect = (currentEffect + 1) % totalEffects;
lastDebounceTime = currentTime;
}
// Обработка кнопки "Предыдущий эффект"
if (currentStatePrev == LOW && lastStatePrev == HIGH && (currentTime - lastDebounceTime > debounceDelay)) {
currentEffect = (currentEffect - 1 + totalEffects) % totalEffects;
lastDebounceTime = currentTime;
}
// Обработка кнопки "Вкл/Выкл"
if (currentStateToggle == LOW && lastStateToggle == HIGH && (currentTime - lastDebounceTime > debounceDelay)) {
effectOn = !effectOn;
lastDebounceTime = currentTime;
}
// Обновляем предыдущее состояние
lastStateNext = currentStateNext;
lastStatePrev = currentStatePrev;
lastStateToggle = currentStateToggle;
}