//Управление автоматическим топливным фильтром //поворот барабана со свечами //продувка свечей //работа по таймеру и диффиренциалу давления //сигнализация по критическому засорению (диффиренциалу) фильтра //подсчет числа прострелов по таймеру и диффиренциалу //сигнализация при отсутствии вращения барабана //(закрыт воздух на привод барабана или он заклинил) //настройка таймеров //эти настройки можно записать в энергонезависимую память //на дисплей выводятся следующие символы : // ! - не прошло минимальное время между прострелами барабана #include <EEPROM.h> //библиотека работы с памятью #include <LiquidCrystal_I2C.h> //библиотеки работы с LCD через I2C #include <Wire.h> //Не забудь шунтировать выход от кнопок резистором 10 КОм const int BtResetPin = 2; //пин кнопки Сброс. const int BtManualFlushPin = 3; //пин кнопки ручной самоочистки const int BtDownPin = 5; //пин кнопки уменьшить const int BtUpPin = 4; //пин кнопки увеличить const int BtSettingPin = 6; //пин кнопки настроек const int DrumRotationPin = 7; //пин реле клапана привода барабана const int FlushPin = 8; //пин реле клапана продувки свечи const int AlarmClogPin = 9; //пин реле сигнализации засорения фильтра //пин реле сигнализации по заклиниванию барабана const int AlarmDrumSeizingPin = 10; //Не забудь шунтировать входы с датчиков резистором 10 КОм const int ProxSwitchPin = 11; //пин конечника разворота барабана //пин диффиренциального датчика 75% (самоочистка по диффиренциалу) const int DiffFlushPin = 12; //пин диффиренциального датчика 100% (сигнализация по диффиренциалу) const int DiffAlarmPin = 13; //int i = 0; //пины модуля I2C LCD-дисплея : //SDA - A4 //SCL - A5 //питание от шилда int Init_Eeprom_Addr = 1000; //номер ячейки в памяти EEPROM (0-1023), куда мы запишем ключ о //самом первом запуске программы //это нужно, так как при первом запуске в памяти нет наших настроек //и нужно загрузить значения по умолчанию byte Init_Key = 223; //это ключ (0-255). //Если при пуске скетча данные из ячейки Init_Eeprom не совпадают //с Init_Key, вводим в настройки значения по умолчанию, //иначе берем настройки из памяти long FLUSH_GAP_TIMER=120000; //время между автоматическими прострелами фильтра, мс const long FLUSH_GAP_TIMER_MAX=86400000; //предел верхней границы, мс const long FLUSH_GAP_TIMER_MIN=100000; //предел нижней границы, мс //минимальное время между автоматическими прострелами фильтра //(пока оно не пройдет, не будет следующего прострела), мс long MIN_GAP_TIMER=20000; const long MIN_GAP_TIMER_MAX=86400000; //предел верхней границы, мс const long MIN_GAP_TIMER_MIN=15000; //предел нижней границы, мс //время ожидания поворота барабана до включения сигнализации, мс long DRUM_WAIT_TIMER=20000; const long DRUM_WAIT_TIMER_MAX=86400000; //предел верхней границы, мс const long DRUM_WAIT_TIMER_MIN=5000; //предел нижней границы, мс long FLUSH_TIMER=9000; //продолжительность прострела (самоочистки), мс const long FLUSH_TIMER_MAX=86400000; //предел верхней границы, мс const long FLUSH_TIMER_MIN=100; //предел нижней границы, мс long DRUM_CYCLE_TIMER=1850; //период движения привода барабана, мс const long DRUM_CYCLE_TIMER_MAX=86400000; //предел верхней границы, мс const long DRUM_CYCLE_TIMER_MIN=100; //предел нижней границы, мс //время подачи воздуха на привод (входит в период движения привода барабана), мс long DRUM_PUSH_TIMER=1150; const long DRUM_PUSH_TIMER_MAX=86400000; //предел верхней границы, мс const long DRUM_PUSH_TIMER_MIN=100; //предел нижней границы, мс //если привод работает при постоянной подачи воздуха, //сделайте DRUM_CYCLE_TIMER = DRUM_PUSH_TIMER long FlushCount = 0; //запоминаем количество прострелов по таймеру long FlushDiffCount = 0; //запоминаем количество прострелов по диффиренциалу давления int SettingNumber = 0; //пункт меню настройки boolean LastButtonSetting = LOW; //предыдущее состояние кнопки boolean CurrentButtonSetting = LOW; //текущее состояние кнопки boolean LastButtonDown = LOW; boolean CurrentButtonDown = LOW; boolean LastButtonUp = LOW; boolean CurrentButtonUp = LOW; boolean LastButtonReset = LOW; boolean CurrentButtonReset = LOW; boolean LastButtonFlush = LOW; boolean CurrentButtonFlush = LOW; boolean FlagSettingLoop = true; //были ли мы в цикле нажатия кнопки Настройки boolean FlagUpLoop = true; //были ли мы в цикле нажатия кнопки Больше boolean FlagDownLoop = true; //были ли мы в цикле нажатия кнопки Меньше boolean FlagResetLoop = true; //были ли мы в цикле нажатия кнопки Reset boolean FlagFlushLoop = true; //были ли мы в цикле нажатия кнопки ручной самоочистки //нужна при нажатии и удерживании кнопки ВВЕРХ unsigned long ButtonHoldTimerUp = 0; //нужна при нажатии и удерживании кнопки ВНИЗ unsigned long ButtonHoldTimerDown = 0; //по прошествии этого времени кнопка ВВЕРХ или ВНИЗ //перейдет в режим удержания, мс const long ButtonHoldIncTime = 500; boolean FlagUpHold = true; //были ли мы в цикле удержания кнопки ВВЕРХ boolean FlagDownHold = true; //были ли мы в цикле удержания кнопки ВНИЗ boolean AlarmFilterClogOn = true; //включена или нет сигнализация по засорению фильтра boolean AlarmDrumSeizingOn = true; //включена или нет сигнализация по заклиниванию барабана boolean ManualModeOn = false; //включен или нет ручной режим //сработала ли сигнализация по засорению фильтра boolean FlagAlarmFilter100Clog = false; //сработала ли очистка по дифф давления boolean FlagFlush75Diff = false; //сработала ли сигнализация по заклиниванию барабана boolean FlagAlarmDrumSeizing = false; boolean FlagSettingIn = false; //находимся ли мы в режиме настройки unsigned long currentTime = 0; //нужна, чтобы убрать delay() const long intervalTime = 1000; //интервал опроса датчика диффиренциала давления в мс //нужна при отсчете времени ожидания вращения барабана (возвращения в нулевую точку), мс unsigned long DrumWaitTime = 0; LiquidCrystal_I2C lcd(0x27,16,2); //Задаем адрес и размерность дисплея. void setup() //**************************************************************** { pinMode (BtResetPin, INPUT); pinMode (BtManualFlushPin, INPUT); pinMode (BtDownPin, INPUT); pinMode (BtUpPin, INPUT); pinMode (BtSettingPin, INPUT); pinMode (DrumRotationPin, OUTPUT); pinMode (FlushPin, OUTPUT); pinMode (AlarmClogPin, OUTPUT); pinMode (AlarmDrumSeizingPin, OUTPUT); pinMode (ProxSwitchPin, INPUT); pinMode (DiffFlushPin, INPUT); pinMode (DiffAlarmPin, INPUT); //если запись в настройки когда-то была, то читаем их if (EEPROM.read(Init_Eeprom_Addr) == Init_Key) { EEPROM.get(0,FLUSH_GAP_TIMER); //для типа long нужны 4 ячейки памяти EEPROM.get(4,FLUSH_TIMER); EEPROM.get(8,DRUM_CYCLE_TIMER); EEPROM.get(12,DRUM_PUSH_TIMER); EEPROM.get(16,DRUM_WAIT_TIMER); EEPROM.get(20,MIN_GAP_TIMER); } else //если записи не было, записываем в память значения по умолчанию { EEPROM.put(0,FLUSH_GAP_TIMER); EEPROM.put(4,FLUSH_TIMER); EEPROM.put(8,DRUM_CYCLE_TIMER); EEPROM.put(12,DRUM_PUSH_TIMER); EEPROM.put(16,DRUM_WAIT_TIMER); EEPROM.put(20,MIN_GAP_TIMER); //и ставим метку, что запись в настройки произведена EEPROM.put(Init_Eeprom_Addr,Init_Key); } lcd.init(); //Инициализация lcd lcd.backlight(); //Включаем подсветку lcd.setCursor(0,0); //рисуем первую строчку lcd.print(" Filter"); lcd.setCursor(0,1); //рисуем вторую строчку lcd.print(" Auto Control"); delay(2000); //Пауза } void loop() //************************************************************ { //-------------------------- включили фильтр ----------------------------- if(FlushCount == 0) { //считываем состояние входа с датчика положения барабана с устраненным дребезгом if(digitalRead(ProxSwitchPin) == HIGH) //если барабан в конечной позиции { //функция автоочистки при первом включении (без вращения барабана) StartFlushingFunc(); FlushCount = FlushCount + 1; } else //если барабан НЕ в конечной позиции { FlushingFunc(); //функция автоочистки FlushCount = FlushCount + 1; } } //--------------- выводим подсказки на экран --------------------------- if(FlagAlarmDrumSeizing == true) //заклинил барабан { lcd.setCursor(0,0); lcd.print("Drum Seizing!!! "); lcd.setCursor(0,1); lcd.print("Press RESET "); } else { if(FlagAlarmFilter100Clog == true) //засорение фильтра 100% { lcd.setCursor(0,0); lcd.print("Filter Clogging!"); lcd.setCursor(0,1); lcd.print("Press RESET "); } else { lcd.setCursor(0,0); if(ManualModeOn == true) //ручной режим { lcd.print("Manual ("); //выводим время с последнего прострела lcd.print((millis() - currentTime)/1000); lcd.print("s)"); } else //автоматический режим { lcd.print("Time="); //выводим время с последнего прострела lcd.print((millis() - currentTime)/1000); lcd.print("s"); } if((millis() - currentTime) < MIN_GAP_TIMER) { //подсказка, если не прошло минимально время с последнего прострела lcd.print("! "); } else { lcd.print(" "); } //засорение фильтра 75%, прошла самоочистка по дифф давлению if(FlagFlush75Diff == true) { if(FlagSettingIn == false) //мы не в настройках { if(ManualModeOn == true) //ручной режим { lcd.setCursor(0,1); //подсказка о необходимости прочистки lcd.print("Need Flushing !!! "); } else //автоматический режим { lcd.setCursor(0,1); //подсказка о прошедшей самоочистки по дифф давлению 75% lcd.print("dP Flushing !!! "); } } } else //все нормально { if(FlagSettingIn == false) //мы не в настройках { lcd.setCursor(0,1); lcd.print("Filtering... OK "); } } } } //если барабан НЕ заклинил и мы НЕ в ручном режиме if(FlagAlarmDrumSeizing == false && ManualModeOn == false) { //----------------- автоматический прострел по времени ------------------ //прошло время между самоочистками if(millis() - currentTime > FLUSH_GAP_TIMER) { SettingExit(); //выходим из настроек FlushingFunc(); //функция автоочистки FlushCount = FlushCount + 1; } //-------------- автоматический прострел по дифф давлению 75% ------------ //если сработал датчик дифф давления 75%, но при этом прошло минимальное время между прострелами if(digitalRead(DiffFlushPin) == HIGH && millis() - currentTime > MIN_GAP_TIMER) { SettingExit(); //выходим из настроек FlushingFunc(); //функция автоочистки FlushDiffCount = FlushDiffCount + 1; FlagFlush75Diff = true; } } //---------------- сигнализация по дифф давлению 100% ------------ if((digitalRead(DiffAlarmPin) == HIGH)) //если сработал датчик дифф давления 100% { if(AlarmFilterClogOn == true) //если сигнализация не отключена { digitalWrite(AlarmClogPin, HIGH); //включаем сигнализацию } SettingExit(); //выходим из настроек FlagAlarmFilter100Clog = true; } //******************** Нажата кнопка Сброс (Reset) ************************* //считываем состояние кнопки с устраненным дребезгом CurrentButtonReset = debounce(LastButtonReset, BtResetPin); if(CurrentButtonReset == HIGH && FlagResetLoop == true) //если кнопка нажата { SettingExit(); //выходим из настроек if(FlagAlarmDrumSeizing == true) { FlagAlarmDrumSeizing = false; //сбрасываем сигналку по заклиниванию барабана digitalWrite(AlarmDrumSeizingPin, LOW); currentTime = millis(); //обнуляем отсчет времени для самоочистки по времени //если барабан не в нулевой позиции, идем на прострел if(digitalRead(ProxSwitchPin) == LOW) { FlushingFunc(); //функция автоочистки } } else { if(FlagAlarmFilter100Clog == true) { //сбрасываем аварию о загрязнении фильтра 100% FlagAlarmFilter100Clog = false; digitalWrite(AlarmClogPin, LOW); } else { if(FlagFlush75Diff == true) { //сбрасываем инфо о простреле по дифф давлению 75% FlagFlush75Diff = false; } } } FlagResetLoop = false; } if(CurrentButtonReset == LOW) { FlagResetLoop = true; } LastButtonReset = CurrentButtonReset; //обновляем текущее значение кнопки //************ Нажата кнопка Manual ручной самоочистки ******************** //считываем состояние кнопки с устраненным дребезгом CurrentButtonFlush = debounce(LastButtonFlush, BtManualFlushPin); if(CurrentButtonFlush == HIGH && FlagFlushLoop == true) { //если была, сбрасываем сигналку по заклиниванию барабана if(FlagAlarmDrumSeizing == true) { FlagAlarmDrumSeizing = false; digitalWrite(AlarmDrumSeizingPin, LOW); } SettingExit(); //выходим из настроек FlushingFunc(); //функция самоочистки FlushCount = FlushCount + 1; FlagFlushLoop = false; } if(CurrentButtonFlush == LOW) { FlagFlushLoop = true; } LastButtonFlush = CurrentButtonFlush; //обновляем текущее значение кнопки //************ Нажата кнопка Настройки ************************ //при каждом нажатии кнопки Настройки //перескакиваем на следующий параметр в очереди. И так по кругу //пока не снимем аварию, в настройки не зайдем if(FlagAlarmDrumSeizing == false && FlagAlarmFilter100Clog == false) { //считываем состояние кнопки с устраненным дребезгом CurrentButtonSetting = debounce(LastButtonSetting, BtSettingPin); if(CurrentButtonSetting == HIGH) //кнопка нажата { if (FlagSettingLoop == true) //эта переменная нужна для однократного нажатия кнопки, //даже если ее удерживать { FlagSettingLoop = false; FlagSettingIn = true; //вошли в режим настроек SettingNumber = SettingNumber + 1; if (SettingNumber > 12) { SettingNumber = 1; } } } else //кнопка отжата { FlagSettingLoop = true; } //обновляем текущее значение кнопки LastButtonSetting = CurrentButtonSetting; } if (FlagSettingIn == true) //если мы в настройках { //----------------- Нажата кнопка Увеличить ----------------------------- ButtonPlus(); //функция реакции на нажатие кнопки Увеличить //----------------- Нажата кнопка Уменьшить ----------------------------- ButtonMinus(); //функция реакции на нажатие кнопки Уменьшить SettingsOnLCD(SettingNumber); //отображаем строку с настройками } else { //--------------------- Нажата кнопка Увеличить ------------------------- ButtonPlusShowCount(); //функция кнопки Больше для показа количества прострелов //--------------------- Нажата кнопка Уменьшить ------------------------- ButtonMinusShowCount(); //функция кнопки Больше для показа количества прострелов } } //void loop() //********************** ФУНКЦИИ ********************************* //*********** Функция отображения настроек на LCD ************* void SettingsOnLCD(int SettingItem) { lcd.setCursor(0,1); switch (SettingItem) { case 1: //время между автоматическими прострелами фильтра lcd.print("1 FluGap="); lcd.print(FLUSH_GAP_TIMER/1000); lcd.print("s "); break; case 2: //минимальное время между автоматическими прострелами фильтра lcd.print("2 MinGap="); lcd.print(MIN_GAP_TIMER/1000); lcd.print("s "); break; case 3: //продолжительность прострела (самоочистки) lcd.print("3 Flush="); lcd.print(FLUSH_TIMER); lcd.print("ms "); break; case 4: //период движения привода барабана lcd.print("4 DrCyc="); lcd.print(DRUM_CYCLE_TIMER); lcd.print("ms "); break; case 5: //время подачи воздуха на привод (входит в период движения привода барабана) lcd.print("5 DrPu="); lcd.print(DRUM_PUSH_TIMER); lcd.print("ms "); break; case 6: //время ожидания поворота барабана до включения сигнализации lcd.print("6 DrWa="); lcd.print(DRUM_WAIT_TIMER/1000); lcd.print("s "); break; case 7: //включение-выключение сигнализации по дифф давления if (AlarmFilterClogOn == true) { lcd.print("7 Alarm Diff ON "); } else { lcd.print("7 Alarm Diff OFF "); } break; case 8: //включение-выключение сигнализации по заклиниванию барабана if (AlarmDrumSeizingOn == true) { lcd.print("8 Alarm Drum ON "); } else { lcd.print("8 Alarm Drum OFF "); } break; case 9: //включение-выключение ручного режима if (ManualModeOn == true) { lcd.print("9 ManualMode ON "); } else { lcd.print("9 ManualMode OFF "); } break; case 10: //чтение настроек из памяти lcd.print("10 ReadSet. (UP) "); break; case 11: //запись настроек в память lcd.print("11 SaveSet. (UP) "); break; case 12: //загрузка значений по умолчанию lcd.print("Default (UP) "); break; } } //********* Функция кнопки Больше, Увеличить, Плюс и т.п. ************* void ButtonPlus() { CurrentButtonUp = debounce(LastButtonUp, BtUpPin); if(CurrentButtonUp == HIGH) //кнопка нажата { if (SettingNumber >= 1 && SettingNumber <= 6 ) //пункты настроек, где нужен разгон параметра в режиме удержания { if(FlagUpHold == true) //отсечка времени удержания кнопки { ButtonHoldTimerUp = millis(); FlagUpHold = false; } if(millis() - ButtonHoldTimerUp > ButtonHoldIncTime) //сначала однократное нажатие, но если держать кнопку более //ButtonHoldIncTime, она переходит в режим удержания { ButtonPlusAction(SettingNumber, true); } if(FlagUpLoop == true) //однократное нажатие, даже если удерживать кнопку, //пока не прошло ButtonHoldIncTime { FlagUpLoop = false; ButtonPlusAction(SettingNumber, false); } } else //пункты настроек, где нужно только однократное нажатие кнопки { if(FlagUpLoop == true) { FlagUpLoop = false; ButtonPlusAction(SettingNumber, false); } } } else //кнопка отжата { FlagUpLoop = true; FlagUpHold = true; } LastButtonUp = CurrentButtonUp; //обновляем текущее значение кнопки } //******* функция кнопки Больше для показа количества прострелов ************ void ButtonPlusShowCount() { CurrentButtonUp = debounce(LastButtonUp, BtUpPin); if(CurrentButtonUp == HIGH) { lcd.setCursor(0,1); lcd.print("Flush="); lcd.print(FlushCount); lcd.print(" "); delay(1000); } LastButtonUp = CurrentButtonUp; //обновляем текущее значение кнопки } //******** Функция изменения параметров при нажатии кнопки Больше ********** void ButtonPlusAction(int SettingItem, boolean IncTrigger) { switch (SettingItem) { case 1: //время между автоматическими прострелами фильтра FLUSH_GAP_TIMER = FLUSH_GAP_TIMER + Inc_Val_Calc(IncTrigger, 1); //если пытаемся уйти за верхний предел if (FLUSH_GAP_TIMER > FLUSH_GAP_TIMER_MAX) { FLUSH_GAP_TIMER = FLUSH_GAP_TIMER_MAX; } break; case 2: //минимальное время между автоматическими прострелами фильтра MIN_GAP_TIMER = MIN_GAP_TIMER + Inc_Val_Calc(IncTrigger, 1); //если пытаемся уйти за верхний предел if (MIN_GAP_TIMER > MIN_GAP_TIMER_MAX) { MIN_GAP_TIMER = MIN_GAP_TIMER_MAX; } //если миним время между прострелами больше, чем установленное if (MIN_GAP_TIMER > FLUSH_GAP_TIMER) { MIN_GAP_TIMER = FLUSH_GAP_TIMER; lcd.setCursor(0,1); lcd.print("GAP >= MINGAP !"); //подсказка delay(1000); } break; case 3: //продолжительность прострела (самоочистки) FLUSH_TIMER = FLUSH_TIMER + Inc_Val_Calc(IncTrigger, 2); //если пытаемся уйти за верхний предел if (FLUSH_TIMER > FLUSH_TIMER_MAX) { FLUSH_TIMER = FLUSH_TIMER_MAX; } break; case 4: //период движения привода барабана DRUM_CYCLE_TIMER = DRUM_CYCLE_TIMER + Inc_Val_Calc(IncTrigger, 2); //если пытаемся уйти за верхний предел if (DRUM_CYCLE_TIMER > DRUM_CYCLE_TIMER_MAX) { DRUM_CYCLE_TIMER = DRUM_CYCLE_TIMER_MAX; } break; case 5: //время подачи воздуха на привод (входит в период движения привода барабана) DRUM_PUSH_TIMER = DRUM_PUSH_TIMER + Inc_Val_Calc(IncTrigger, 2); //если пытаемся установить время подачи воздуха на привод больше, //чем время всего цикла if (DRUM_PUSH_TIMER > DRUM_CYCLE_TIMER) { DRUM_PUSH_TIMER = DRUM_CYCLE_TIMER; lcd.setCursor(0,1); lcd.print("TCYCLE >= TPUSH!"); //подсказка delay(1000); } //если пытаемся уйти за верхний предел if (DRUM_PUSH_TIMER > DRUM_PUSH_TIMER_MAX) { DRUM_PUSH_TIMER = DRUM_PUSH_TIMER_MAX; } break; case 6: //время ожидания поворота барабана до включения сигнализации DRUM_WAIT_TIMER = DRUM_WAIT_TIMER + Inc_Val_Calc(IncTrigger, 1); //если пытаемся уйти за верхний предел if (DRUM_WAIT_TIMER > DRUM_WAIT_TIMER_MAX) { DRUM_WAIT_TIMER = DRUM_WAIT_TIMER_MAX; } break; case 7: //включение-выключение сигнализации по дифф давления if (AlarmFilterClogOn == true) { AlarmFilterClogOn = false; } else { AlarmFilterClogOn = true; } break; case 8: //включение-выключение сигнализации по заклиниванию барабана if (AlarmDrumSeizingOn == true) { AlarmDrumSeizingOn = false; } else { AlarmDrumSeizingOn = true; } break; case 9: //включение-выключение ручного режима if (ManualModeOn == true) { ManualModeOn = false; } else { ManualModeOn = true; } break; case 10: //чтение настроек из EEPROM EEPROM.get(0,FLUSH_GAP_TIMER); //для типа long нужны 4 ячейки памяти EEPROM.get(4,FLUSH_TIMER); EEPROM.get(8,DRUM_CYCLE_TIMER); EEPROM.get(12,DRUM_PUSH_TIMER); EEPROM.get(16,DRUM_WAIT_TIMER); EEPROM.get(20,MIN_GAP_TIMER); lcd.setCursor(0,1); lcd.print("Reading... OK "); delay(2000); break; case 11: //запись настроек в EEPROM EEPROM.put(0,FLUSH_GAP_TIMER); EEPROM.put(4,FLUSH_TIMER); EEPROM.put(8,DRUM_CYCLE_TIMER); EEPROM.put(12,DRUM_PUSH_TIMER); EEPROM.put(16,DRUM_WAIT_TIMER); EEPROM.put(20,MIN_GAP_TIMER); EEPROM.put(Init_Eeprom_Addr,Init_Key); //ставим метку, что запись в настройки произведена lcd.setCursor(0,1); lcd.print("Saving... OK "); delay(2000); break; case 12: //загрузка значений по умолчанию. Берем из начала скетча FLUSH_GAP_TIMER = 120000; FLUSH_TIMER = 9000; DRUM_CYCLE_TIMER = 1850; DRUM_PUSH_TIMER = 1150; DRUM_WAIT_TIMER = 20000; MIN_GAP_TIMER = 20000; lcd.setCursor(0,1); lcd.print("Loading... OK "); delay(2000); break; } } //********* Функция кнопки Меньше, Уменьшить, Минус и т.п. ************* void ButtonMinus() { CurrentButtonDown = debounce(LastButtonDown, BtDownPin); if(CurrentButtonDown == HIGH) //кнопка нажата { if (SettingNumber >= 1 && SettingNumber <= 6 ) //пункты настроек, где нужен разгон параметра в режиме удержания { if(FlagDownHold == true) //отсечка времени удержания кнопки { ButtonHoldTimerDown = millis(); FlagDownHold = false; } if(millis() - ButtonHoldTimerDown > ButtonHoldIncTime) //сначала однократное нажатие, но если держать кнопку более //ButtonHoldIncTime, она переходит в режим удержания { ButtonMinusAction(SettingNumber, true); } if(FlagDownLoop == true) //однократное нажатие, даже если удерживать кнопку, //пока не прошло ButtonHoldIncTime { FlagDownLoop = false; ButtonMinusAction(SettingNumber, false); } } else //пункты настроек, где нужно только однократное нажатие кнопки { if(FlagDownLoop == true) { FlagDownLoop = false; ButtonMinusAction(SettingNumber, false); } } } else //кнопка отжата { FlagDownLoop = true; FlagDownHold = true; } LastButtonDown = CurrentButtonDown; //обновляем текущее значение кнопки } //******* функция кнопки Меньше для показа количества прострелов ************ void ButtonMinusShowCount() { CurrentButtonDown = debounce(LastButtonDown, BtDownPin); if(CurrentButtonDown == HIGH) { lcd.setCursor(0,1); lcd.print("dPFlush="); lcd.print(FlushDiffCount); lcd.print(" "); delay(1000); } LastButtonDown = CurrentButtonDown; //обновляем текущее значение кнопки } //******** Функция изменения параметров при нажатии кнопки Меньше ********** void ButtonMinusAction(int SettingItem, boolean IncTrigger) { switch (SettingItem) { case 1: //время между автоматическими прострелами фильтра FLUSH_GAP_TIMER = FLUSH_GAP_TIMER - Inc_Val_Calc(IncTrigger, 1); //если пытаемся уйти за нижний предел if (FLUSH_GAP_TIMER < FLUSH_GAP_TIMER_MIN) { FLUSH_GAP_TIMER = FLUSH_GAP_TIMER_MIN; } //если миним время между прострелами больше, чем установленное if (FLUSH_GAP_TIMER < MIN_GAP_TIMER) { FLUSH_GAP_TIMER = MIN_GAP_TIMER; lcd.setCursor(0,1); lcd.print("GAP >= MINGAP ! "); //подсказка delay(1000); } break; case 2: //минимальное время между автоматическими прострелами фильтра MIN_GAP_TIMER = MIN_GAP_TIMER - Inc_Val_Calc(IncTrigger, 1); //если пытаемся уйти за нижний предел if (MIN_GAP_TIMER < MIN_GAP_TIMER_MIN) { MIN_GAP_TIMER = MIN_GAP_TIMER_MIN; } break; case 3: //продолжительность прострела (самоочистки) FLUSH_TIMER = FLUSH_TIMER - Inc_Val_Calc(IncTrigger, 2); //если пытаемся уйти за нижний предел if (FLUSH_TIMER < FLUSH_TIMER_MIN) { FLUSH_TIMER = FLUSH_TIMER_MIN; } break; case 4: //период движения привода барабана DRUM_CYCLE_TIMER = DRUM_CYCLE_TIMER - Inc_Val_Calc(IncTrigger, 2); //если пытаемся установить время всего цикла меньше, //чем время подачи воздуха на привод if (DRUM_CYCLE_TIMER < DRUM_PUSH_TIMER) { DRUM_CYCLE_TIMER = DRUM_PUSH_TIMER; lcd.setCursor(0,1); lcd.print("TCYCLE >= TPUSH!"); //подсказка delay(1000); } //если пытаемся уйти за нижний предел if (DRUM_CYCLE_TIMER < DRUM_CYCLE_TIMER_MIN) { DRUM_CYCLE_TIMER = DRUM_CYCLE_TIMER_MIN; } break; case 5: //время подачи воздуха на привод (входит в период движения привода барабана) DRUM_PUSH_TIMER = DRUM_PUSH_TIMER - Inc_Val_Calc(IncTrigger, 2); //если пытаемся уйти за нижний предел if (DRUM_PUSH_TIMER < DRUM_PUSH_TIMER_MIN) { DRUM_PUSH_TIMER = DRUM_PUSH_TIMER_MIN; } break; case 6: //время ожидания поворота барабана до включения сигнализации DRUM_WAIT_TIMER = DRUM_WAIT_TIMER - Inc_Val_Calc(IncTrigger, 1); //если пытаемся уйти за нижний предел if (DRUM_WAIT_TIMER < DRUM_WAIT_TIMER_MIN) { DRUM_WAIT_TIMER = DRUM_WAIT_TIMER_MIN; } break; case 7: //включение-выключение сигнализации по дифф давления if (AlarmFilterClogOn == true) { AlarmFilterClogOn = false; } else { AlarmFilterClogOn = true; } break; case 8: //включение-выключение сигнализации по заклиниванию барабана if (AlarmDrumSeizingOn == true) { AlarmDrumSeizingOn = false; } else { AlarmDrumSeizingOn = true; } break; case 9: //включение-выключение ручного режима if (ManualModeOn == true) { ManualModeOn = false; } else { ManualModeOn = true; } break; } } //*************** Функция устранения дребезга контактов *********** boolean debounce(boolean last, int ButtonPinDebounce) { boolean current = digitalRead(ButtonPinDebounce); //считываем текущее состояние кнопки if(last != current) //если оно иное, чем предыдущее... { delay(50); //ждем 50 мс current = digitalRead(ButtonPinDebounce); //считываем состояние снова } return current; //возвращаем текущее состояние кнопки } //*************** функция самоочистки ************************ void FlushingFunc() { lcd.setCursor(0,0); if(ManualModeOn == true) { lcd.print("Manual Mode "); } else { lcd.print("Time=0 "); } //вращаем барабан lcd.setCursor(0,1); lcd.print("Drum rotating... "); DrumWaitTime = millis(); //обнуляем отсчет времени разворота барабана //если привод барабана работает при постоянно открытом клапане if(DRUM_PUSH_TIMER == DRUM_CYCLE_TIMER) { do //вращаем барабан, пока он не уйдет с нулевой позиции { digitalWrite(DrumRotationPin, HIGH); //барабан не ушел с нулевой точки до DRUM_WAIT_TIMER if(millis() - DrumWaitTime > DRUM_WAIT_TIMER) { DrumSeizing(); return; } } while (digitalRead(ProxSwitchPin) == HIGH); do //вращаем барабан, пока он не вернется в нулевую позицию { digitalWrite(DrumRotationPin, HIGH); //барабан не вернулся в нулевую точку до DRUM_WAIT_TIMER if(millis() - DrumWaitTime > DRUM_WAIT_TIMER) { DrumSeizing(); return; } } while (digitalRead(ProxSwitchPin) == LOW); digitalWrite(DrumRotationPin, LOW); lcd.setCursor(0,1); lcd.print("Flushing... "); digitalWrite(FlushPin, HIGH); delay(FLUSH_TIMER); digitalWrite(FlushPin, LOW); currentTime = millis(); //обнуляем отсчет времени для самоочистки по времени } else //если привод барабана работает от включ-выкл клапана { do //вращаем барабан, пока он не уйдет с нулевой позиции { digitalWrite(DrumRotationPin, HIGH); delay(DRUM_PUSH_TIMER); digitalWrite(DrumRotationPin, LOW); delay(DRUM_CYCLE_TIMER-DRUM_PUSH_TIMER); //барабан не ушел с нулевой точки до DRUM_WAIT_TIMER if(millis() - DrumWaitTime > DRUM_WAIT_TIMER) { DrumSeizing(); return; } } while (digitalRead(ProxSwitchPin) == HIGH); do //вращаем барабан, пока он не вернется в нулевую позицию { digitalWrite(DrumRotationPin, HIGH); delay(DRUM_PUSH_TIMER); digitalWrite(DrumRotationPin, LOW); delay(DRUM_CYCLE_TIMER-DRUM_PUSH_TIMER); //барабан не вернулся в нулевую точку до DRUM_WAIT_TIMER if(millis() - DrumWaitTime > DRUM_WAIT_TIMER) { DrumSeizing(); return; } } while (digitalRead(ProxSwitchPin) == LOW); lcd.setCursor(0,1); lcd.print("Flushing... "); digitalWrite(FlushPin, HIGH); delay(FLUSH_TIMER); digitalWrite(FlushPin, LOW); currentTime = millis(); //обнуляем отсчет времени для самоочистки по времени } } //***** Функция прострела свечи при запуске фильтра (без вращения барабана) ******* void StartFlushingFunc() { lcd.setCursor(0,1); lcd.print("Flushing... "); digitalWrite(FlushPin, HIGH); delay(FLUSH_TIMER); digitalWrite(FlushPin, LOW); currentTime = millis(); //обнуляем отсчет времени для самоочистки по времени } //********** функция вызываемая при заклинивании барабана *************** void DrumSeizing() { digitalWrite(DrumRotationPin, LOW); digitalWrite(FlushPin, LOW); if(AlarmDrumSeizingOn == true) { digitalWrite(AlarmDrumSeizingPin, HIGH); } else { digitalWrite(AlarmDrumSeizingPin, LOW); } FlagAlarmDrumSeizing = true; SettingExit(); } //*************** функция выхода из настроек ************************ void SettingExit() { if(FlagSettingIn == true) //если были в настройках { FlagSettingIn = false; //выходим из режима настроек SettingNumber = SettingNumber - 1; //чтобы остаться на том же пункте меню } } //*************** Функция разгона приращения параметра ************ float Inc_Val_Calc(boolean IncTrigger, int IncVariant) { static int count_inc = 0; //счетчик итераций //IncVariant - разные варианты разгона if (IncTrigger == true) //пришел сигнал на разгон { count_inc = count_inc + 1; if (IncVariant == 1) { //играя этими числами, вы можете подстраивать разгон параметра под себя if (count_inc > 0 && count_inc <= 30) { return 1000; } if (count_inc > 30 && count_inc <= 60) { return 2000; } if (count_inc > 60 && count_inc <= 90) { return 5000; } if (count_inc > 90) { return 20000; } } if (IncVariant == 2) { //играя этими числами, вы можете подстраивать разгон параметра под себя if (count_inc > 0 && count_inc <= 30) { return 100; } if (count_inc > 30 && count_inc <= 60) { return 200; } if (count_inc > 60 && count_inc <= 90) { return 1000; } if (count_inc > 90 && count_inc <= 120) { return 2000; } if (count_inc > 120) { return 5000; } } } else { count_inc = 0; if (IncVariant == 1) { return 1000; //приращение по умолчанию } if (IncVariant == 2) { return 100; //приращение по умолчанию } } }