Контроллер RGB ленты (WIP)

Описание

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

Теория

OLED дисплей

Дисплей имеет разрешение 128X64 управляет им драйвер SSD1306 (или его аналог). Работа проходит по протоколу I2C.
Де-факто стандартная Arduino библиотека: U8g2 - нам потребуется ее текстовая часть - u8x8.

Ротационный энкодер

Энкодер нужен, чтобы преобразовать механический поворот на определенный угол в цифровой сигнал. В нашем наборе присутствует модуль инкрементального энкодера. Такой применяется главным образом для управления пользовательским интерфейсом, похожую "крутилку" вы встретите в стиральной машине, магнитолле авто, экране 3D принтера итд. На модуле распаян RC-фильтр, чтобы предотвратить дребезг.
На 5v и GND подается питание, key отвечает за нажатие кнопки. s1 и s2 отвечают за поворот - они порождают два коротких сигнала с некоторым сдвигом.


Обработку такого сигнала желательно проводить используя аппаратные таймеры и прерывания. Некоторые микроконтроллеры имеют даже аппаратную поддержку энкодеров. Все это выходит за рамки курса - мы будем использовать библиотеку EncButton.

Полезные ссылки

lastminuteengineers

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