Хотел бы поделится результатами моего проекта по созданию блока управления для управления работы насосов теплого пола, насоса радиаторов и актуатора (псевдо-сервопривода)Вот что внутри его 3-х ходового клапана. Вот описание актуатора
Долго искал алгоритм работы актуатора на просторах ИНТЕРНЕТА, но «Гугл в помощь, не помог». В итоге искомое решение (строчка кода) было найдено в самом неожиданном месте. Представляю свой код работы на оценку публики любую критику и улучшения приветствуются.
#include <EEPROM.h>
#include <GyverOLED.h> // Библиотека дисплея
#include <OneWire.h>
#include <DallasTemperature.h>
#include <GyverEncoder.h>
#include <RF24.h>
#include "rotaryDecoderSwitch5.h"
#define CLK 3
#define DT 4
#define SW 5
#define ONE_WIRE_BUS D4 //где 2 это номер цифрового пина arduino к которому подключен датчик
OneWire oneWire(ONE_WIRE_BUS); //// настроем библиотеку 1-Wire для связи с датчиком
DallasTemperature sensors(&oneWire);// // создадим объект для работы с библиотекой DallasTemperature
/*DeviceAddress TcoilIN = {
0x28, 0xBA, 0x6F, 0x77, 0x91, 0x10, 0x02, 0x55 }; // адрес датчика DS18B20 280054B604000092
*/
DeviceAddress Tfc = { // температура первичного кольца на выходе
0x28, 0xFF, 0x70, 0x77, 0x91, 0x10, 0x02, 0xD8 };
GyverOLED<SSD1306_128x64, OLED_NO_BUFFER> oled;
rotaryDecoderSwitch5 decoder(0x20);
Encoder enc;
//-------------NRF24-----------------
/*
Создаём объект radio для работы с библиотекой RF24,
указывая номера выводов модуля (CE, SS).
*/
RF24 radio(D0, D8); // for wemos ESP8266 D1 mini R2
float RX_value[2]; // Массив для передачи данных о температуре и влажности
//--------------------------------------------------------------------
uint8_t pipe = 0x0123456789LL; // Объявляем переменную в которую будет сохраняться номер трубы по которой приняты данные.
float TempRoom ;
float HumRoom ;
//---------------------------------------------------------
int menuItem = 1; // переменная для выбора подменю
int page = 1; // страница меню
int SelectCoil_pump ; //состояния насоса батарей было 1
int ConditionFloor_pump; //состояния насоса БКН было 1
int SetSec ; // время работы таймера в секундах для реле 750мс поворот на 1 градус 90 угол поворота/120 время в сек поворота
int interval = 10; // время работы таймера,sec
//------------------
long OledUpdateTime;
bool opening; // флаг для включения реле актуатора 3х ходового клапана
bool closing;// флаг для выключения реле актуатора 3х ходового клапана
bool stoppage = 1;// остановка программы для управления меню
unsigned long tmr; //таймер включения реле актуатора 3х ходового клапана
unsigned long timer; // таймер выключения реле актуатора 3х ходового клапана
unsigned long updateTempTime; // таймер для обновления показания температур
unsigned long XXX;
unsigned long closeAct;
bool ActuaStop = 1; //флаг начального этапа 100% закрытие актуатора байпас закрыт
bool FlagcoilP; // флаг насоса батарей
bool FlagFloorP; // флаг насоса пола
int count = 0; //счетчик для актуатора
int TsetFC ;// установка температуры в первичном кольце
int TroomSet ; // уставка температуры в комнате на 2-м этаже
int DIFF = 1; // деференциала температуры воздуха для второго этажа 3
const byte coil_pump = 6; // насос батарей
const byte floor_pump = 2; // насос теплого пола
const byte opRelay = 1; // реле привода открытие
const byte clRelay = 0; // реле привода закрытие
float Tc; // подача в первичное кольцо
const char *names[] = {
"АВТО", //0
"ВЫКЛ" //1
};
//------------------------
const uint8_t frame0_16x16_1[] PROGMEM = { // 3х ходовой клапан бездействие
0x31, 0x49, 0x85, 0x05, 0x09, 0x31, 0x01, 0x11, 0x29, 0x49, 0x89, 0x49, 0xA9, 0x91, 0x41, 0xE1,
0x8C, 0x90, 0xA0, 0xA1, 0x92, 0x8C, 0x80, 0x84, 0x8A, 0x89, 0x88, 0x89, 0x8A, 0x84, 0x81, 0x83,
};
const uint8_t frame0_16x16_2[] PROGMEM = { // 3х ходовой клапан приоткрытие
0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x48, 0x88, 0x48, 0xA8, 0x90, 0x40, 0xE0,
0x0C, 0x18, 0x3F, 0x18, 0x0C, 0x00, 0x00, 0x04, 0x0E, 0x0F, 0x0F, 0x0F, 0x0E, 0x04, 0x01, 0x03,
};
const uint8_t frame0_16x16_3[] PROGMEM = { // 3х ходовой клапан призакрытие
0x30, 0x18, 0xFC, 0x18, 0x30, 0x00, 0x00, 0x10, 0x38, 0x78, 0xF8, 0x78, 0xB8, 0x90, 0x40, 0xE0,
0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0A, 0x09, 0x08, 0x09, 0x0A, 0x04, 0x01, 0x03,
};
const uint8_t frame0_16x16_4[] PROGMEM = { // насос батарей
0x00, 0xE0, 0x10, 0x48, 0x84, 0x02, 0x42, 0xA2, 0x92, 0x4A, 0x82, 0x06, 0x0E, 0x1E, 0xF2, 0x12,
0x48, 0x4F, 0x78, 0x70, 0x60, 0x41, 0x52, 0x49, 0x45, 0x42, 0x40, 0x21, 0x12, 0x08, 0x07, 0x00,
};
const uint8_t frame0_16x16_5[] PROGMEM = {// насос батарей
0x00, 0xE0, 0x10, 0x08, 0x04, 0x02, 0x02, 0x82, 0x82, 0x02, 0x02, 0x06, 0x0E, 0x1E, 0xF2, 0x12,
0x48, 0x4F, 0x78, 0x70, 0x60, 0x40, 0x40, 0x41, 0x41, 0x40, 0x40, 0x20, 0x10, 0x08, 0x07, 0x00,
};
const uint8_t frame0_16x16_6[] PROGMEM = { // БКН выключен
0x00, 0xf0, 0xf8, 0x04, 0x04, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0xf8, 0xf0, 0x00,
0x00, 0x1f, 0x3f, 0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0x3f, 0x1f, 0x00,
};
const uint8_t frame0_16x16_7[] PROGMEM = { // БКН включен
0x00, 0xf0, 0xf8, 0x04, 0x04, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0xf8, 0xf0, 0x00,
0x00, 0x1f, 0x3f, 0x40, 0x91, 0x9b, 0x95, 0x91, 0x91, 0x91, 0x91, 0x91, 0x51, 0x3f, 0x1f, 0x11,
};
const unsigned char* icon16x16[] = {
frame0_16x16_1,
frame0_16x16_2,
frame0_16x16_3,
frame0_16x16_4,
frame0_16x16_5,
frame0_16x16_6,
frame0_16x16_7
};
void setup() {
Serial.begin(115200);
EEPROM.begin(512); //Инициализация EEPROM с размером 100 байт
//----------------------------------
TsetFC = EEPROM.read(1);
Serial.print( "adres1 ");
Serial.println(TsetFC);
SelectCoil_pump = EEPROM.read(2);
Serial.print( "adres2 ");
Serial.println(SelectCoil_pump);
ConditionFloor_pump = EEPROM.read(3);
Serial.print( "adres3 ");
Serial.println(ConditionFloor_pump);
SetSec = EEPROM.read(4);
Serial.print( "adres4 ");
Serial.println(SetSec);
TroomSet = EEPROM.read(0);
Serial.print( "adres0 ");
Serial.println(TroomSet);
FlagcoilP = EEPROM.read(5);
Serial.print( "adres5 ");
Serial.println(FlagcoilP);
FlagFloorP = EEPROM.read(6);
Serial.print( "adres6 ");
Serial.println(FlagFloorP);
//--------------------------------------
Wire.begin();
Wire.setClock(100000);
decoder.begin(5);
decoder.readInitialState();
enc.setType(TYPE2); // инициализация энкодера
//----------------------------------
Serial.flush();
Serial.println("temperature,humudity");
radio.begin();
/*
Указываем канал передачи данных (от 0 до 127)
(на одном канале может быть только 1 приёмник и до 6 передатчиков).
Выбираем канал в котором нет шумов!
*/
radio.setChannel(116);
/*
Указываем скорость передачи данных
RF24_250KBPS = 250Кбит/сек
RF24_1MBPS = 1Мбит/сек
RF24_2MBPS = 2Мбит/сек
Скорость должна быть одинакова на приёмнике и передатчике.
При самой низкой скорости имеем самую высокую чувствительность и дальность.
*/
radio.setDataRate(RF24_1MBPS);
/*
Указываем мощность передатчика
RF24_PA_MIN=-18dBm
RF24_PA_LOW=-12dBm
RF24_PA_HIGH=-6dBm
RF24_PA_MAX=0dBm
*/
radio.setPALevel(RF24_PA_MAX);
/*
Открываем 1 трубу с адресом 1 передатчика 0x0123456789LL, для приема данных.
*/
radio.openReadingPipe(1, 0x0123456789LL);
/*
Включаем приемник, начинаем прослушивать открытые трубы.
*/
radio.startListening();
//------------------------------------
// sensors.setResolution(TcoilIN, 12);//Мы можем самостоятельно задать необходимое разрешение, установив
//количество бит точности – 9, 10, 11 и 12. В этих случаях разрешающие
//способности будут соответственно равны 0,5С, 0,25С, 0,125С и 0,0625С.
sensors.begin();
sensors.setResolution(Tfc, 12);
decoder.write1(opRelay, LOW);
decoder.write1(clRelay, LOW);
decoder.write1(coil_pump, LOW);
decoder.write1(floor_pump, LOW);
//-------------------------------------
oled.init(); // инициализация дисплея
oled.clear(); // отчистка дисплея
oled.setContrast(15); // Макс. яркость яркость 0..15
oled.setCursor(5, 0); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("Управление");
oled.setCursor(5, 2); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("3х ходовой");
oled.setCursor(5, 4); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("клапан");
oled.setCursor(5, 6); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("v 6.4");
delay (3000);
oled.clear(); // отчистка дисплея
}
void loop() {
// обязательная функция отработки. Должна постоянно опрашиваться
enc.tick(decoder.read1(CLK), decoder.read1(DT), ! decoder.read1(SW));
encoder ();
drawMenu();
work_Relay ();
working();
//-------------------------------------------------
if(millis()-updateTempTime >=5180){
updateTempTime = millis();
sensors.requestTemperatures();
Serial.print("температура первичного кольца ");
Tc = sensors.getTempC(Tfc);
Serial.println(Tc);
//---------------------NRF24--------------
if (radio.available(&pipe)) {
// Читаем данные из буфера в массив receivedData указывая
// сколько всего байт может поместиться в массив.
radio.read(&RX_value, sizeof(RX_value));
// Если данные пришли от 1 передатчика (по 1 трубе),
// то можно выполнить соответствующее действие ...
Serial.print("temperature ");
Serial.println (TempRoom =RX_value[0] );
}
}
}
void drawMenu() {
if (millis() - OledUpdateTime >= 1000) // обновление дисплея
{
OledUpdateTime = millis();
if (page == 1) { //ГЛАВНАЯ СТРАНИЦА
oled.setCursor(0, 0); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("ТЕМП");
// oled.line(0, 16, 127, 16); // линия x0,y0,x1,y1
oled.line(50, 30, 65, 30); // линия x0,y0,x1,y1
oled.line(40, 45, 65, 45); // линия x0,y0,x1,y1
oled.line(40, 60, 65, 60); // линия x0,y0,x1,y1
// температура тнплоносителя на входе в первичное кольцо
oled.setCursor(2, 2); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("Tпод");
oled.setCursor(70, 2); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print(Tc,1);// вывод значения на дисплей с одним знаком после запятой регулируется ,1
// вывод температуры обратки
oled.setCursor(2, 4 ); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("Tком");
oled.setCursor(70, 4); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print(TempRoom,1);// вывод значения на дисплей с одним знаком после запятой регулируется ,1
// вывод температуры уставки в комнате
oled.setCursor(2, 6 ); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("Уком");
oled.setCursor(70, 6); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print(TroomSet);
}
if (page == 2) {
oled.setCursor(40, 0); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("МЕНЮ");
if (menuItem == 1) {
oled.roundRect(4, 3 * 8, 127, (3 * 8) + 6, OLED_STROKE); // прямоугольник (x0,y0,x1,y1)
// Указатель в виде битмапа (картинки)
/*oled.drawBitmap(0, pointer * 8, ptr_bmp, 10, 8);*/
oled.setCursor(8, 3); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.autoPrintln(true); // автоматически переносить текст
oled.print("НАС-КА Т ПЕРВ КОЛЬЦ");
} else {
oled.setCursor(8, 3); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.autoPrintln(true); // автоматически переносить текст
oled.print("нас-ка Т перв кольц");
}
if (menuItem == 2) {
oled.roundRect(4, 4 * 8, 127, (4 * 8) + 6, OLED_STROKE); // прямоугольник (x0,y0,x1,y1)
oled.setCursor(8, 4); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("НАСТ РАБОТЫ КЛАПАНА");
} else {
oled.setCursor(8, 4); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("наст работы клапана");
}
if (menuItem == 3) {
oled.roundRect(4, 5 * 8, 120, (5 * 8) + 6, OLED_STROKE); // прямоугольник (x0,y0,x1,y1)
oled.setCursor(8, 5); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("ТЕМП УСТАН 2 ЭТАЖ");
} else {
oled.setCursor(8, 5); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("темп устан 2 этаж");
}
if (menuItem == 4) {
oled.roundRect(4, 6 * 8, 50, (6 * 8) + 6, OLED_STROKE); // прямоугольник (x0,y0,x1,y1)
oled.setCursor(8, 6); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("НАСОСЫ");
} else {
oled.setCursor(8, 6); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("насосы");
}
if (menuItem == 5) {
oled.roundRect(4, 7 * 8, 40, (7 * 8) + 6, OLED_STROKE); // прямоугольник (x0,y0,x1,y1)
// Указатель в виде битмапа (картинки)
/*oled.drawBitmap(0, pointer * 8, ptr_bmp, 10, 8);*/
oled.setCursor(8, 7); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("ВЫХОД");
} else {
oled.setCursor(8, 7); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("выход");
}
} else if (page == 3) {
oled.setCursor(0, 0); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("настройка темп первич кольцо");
oled.setCursor(45, 4); // курсор в (пиксель X, строка Y)
oled.setScale(3);
oled.print(TsetFC);
}
else if (page == 4) {
oled.setCursor(0, 0); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("время в сек работы реле");
oled.setCursor(35, 4); // курсор в (пиксель X, строка Y)
oled.setScale(3);
oled.print(SetSec);
}
else if (page == 5) {
oled.setCursor(0, 0); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("настройка темп на 2-м этаж");
oled.setCursor(45, 4); // курсор в (пиксель X, строка Y)
oled.setScale(3);
oled.print(TroomSet); // убрать кавычки///---------------////
}
else if (page == 6) {
oled.setCursor(0, 0); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("РЕЖ НАСОСА");
if (menuItem == 1) { // насос батарей
oled.roundRect(2, 2 * 10, 118, (2 * 10) + 18, OLED_STROKE); // прямоугольник (x0,y0,x1,y1)
oled.setCursor(8, 3); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("НАС БАТАР");
} else {
oled.setCursor(8, 2); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("НАС БАТАР");
}
if (menuItem == 2) { // насос БКН
oled.roundRect(2, 4 * 10, 118, (4 * 10) + 18, OLED_STROKE); // прямоугольник (x0,y0,x1,y1)
oled.setCursor(8, 5); // курсор в (пиксель X, строка Y)
oled.setScale(2);
oled.print("НАСОС ПОЛ");
} else {
oled.setCursor(8, 6); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("НАСОС ПОЛ");
}
}
else if (page == 7) {
if (SelectCoil_pump == 1) {
oled.setCursor(0, 0); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("настройка состояния насоса батарей");
oled.setCursor(20, 4); // курсор в (пиксель X, строка Y)
oled.setScale(3);
oled.print(names[0]);
} else if (SelectCoil_pump == 2) {
oled.setCursor(0, 0); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("настройка состояния насоса батарей");
oled.setCursor(20, 4); // курсор в (пиксель X, строка Y)
oled.setScale(3);
oled.print(names[1]);
}
}
else if (page == 8) {
if (ConditionFloor_pump == 1) {
oled.setCursor(0, 0); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("настройка состояния насоса пола");
oled.setCursor(20, 4); // курсор в (пиксель X, строка Y)
oled.setScale(3);
oled.print(names[0]);
} else if (ConditionFloor_pump == 2) {
oled.setCursor(0, 0); // курсор в (пиксель X, строка Y)
oled.setScale(1);
oled.print("настройка состояния насоса пола");
oled.setCursor(20, 4); // курсор в (пиксель X, строка Y)
oled.setScale(3);
oled.print(names[1]);
}
}
}
}
void work_Relay (){ // актуатор
if((millis()-closeAct) > 20000){
if (TempRoom< TroomSet-DIFF && ActuaStop && stoppage){ // момент начала закрытия байпаса
count ++;
Serial.print("counter :");
Serial.println(count);
Serial.println("актуатор закрывает байпас для прогреса батарей");
decoder.write1(opRelay, LOW); //выключаем реле
decoder.write1(clRelay, HIGH);
oled.drawBitmap(94, 0, icon16x16[1], 16, 16);// клапан прикрывается
}
if (TempRoom< TroomSet-DIFF && count == 6 && stoppage){ // момент полного закрытия байпаса
ActuaStop = 0;
count = 0;
Serial.println("актуатор ЗАКРЫЛ байпас ПОЛНОСТЬЮ ");
decoder.write1(opRelay, LOW); //выключаем реле
decoder.write1(clRelay, LOW);
oled.drawBitmap(94, 0, icon16x16[0], 16, 16); // клапан закрыт
}
if (TempRoom == TroomSet-DIFF && stoppage) {
ActuaStop = 1;
}
closeAct = millis();
}
//---------------------------------------------------
if(TempRoom< TroomSet-DIFF || TempRoom > TroomSet+DIFF && stoppage){
///----------------+++++++++++++
if (TempRoom < TroomSet-DIFF) { // строка мониторит факт нажатия кнопки на Nextion
if ((millis()- tmr) > (opening ? (SetSec*1000) : 30000)) { //условие каждые 2 секунд включать реле на 60 секунд отключать.
opening =! opening;
Serial.println("включаем руле на приоткрытие 2 сек Вкл 5 сек Вык");
decoder.write1(opRelay, LOW); //выключаем реле
decoder.write1(clRelay, opening);
oled.drawBitmap(94, 0, icon16x16[2], 16, 16);// клапан приоткрывается
tmr =millis();
}
closeAct = millis();
}
if (TempRoom >= TroomSet){
if ((millis()- timer) > (closing ? (SetSec*1000) : 30000)) { //условие каждые 2 секунд включать реле на 60 секунд отключать.
closing =! closing;
Serial.println("включаем руле на закрытие 2 сек Вкл 5 сек Вык");
decoder.write1(opRelay, closing); //выключаем реле
decoder.write1(clRelay, LOW);
oled.drawBitmap(94, 0, icon16x16[1], 16, 16);// клапан прикрывается
timer =millis();
}
}
}
}
void encoder () {
switch (page) { //выбор страницы и что делать на ней энкодером
case 1:
if (enc.isClick()) {
oled.clear();
Serial.println("нажата кнопка вход в меню******************");
page = 2;
}; break;
case 2: // работа на страничке с настройкой меню
if (enc.isRight() ) {
menuItem ++;
oled.clear();
Serial.println("Right");
if (menuItem > 5) menuItem = 1;
Serial.println(menuItem);
}
//untuk button down
if (enc.isLeft() ) {
menuItem --;
oled.clear();
Serial.println("Left");
if (menuItem < 1) menuItem = 5;
Serial.println(menuItem);
}; break;
case 3: // работа со страничкой настпойки температуры в первичном кольце
if (enc.isRight() ) {
TsetFC++;
TsetFC = constrain(TsetFC, 39, 65);
Serial.println("TsetFC UP");
Serial.println(TsetFC);
}
if (enc.isLeft() ) {
TsetFC--;
TsetFC = constrain(TsetFC, 39, 65);
Serial.println("TsetFC DOWN");
Serial.println(TsetFC);
}; break;
case 4:
if (enc.isRight() ) {
SetSec++;
SetSec = constrain(SetSec, 0, 80);
Serial.println("SetSec UP");
Serial.println(SetSec);
}
if (enc.isLeft() ) {
SetSec--;
SetSec = constrain(SetSec, 0, 80);
Serial.println("SetSec DOWN");
Serial.println(SetSec);
}; break;
// уставка температуры в комнате на 2-м этаже
case 5:
if (enc.isRight() ) {
TroomSet++;
TroomSet = constrain(TroomSet, 5, 26);
Serial.println("TroomSet up");
Serial.println(TroomSet);
}
if (enc.isLeft() ) {
TroomSet--;
TroomSet = constrain(TroomSet, 5, 26);
Serial.println("TroomSet DOWN");
Serial.println(TroomSet);
}; break;
case 6: // работа со страничкой настройки выбора насоса
if (enc.isRight() ) {
menuItem ++;
oled.clear();
Serial.println("Right");
if (menuItem > 2) menuItem = 1;
Serial.println(menuItem);
}
//untuk button down
if (enc.isLeft() ) {
menuItem --;
oled.clear();
Serial.println("Left");
if (menuItem < 1) menuItem = 2;
Serial.println(menuItem);
}; break;
case 7:
if (enc.isRight() ) {
SelectCoil_pump ++;
oled.clear();
Serial.println("Right");
if (SelectCoil_pump > 2) SelectCoil_pump = 1;
Serial.println(SelectCoil_pump);
}
//untuk button down
if (enc.isLeft() ) {
SelectCoil_pump --;
oled.clear();
Serial.println("Left");
if (SelectCoil_pump < 1) SelectCoil_pump = 2;
Serial.println(SelectCoil_pump);
}; break;
case 8:
if (enc.isRight() ) {
ConditionFloor_pump ++;
oled.clear();
Serial.println("Right");
if (ConditionFloor_pump > 2) ConditionFloor_pump = 1;
Serial.println(ConditionFloor_pump);
}
//untuk button down
if (enc.isLeft() ) {
ConditionFloor_pump --;
oled.clear();
Serial.println("Left");
if (ConditionFloor_pump < 1) ConditionFloor_pump = 2;
Serial.println(ConditionFloor_pump);
}; break;
// время работы таймера в секундах для реле
}
// обработка нажатия на энкодер
if (enc.isClick()) {
Serial.println("***************Click*******************");
stoppage = 0;
if (page == 2 && menuItem == 1) {
oled.clear();
Serial.println("21");
page = 3;
} else if (page == 2 && menuItem == 2) {
oled.clear();
Serial.println("22");
page = 4;
} else if (page == 2 && menuItem == 3) {
oled.clear();
Serial.println("23");
page = 5;
} else if (page == 2 && menuItem == 4) {
oled.clear();
Serial.println("23");
page = 6;
} else if (page == 2 && menuItem == 5) {
oled.clear();
Serial.println("25");
page = 1;
stoppage = 1;
}
else if (page == 3) {
EEPROM.write(1, TsetFC);
EEPROM.commit(); // Сохранение изменений
oled.rect(40, 28, 83, 56, OLED_STROKE); // прямоугольник (x0,y0,x1,y1)
}
else if (page == 4) {
EEPROM.write(4, SetSec);
EEPROM.commit(); // Сохранение изменений
oled.rect(30, 28, 63, 56, OLED_STROKE); // прямоугольник (x0,y0,x1,y1)
}
else if (page == 5) {
EEPROM.write(0, TroomSet);
EEPROM.commit(); // Сохранение изменений
oled.rect(34, 28, 88, 56, OLED_STROKE); // прямоугольник (x0,y0,x1,y1)
}
else if (page == 6 && menuItem == 1) {
oled.clear();
Serial.println("61");
page = 7;
} else if (page == 6 && menuItem == 2) {
oled.clear();
Serial.println("62");
page = 8;
}
else if (page == 7) {
if (SelectCoil_pump == 1) {
Serial.println("pump in");
EEPROM.write(2, SelectCoil_pump);
FlagcoilP = 1;
EEPROM.write(5, FlagcoilP);
EEPROM.commit(); // Сохранение изменений
oled.drawBitmap(112, 16, icon16x16[3], 16, 16); // радиаторный насос включен
} else if (SelectCoil_pump == 2) {
Serial.println("pump out");
EEPROM.write(2, SelectCoil_pump);
FlagcoilP = 0;
EEPROM.write(5, FlagcoilP);
EEPROM.commit(); // Сохранение изменений
oled.drawBitmap(112, 16, icon16x16[4], 16, 16);// радиаторный насос выключен
}
}
else if (page == 8) {
if (ConditionFloor_pump == 1) {
Serial.println("floor pump start");
oled.drawBitmap(112, 16, icon16x16[6], 16, 16);// насос теплого пола включен
EEPROM.write(3, ConditionFloor_pump );
FlagFloorP = 1;
EEPROM.write(6, FlagFloorP);
EEPROM.commit(); // Сохранение изменений
} else if (ConditionFloor_pump == 2) {
Serial.println("floor pump stop");
oled.drawBitmap(112, 16, icon16x16[7], 16, 16);// насос теплого пола выключен
EEPROM.write(3, ConditionFloor_pump );
FlagFloorP = 0;
EEPROM.write(6, FlagFloorP);
EEPROM.commit(); // Сохранение изменений
}
}
}
// untuk button back
if (enc.isHolded()) {
Serial.println("Holded");
if (page == 3 || page == 4 || page == 7 || page == 8) {
oled.clear();
page = 2;
}
else if (page == 5 || page == 6) {
oled.clear();
page = 2;
}
}
}
void working(){
//------------------------PUMPS STOP-----------------------
if(millis()-XXX >=24230){
if(!FlagcoilP && !FlagFloorP){
decoder.write1(coil_pump, LOW);
decoder.write1(floor_pump, LOW);
oled.drawBitmap(112, 0, icon16x16[4], 16, 16);// радиаторный насос выключен
oled.drawBitmap(74, 0, icon16x16[7], 16, 16);// насос теплого пола выключен
Serial.println("насосы выключенны через меню");
}
else if(Tc <= 39 || Tc<TsetFC && stoppage) { // температура ниже 39 все стоит
decoder.write1(coil_pump, LOW);
decoder.write1(floor_pump, LOW);
oled.drawBitmap(112, 0, icon16x16[4], 16, 16);// радиаторный насос выключен
oled.drawBitmap(74, 0, icon16x16[7], 16, 16);// насос теплого пола выключен
Serial.println("насосы выключенны по достижении миним температуры");
}
//-------------------------------------В РЕЖИМЕ "ВЫК" ХОТЯ БЫ ОДИН НАСОС---------
else if(Tc>TsetFC && TempRoom < TroomSet - DIFF && stoppage && FlagcoilP && !FlagFloorP ){ // насос батареи в режиме АВТО, а насос нагревателя ВЫК
decoder.write1(coil_pump, HIGH);
decoder.write1(floor_pump, LOW);
oled.drawBitmap(112, 0, icon16x16[3], 16, 16); // радиаторный насос включен
oled.drawBitmap(74, 0, icon16x16[7], 16, 16);// насос теплого пола выключен
Serial.println("насос батареи в режиме АВТО, а насос нагревателя ВЫК");
}
else if(Tc>TsetFC && TempRoom < TroomSet - DIFF && stoppage && !FlagcoilP && FlagFloorP ){ // насос батареи в режиме ВЫК, а насос нагревателя АВТО
decoder.write1(coil_pump, LOW);
decoder.write1(floor_pump, HIGH);
oled.drawBitmap(112, 0, icon16x16[4], 16, 16);// радиаторный насос выключен
oled.drawBitmap(72, 0, icon16x16[6], 16, 16);// насос теплого пола включен
Serial.println("насос батареи в режиме ВЫК, а насос нагревателя АВТО");
}
else if(Tc>TsetFC && TempRoom >= 26 && stoppage && FlagcoilP && !FlagFloorP ) { // насос Нагревателя ВЫК , а насос батарей в АВТО
decoder.write1(coil_pump, LOW);
decoder.write1(floor_pump, LOW);
oled.drawBitmap(112, 0, icon16x16[4], 16, 16);// радиаторный насос выключен
oled.drawBitmap(74, 0, icon16x16[7], 16, 16);// насос теплого пола выключен
Serial.println("выкл температура в комнате 26 град");
}
else if(Tc>TsetFC && TempRoom >= 26 && stoppage && !FlagcoilP && FlagFloorP ) { // насос Нагревателя ВЫК , а насос батарей в АВТО
decoder.write1(coil_pump, LOW);
decoder.write1(floor_pump, HIGH);
oled.drawBitmap(112, 0, icon16x16[4], 16, 16);// радиаторный насос выключен
oled.drawBitmap(72, 0, icon16x16[6], 16, 16);// насос теплого пола включен
Serial.println("выкл температура в комнате 26 град но теп пол работают");
}
//---------------------------------------------В РЕЖИМЕ "АВТО" или "ВКЛЮЧЕНО"---------------------------------
if(FlagcoilP && FlagFloorP){ // если оба флага включены
if(Tc>TsetFC && TempRoom < TroomSet && stoppage ){ //оба насоса АВТО
decoder.write1(coil_pump, HIGH);
decoder.write1(floor_pump, HIGH);
oled.drawBitmap(112, 0, icon16x16[3], 16, 16); // радиаторный насос включен
oled.drawBitmap(72, 0, icon16x16[6], 16, 16);// насос теплого пола включен
Serial.println("оба насоса работают в АВТО");
}
else if(Tc>TsetFC && TempRoom == TroomSet && stoppage){ //
decoder.write1(coil_pump, LOW);
decoder.write1(floor_pump, HIGH);
oled.drawBitmap(112, 0, icon16x16[4], 16, 16);// радиаторный насос выключен
oled.drawBitmap(72, 0, icon16x16[6], 16, 16);// насос теплого пола включен
Serial.println("насос батарей в АВТО");
}
else if(Tc>TsetFC && TempRoom < TroomSet - DIFF && stoppage){ //
decoder.write1(coil_pump, HIGH);
decoder.write1(floor_pump, HIGH);
oled.drawBitmap(112, 0, icon16x16[3], 16, 16); // радиаторный насос включен
oled.drawBitmap(72, 0, icon16x16[6], 16, 16);// насос теплого пола включен
Serial.println("оба насоса работают в авто");
}
else if(Tc>TsetFC && TempRoom >= 26 && stoppage){ //
decoder.write1(coil_pump, LOW);
decoder.write1(floor_pump, HIGH);
oled.drawBitmap(112, 0, icon16x16[4], 16, 16);// радиаторный насос выключен
oled.drawBitmap(72, 0, icon16x16[6], 16, 16);// насос теплого пола включен
Serial.println(" только насоса пола работает в авто");
}
else if (Tc>90 && stoppage){ //НАСОВЫ ОСТАНАВЛИВАЮТСЯ
decoder.write1(coil_pump, LOW);
decoder.write1(floor_pump, LOW);
oled.drawBitmap(112, 0, icon16x16[4], 16, 16);// радиаторный насос выключен
oled.drawBitmap(74, 0, icon16x16[7], 16, 16);// насос теплого пола выключен
Serial.println("отключение насосов 90 град");
}
}
XXX = millis();
}
}
из чего состоит блок управления
Итак если с работой насосов более менее понятно. При достижении заданной температуры при заданных условиях насосы включаются и выключаются. Главный параметр это температура теплоносителя в первичном контуре от DS18B20 sensor.
С актуатором немного другая ситуация но вполне схожая. Называть привод сервоприводом, язык не поворачивается, т.к. в не отсутствует обратная связь благодаря которой мы могли бы отлеживать положение заслонки в реальном времени. Там реально присутствуют только концевики крайних положений. Т.е. принцип работы подать питание либо на открытие либо на закрытие и когда заслонка подойдет в одно из крайних положений, сработает конечник и отключит питание на эл мотор.
При начальном запуске заслонка перемещается в сторону закрытия байпаса в течении 120 сек, это сделано в виду того, что может быть оператор «вручную» открыл клапан и его нужно установить в начальное положение. Дальше управление ожидает получение температуры в комнате по средству радио модуля NRF24. После в коде идет сравнение условий Температуры в комнате и температуры уставки (настройки). Сам рабочий процесс происходит в пределах Температура установки и минус 1 С (дельта) и Температура установки. Пример если у нас установка на 22С ; то активация начнется (байпас закрыт) при 21С, при 22 С заслонка начнет(открывать байпас) для подмеса для уменьшения температуры теплоносителя.
Заслонка открывается по шагово и не работает в режиме полного открытия-закрытия. Шаг имеет ход работы 1-2 сек (выставляется в меню) и 3 секунд ожидания( прописывается в коде).
работа блока управления непосредственно на месте
Буду надеется что кому-то пригодится это проект или один из вариантов работы актуатора.



