Описание
Делаем контроллер RGB ленты. Меню будем отображать на OLED экране, управление производить ротационным энкодером. Работу с периферией отдаем библиотекам.

Теория
OLED дисплей
Дисплей имеет разрешение 128X64
управляет им драйвер SSD1306
(или его аналог). Работа проходит по протоколу I2C
.
Де-факто стандартная Arduino библиотека: U8g2
- нам потребуется ее текстовая часть - u8x8
.
Ротационный энкодер
Энкодер нужен, чтобы преобразовать механический поворот на определенный угол в цифровой сигнал. В нашем наборе присутствует модуль инкрементального энкодера. Такой применяется главным образом для управления пользовательским интерфейсом, похожую "крутилку" вы встретите в стиральной машине, магнитолле авто, экране 3D принтера итд. На модуле распаян RC-фильтр, чтобы предотвратить дребезг.
На 5v
и GND
подается питание, key
отвечает за нажатие кнопки. s1
и s2
отвечают за поворот - они порождают два коротких сигнала с некоторым сдвигом.

Обработку такого сигнала желательно проводить используя аппаратные таймеры и прерывания. Некоторые микроконтроллеры имеют даже аппаратную поддержку энкодеров. Все это выходит за рамки курса - мы будем использовать библиотеку
EncButton
.Полезные ссылки
WS2812B
Библиотека FastLED
.
Код
Следует жестко разделять состояние, события и отображение - это сильно упростит вам жизнь. Примеры использования sprintf
Вариант решения:
typedef struct State {
Mode mode = Mode::value;
...
uint8_t someValue = 0;
...
bool hasChanged = true;
} State;
State state;
void handleAction(action) {
if(action) {
if(state.someValue) {
// здесь ожидаем много ветвлений
}
}
// где-то внутри функции мы будем знать, что изменили состояние
// либо же, будем знать что любое событие изменяет состояние
state.hasChanged = true;
}
char strTmp[16] = {0};
void display() {
// в простейшем случае, функция каждый раз перерисовывает содержание дисплея исходя из состояния.
// конечно, это можно оптимизировать, храня копию предыдущего состояния и перерисовывать только измененные элементы UI
// Сильно упрощает жизнь sprintf
sprintf(strTmp, "%s%s ", что-то == как-то ? "-" : " ", имена[state.поле]);
}
void loop(void) {
if(Событие) {
handleAction(Action::Событие);
}
// не стоит каждый раз перерисовывать дисплей.
// Только если состояние изменилось
if (state.hasChanged) {
display();
state.hasChanged = false;
}
// как часто стоит обновлять ленту уже зависит от режима
led();
}
Задачи
Реализовать контроллер. Должно быть несколько режимов - статический (цвет+яркость) и динамические на ваш вкус. Меню так же на ваш вкус - должно быть понятным и удобным.
WIP