Это устройство обеспечивает нагрев бассейна и запуск фильтрационной установки вручную или по таймеру. Основное внимание при разработке было уделено интерфейсу пользователя.
ВИДЕО
Извините за столь долгое вступление на видео, хотя мне кажется, что надо погрузить потенциального читателя в суть мотивации по созданию контроллера. Все схемы и описание функции показаны в этом видео далее.
Код достаточно объемный и разделен на несколько файлов:
MAIN
// **********************************************
// Arduino pool controller
// DS3231 RTC | TM1638 | 2 x DS18B20
// WatchDog Enable
// Bootloader MiniCore | MCU ATmega328PB
// V.11 Steve Massikker 2026
// **********************************************
// #include <avr/wdt.h> // Watch Dog
#include <ErriezLKM1638Board.h>
#include <DS3231.h>
#include <Wire.h>
#include <microDS18B20.h>
#include <EEPROM.h>
#define RELAY_FILTER 15
#define RELAY_HEATER 17
#define RELAY_PUMP 16
#define BTN_DISPLAY 7
#define BTN_PLUS 8
#define BTN_ENTER 9
#define BTN_SELECT 10
#define LED_AUTO_FILTER 6
#define LED_AUTO_HEATER 5
#define TM1638_CLK 3
#define TM1638_DIO 2
#define TM1638_STB0 4
LKM1638Board lkm1638(TM1638_CLK, TM1638_DIO, TM1638_STB0);
RTClib myRTC;
MicroDS18B20<11> sensor_common;
MicroDS18B20<12> sensor_heater;
// Clock
uint8_t current_hour = 0;
uint8_t current_minutes = 0;
// Temperature
uint8_t common_temperature = 0;
uint8_t heater_temperature = 0;
// Display
uint8_t displayModes = 0; // 0 - Time&CommonTemperature | 1 - CommonTemp->HeaterTemperature | 2 - Display Off | 3 - Programming (WhiteLED)
uint8_t segment0, segment1, segment2, segment3,
segment4, segment5, segment6, segment7;
// Control
uint8_t filter_mode = 0; // Filtration | 0 - OFF | 1 - RUN | 2 - AUTO | 5 - AUTO RUN
uint8_t heater_mode = 0; // Heating & Pump | 0 - OFF | 1 - RUN | 2 - AUTO | 3 - PUMP ONLY | 5 - AUTO RUN
bool flag_change_modes = false;
bool flag_change_relays = false;
bool heater_run = false;
bool pump_run = false;
bool filter_run = false;
// Progdata
uint8_t selectDevice = 0; // Programming FILTER - 0 | Programming HEATER - 1 | et max. temperature of heating wather - 2
bool flagProgramming = false;
uint8_t hour_START_FILTER;
uint8_t hour_STOP_FILTER;
uint8_t hour_START_HEATER;
uint8_t hour_STOP_HEATER;
uint8_t set_MaxTEMP;
uint32_t tmrAlarmTemperature;
void setup() {
Serial.begin(9600);
Wire.begin();
lkm1638.begin();
lkm1638.clear();
lkm1638.setColorLED(4, LedRed); // LED FILTER RED
lkm1638.setColorLED(5, LedRed); // LED HEATER RED
// Set Time
DateTime now = myRTC.now();
current_hour = now.hour();
current_minutes = now.minute();
// Get Temperature
sensor_common.requestTemp();
sensor_heater.requestTemp();
// Pinout
pinMode(LED_AUTO_FILTER, OUTPUT);
pinMode(LED_AUTO_HEATER, OUTPUT);
pinMode(RELAY_FILTER, OUTPUT);
pinMode(RELAY_HEATER, OUTPUT);
pinMode(RELAY_PUMP, OUTPUT);
pinMode(BTN_DISPLAY, INPUT_PULLUP);
pinMode(BTN_PLUS, INPUT_PULLUP);
pinMode(BTN_ENTER, INPUT_PULLUP);
pinMode(BTN_SELECT, INPUT_PULLUP);
digitalWrite(LED_AUTO_FILTER, LOW);
digitalWrite(LED_AUTO_HEATER, LOW);
digitalWrite(RELAY_FILTER, HIGH);
digitalWrite(RELAY_HEATER, HIGH);
digitalWrite(RELAY_PUMP, HIGH);
// EEPROM
hour_START_FILTER = EEPROM.read(3);
hour_STOP_FILTER = EEPROM.read(4);
hour_START_HEATER = EEPROM.read(5);
hour_STOP_HEATER = EEPROM.read(6);
set_MaxTEMP = EEPROM.read(7);
/*
Serial.print("hour_START_FILTER - ");
Serial.println(hour_START_FILTER);
Serial.print("hour_STOP_FILTER - ");
Serial.println(hour_STOP_FILTER);
Serial.print("hour_START_HEATER - ");
Serial.println(hour_START_HEATER);
Serial.print("hour_STOP_HEATER - ");
Serial.println(hour_STOP_HEATER);
Serial.print("set_MaxTEMP - ");
Serial.println(set_MaxTEMP);
*/
// delay(100);
// wdt_enable(WDTO_2S);
}
// MAIN LOOP---------------------
void loop() {
//tmr_1();
temperature();
timeRTC();
control_buttons();
main_logic();
display_1638();
relays();
blink_autoLEDs();
}
// SERVICE FUNCTIONS----------------------
void blink_autoLEDs() {
if (filter_mode == 5 || heater_mode == 5) {
static uint32_t tmr;
static int val = 0;
static bool dir = true;
if (millis() - tmr >= 12) {
tmr = millis();
if (dir) val++;
else val--;
if (val >= 92 || val <= 0) dir = !dir;
}
if (filter_mode == 5) analogWrite(LED_AUTO_FILTER, val);
if (heater_mode == 5) analogWrite(LED_AUTO_HEATER, val);
}
}
void tmr_1() { // Checkout code
static uint32_t tmr;
if (millis() - tmr >= 800) {
tmr = millis();
//Serial.print(filter_mode);
//Serial.print(" | heater - ");
//Serial.println(heater_mode);
//Serial.println(flag_change_modes);
}
}
DIGIT INDICATOR
void display_1638() {
// Symbols
uint8_t symbols
= {
// 0-O | 1 | 2 | 3 | 4
0b0111111,0b0000110,0b1011011,0b1001111,0b1100110,
// 5 | 6 | 7 | 8 | 9
0b1101101,0b1111101,0b0000111,0b1111111,0b1101111,
// - 10| none 11| П 12| Р 13| Г 14
0b1000000,0b0000000,0b0110111,0b1110011,0b0110001,
//Celsius| C 16| h 17| L 18| H 19
0b1100011,0b0111001,0b1110100,0b0111000,0b1110110,
// F 20
0b1110001};
static uint32_t updateDigits;
if (millis() - updateDigits >= 200) {
updateDigits = millis();
uint8_t current_hour_1digit = current_hour/10;
uint8_t current_hour_2digit = current_hour - current_hour_1digit*10;
uint8_t current_minute_1digit = current_minutes/10;
uint8_t current_minute_2digit = current_minutes - current_minute_1digit*10;
uint8_t common_temperature_1digit = common_temperature/10;
uint8_t common_temperature_2digit = common_temperature - common_temperature_1digit*10;
uint8_t heater_temperature_1digit = heater_temperature/10;
uint8_t heater_temperature_2digit = heater_temperature - heater_temperature_1digit*10;
uint8_t hour_START_FILTER_1digit = hour_START_FILTER/10;
uint8_t hour_START_FILTER_2digit = hour_START_FILTER - hour_START_FILTER_1digit*10;
uint8_t hour_STOP_FILTER_1digit = hour_STOP_FILTER/10;
uint8_t hour_STOP_FILTER_2digit = hour_STOP_FILTER - hour_STOP_FILTER_1digit*10;
uint8_t hour_START_HEATER_1digit = hour_START_HEATER/10;
uint8_t hour_START_HEATER_2digit = hour_START_HEATER - hour_START_HEATER_1digit*10;
uint8_t hour_STOP_HEATER_1digit = hour_STOP_HEATER/10;
uint8_t hour_STOP_HEATER_2digit = hour_STOP_HEATER - hour_STOP_HEATER_1digit*10;
uint8_t set_MaxTEMP_1digit = set_MaxTEMP/10;
uint8_t set_MaxTEMP_2digit = set_MaxTEMP - set_MaxTEMP_1digit*10;
switch (displayModes) {
case 0: // Time & Common temperature
if (current_hour_1digit == 0) segment0 = symbols[11];
else segment0 = symbols[current_hour_1digit];
segment1 = symbols[current_hour_2digit];
segment2 = symbols[10];
segment3 = symbols[current_minute_1digit];
segment4 = symbols[current_minute_2digit];
segment5 = symbols[11];
segment6 = symbols[common_temperature_1digit];
segment7 = symbols[common_temperature_2digit];
break;
case 1: // Common temperature & Heater temperature
segment0 = symbols[common_temperature_1digit];
segment1 = symbols[common_temperature_2digit];
segment2 = symbols[15];
segment3 = symbols[10];
segment4 = symbols[19];
segment5 = symbols[heater_temperature_1digit];
segment6 = symbols[heater_temperature_2digit];
segment7 = symbols[15];
break;
case 2:
segment0 = symbols[11];
segment1 = symbols[11];
segment2 = symbols[11];
segment3 = symbols[11];
segment4 = symbols[11];
segment5 = symbols[11];
segment6 = symbols[11];
segment7 = symbols[11];
break;
case 3: // Programming
if (selectDevice == 0) { // 0 - Filter | 1 - Heater | 2 - max. temperature
segment0 = symbols[20];
segment1 = symbols[hour_START_FILTER_1digit];
segment2 = symbols[hour_START_FILTER_2digit];
segment3 = symbols[17];
segment4 = symbols[10];
segment5 = symbols[hour_STOP_FILTER_1digit];
segment6 = symbols[hour_STOP_FILTER_2digit];
segment7 = symbols[17];
}
else if (selectDevice == 1) {
segment0 = symbols[19];
segment1 = symbols[hour_START_HEATER_1digit];
segment2 = symbols[hour_START_HEATER_2digit];;
segment3 = symbols[17];
segment4 = symbols[10];
segment5 = symbols[hour_STOP_HEATER_1digit];
segment6 = symbols[hour_STOP_HEATER_2digit];
segment7 = symbols[17];
}
else {
segment0 = symbols[12];
segment1 = symbols[0];
segment2 = symbols[13];
segment3 = symbols[0];
segment4 = symbols[14];
segment5 = symbols[set_MaxTEMP_1digit];
segment6 = symbols[set_MaxTEMP_2digit];
segment7 = symbols[15];
}
break;
}
lkm1638.setSegmentsDigit(7, segment0);
lkm1638.setSegmentsDigit(6, segment1);
lkm1638.setSegmentsDigit(5, segment2);
lkm1638.setSegmentsDigit(4, segment3);
lkm1638.setSegmentsDigit(3, segment4);
lkm1638.setSegmentsDigit(2, segment5);
lkm1638.setSegmentsDigit(1, segment6);
lkm1638.setSegmentsDigit(0, segment7);
}
}
INPUT COMMANDS
static void control_buttons() {
static uint8_t keys = 0;
static uint8_t lastKeys = 0;
static uint32_t debounce;
// Change Display modes
if (millis() - debounce >= 300) {
if (digitalRead(BTN_DISPLAY) == LOW) {
debounce = millis();
displayModes++;
if (displayModes >= 4) displayModes = 0;
// Serial.println(displayModes);
// 0 - Time&CommonTemperature
// 1 - CommonTemp->HeaterTemperature
// 2 - Display Off //
// 3 - Programming (WhiteLED)
if (displayModes == 3) lkm1638.setColorLED(6, LedRed);
else lkm1638.setColorLED(6, LedOff);
}
}
// 1638 buttons
keys = lkm1638.getButtons();
// Check if button changed & status LEDs
if (lastKeys != keys) {
lastKeys = keys;
if(keys != 0) { // Clear last 0 - keys
flag_change_modes = true;
switch(keys) {
case 2: // Heater PUMP ONLY
heater_mode = 3;
lkm1638.setColorLED(0, LedRed);
lkm1638.setColorLED(2, LedOff);
lkm1638.setColorLED(5, LedOff);
digitalWrite(LED_AUTO_HEATER, LOW);
break;
case 4: // Heater OFF
heater_mode = 0;
lkm1638.setColorLED(0, LedOff);
lkm1638.setColorLED(2, LedOff);
lkm1638.setColorLED(5, LedRed);
digitalWrite(LED_AUTO_HEATER, LOW);
break;
case 8: // Heater RUN
heater_mode = 1;
lkm1638.setColorLED(0, LedOff);
lkm1638.setColorLED(2, LedRed);
lkm1638.setColorLED(5, LedOff);
digitalWrite(LED_AUTO_HEATER, LOW);
break;
case 16: // Heater AUTO
heater_mode = 2;
lkm1638.setColorLED(0, LedOff);
lkm1638.setColorLED(2, LedOff);
lkm1638.setColorLED(5, LedOff);
analogWrite(LED_AUTO_HEATER, 64);
break;
case 32: // Filtration AUTO
filter_mode = 2;
lkm1638.setColorLED(3, LedOff);
lkm1638.setColorLED(4, LedOff);
analogWrite(LED_AUTO_FILTER, 64);
break;
case 64: // Filtration RUN
filter_mode = 1;
lkm1638.setColorLED(3, LedRed);
lkm1638.setColorLED(4, LedOff);
digitalWrite(LED_AUTO_FILTER, LOW);
break;
case 128: // Filtration OFF
filter_mode = 0;
lkm1638.setColorLED(3, LedOff);
lkm1638.setColorLED(4, LedRed);
digitalWrite(LED_AUTO_FILTER, LOW);
break;
}
}
}
}
MAIN CONTROL
void main_logic(){
// Control modes---------------
// filter_mode:
// 0 - OFF | 1 - RUN | 2 - AUTO |
// 5 - AUTO RUN
// heater_mode:
// 0 - OFF | 1 - RUN | 2 - AUTO |
// 3 - PUMP ONLY | 5 - AUTO RUN
if (flag_change_modes) {
// FILTER
switch (filter_mode) {
case 0: // OFF
filter_run = false;
flag_change_relays = true;
break;
case 1: // RUN
filter_run = true;
flag_change_relays = true;
break;
case 2: // AUTO
filter_run = false;
flag_change_relays = true;
break;
}
// HEATER
switch (heater_mode) {
case 0: // OFF
heater_run = false;
pump_run = false;
flag_change_relays = true;
break;
case 1: // RUN PUMP & HEATER
heater_run = true;
pump_run = true;
flag_change_relays = true;
break;
case 2: // AUTO
heater_run = false;
pump_run = false;
flag_change_relays = true;
break;
case 3: // RUN PUMP ONLY
heater_run = false;
pump_run = true;
flag_change_relays = true;
break;
}
flag_change_modes = false;
}
// Set Auto--------------------
if (displayModes == 3) {
// selectDevice → 0 - Filter | 1 - Heater | 2 - max. temperature
static uint32_t debounce_1, debounce_2, debounce_3;
static bool start_stop_filter = true;
static bool start_stop_heater = true;
if (millis() - debounce_1 >= 300) {
if (digitalRead(BTN_SELECT) == LOW) {
debounce_1 = millis();
selectDevice++;
if (selectDevice >= 3) selectDevice = 0;
}
}
if (millis() - debounce_2 >= 300) {
if (digitalRead(BTN_PLUS) == LOW) {
debounce_2 = millis();
// 0 - Filter
if (selectDevice == 0) {
if (start_stop_filter) {
hour_START_FILTER++;
if (hour_START_FILTER >= 24) hour_START_FILTER = 0;
}
else {
hour_STOP_FILTER++;
if (hour_STOP_FILTER >= 24) hour_STOP_FILTER = 0;
}
}
// 1 - Heater
else if (selectDevice == 1) {
if (start_stop_heater) {
hour_START_HEATER++;
if (hour_START_HEATER >= 24) hour_START_HEATER = 0;
}
else {
hour_STOP_HEATER++;
if (hour_STOP_HEATER >= 24) hour_STOP_HEATER = 0;
}
}
// 2 - max. temperature
else {
set_MaxTEMP++;
if (set_MaxTEMP > 35) set_MaxTEMP = 15;
}
}
}
if (millis() - debounce_3 >= 300) {
if (digitalRead(BTN_ENTER) == LOW) {
debounce_3 = millis();
// FILTER
if (selectDevice == 0) {
if (start_stop_filter) { // Start time
EEPROM.update(3, hour_START_FILTER);
}
else { // Stop time
EEPROM.update(4, hour_STOP_FILTER);
}
start_stop_filter = !start_stop_filter;
}
// HEATER
else if (selectDevice == 1) {
if (start_stop_heater) { // Start time
EEPROM.update(5, hour_START_HEATER);
}
else { // Stop time
EEPROM.update(6, hour_STOP_HEATER);
}
start_stop_heater = !start_stop_heater;
}
// Set maximum temperature of wather for heating
else {
EEPROM.update(7, set_MaxTEMP);
}
}
}
}
// Run Auto--------------------
// FILTER
if (filter_mode == 2 || filter_mode == 5) {
bool flag_autorun;
if (hour_START_FILTER == hour_STOP_FILTER) flag_autorun = false; // Incorrect data
if (hour_START_FILTER < hour_STOP_FILTER) { // 0----START----STOP----23
if (current_hour >= hour_START_FILTER && current_hour < hour_STOP_FILTER) {
flag_autorun = true;
}
else flag_autorun = false;
}
else { // --START—23—0—STOP–
if ((current_hour >= hour_START_FILTER && current_hour <= 23) || current_hour < hour_STOP_FILTER) {
flag_autorun = true;
}
else flag_autorun = false;
}
if (flag_autorun) {
filter_run = true;
filter_mode = 5;
if (digitalRead(RELAY_FILTER) == HIGH) flag_change_relays = true;
// IF RELAY OFF set flag relays active
}
else {
filter_run = false;
filter_mode = 2;
analogWrite(LED_AUTO_FILTER, 64);
if (digitalRead(RELAY_FILTER) == LOW) flag_change_relays = true;
// IF RELAY WORKING set flag relays active
}
}
// HEAT
if (heater_mode == 2) {
bool flag_autorun;
if (hour_START_HEATER == hour_STOP_HEATER) flag_autorun = false; // Incorrect data
if (hour_START_HEATER < hour_STOP_HEATER) { // 0----START----STOP----23
if (current_hour >= hour_START_HEATER && current_hour < hour_STOP_HEATER) {
flag_autorun = true;
}
else flag_autorun = false;
}
else { // --START—23—0—STOP–
if ((current_hour >= hour_START_HEATER && current_hour <= 23) || current_hour < hour_STOP_HEATER) {
flag_autorun = true;
}
else flag_autorun = false;
}
if (flag_autorun) {
heater_run = true;
pump_run = true;
heater_mode = 5;
if (digitalRead(RELAY_HEATER) == HIGH) flag_change_relays = true;
// IF RELAY OFF set flag relays active
}
else {
heater_run = false;
pump_run = false;
heater_mode = 2;
if (digitalRead(RELAY_HEATER) == LOW) flag_change_relays = true;
// IF RELAY WORKING set flag relays active
}
}
// TEMPERATURE LIMIT
if (millis() - tmrAlarmTemperature >= 10000) {
tmrAlarmTemperature = millis();
if (set_MaxTEMP <= heater_temperature) {
flag_change_relays = true;
heater_run = false;
pump_run = false;
heater_mode = 0;
}
// Serial.print("MAX TEMP: “);
// Serial.print(set_MaxTEMP);
// Serial.print(” - SENSOR: ");
// Serial.println(common_temperature);
}
}

