//управление работой сепаратора //автоматический прострел //нет контроля давления топлива, воды, температуры топлива //настройка таймеров //сохранение настроек в память и чтение из нее #include <EEPROM.h> //библиотека работы с памятью #include <LiquidCrystal_I2C.h> //библиотеки работы с LCD через I2C #include <Wire.h> //Не забудь шунтировать выход от кнопок резистором 10 КОм const int BtStartPin = 4; //пин кнопки Пуск/Стоп const int BtDownPin = 5; //пин кнопки Уменьшить const int BtUpPin = 6; //пин кнопки Увеличить const int BtSettingPin = 7; //пин кнопки Настройки const int Pin_Relay_FuelFeed = 8; //пин реле клапана подачи топлива. const int Pin_Relay_Displacement = 9; //пин реле заполнения барабана водой const int Pin_Relay_Control = 10; //пин реле управляющей воды //пины модуля I2C LCD-дисплея : //SDA - A4 //SCL - A5 //питание от шилда int Init_Eeprom_Addr = 1000; //номер ячейки в памяти EEPROM (0-1023), куда мы запишем ключ о //самом первом запуске программы //это нужно, так как при первом запуске в памяти нет наших настроек //и нужно загрузить значения по умолчанию byte Init_Key = 226; //это ключ (0-255). //Если при пуске скетча данные из ячейки Init_Eeprom не совпадают //с Init_Key, вводим в настройки значения по умолчанию, //иначе берем настройки из памяти long TimeSeparation = 2700000; //время между прострелами, мс const long TimeSeparation_Min = 100000; //min --**--, мс const long TimeSeparation_Max = 14400000; //max --**--, мс //время ожидания после отключения подачи топлива, мс long TimeFuelOff = 10000; const long TimeFuelOff_Min = 1000; //min --**--, мс const long TimeFuelOff_Max = 32000; //max --**--, мс long TimeDisplace = 8000; //время заполнения барабана водой, мс const long TimeDisplace_Min = 1000; //min --**--, мс const long TimeDisplace_Max = 32000; //max --**--, мс //время ожидания после заполнения барабана водой, мс long TimeWaitAfterDispl = 10000; const long TimeWaitAfterDispl_Min = 1000; //min --**--, мс const long TimeWaitAfterDispl_Max = 30000; //max --**--, мс //время подачи воды для частичной очистки барабана (partial ejection), мс long TimePartEject = 1500; const long TimePartEject_Min = 500; //min --**--, мс const long TimePartEject_Max = 30000; //max --**--, мс //время ожидания после частичного прострела барабана (восстановление обортов), мс long TimeWaitAfterPartEject = 10000; const long TimeWaitAfterPartEject_Min = 1000; //min --**--, мс const long TimeWaitAfterPartEject_Max = 100000; //max --**--, мс //время подачи воды для полной очистки барабана (total ejection), мс long TimeTotalEject = 3000; const long TimeTotalEject_Min = 1000; //min --**--, мс const long TimeTotalEject_Max = 30000; //max --**--, мс //время ожидания после полного прострела барабана (восстановление обортов), мс long TimeWaitAfterTotalEject = 20000; const long TimeWaitAfterTotalEject_Min = 1000; //min --**--, мс const long TimeWaitAfterTotalEject_Max = 100000; //max --**--, мс long TimeClose = 80; //время подачи воды (импульс) для закрытия барабана, мс const long TimeClose_Min = 10; //min --**--, мс const long TimeClose_Max = 9999; //max --**--, мс long TimeAfterClose = 3000; //время ожидания после закрытия барабана, мс const long TimeAfterClose_Min = 1000; //min --**--, мс const long TimeAfterClose_Max = 30000; //max --**--, мс //интервал между импульсами на закрытие бабарабана в работе для компенсации утечек, мс long TimeImpulseGap = 240000; const long TimeImpulseGap_Min = 10000; //min --**--, мс const long TimeImpulseGap_Max = 10000000; //max --**--, мс long TimeStartImpulse = 3000; //импульс воды при запуске сепаратора, мс const long TimeStartImpulse_Min = 1000; //min --**--, мс const long TimeStartImpulse_Max = 30000; //max --**--, мс //время заполнения барабана (работа с гидрозатвором), мс long TimeFilling = 0; const long TimeFilling_Min = 0; //min --**--, мс const long TimeFilling_Max = 30000; //max --**--, мс //время ожидания после заполнения барабана (работа с гидрозатвором), мс long TimeWaitAfterFilling = 0; const long TimeWaitAfterFilling_Min = 0; //min --**--, мс const long TimeWaitAfterFilling_Max = 30000; //max --**--, мс //количество частичных прострелов барабана, после которых идет полный прострел int PartTotalEjection = 5; const int PartTotalEjection_Min = 1; //min const int PartTotalEjection_Max = 1000; //max int PartTotalCount = 0; //счетчик таких прострелов unsigned long SeparationCount = 0; //нужна в отсчете времени сепарации int SettingNumber = 0; //пункт меню настройки boolean LastButtonSetting = LOW; //предыдущее состояние кнопки boolean CurrentButtonSetting = LOW; //текущее состояние кнопки boolean LastButtonDown = LOW; boolean CurrentButtonDown = LOW; boolean LastButtonUp = LOW; boolean CurrentButtonUp = LOW; boolean LastButtonStart = LOW; boolean CurrentButtonStart = LOW; boolean SeparatorRun = false; //работает ли сепаратор (нажата ли кнопка Старт) boolean FlagSettingLoop = true; //были ли мы в цикле нажатия кнопки Настройки boolean FlagUpLoop = true; //были ли мы в цикле нажатия кнопки Больше boolean FlagDownLoop = true; //были ли мы в цикле нажатия кнопки Меньше //нужна при нажатии и удерживании кнопки ВВЕРХ unsigned long ButtonHoldTimerUp = 0; //нужна при нажатии и удерживании кнопки ВНИЗ unsigned long ButtonHoldTimerDown = 0; //по прошествии этого времени кнопка ВВЕРХ или ВНИЗ //перейдет в режим удержания, мс const long ButtonHoldIncTime = 500; boolean FlagUpHold = true; //были ли мы в цикле удержания кнопки ВВЕРХ boolean FlagDownHold = true; //были ли мы в цикле удержания кнопки ВНИЗ boolean FlagSettingIn = false; //находимся ли мы в режиме настройки unsigned long currentTime = 0; //нужна, чтобы убрать delay() //нужна для отсчета времени с момента импульса на закрытие барабана unsigned long ImpulseCountTime = 0; LiquidCrystal_I2C lcd(0x27,16,2); //Задаем адрес и размерность дисплея. void setup() //********************************************************* { pinMode (Pin_Relay_FuelFeed, OUTPUT); pinMode (Pin_Relay_Displacement, OUTPUT); pinMode (Pin_Relay_Control, OUTPUT); pinMode (BtSettingPin, INPUT); pinMode (BtDownPin, INPUT); pinMode (BtUpPin, INPUT); pinMode (BtStartPin, INPUT); //если запись в настройки когда-то была, то читаем их if (EEPROM.read(Init_Eeprom_Addr) == Init_Key) { EEPROM.get(0,TimeSeparation); //для типа long нужны 4 ячейки памяти EEPROM.get(4,TimeFuelOff); EEPROM.get(8,TimeDisplace); EEPROM.get(12,TimeWaitAfterDispl); EEPROM.get(16,TimePartEject); EEPROM.get(20,TimeWaitAfterPartEject); EEPROM.get(24,TimeTotalEject); EEPROM.get(28,TimeWaitAfterTotalEject); EEPROM.get(32,TimeClose); EEPROM.get(36,TimeAfterClose); EEPROM.get(40,TimeFilling); EEPROM.get(44,TimeWaitAfterFilling); EEPROM.get(48,TimeImpulseGap); EEPROM.get(52,TimeStartImpulse); EEPROM.get(56,PartTotalEjection); } else //если записи не было, записываем в память значения по умолчанию { EEPROM.put(0,TimeSeparation); //для типа long нужны 4 ячейки памяти EEPROM.put(4,TimeFuelOff); EEPROM.put(8,TimeDisplace); EEPROM.put(12,TimeWaitAfterDispl); EEPROM.put(16,TimePartEject); EEPROM.put(20,TimeWaitAfterPartEject); EEPROM.put(24,TimeTotalEject); EEPROM.put(28,TimeWaitAfterTotalEject); EEPROM.put(32,TimeClose); EEPROM.put(36,TimeAfterClose); EEPROM.put(40,TimeFilling); EEPROM.put(44,TimeWaitAfterFilling); EEPROM.put(48,TimeImpulseGap); EEPROM.put(52,TimeStartImpulse); EEPROM.put(56,PartTotalEjection); //и ставим метку, что запись в настройки произведена EEPROM.put(Init_Eeprom_Addr,Init_Key); } lcd.init(); //Инициализация lcd lcd.backlight(); //Включаем подсветку lcd.setCursor(0,0); lcd.print(" Separator "); lcd.setCursor(0,1); lcd.print(" Auto Control "); delay(2000); //Пауза lcd.setCursor(0,0); lcd.print("Separation Stop "); lcd.setCursor(0,1); lcd.print("Sep.Time "); lcd.print(TimeSeparation/1000); lcd.print(" s "); } void loop() //******************************************************* { if (SeparatorRun == true) //если идет сепарация { lcd.setCursor(0,0); lcd.print("Separation "); //----------- прошел интервал между импульсами на закрытие барабана --------------- //эти имульсы компенсируют утечку закрывающей барабан воды if(millis() - ImpulseCountTime >= TimeImpulseGap) { lcd.setCursor(0,0); lcd.print("Close Impulse "); digitalWrite(Pin_Relay_Control, HIGH); //открываем клапан управления барабаном delay(TimeClose); digitalWrite(Pin_Relay_Control, LOW); //закрываем клапан управления барабаном ImpulseCountTime = millis(); } //----------- отсчет времени сепарации и вывод на экран ----------------------- if(millis() - currentTime > 1000 && millis() - SeparationCount < TimeSeparation) { currentTime = millis(); //начинаем отсчет 1000 мс //выводим на экран только, если мы не в настройках if (FlagSettingIn == false) { lcd.setCursor(0,1); lcd.print("Sep.Time "); lcd.print((millis() - SeparationCount)/1000); //выводим на экран отсчет lcd.print(" s "); } } //--------------- прошел интервал сепарации между прострелами ----------------- if(millis() - SeparationCount >= TimeSeparation) { if(PartTotalCount >= PartTotalEjection) { FlagSettingIn = false; //вышли из режима настойки TotalEjection(); //функция полного прострела барабана FeedValveOpen(); //функция открытия клапана топлива PartTotalCount = 0; //обнуляем счетчик частичных прострелов SeparatorRun = true; SeparationCount = millis(); ImpulseCountTime = millis(); } else { FlagSettingIn = false; //вышли из режима настойки PartialEjection(); //функция частичного прострела барабана FeedValveOpen(); //функция открытия клапана топлива PartTotalCount = PartTotalCount + 1; SeparatorRun = true; SeparationCount = millis(); ImpulseCountTime = millis(); } } } //if (SeparatorRun == true) if (SeparatorRun == false) //если сепарация остановлена { if (FlagSettingIn == false) //выводим на экран только, если мы не в настройках { lcd.setCursor(0,1); lcd.print("Sep.Time "); lcd.print(TimeSeparation/1000); //выводим на экран время сепарации lcd.print(" s "); } } //-------------------- нажата кнопка Старт/Стоп ---------------------------------- //считываем состояние кнопки с устраненным дребезгом CurrentButtonStart = debounce(LastButtonStart, BtStartPin); if(CurrentButtonStart == HIGH) { //если сепаратор работал, простреливаем барабан и останавливаем работу if(SeparatorRun == true) { FlagSettingIn = false; //вышли из режима настойки lcd.setCursor(0,0); lcd.print("Separation Stop "); lcd.setCursor(0,1); lcd.print(" "); SeparationCount = 0; currentTime = 0; TotalEjection(); //функция полного прострела барабана lcd.setCursor(0,0); lcd.print("Separation Stop "); lcd.setCursor(0,1); lcd.print("Sep.Time "); lcd.print(TimeSeparation/1000); lcd.print(" s "); SeparatorRun = false; } //если сепаратор не работал, простреливаем барабан и пускаем в работу else { FlagSettingIn = false; //вышли из режима настойки StartEjection(); //функция прострела барабана при запуске сепаратора FeedValveOpen(); //функция откытия клапана топлива SeparatorRun = true; SeparationCount = millis(); //обнуляем счетчики ImpulseCountTime = millis(); } } //************ Нажата кнопка Настройки ************************************ //при каждом нажатии кнопки перескакиваем на следующий параметр в очереди. //Дойдя до конца меню, выходим из настроек //считываем состояние кнопки с устраненным дребезгом CurrentButtonSetting = debounce(LastButtonSetting, BtSettingPin); if(CurrentButtonSetting == HIGH) //если кнопка нажата { //эта переменная нужна для однократного нажатия кнопки, //даже если ее удерживать if (FlagSettingLoop == true) { FlagSettingLoop = false; FlagSettingIn = true; //вошли в режим настройки SettingNumber = SettingNumber + 1; if (SettingNumber > 18) { SettingNumber = 0; FlagSettingIn = false; //вышли из режима настройки } } } else { FlagSettingLoop = true; } LastButtonSetting = CurrentButtonSetting; //обновляем текущее значение кнопки if (FlagSettingIn == true) //если мы в настройках { //******************* Нажата кнопка Увеличить ************************** CurrentButtonUp = debounce(LastButtonUp, BtUpPin); ButtonPlus(CurrentButtonUp); //функция реакции на нажатие кнопки Увеличить LastButtonUp = CurrentButtonUp; //обновляем текущее значение кнопки //******************* Нажата кнопка Уменьшить ************************** CurrentButtonDown = debounce(LastButtonDown, BtDownPin); ButtonMinus(CurrentButtonDown); //функция реакции на нажатие кнопки Уменьшить LastButtonDown = CurrentButtonDown; //обновляем текущее значение кнопки SettingsOnLCD(SettingNumber); //отображаем строку с настройками } } //void loop() //********************** ФУНКЦИИ ********************************* //*********** Функция отображения настроек на LCD ************* void SettingsOnLCD(int SettingItem) { lcd.setCursor(0,1); switch (SettingItem) { case 1: //время сепарации между прострелами lcd.print("1 TSepar "); lcd.print(TimeSeparation/1000); lcd.print(" s "); break; case 2: //время ожидания после отключения подачи топлива lcd.print("2 TCircul. "); lcd.print(TimeFuelOff/1000); lcd.print(" s "); break; case 3: //время заполнения барабана водой lcd.print("3 TDispl. "); lcd.print(TimeDisplace/1000); lcd.print(" s "); break; case 4: //время ожидания после заполнения барабана водой lcd.print("4 TimeWAD "); lcd.print(TimeWaitAfterDispl/1000); lcd.print(" s "); break; case 5: //время подачи воды для частичного прострела барабана lcd.print("5 PEjec "); lcd.print(TimePartEject); lcd.print(" ms "); break; //время ожидания после частичного прострела барабана (восстановление обортов) case 6: lcd.print("6 TimeWAPE "); lcd.print(TimeWaitAfterPartEject/1000); lcd.print(" s "); break; case 7: //время подачи воды для полного прострела барабана lcd.print("7 TEjec "); lcd.print(TimeTotalEject); lcd.print(" ms "); break; //время ожидания после полного прострела барабана (восстановление обортов) case 8: lcd.print("8 TimeWATE "); lcd.print(TimeWaitAfterTotalEject/1000); lcd.print(" s "); break; case 9: //время подачи воды (импульса) для закрытия барабана lcd.print("9 TClose "); lcd.print(TimeClose); lcd.print(" ms "); break; case 10: //время ожидания после закрытия барабана lcd.print("10 TimeWACD "); lcd.print(TimeAfterClose/1000); lcd.print(" s "); break; case 11: //время заполнения барабана гидрозатвором lcd.print("11 TFilling "); lcd.print(TimeFilling/1000); lcd.print(" s "); break; case 12: //время ожидания после заполнения барабана гидрозатвором lcd.print("12 TimeWAF "); lcd.print(TimeWaitAfterFilling/1000); lcd.print(" s "); break; case 13: //интервал между импульсами на закрытие бабарабана lcd.print("13 TimeIGa "); lcd.print(TimeImpulseGap/1000); lcd.print(" s "); break; case 14: //импульс воды при запуске сепаратора lcd.print("14 StartImp "); lcd.print(TimeStartImpulse/1000); lcd.print(" s "); break; //количество частичных прострелов барабана, после которых идет полный прострел case 15: lcd.print("15 P/T Ejec "); lcd.print(PartTotalEjection); lcd.print(" "); break; case 16: //запись настроек в EEPROM lcd.print("SaveSet. (UP) "); break; case 17: //чтение настроек из EEPROM lcd.print("ReadSet. (UP) "); break; case 18: //загрузка значений по умолчанию lcd.print("Default (UP) "); break; } } //********* Функция кнопки Больше, Увеличить, Плюс и т.п. ************* void ButtonPlus(boolean BtState) //BtState - состояние кнопки (нажата-отжата) { if(BtState == HIGH) //кнопка нажата { if (SettingNumber >= 1 && SettingNumber <= 15 ) //пункты настроек, где нужен разгон параметра в режиме удержания { 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; } } //******** Функция изменения параметров при нажатии кнопки Больше ********** void ButtonPlusAction(int SettingItem, boolean IncTrigger) { switch (SettingItem) { case 1: //время сепарации между прострелами TimeSeparation = TimeSeparation + Inc_Val_Calc(IncTrigger, 1); if (TimeSeparation > TimeSeparation_Max) //если пытаемся уйти за верхний предел { TimeSeparation = TimeSeparation_Max; } break; case 2: //время ожидания после отключения подачи топлива TimeFuelOff = TimeFuelOff + Inc_Val_Calc(IncTrigger, 2); if (TimeFuelOff > TimeFuelOff_Max) //если пытаемся уйти за верхний предел { TimeFuelOff = TimeFuelOff_Max; } break; case 3: //время заполнения барабана водой (Displacement) TimeDisplace = TimeDisplace + Inc_Val_Calc(IncTrigger, 2); if (TimeDisplace > TimeDisplace_Max) //если пытаемся уйти за верхний предел { TimeDisplace = TimeDisplace_Max; } break; case 4: //время ожидания после заполнения барабана водой TimeWaitAfterDispl = TimeWaitAfterDispl + Inc_Val_Calc(IncTrigger, 2); if (TimeWaitAfterDispl > TimeWaitAfterDispl_Max) //если пытаемся уйти за верхний предел { TimeWaitAfterDispl = TimeWaitAfterDispl_Max; } break; case 5: //время подачи воды для частичного прострела барабана TimePartEject = TimePartEject + Inc_Val_Calc(IncTrigger, 3); if (TimePartEject > TimePartEject_Max) //если пытаемся уйти за верхний предел { TimePartEject = TimePartEject_Max; } break; //время ожидания после частичного прострела барабана (восстановление обортов), мс case 6: TimeWaitAfterPartEject = TimeWaitAfterPartEject + Inc_Val_Calc(IncTrigger, 2); if (TimeWaitAfterPartEject > TimeWaitAfterPartEject_Max) //если пытаемся уйти за верхний предел { TimeWaitAfterPartEject = TimeWaitAfterPartEject_Max; } break; case 7: //время подачи воды для полного прострела барабана TimeTotalEject = TimeTotalEject + Inc_Val_Calc(IncTrigger, 3); if (TimeTotalEject > TimeTotalEject_Max) //если пытаемся уйти за верхний предел { TimeTotalEject = TimeTotalEject_Max; } break; //время ожидания после полного прострела барабана (восстановление обортов), мс case 8: TimeWaitAfterTotalEject = TimeWaitAfterTotalEject + Inc_Val_Calc(IncTrigger, 2); if (TimeWaitAfterTotalEject > TimeWaitAfterTotalEject_Max) //если пытаемся уйти за верхний предел { TimeWaitAfterTotalEject = TimeWaitAfterTotalEject_Max; } break; case 9: //время подачи воды (импульса) для закрытия барабана TimeClose = TimeClose + Inc_Val_Calc(IncTrigger, 3); if (TimeClose > TimeClose_Max) //если пытаемся уйти за верхний предел { TimeClose = TimeClose_Max; } break; case 10: //время ожидания после закрытия барабана TimeAfterClose = TimeAfterClose + Inc_Val_Calc(IncTrigger, 2); if (TimeAfterClose > TimeAfterClose_Max) //если пытаемся уйти за верхний предел { TimeAfterClose = TimeAfterClose_Max; } break; case 11: //время заполнения барабана гидрозатвором (Filling) TimeFilling = TimeFilling + Inc_Val_Calc(IncTrigger, 2); if (TimeFilling > TimeFilling_Max) //если пытаемся уйти за верхний предел { TimeFilling = TimeFilling_Max; } break; case 12: //время ожидания после заполнения барабана гидрозатвором TimeWaitAfterFilling = TimeWaitAfterFilling + Inc_Val_Calc(IncTrigger, 2); if (TimeWaitAfterFilling > TimeWaitAfterFilling_Max) //если пытаемся уйти за верхний предел { TimeWaitAfterFilling = TimeWaitAfterFilling_Max; } break; case 13: //интервал между импульсами на закрытие барабана TimeImpulseGap = TimeImpulseGap + Inc_Val_Calc(IncTrigger, 1); if (TimeImpulseGap > TimeImpulseGap_Max) //если пытаемся уйти за верхний предел { TimeImpulseGap = TimeImpulseGap_Max; } break; case 14: //импульс воды при запуске сепаратора TimeStartImpulse = TimeStartImpulse + Inc_Val_Calc(IncTrigger, 2); if (TimeStartImpulse > TimeStartImpulse_Max) //если пытаемся уйти за верхний предел { TimeStartImpulse = TimeStartImpulse_Max; } break; //количество частичных прострелов барабана, после которых идет полный прострел case 15: PartTotalEjection = PartTotalEjection + Inc_Val_Calc(IncTrigger, 4); if (PartTotalEjection > PartTotalEjection_Max) //если пытаемся уйти за верхний предел { PartTotalEjection = PartTotalEjection_Max; } break; case 16: //запись настроек в EEPROM EEPROM.put(0,TimeSeparation); //для типа long нужны 4 ячейки памяти EEPROM.put(4,TimeFuelOff); EEPROM.put(8,TimeDisplace); EEPROM.put(12,TimeWaitAfterDispl); EEPROM.put(16,TimePartEject); EEPROM.put(20,TimeWaitAfterPartEject); EEPROM.put(24,TimeTotalEject); EEPROM.put(28,TimeWaitAfterTotalEject); EEPROM.put(32,TimeClose); EEPROM.put(36,TimeAfterClose); EEPROM.put(40,TimeFilling); EEPROM.put(44,TimeWaitAfterFilling); EEPROM.put(48,TimeImpulseGap); EEPROM.put(52,TimeStartImpulse); EEPROM.put(56,PartTotalEjection); //ставим метку, что запись в настройки произведена EEPROM.put(Init_Eeprom_Addr,Init_Key); lcd.setCursor(0,1); lcd.print("Saving... OK "); delay(2000); break; case 17: //чтение настроек из EEPROM EEPROM.get(0,TimeSeparation); //для типа long нужны 4 ячейки памяти EEPROM.get(4,TimeFuelOff); EEPROM.get(8,TimeDisplace); EEPROM.get(12,TimeWaitAfterDispl); EEPROM.get(16,TimePartEject); EEPROM.get(20,TimeWaitAfterPartEject); EEPROM.get(24,TimeTotalEject); EEPROM.get(28,TimeWaitAfterTotalEject); EEPROM.get(32,TimeClose); EEPROM.get(36,TimeAfterClose); EEPROM.get(40,TimeFilling); EEPROM.get(44,TimeWaitAfterFilling); EEPROM.get(48,TimeImpulseGap); EEPROM.get(52,TimeStartImpulse); EEPROM.get(56,PartTotalEjection); lcd.setCursor(0,1); lcd.print("Reading... OK "); delay(2000); break; case 18: //загрузка значений по умолчанию. Берем из начала скетча TimeSeparation = 2700000; TimeFuelOff = 10000; TimeDisplace = 8000; TimeWaitAfterDispl = 10000; TimePartEject = 1500; TimeWaitAfterPartEject = 10000; TimeTotalEject = 3000; TimeWaitAfterTotalEject = 20000; TimeClose = 80; TimeAfterClose = 3000; TimeFilling = 0; TimeWaitAfterFilling = 0; TimeImpulseGap = 240000; TimeStartImpulse = 3000; PartTotalEjection = 5; lcd.setCursor(0,1); lcd.print("Loading... OK "); delay(2000); break; } } //********* Функция кнопки Меньше, Уменьшить, Минус или т.п. ************* void ButtonMinus(boolean BtState) //BtState - состояние кнопки (нажата-отжата) { if(BtState == HIGH) //кнопка нажата { if (SettingNumber >= 1 && SettingNumber <= 15 ) //пункты настроек, где нужен разгон параметра в режиме удержания { 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; } } //******** Функция изменения параметров при нажатии кнопки Меньше ********** void ButtonMinusAction(int SettingItem, boolean IncTrigger) { switch (SettingItem) { case 1: //время сепарации между прострелами TimeSeparation = TimeSeparation - Inc_Val_Calc(IncTrigger, 1); if (TimeSeparation < TimeSeparation_Min) //если пытаемся уйти за нижний предел { TimeSeparation = TimeSeparation_Min; } break; case 2: //время ожидания после отключения подачи топлива TimeFuelOff = TimeFuelOff - Inc_Val_Calc(IncTrigger, 2); if (TimeFuelOff < TimeFuelOff_Min) //если пытаемся уйти за нижний предел { TimeFuelOff = TimeFuelOff_Min; } break; case 3: //время заполнения барабана водой (Displacement) TimeDisplace = TimeDisplace - Inc_Val_Calc(IncTrigger, 2); if (TimeDisplace < TimeDisplace_Min) //если пытаемся уйти за нижний предел { TimeDisplace = TimeDisplace_Min; } break; case 4: //время ожидания после заполнения барабана водой TimeWaitAfterDispl = TimeWaitAfterDispl - Inc_Val_Calc(IncTrigger, 2); if (TimeWaitAfterDispl < TimeWaitAfterDispl_Min) //если пытаемся уйти за нижний предел { TimeWaitAfterDispl = TimeWaitAfterDispl_Min; } break; case 5: //время подачи воды для частичного прострела барабана TimePartEject = TimePartEject - Inc_Val_Calc(IncTrigger, 3); if (TimePartEject < TimePartEject_Min) //если пытаемся уйти за нижний предел { TimePartEject = TimePartEject_Min; } break; //время ожидания после частичного прострела барабана (восстановление обортов), мс case 6: TimeWaitAfterPartEject = TimeWaitAfterPartEject - Inc_Val_Calc(IncTrigger, 2); if (TimeWaitAfterPartEject < TimeWaitAfterPartEject_Min) //если пытаемся уйти за нижний предел { TimeWaitAfterPartEject = TimeWaitAfterPartEject_Min; } break; case 7: //время подачи воды для полного прострела барабана TimeTotalEject = TimeTotalEject - Inc_Val_Calc(IncTrigger, 3); if (TimeTotalEject < TimeTotalEject_Min) //если пытаемся уйти за нижний предел { TimeTotalEject = TimeTotalEject_Min; } break; //время ожидания после полного прострела барабана (восстановление обортов), мс case 8: TimeWaitAfterTotalEject = TimeWaitAfterTotalEject - Inc_Val_Calc(IncTrigger, 2); if (TimeWaitAfterTotalEject < TimeWaitAfterTotalEject_Min) //если пытаемся уйти за нижний предел { TimeWaitAfterTotalEject = TimeWaitAfterTotalEject_Min; } break; case 9: //время подачи воды (импульса) для закрытия барабана TimeClose = TimeClose - Inc_Val_Calc(IncTrigger, 3); if (TimeClose < TimeClose_Min) //если пытаемся уйти за нижний предел { TimeClose = TimeClose_Min; } break; case 10: //время ожидания после закрытия барабана TimeAfterClose = TimeAfterClose - Inc_Val_Calc(IncTrigger, 2); if (TimeAfterClose < TimeAfterClose_Min) //если пытаемся уйти за нижний предел { TimeAfterClose = TimeAfterClose_Min; } break; case 11: //время заполнения барабана гидрозатвором (Filling) TimeFilling = TimeFilling - Inc_Val_Calc(IncTrigger, 2); if (TimeFilling < TimeFilling_Min) //если пытаемся уйти за нижний предел { TimeFilling = TimeFilling_Min; } break; case 12: //время ожидания после заполнения барабана гидрозатвором TimeWaitAfterFilling = TimeWaitAfterFilling - Inc_Val_Calc(IncTrigger, 2); if (TimeWaitAfterFilling < TimeWaitAfterFilling_Min) //если пытаемся уйти за нижний предел { TimeWaitAfterFilling = TimeWaitAfterFilling_Min; } break; case 13: //интервал между импульсами на закрытие барабана TimeImpulseGap = TimeImpulseGap - Inc_Val_Calc(IncTrigger, 1); if (TimeImpulseGap < TimeImpulseGap_Min) //если пытаемся уйти за нижний предел { TimeImpulseGap = TimeImpulseGap_Min; } break; case 14: //импульс воды при запуске сепаратора TimeStartImpulse = TimeStartImpulse - Inc_Val_Calc(IncTrigger, 2); if (TimeStartImpulse < TimeStartImpulse_Min) //если пытаемся уйти за нижний предел { TimeStartImpulse = TimeStartImpulse_Min; } break; //количество частичных прострелов барабана, после которых идет полный прострел case 15: PartTotalEjection = PartTotalEjection - Inc_Val_Calc(IncTrigger, 4); if (PartTotalEjection < PartTotalEjection_Min) //если пытаемся уйти за нижний предел { PartTotalEjection = PartTotalEjection_Min; } break; } } //************** функция частичного прострела барабана ********************* void PartialEjection() { //переводим топливо на рециркуляцию digitalWrite(Pin_Relay_FuelFeed, LOW); lcd.setCursor(0,0); lcd.print("Recirculation... "); lcd.setCursor(0,1); lcd.print(TimeFuelOff/1000); lcd.print(" sec "); delay(TimeFuelOff); //ждем пока упадет давление //подаем воду в барабан digitalWrite(Pin_Relay_Displacement, HIGH); lcd.setCursor(0,0); lcd.print("Displacement... "); lcd.setCursor(0,1); lcd.print(TimeDisplace/1000); lcd.print(" sec "); delay(TimeDisplace); //закрываем воду в барабан digitalWrite(Pin_Relay_Displacement, LOW); lcd.setCursor(0,0); lcd.print("Wait after Displ"); lcd.setCursor(0,1); lcd.print(TimeWaitAfterDispl/1000); lcd.print(" sec "); delay(TimeWaitAfterDispl); //подаем управляющую воду на открытие барабана - прострел lcd.setCursor(0,0); lcd.print("Ejection... "); lcd.setCursor(0,1); lcd.print(TimePartEject); lcd.print(" ms "); digitalWrite(Pin_Relay_Control, HIGH); delay(TimePartEject); //закрываем управляющую воду на открытие барабана digitalWrite(Pin_Relay_Control, LOW); //и ждем восстановления оборотов lcd.setCursor(0,0); lcd.print("Speed Recovery "); lcd.setCursor(0,1); lcd.print(TimeWaitAfterPartEject/1000); lcd.print(" sec "); delay(TimeWaitAfterPartEject); //подаем управляющую воду на закрытие барабана digitalWrite(Pin_Relay_Control, HIGH); delay(TimeClose); digitalWrite(Pin_Relay_Control, LOW); lcd.setCursor(0,0); lcd.print("Close Drum... "); lcd.setCursor(0,1); lcd.print("Wait... "); //ждем после закрытия барабана delay(TimeAfterClose); //если мы используем гидрозатвор if (TimeFilling != 0) { //заполняем барабан гидрозатвором digitalWrite(Pin_Relay_Displacement, HIGH); lcd.setCursor(0,0); lcd.print("Filling... "); lcd.setCursor(0,1); lcd.print(TimeFilling/1000); lcd.print(" sec "); delay(TimeFilling); //закрываем воду в барабан и ждем digitalWrite(Pin_Relay_Displacement, LOW); lcd.setCursor(0,0); lcd.print("Wait after Filli"); lcd.setCursor(0,1); lcd.print(TimeWaitAfterFilling/1000); lcd.print(" sec "); delay(TimeWaitAfterFilling); } } //********* функция полного прострела барабана ***************** void TotalEjection() { //переводим топливо на рециркуляцию digitalWrite(Pin_Relay_FuelFeed, LOW); lcd.setCursor(0,0); lcd.print("Recirculation... "); lcd.setCursor(0,1); lcd.print(TimeFuelOff/1000); lcd.print(" sec "); delay(TimeFuelOff); //ждем пока упадет давление //подаем воду в барабан digitalWrite(Pin_Relay_Displacement, HIGH); lcd.setCursor(0,0); lcd.print("Displacement... "); lcd.setCursor(0,1); lcd.print(TimeDisplace/1000); lcd.print(" sec "); delay(TimeDisplace); //закрываем воду в барабан digitalWrite(Pin_Relay_Displacement, LOW); lcd.setCursor(0,0); lcd.print("Wait after Displ"); lcd.setCursor(0,1); lcd.print(TimeWaitAfterDispl/1000); lcd.print(" sec "); delay(TimeWaitAfterDispl); //подаем управляющую воду на открытие барабана - прострел lcd.setCursor(0,0); lcd.print("Total Ejection... "); lcd.setCursor(0,1); lcd.print(TimeTotalEject); lcd.print(" ms "); digitalWrite(Pin_Relay_Control, HIGH); delay(TimeTotalEject); //закрываем управляющую воду на открытие барабана digitalWrite(Pin_Relay_Control, LOW); //и ждем восстановления оборотов lcd.setCursor(0,0); lcd.print("Speed Recovery "); lcd.setCursor(0,1); lcd.print(TimeWaitAfterTotalEject/1000); lcd.print(" sec "); delay(TimeWaitAfterTotalEject); //подаем управляющую воду на закрытие барабана digitalWrite(Pin_Relay_Control, HIGH); delay(TimeClose); digitalWrite(Pin_Relay_Control, LOW); lcd.setCursor(0,0); lcd.print("Close Drum... "); lcd.setCursor(0,1); lcd.print("Wait... "); //ждем после закрытия барабана delay(TimeAfterClose); if (TimeFilling != 0) //если мы используем гидрозатвор { //заполняем барабан гидрозатвором digitalWrite(Pin_Relay_Displacement, HIGH); lcd.setCursor(0,0); lcd.print("Filling... "); lcd.setCursor(0,1); lcd.print(TimeFilling/1000); lcd.print(" sec "); delay(TimeFilling); //закрываем воду в барабан и ждем digitalWrite(Pin_Relay_Displacement, LOW); lcd.setCursor(0,0); lcd.print("Wait after Filli"); lcd.setCursor(0,1); lcd.print(TimeWaitAfterFilling/1000); lcd.print(" sec "); delay(TimeWaitAfterFilling); } } //********* функция прострела барабана при запуске сепаратора *************** void StartEjection() { //переводим топливо на рециркуляцию digitalWrite(Pin_Relay_FuelFeed, LOW); lcd.setCursor(0,0); lcd.print("Recirculation... "); lcd.setCursor(0,1); lcd.print(TimeFuelOff/1000); lcd.print(" sec "); delay(TimeFuelOff); //ждем пока упадет давление //подаем начальный импульс воды на управление барабана lcd.setCursor(0,0); lcd.print("Start Impuls... "); lcd.setCursor(0,1); lcd.print(TimeStartImpulse); lcd.print(" ms "); digitalWrite(Pin_Relay_Control, HIGH); delay(TimeStartImpulse); //закрываем управляющую воду на открытие барабана digitalWrite(Pin_Relay_Control, LOW); //и ждем восстановления оборотов lcd.setCursor(0,0); lcd.print("Speed Recovery "); lcd.setCursor(0,1); lcd.print(TimeWaitAfterPartEject/1000); lcd.print(" sec "); delay(TimeWaitAfterPartEject); //подаем воду в барабан digitalWrite(Pin_Relay_Displacement, HIGH); lcd.setCursor(0,0); lcd.print("Displacement... "); lcd.setCursor(0,1); lcd.print(TimeDisplace/1000); lcd.print(" sec "); delay(TimeDisplace); //закрываем воду в барабан digitalWrite(Pin_Relay_Displacement, LOW); lcd.setCursor(0,0); lcd.print("Wait after Displ"); lcd.setCursor(0,1); lcd.print(TimeWaitAfterDispl/1000); lcd.print(" sec "); delay(TimeWaitAfterDispl); //подаем управляющую воду на открытие барабана - прострел lcd.setCursor(0,0); lcd.print("Total Ejection... "); lcd.setCursor(0,1); lcd.print(TimeTotalEject); lcd.print(" ms "); digitalWrite(Pin_Relay_Control, HIGH); delay(TimeTotalEject); //закрываем управляющую воду на открытие барабана digitalWrite(Pin_Relay_Control, LOW); //и ждем восстановления оборотов lcd.setCursor(0,0); lcd.print("Speed Recovery "); lcd.setCursor(0,1); lcd.print(TimeWaitAfterTotalEject/1000); lcd.print(" sec "); delay(TimeWaitAfterTotalEject); //подаем управляющую воду на закрытие барабана digitalWrite(Pin_Relay_Control, HIGH); delay(TimeClose); digitalWrite(Pin_Relay_Control, LOW); lcd.setCursor(0,0); lcd.print("Close Drum... "); lcd.setCursor(0,1); lcd.print("Wait... "); //ждем после закрытия барабана delay(TimeAfterClose); if (TimeFilling != 0) //если мы используем гидрозатвор { //заполняем барабан гидрозатвором digitalWrite(Pin_Relay_Displacement, HIGH); lcd.setCursor(0,0); lcd.print("Filling... "); lcd.setCursor(0,1); lcd.print(TimeFilling/1000); lcd.print(" sec "); delay(TimeFilling); //закрываем воду в барабан и ждем digitalWrite(Pin_Relay_Displacement, LOW); lcd.setCursor(0,0); lcd.print("Wait after Filli"); lcd.setCursor(0,1); lcd.print(TimeWaitAfterFilling/1000); lcd.print(" sec "); delay(TimeWaitAfterFilling); } } //********* функция открытия топливного клапана *************** void FeedValveOpen() { //открываем подачу топлива digitalWrite(Pin_Relay_FuelFeed, HIGH); lcd.setCursor(0,0); lcd.print("Feed Valve Open"); delay(1000); } //*************** Функция устранения дребезга контактов *********** boolean debounce(boolean last, int ButtonPinDebounce) { boolean current = digitalRead(ButtonPinDebounce); //считываем текущее состояние кнопки if(last != current) //если оно иное, чем предыдущее... { delay(50); //ждем 50 мс current = digitalRead(ButtonPinDebounce); //считываем состояние снова } return current; //возвращаем текущее состояние кнопки } //*************** Функция разгона приращения параметра ************ 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 1000; } if (count_inc > 30 && count_inc <= 60) { return 2000; } if (count_inc > 60) { return 5000; } } if (IncVariant == 3) { //играя этими числами, вы можете подстраивать разгон параметра под себя if (count_inc > 0 && count_inc <= 30) { return 5; } if (count_inc > 30 && count_inc <= 60) { return 10; } if (count_inc > 60 && count_inc <= 90) { return 50; } if (count_inc > 90) { return 100; } } if (IncVariant == 4) { //играя этими числами, вы можете подстраивать разгон параметра под себя if (count_inc > 0 && count_inc <= 30) { return 1; } if (count_inc > 30 && count_inc <= 60) { return 2; } if (count_inc > 60) { return 5; } } } else { count_inc = 0; if (IncVariant == 1) { return 1000; //приращение по умолчанию } if (IncVariant == 2) { return 1000; //приращение по умолчанию } if (IncVariant == 3) { return 5; //приращение по умолчанию } if (IncVariant == 4) { return 1; //приращение по умолчанию } } }