#include <FastLED.h>
#include <EncButton.h>
#include <U8x8lib.h>
#define LED 5
#define BRIGHTNESS 5
#define NUM_LEDS 8
CRGB leds[NUM_LEDS];
#define ENC_A 2
#define ENC_B 3
#define ENC_BUTTON 4
enum class Mode {
value,
rainbow
};
enum class Field {
r,
g,
b,
changing_mode,
speed
};
// fields for value mode
int valueModeListLen = 4;
Field valueModeList[4] = {
Field::changing_mode,
Field::r,
Field::g,
Field::b
};
// fields for rainbow mode
int rainbowModeListLen = 2;
Field rainbowModeList[4] = {
Field::changing_mode,
Field::speed
};
typedef struct State {
Mode mode = Mode::value;
bool hasChanged = true;
// choosing parameters
bool isChanging = true; // changing some parameter
int whatChanging = 0; // rgb_mode default
// value mode parameters
uint32_t r = 0;
uint32_t g = 0;
uint32_t b = 0;
// rainbow mode parameters
int speed = 0;
} State;
State state;
int rainbow_position = 0;
uint32_t rainbow_colors[8] = {
CRGB::Red,
CRGB::Red,
CRGB::Yellow,
CRGB::Yellow,
CRGB::Green,
CRGB::Green,
CRGB::Blue,
CRGB::Blue,
};
EncButton enc = EncButton(ENC_A, ENC_B, ENC_BUTTON);
long prevTime = 0;
int freq = 100;
// ====================== SCREEN =============================================
U8X8_SSD1306_128X64_NONAME_HW_I2C screen = U8X8_SSD1306_128X64_NONAME_HW_I2C();
// ====================== SETUP ==============================================
void setup() {
rainbow_position = 0;
FastLED.addLeds<NEOPIXEL, LED>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
enc.attach(encHandler);
state.r = 255;
screen.begin();
}
void loop() {
screen.setFont(u8x8_font_chroma48medium8_r);
screen.drawString(0,0,"Hello World!");
// our algo
enc.tick();
// if (action != Action::none) {
// state.hasChanged = true;
// }
// состояние изменилось - перерисуем
// if (state.hasChanged) {
// display();
// state.hasChanged = false;
// }
//
if (millis() - prevTime > freq) {
showLED();
prevTime = millis();
}
// // try red
// state.r = 255;
// state.g = 255;
// state.b = 255;
// showLED();
// test
// leds[0] = CRGB::White; FastLED.show();
// delay(100);
// leds[0] = CRGB::Black; FastLED.show();
// delay(100);
}
void encHandler() {
state.hasChanged = true;
switch (enc.action()) {
case EB_PRESS:
handlePressed();
break;
case EB_TURN:
handleRotation();
break;
}
}
void handleRotation() {
// if rotating with not isChanging - change field whatChanging
if (not state.isChanging) {
// in value mode we can
if (state.mode == Mode::value) {
if (enc.right()) {
state.whatChanging++;
state.whatChanging = state.whatChanging % valueModeListLen;
} else {
state.whatChanging = state.whatChanging == 0 ? valueModeListLen : state.whatChanging - 1;
}
} else if (state.mode == Mode::rainbow) {
if (enc.right()) {
state.whatChanging++;
state.whatChanging = state.whatChanging % rainbowModeListLen;
} else {
state.whatChanging = state.whatChanging == 0 ? rainbowModeListLen : state.whatChanging - 1;
}
}
return;
}
// if rotating with isChanging - change field
if (state.isChanging) {
// get what we change
Field new_action;
if (state.mode == Mode::value) {
new_action = valueModeList[state.whatChanging];
} else if (state.mode == Mode::rainbow) {
new_action = rainbowModeList[state.whatChanging];
}
// choose what to do
switch (valueModeList[state.whatChanging]) {
case Field::changing_mode:
if (state.mode == Mode::value) {
state.mode = Mode::rainbow;
} else if (state.mode == Mode::rainbow) {
state.mode = Mode::value;
}
break;
}
}
}
void handlePressed() {
state.isChanging = not state.isChanging;
}
void showLED() {
if (state.mode == Mode::value) {
uint32_t color = 0x000000;
if (state.mode == Mode::value) {
color += state.r << 16;
color += state.g << 8;
color += state.b;
}
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = color;
}
} else if (state.mode == Mode::rainbow) {
for (int color_pos = 0; color_pos < 8; color_pos++) {
leds[rainbow_position % 8] = rainbow_colors[color_pos];
rainbow_position++;
}
rainbow_position++;
rainbow_position = rainbow_position % NUM_LEDS;
}
FastLED.show();
}
char strTmp[16] = {0};
void display() {
// в простейшем случае, функция каждый раз перерисовывает содержание дисплея исходя из состояния.
// конечно, это можно оптимизировать, храня копию предыдущего состояния и перерисовывать только измененные элементы UI
// Сильно упрощает жизнь sprintf
// sprintf(strTmp, "%s%s ", что-то == как-то ? "-" : " ", имена[state.поле]);
}