/*
Скетч к проекту "RGBspot"
- Страница проекта (схемы, описания): https://alexgyver.ru/rgbspot/
- Исходники на GitHub: https://github.com/AlexGyver/RGBspot
Проблемы с загрузкой? Читай гайд для новичков: https://alexgyver.ru/arduino-first/
AlexGyver, AlexGyver Technologies, 2021
*/
/*
Необходимые библиотеки можно установить через менеджер библиотеки
- EncButton
- GyverNTC
- GRGB
- EEManager
*/
/*
Настройки компиляции и фьюзов:
MiniCore https://github.com/MCUdude/MiniCore
- ATmega328
- No bootloader
- Clock: Internal 8 MHz
При 8 МГц частота ШИМ на presc /1 составляет ~16 кГц
*/
// пины заданы здесь
#include "pinMap.h"
// энкодер
#include <EncButton.h>
EncButton<EB_TICK, P_ENC_A, P_ENC_B, P_BTN> enc(INPUT);
// термистор
#include <GyverNTC.h>
GyverNTC therm(P_NTC, 10000, 3950);
// дисплей
#include "SevSeg.h"
const uint8_t digs[] = {P_G4, P_G3, P_G2, P_G1};
const uint8_t segs[] = {P_SSA, P_SSB, P_SSC, P_SSD, P_SSE, P_SSF, P_SSG};
SevSeg<4, SS_CATHODE> disp(digs, segs);
// светодиод
#include <GRGB.h>
GRGB led(COMMON_CATHODE, P_LED_R, P_LED_G, P_LED_B);
// настройки для eeprom
struct Settings {
uint8_t mode = 0; // 0 hue, 1 kelvin
uint8_t hue = 0; // цвет
uint8_t hueB = 0; // яркость при цвете
uint8_t temp = 0; // температура
uint8_t tempB = 0; // яркость при температуре
};
Settings settings;
// менеджер eeprom
#include <EEManager.h>
EEManager memory(settings, 10000); // 10 сек
void setup() {
/*
// Пины D3 и D11 - 8 кГц
TCCR2B = 0b00000010; // x8
TCCR2A = 0b00000011; // fast pwm
// Пины D9 и D10 - 7.8 кГц
TCCR1A = 0b00000001; // 8bit
TCCR1B = 0b00001010; // x8 fast pwm
*/
// Пины D3 и D11 - 31.4 кГц
TCCR2B = 0b00000001; // x1
TCCR2A = 0b00000001; // phase correct
// Пины D9 и D10 - 31.4 кГц
TCCR1A = 0b00000001; // 8bit
TCCR1B = 0b00000001; // x1 phase correct
pinMode(P_FAN, OUTPUT);
// запуск епром с адреса 0, ключ 2 (любой 0-255)
// https://github.com/GyverLibs/EEManager
memory.begin(0, 2);
// принудительно обновляем
updateLED();
updateDisp();
}
// режим настройки
byte dispMode = 0; // 0 color, 1 bright
void loop() {
memory.tick(); // менеджер епром
disp.tick(); // динамо дисплея
coolingTick(); // регулирование вентилятора
if (enc.tick()) { // опрос, если было событие
// по клику меняем режим вывода
if (enc.click()) dispMode = !dispMode;
// по удержанию меняем режим настройки величина/яркость
if (enc.held()) {
settings.mode = !settings.mode;
dispMode = 0;
}
// поворот - меняем величину
if (enc.turn()) {
int val = enc.getDir(); // направление поворота
if (enc.fast()) val *= 5; // быстрый поворот - в 5 раз быстрее
if (dispMode) {
if (!settings.mode) settings.hueB += val;
else settings.tempB += val;
} else {
if (!settings.mode) settings.hue += val;
else settings.temp += val;
}
}
// обновляем
updateLED();
updateDisp();
enc.resetState(); // сбрасываем флаги (очищаем остальные события)
memory.update(); // откладываем обновление епром
}
}
void coolingTick() {
// таймер на 1 сек
static uint32_t tmr;
if (millis() - tmr >= 1000) {
tmr = millis();
static float temp = 25; // фильтрованная температура
temp += (therm.getTemp() - temp) * 0.2; // фильтр
// линейное регулирование
int duty = map(int(temp), 30, 45, 10, 255);
duty = constrain(duty, 10, 255);
analogWrite(P_FAN, duty);
}
}
void updateDisp() {
// буквы http://www.uize.com/examples/seven-segment-display.html
disp.clear();
if (!settings.mode) { // hue
if (dispMode) {
disp.setOneByte(3, 0x1f);
disp.setInt(settings.hueB);
} else {
disp.setOneByte(3, 0x17);
disp.setInt(settings.hue);
}
} else { // temp
if (dispMode) {
disp.setOneByte(3, 0x1f);
disp.setInt(settings.tempB);
} else {
disp.setOneByte(3, 0x0f);
disp.setInt(settings.temp);
}
}
}
void updateLED() {
// setWheel принимает 0-1530, у нас 8 бит - умножаем на 6 (1530 == 255 * 6)
if (!settings.mode) led.setWheel(settings.hue * 6, settings.hueB);
else led.setKelvin(settings.temp * 100, settings.tempB);
}