//Управление горелкой типа Monarch (Weishaupt L7Z) //Вариант неисправности контроллера управления горением //(включение продувки и насоса, зажигания и топливных клапанов) //Контроллер темпертуры исправен //Защиты по обрыву пламени НЕТ //включение и выключение котла от контроллера температуры //---------- Внимание -------- //питание контроллера температуры - 220 В, поэтому вход к реле //контроллера на пин 4 подсоедините к питанию Ардуино или шилда 5 В //последовательный запуск продувки, топливных клапанов и искры по таймерам //настройка таймеров //эти настройки можно записать в энергонезависимую память //если заслонка горелки не работает, сразу установите ее на открытие #include <EEPROM.h> //библиотека работы с памятью #include <LiquidCrystal_I2C.h> //библиотеки работы с LCD через I2C #include <Wire.h> //Не забудь шунтировать выходы от кнопок резистором 10 КОм const int BtDownPin = 5; //пин кнопки уменьшить. const int BtUpPin = 6; //пин кнопки увеличить const int BtSettingPin = 7; //пин кнопки настроек const int MotorPin = 9; //пин управления реле продувки const int FuelValvePin = 11; //пин управления реле топливных клапанов const int IgnitionPin = 10; //пин управления искры const int RelayStartPin = 12; //пин от контроллера температуры //Его тоже нужно шунтировать резистором 10 КОм const int BtBoilerOnPin = 13; //пин кнопки включения/выключения котла //пины модуля I2C LCD-дисплея : //SDA - A4 //SCL - A5 //питание от шилда int Init_Eeprom_Addr = 1000; //номер ячейки в памяти EEPROM (0-1023), куда мы запишем ключ о //самом первом запуске программы //это нужно, так как при первом запуске в памяти нет наших настроек //и нужно загрузить значения по умолчанию byte Init_Key = 230; //это ключ (0-255). //Если при пуске скетча данные из ячейки Init_Eeprom не совпадают //с Init_Key, вводим в настройки значения по умолчанию, //иначе берем настройки из памяти long BLOW_TIMER=30000; //время продувки котла //предел верхней границы, выше нее подниматься нельзя, мс long BLOW_TIMER_MAX=99000; //предел нижней границы, ниже нее опустить нельзя, мс int BLOW_TIMER_MIN=5000; int IGNITION_TIMER=3000; //время поджига искры //предел верхней границы, выше нее подниматься нельзя, мс int IGNITION_TIMER_MAX=5000; //предел нижней грницы, ниже нее опустить нельзя, мс int IGNITION_TIMER_MIN=1000; long BlowTick = 0; //нужна в отсчете времени продувки и поджига искры int BlowCountDown = 0; //нужна в отображении времени продувки на LCD int SettingNumber = 1; //пункт меню настройки boolean LastButtonSetting = LOW; //предыдущее состояние кнопки Настройки boolean CurrentButtonSetting = LOW; //текущее состояние кнопки Настройки boolean LastButtonDown = LOW; // --- Меньше boolean CurrentButtonDown = LOW; // --- Меньше boolean LastButtonUp = LOW; // --- Больше boolean CurrentButtonUp = LOW; // --- Больше boolean LastRelayStart = LOW; //предыдущее состояние реле boolean CurrentRelayStart = LOW; //текущее состояние реле boolean LastButtonBoiler = LOW; //предыдущее состояние кнопки включения котла boolean CurrentButtonBoiler = LOW; //текущее состояние кнопки включения котла boolean FlagSettingLoop = true; //были ли мы в цикле нажатия кнопки Настройки boolean FlagUpLoop = true; //были ли мы в цикле нажатия кнопки Больше boolean FlagDownLoop = true; //были ли мы в цикле нажатия кнопки Меньше boolean FlagBoilerLoop = true; //были ли мы в цикле нажатия кнопки включения котла boolean FlagStartMotor = false; //нужна для запуска отсчета времени продувки boolean FlagBoilerOn = false; //включен или нет котел LiquidCrystal_I2C lcd(0x27,16,2); //Задаем адрес и размерность дисплея. void setup() //*********************************************************** { pinMode (BtSettingPin, INPUT); pinMode (BtDownPin, INPUT); pinMode (BtUpPin, INPUT); pinMode (MotorPin, OUTPUT); pinMode (FuelValvePin, OUTPUT); pinMode (IgnitionPin, OUTPUT); pinMode (RelayStartPin, INPUT); pinMode (BtBoilerOnPin, INPUT); //если запись в настройки когда-то была, то читаем их if (EEPROM.read(Init_Eeprom_Addr) == Init_Key) { EEPROM.get(0,BLOW_TIMER); EEPROM.get(4,IGNITION_TIMER); } else //если записи не было, записываем в память значения по умолчанию { EEPROM.put(0,BLOW_TIMER); EEPROM.put(4,IGNITION_TIMER); //и ставим метку, что запись в настройки произведена EEPROM.put(Init_Eeprom_Addr,Init_Key); } lcd.init(); //Инициализация lcd lcd.backlight(); //Включаем подсветку lcd.setCursor(0,0); //ставим курсор в начало первой строки lcd.print(" Boiler"); lcd.setCursor(0,1); //ставим курсор в начало второй строки lcd.print(" Control"); delay(2000); //Пауза SettingsOnLCD(SettingNumber); //отображаем строку с настройками } void loop() //*********************************************** { //************ Пуск, остановка или работа котла ******** //считываем состояние реле от контроллера температуры с устраненным дребезгом CurrentRelayStart = debounce(LastRelayStart, RelayStartPin); if(FlagBoilerOn == true) //если котел включен { if(CurrentRelayStart == HIGH) //есть сигнал от контроллера температуры { if (FlagStartMotor == false) { BoilerStart(); //если котел не работал, то пускаем } else { BoilerRun(); //если котел уже работает } } else //если сигнала от контроллера температуры нет { BoilerStop(); } } else //если котел выключен { BoilerOff(); } //************ Нажата кнопка Включения/выключения котла ******************** //считываем состояние кнопки с устраненным дребезгом CurrentButtonBoiler = debounce(LastButtonBoiler, BtBoilerOnPin); if(CurrentButtonBoiler == HIGH) //если кнопка нажата { if (FlagBoilerLoop == true) //эта переменная нужна для однократного нажатия кнопки, //даже если ее удерживать { FlagBoilerLoop = false; if(FlagBoilerOn == true) { FlagBoilerOn = false; } else { FlagBoilerOn = true; } } } else { FlagBoilerLoop = true; } LastButtonBoiler = CurrentButtonBoiler; //обновляем текущее значение кнопки //************ Нажата кнопка Настройки ******************** //при каждом нажатии кнопки Настройки //перескакиваем на следующий параметр в очереди. И так по кругу //считываем состояние кнопки с устраненным дребезгом CurrentButtonSetting = debounce(LastButtonSetting, BtSettingPin); if(CurrentButtonSetting == HIGH) //если кнопка нажата { if (FlagSettingLoop == true) //эта переменная нужна для однократного нажатия кнопки, //даже если ее удерживать { FlagSettingLoop = false; SettingNumber = SettingNumber + 1; if (SettingNumber > 5) { SettingNumber = 1; } } } else { FlagSettingLoop = true; } LastButtonSetting = CurrentButtonSetting; //обновляем текущее значение кнопки //*************** Нажата кнопка Увеличить ********************** CurrentButtonUp = debounce(LastButtonUp, BtUpPin); if(CurrentButtonUp == HIGH && FlagUpLoop == true) //если кнопка нажата { ButtonPlusAction(SettingNumber, false); //функция реакции на нажатие кнопки Увеличить FlagUpLoop = false; } if(CurrentButtonUp == LOW) { FlagUpLoop = true; } LastButtonUp = CurrentButtonUp; //обновляем текущее значение кнопки //************** Нажата кнопка Уменьшить ********************** CurrentButtonDown = debounce(LastButtonDown, BtDownPin); if(CurrentButtonDown == HIGH && FlagDownLoop == true) //если кнопка нажата { ButtonMinusAction(SettingNumber, false); //функция реакции на нажатие кнопки Уменьшить FlagDownLoop = false; } if(CurrentButtonDown == LOW) { FlagDownLoop = true; } LastButtonDown = CurrentButtonDown; //обновляем текущее значение кнопки SettingsOnLCD(SettingNumber); //отображаем строку с настройками } //void loop() //********************** ФУНКЦИИ ********************************* //*********** функция отображения настроек на LCD ************* void SettingsOnLCD(int SettingItem) { lcd.setCursor(0,1); switch (SettingItem) { case 1: //время продувки lcd.print("1 Blow Time "); lcd.print(BLOW_TIMER/1000); lcd.print(" s "); break; case 2: //время зажигания lcd.print("2 Igni Time "); lcd.print(IGNITION_TIMER/1000); lcd.print(" s "); break; case 3: //запись настроек в EEPROM lcd.print("3 SaveSet. (UP) "); break; case 4: //чтение настроек из EEPROM lcd.print("4 ReadSet. (UP) "); break; case 5: //загрузка значений по умолчанию lcd.print("5 Default (UP) "); break; } } //******** Функция изменения параметров при нажатии кнопки Больше ********** void ButtonPlusAction(int SettingItem, boolean IncTrigger) { switch (SettingItem) { case 1: //время продувки BLOW_TIMER = BLOW_TIMER + 1000; if (BLOW_TIMER > BLOW_TIMER_MAX) //если пытаемся уйти за верхний предел { BLOW_TIMER = BLOW_TIMER_MAX; } break; case 2: //время зажигания IGNITION_TIMER = IGNITION_TIMER + 1000; //если пытаемся уйти за верхний предел if (IGNITION_TIMER > IGNITION_TIMER_MAX) { IGNITION_TIMER = IGNITION_TIMER_MAX; } break; case 3: //запись настроек в EEPROM EEPROM.put(0,BLOW_TIMER); EEPROM.put(4,IGNITION_TIMER); //ставим метку, что запись в настройки произведена EEPROM.put(Init_Eeprom_Addr,Init_Key); lcd.setCursor(0,1); lcd.print("Saving... OK "); delay(2000); break; case 4: //чтение настроек из EEPROM EEPROM.get(0,BLOW_TIMER); EEPROM.get(4,IGNITION_TIMER); lcd.setCursor(0,1); lcd.print("Reading... OK "); delay(2000); break; case 5: //загрузка значений по умолчанию. Берем из начала скетча BLOW_TIMER = 30000; IGNITION_TIMER = 3000; lcd.setCursor(0,1); lcd.print("Loading... OK "); delay(2000); break; } } //******** Функция изменения параметров при нажатии кнопки Меньше ********** void ButtonMinusAction(int SettingItem, boolean IncTrigger) { switch (SettingItem) { case 1: //время продувки BLOW_TIMER = BLOW_TIMER - 1000; if (BLOW_TIMER < BLOW_TIMER_MIN) //если пытаемся уйти за нижний предел { BLOW_TIMER = BLOW_TIMER_MIN; } break; case 2: //время зажигания IGNITION_TIMER = IGNITION_TIMER - 1000; //если пытаемся уйти за нижний предел if (IGNITION_TIMER < IGNITION_TIMER_MIN) { IGNITION_TIMER = IGNITION_TIMER_MIN; } break; } } //************ функция запуска котла *********************** void BoilerStart() { digitalWrite(MotorPin, HIGH); //пускаем продувку BlowTick = 0; BlowCountDown = BLOW_TIMER/1000; //время для обратного отсчета, сек while (BlowTick < BLOW_TIMER) //пока не кончилось время продувки { BlowTick = BlowTick + 1000; lcd.setCursor(0,0); lcd.print("Blowing "); //выводим на экран обратный отсчет времени продувки lcd.print(BlowCountDown); BlowCountDown = BlowCountDown - 1; lcd.print(" sec "); delay(1000); //задержка в 1 сек } digitalWrite(FuelValvePin, HIGH); //открываем топливные клапана digitalWrite(IgnitionPin, HIGH); //зажигаем искру BlowTick = 0; //пока не кончилось время поджига искры while (BlowTick < IGNITION_TIMER) { lcd.setCursor(0,0); lcd.print("Ignition... "); delay(1000); BlowTick = BlowTick + 1000; } digitalWrite(IgnitionPin, LOW); //гасим искру lcd.setCursor(0,0); lcd.print("Boiler Running "); FlagStartMotor = true; } //************ функция работы котла *********************** void BoilerRun() { lcd.setCursor(0,0); lcd.print("Boiler Running "); } //************ функция остановки котла *********************** void BoilerStop() { digitalWrite(MotorPin, LOW); //все выключаем digitalWrite(FuelValvePin, LOW); digitalWrite(IgnitionPin, LOW); FlagStartMotor = false; lcd.setCursor(0,0); lcd.print("Boiler Stop "); } //************ функция выключения котла *********************** void BoilerOff() { digitalWrite(MotorPin, LOW); //все выключаем digitalWrite(FuelValvePin, LOW); digitalWrite(IgnitionPin, LOW); FlagStartMotor = false; lcd.setCursor(0,0); lcd.print("Boiler OFF "); } //*************** Функция устранения дребезга контактов *********** boolean debounce(boolean last, int ButtonPinDebounce) { boolean current = digitalRead(ButtonPinDebounce); //считываем текущее состояние кнопки if(last != current) //если оно иное, чем предыдущее... { delay(50); //ждем 50 мс current = digitalRead(ButtonPinDebounce); //считываем состояние снова } return current; //возвращаем текущее состояние кнопки }