Помогите заставить конечный автомат работать правильно

Тема в разделе "Arduino & Shields", создана пользователем chudos, 18 мар 2016.

  1. chudos

    chudos Нуб

    День добрый.

    Пытаюсь заставить конечный автомат работать правильно, но пока тщетно.

    Прощу помощи, т.к. в программировании я очень слаб.

    Суть программы: существует некий конечный автомат с определенными режимами (GOROD, TRASSA,DOGD,OFF).

    Каждый режим отвечает за включение мотора в определенных временных условиях, перключение режимов осуществляется кнопкой1

    Режим OFF выключает мотор-кнопка 2

    Также есть определенные ограничения описанные в функциях Regim_t SpeedSensorReturnRegim() и void SpeedSensor() которые отвечают за выключение мотора (при наступлении определенных условий) и возврат режима после после окончания ограничения.

    Есть еще вольтметр, термометр и вывод всего этого на экран, но это уже суть.

    Проблема в следующем: после загрузки скетча в ардуино уно включается первый режим (GOROD), по нажатию кнопки должна происходить смена режима, но ничего не происходит (сам режим GOROD работает вроде правильно).

    Код писал не сам (выдирал куски кода аналогичного устройства и переделывал под себя). Подразумеваю, что ошибка либо в определение typedef enum или в функции Button_1().
    Заранее спасибо

    Код (C++):


    //Управление сказчиком

    //пины 6 и 3 это кнопки
    //пин 2 выход на насос
    //программа 1 - "город" - 2 капли в минуту (2 открытия в минуту)
    //программа 2 - "трасса" - 3-4 капли в минуту (3-4 открытия в минуту)
    //программа 3 - "дождь" - 10 капель в минуту (10 открытия в минуту)
    //кнопка 3 - выключает автосмажчик
    //!!!!количество открытий в минуту и время открытия пока ориентировочное!!!!

    //Вывод на экран
    //пины 4,5,10-13 для соединения с экраном
    //на экран выводится только информация какой режим сейчас включен
    //Подключаем стандартную библиотеку LiquidCrystal
    //--------------------------------------------------------------------------------------------------



    #define BUTTON_1 6            //включает программу смазки 1 - "город" на второй ноге
                        //каждое последующее нажатие включает следующую программу
    #define BUTTON_2 3            //batton_2 - выключает смазчик на 3-й ноге
    #define motor 7              //транзистор управляющий насосом на 7-й ноге
    #define speedsensor 2         //датчик скорости подключен к пину D2
    long speedlimit=5;            //количество импульсов за один оборот колеса (при скорости примерно 7км/ч)
                        //!!!!! ВНИМАНИЕ
                        //ЭТО ЗНАЧЕНИЕ НУЖНО ПОЛУЧИТЬ НАТУРНО (ИЗМЕРИТЬ НА ДАТЧИКЕ ПРИ ВРАЩАЮЩЕМСЯ КОЛЕСЕ

    #define SEC 1000            //1секунда=период таймера(1мс)*коэффициет(1000)
    #define TIME_MEASURE_VOLTAGE 1*SEC
    #define K_VOLT 0.14//0.18//0.14     //коэффициент делителя(для определения напряжения) (0.14 R1 = 13k, R2 = )
    #define V_MAX 5
    #define VIN A1

    int val_1 =0;             //переменная для хранения состояния кнопки1
    int val_2 =0;             //переменная для хранения состояния кнопки2

    unsigned long sp=0;           //переменная для хранения данных с датчика скорости
    long T_speed = 1000;          //интервал времени для определения текущей скорости (1 секунда)
    unsigned long previousMillis_sp = 0;  //время последнего импульса

    unsigned long previousMillis = 0;   //храним время последнего переключения светодиода

    long interval_on = 3000;        //интервал между вкл/выкл насоса (3 секунда)
    long interval_7 = 7000;         //интервал между вкл/выкл насоса (7 секунда)
    long interval_17 = 17000;       //интервал между вкл/выкл насоса (17 секунда)
    long interval_27 = 27000;       //интервал между вкл/выкл насоса (27 секунда)

    #include <LiquidCrystal.h>        //библиотека экрана
    LiquidCrystal lcd(4,5,10,11,12,13);

    #include <math.h>
    #define T A0                //датчик температуры подключен к А0

    //--------------------------------------------------------------------------------------------------
    boolean buttonWasUp_1 = true;  // была ли кнопка1 отпущена?
    boolean buttonWasUp_2 = true;  // была ли кнопка2 отпущена?
    //--------------------------------------------------------------------------------------------------

    uint16_t voltage = 0;
    boolean fMeasureVoltage = true;
    uint16_t tMeasureVoltage = TIME_MEASURE_VOLTAGE;

    //--------------------------------------------------------------------------------------------------

    typedef enum{GOROD, TRASSA, DOGD, OFF} Regim_t;
    Regim_t regim, prevRegim;
    //enum Regim_t regim = GOROD;
    bool fOn = false;

    //--------------------------------------------------------------------------------------------------

    void OutLCD(String s){           //функция печати на экран режима
      lcd.setCursor(8,1);           //устанавливаем курсор в первую строку, 8-я колонна
      lcd.print(s);
    }

    //--------------------------------------------------------------------------------------------------

    void On(){                //функция отвечающая за включение насоса
      digitalWrite(motor, HIGH);
    }

    void Off(){               //функция отвечающая за выключение насоса
      digitalWrite(motor, LOW);
    }

    //--------------------------------------------------------------------------------------------------

    void WorkPump(int delay){               //функция отвечающая за выбор режима
      unsigned long currentMillis = millis();
      if (fOn) {
        On();
      if(currentMillis - previousMillis > interval_on){ //проверяем не прошел ли нужный интервал,если прошел то
        Off();                      //закрыть клапан
        fOn = false;
        previousMillis = currentMillis;         //сохраняем время последнего переключения
      }
    }
      if (!fOn) {
        Off();
      if(currentMillis - previousMillis > delay){     //проверяем не прошел ли нужный интервал,если прошел то
        fOn = true;
        previousMillis = currentMillis;         //сохраняем время последнего переключения
      }
      }
    }

    //--------------------------------------------------------------------------------------------------

    Regim_t SpeedSensorReturnRegim() {
      unsigned long currentMillis = millis();
        if ((currentMillis - previousMillis_sp > T_speed)&&sp++ <speedlimit){
        prevRegim = regim;
        regim = OFF;
        previousMillis_sp = currentMillis;        //сохраняем время последнего переключения  
        lcd.setCursor(11,1);           //устанавливаем курсор в первую строку, 11-я колонна
        lcd.print("non active");
          }
      else{
        regim = prevRegim;
        return regim;
      }
    }

    //--------------------------------------------------------------------------------------------------
    void SpeedSensor(){                   //функция отвечающая за расчет  ограничителя
      unsigned long currentMillis = millis();
      sp++;
        if(((currentMillis - previousMillis_sp) > T_speed) && sp++ <speedlimit){
          regim = OFF;
          previousMillis_sp = currentMillis;        //сохраняем время последнего переключения
          sp=0;
        }
    }

    //--------------------------------------------------------------------------------------------------

    void SensorVolt() {
      int sensorValue;

      if (fMeasureVoltage)
      {
        sensorValue = analogRead(VIN);
        voltage = (int)(((sensorValue / 1023.0f * V_MAX) / K_VOLT) * 1000);
        fMeasureVoltage = false;
      }
      lcd.setCursor(9,2);
      lcd.print(voltage);
      delay(1000);
    }

    void SensorTemp(){
      int val;
      double temp;
      val=analogRead(T);
      temp=Thermister(val);
        long Temperature=temp;
      lcd.setCursor(13,3);
      lcd.print(Temperature);
      delay(1000);
    }
    //--------------------------------------------------------------------------------------------------

    void Button_1(){
        boolean buttonIsUp_1 = digitalRead(BUTTON_1);

        if (buttonWasUp_1 && !buttonIsUp_1) {
            delay(10);
            buttonIsUp_1 = digitalRead(BUTTON_1);
            if (!buttonIsUp_1) {
                int a=(int)regim;
                regim=(Regim_t)a++;          
            }
        }
    // запоминаем последнее состояние кнопки для новой итерации
    buttonWasUp_1 = buttonIsUp_1;
    }

    void Button_2(){
        boolean buttonIsUp_2 = digitalRead(BUTTON_2);

        if (buttonWasUp_2 && !buttonIsUp_2) {
            delay(10);
            buttonIsUp_2 = digitalRead(BUTTON_2);
            if (!buttonIsUp_2) {
                regim = OFF;
            }
        }
    // запоминаем последнее состояние кнопки для новой итерации
    buttonWasUp_2 = buttonIsUp_2;
    }

    //--------------------------------------------------------------------------------------------------

    void setup (){
    pinMode(motor, OUTPUT);           //транзистор управляющий клапаном на 6-й ноге
    pinMode(BUTTON_1, INPUT_PULLUP);         //кнопка 1 - вход
    pinMode(BUTTON_2, INPUT_PULLUP);         //кнопка 2 - вход
    pinMode(speedsensor, INPUT);
    attachInterrupt(0,SpeedSensor, FALLING);  //Подсчет импульсов
    voltage = analogRead(VIN);
    lcd.begin(20, 4);             //устанавливаем размер (количество столбцов и строк) экрана
    lcd.setCursor(0,1);             //устанавливаем курсор
    lcd.print("Smazka-");           //печатаем первую часть строки

    lcd.setCursor(1,2);             //устанавливаем курсор
    lcd.print("Voltage-");            //печатаем первую часть строки

    lcd.setCursor(1,3);             //устанавливаем курсор
    lcd.print("Temperature-");          //печатаем первую часть строки
    }

    //--------------------------------------------------------------------------------------------------
    double Thermister(int RawADC){
    double Temp;
    Temp = log(((10240000/RawADC) - 10000));
    Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
    Temp = Temp - 273.15;
    return Temp;
    }
    //--------------------------------------------------------------------------------------------------

    void loop() {

      if ((int)regim > DOGD){
        regim = GOROD;
      }

      SpeedSensorReturnRegim();

      SensorTemp();

      SensorVolt();

      SpeedSensor();

      switch (regim){
        case GOROD:
        OutLCD("Gorod");
        WorkPump( interval_27 );
      break;

      case TRASSA:
        OutLCD("Trassa");
        WorkPump( interval_17 );
      break;

      case DOGD:
        OutLCD("Dogd");
        WorkPump( interval_7 );
      break;

      case OFF:
        OutLCD("OFF");
        Off();
      break;
    }

    }
     
     
    Последнее редактирование: 18 мар 2016
  2. Tomasina

    Tomasina Сушитель лампочек Модератор

    Код (C++):


    //Управление сказчиком

    //пины 6 и 3 это кнопки
    //пин 2 выход на насос
    //программа 1 - "город" - 2 капли в минуту (2 открытия в минуту)
    //программа 2 - "трасса" - 3-4 капли в минуту (3-4 открытия в минуту)
    //программа 3 - "дождь" - 10 капель в минуту (10 открытия в минуту)
    //кнопка 3 - выключает автосмажчик
    //!!!!количество открытий в минуту и время открытия пока ориентировочное!!!!

    //Вывод на экран
    //пины 4,5,10-13 для соединения с экраном
    //на экран выводится только информация какой режим сейчас включен
    //Подключаем стандартную библиотеку LiquidCrystal
    //--------------------------------------------------------------------------------------------------


    #include <math.h>
    #include <LiquidCrystal.h>               //библиотека экрана

    #define BUTTON_1                  6      //включает программу смазки 1 - "город" на второй ноге
    //каждое последующее нажатие включает следующую программу
    #define BUTTON_2                  3      //batton_2 - выключает смазчик на 3-й ноге
    #define MOTOR                     7      //транзистор управляющий насосом на 7-й ноге
    #define SPEED_SENSOR              2      //датчик скорости подключен к пину D2
    #define T                         A0     //датчик температуры подключен к А0
    #define SEC                       1000   //1секунда=период таймера(1мс)*коэффициет(1000)
    #define TIME_MEASURE_VOLTAGE      (1 * SEC)
    #define K_VOLT                    0.14   //0.184     //коэффициент делителя(для определения напряжения) (0.14 R1 = 13k, R2 = )
    #define V_MAX                     5
    #define VIN                       A1

    unsigned long speedLimit =        5;     //количество импульсов за один оборот колеса (при скорости примерно 7км/ч)
    //!!!!! ВНИМАНИЕ
    //ЭТО ЗНАЧЕНИЕ НУЖНО ПОЛУЧИТЬ НАТУРНО (ИЗМЕРИТЬ НА ДАТЧИКЕ ПРИ ВРАЩАЮЩЕМСЯ КОЛЕСЕ

    int val_1 =                       0;     //переменная для хранения состояния кнопки1
    int val_2 =                       0;     //переменная для хранения состояния кнопки2
    unsigned long sp=                 0;     //переменная для хранения данных с датчика скорости
    unsigned long T_speed =           1000;  //интервал времени для определения текущей скорости (1 секунда)
    unsigned long previousMillis_sp = 0;     //время последнего импульса
    unsigned long previousMillis =    0;     //храним время последнего переключения светодиода
    unsigned long interval_on =       3000;  //интервал между вкл/выкл насоса (3 секунда)
    unsigned long interval_7 =        7000;  //интервал между вкл/выкл насоса (7 секунда)
    unsigned long interval_17 =       17000; //интервал между вкл/выкл насоса (17 секунда)
    unsigned long interval_27 =       27000; //интервал между вкл/выкл насоса (27 секунда)
    boolean buttonWasUp_1 =          true;  // была ли кнопка1 отпущена?
    boolean buttonWasUp_2 =          true;  // была ли кнопка2 отпущена?
    uint16_t voltage =               0;
    boolean fMeasureVoltage =        true;
    bool fOn =                       false;
    uint16_t tMeasureVoltage =       TIME_MEASURE_VOLTAGE;

    enum{
      GOROD, TRASSA, RAIN, OFF}
    Regim_t;
    byte regim, prevRegim;
    //enum Rregim = GOROD;

    LiquidCrystal lcd(4,5,10,11,12,13);

    //--------------------------------------------------------------------------------------------------

    void setup (){
      pinMode(MOTOR, OUTPUT);           //транзистор управляющий клапаном на 6-й ноге
      pinMode(BUTTON_1, INPUT_PULLUP);         //кнопка 1 - вход
      pinMode(BUTTON_2, INPUT_PULLUP);         //кнопка 2 - вход
      pinMode(SPEED_SENSOR, INPUT);
      attachInterrupt(0,SpeedSensor, FALLING);  //Подсчет импульсов
      voltage = analogRead(VIN);
      lcd.begin(20, 4);             //устанавливаем размер (количество столбцов и строк) экрана
      lcd.setCursor(0,1);             //устанавливаем курсор
      lcd.print("Smazka-");           //печатаем первую часть строки

      lcd.setCursor(1,2);             //устанавливаем курсор
      lcd.print("Voltage-");            //печатаем первую часть строки

      lcd.setCursor(1,3);             //устанавливаем курсор
      lcd.print("Temperature-");          //печатаем первую часть строки
    }


    //--------------------------------------------------------------------------------------------------

    void OutLCD(String s){           //функция печати на экран режима
      lcd.setCursor(8,1);           //устанавливаем курсор в первую строку, 8-я колонна
      lcd.print(s);
    }

    //--------------------------------------------------------------------------------------------------

    void On(){                //функция отвечающая за включение насоса
      digitalWrite(MOTOR, HIGH);
    }

    void Off(){               //функция отвечающая за выключение насоса
      digitalWrite(MOTOR, LOW);
    }

    //--------------------------------------------------------------------------------------------------

    void WorkPump(int delay){               //функция отвечающая за выбор режима
      unsigned long currentMillis = millis();
      if (fOn) {
        On();
        if(currentMillis - previousMillis > interval_on){ //проверяем не прошел ли нужный интервал,если прошел то
          Off();                      //закрыть клапан
          fOn = false;
          previousMillis = currentMillis;         //сохраняем время последнего переключения
        }
      }
      if (!fOn) {
        Off();
        if(currentMillis - previousMillis > delay){     //проверяем не прошел ли нужный интервал,если прошел то
          fOn = true;
          previousMillis = currentMillis;         //сохраняем время последнего переключения
        }
      }
    }

    //--------------------------------------------------------------------------------------------------

    byte SpeedSensorReturnRegim() {
      unsigned long currentMillis = millis();
      if ((currentMillis - previousMillis_sp > T_speed)&&sp++ <speedLimit){
        prevRegim = regim;
        regim = OFF;
        previousMillis_sp = currentMillis;        //сохраняем время последнего переключения
        lcd.setCursor(11,1);           //устанавливаем курсор в первую строку, 11-я колонна
        lcd.print("non active");
      }
      else{
        regim = prevRegim;
        return regim;
      }
    }

    //--------------------------------------------------------------------------------------------------
    void SpeedSensor(){                   //функция отвечающая за расчет  ограничителя
      unsigned long currentMillis = millis();
      sp++;
      if(((currentMillis - previousMillis_sp) > T_speed) && sp++ <speedLimit){
        regim = OFF;
        previousMillis_sp = currentMillis;        //сохраняем время последнего переключения
        sp=0;
      }
    }

    //--------------------------------------------------------------------------------------------------

    void SensorVolt() {
      int sensorValue;

      if (fMeasureVoltage)
      {
        sensorValue = analogRead(VIN);
        voltage = (int)(((sensorValue / 1023.0f * V_MAX) / K_VOLT) * 1000);
        fMeasureVoltage = false;
      }
      lcd.setCursor(9,2);
      lcd.print(voltage);
      delay(1000);
    }

    void SensorTemp(){
      int val;
      double temp;
      val=analogRead(T);
      temp=Thermister(val);
      long Temperature=temp;
      lcd.setCursor(13,3);
      lcd.print(Temperature);
      delay(1000);
    }
    //--------------------------------------------------------------------------------------------------

    void Button_1(){
      boolean buttonIsUp_1 = digitalRead(BUTTON_1);

      if (buttonWasUp_1 && !buttonIsUp_1) {
        delay(10);
        buttonIsUp_1 = digitalRead(BUTTON_1);
        if (!buttonIsUp_1) regim++;
        if (regim == OFF) regim = GOROD;
      }
      // запоминаем последнее состояние кнопки для новой итерации
      buttonWasUp_1 = buttonIsUp_1;
    }

    void Button_2(){
      boolean buttonIsUp_2 = digitalRead(BUTTON_2);

      if (buttonWasUp_2 && !buttonIsUp_2) {
        delay(10);
        buttonIsUp_2 = digitalRead(BUTTON_2);
        if (!buttonIsUp_2) regim = OFF;
      }
      // запоминаем последнее состояние кнопки для новой итерации
      buttonWasUp_2 = buttonIsUp_2;
    }


    //--------------------------------------------------------------------------------------------------
    double Thermister(int RawADC){
      double Temp;
      Temp = log(((10240000/RawADC) - 10000));
      Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
      Temp = Temp - 273.15;
      return Temp;
    }
    //--------------------------------------------------------------------------------------------------

    void loop() {

      if (regim > RAIN){
        regim = GOROD;
      }

      SpeedSensorReturnRegim();

      SensorTemp();

      SensorVolt();

      SpeedSensor();

      switch (regim){
      case GOROD:
        OutLCD("Gorod");
        WorkPump( interval_27 );
        break;

      case TRASSA:
        OutLCD("Trassa");
        WorkPump( interval_17 );
        break;

      case RAIN:
        OutLCD("RAIN");
        WorkPump( interval_7 );
        break;

      case OFF:
        OutLCD("OFF");
        Off();
        break;
      }

    }

     
     
  3. chudos

    chudos Нуб

    [QUOTE="Tomasina]

    [/QUOTE]
    Только сейчас заметил,что Вы изменили несколько строк)))
    Спасибо, правда проверить рабоспособность смогу только дома(на работе нет не ардуины, не конпки)
     
  4. chudos

    chudos Нуб

    А зачем это (в функции void Botton_1):
    if(regim == OFF) regim = GOROD;} если в loop{} есть такое:
    if(regim > RAIN){
    regim = GOROD;}
     
  5. Tomasina

    Tomasina Сушитель лампочек Модератор

    в функции void Botton_1 идет последовательное переключение режимов, кроме режима OFF (за это отвечает вторая кнопка).
    Зачем в loop есть условие if (regim > RAIN) - мне пока непонятно.
     
  6. chudos

    chudos Нуб

    Оно у меня изначально там было, а Вы добавили мне в функцию Botton_1()
    if(regim == OFF) regim = GOROD;}

    Возможно, стоит этот код из loop переместить в функцию вместо if(regim == OFF) regim = GOROD;} ведь если я добавлю еще один, два три режима(которые тоже не будут активны по нажатию первой кнопки как и OFF), то
    if(regim > RAIN){
    regim = GOROD;} в функции будет уместно. Так?
     
  7. Tomasina

    Tomasina Сушитель лампочек Модератор

    Оба выражения выполняют одну и ту же функцию, поэтому "остаться должен только один" :)
    Но вот привязываться к RAIN как к крайнему элементу - мне не нравится, при добавлении режимов придется выискивать в коде этот RAIN и менять его на новый элемент. Т.е. возможен фактор человеческой ошибки.
    Привязка к regim == OFF (а лучше даже regim >= OFF) более корректна (при условии что это всегда последний элемент), т.к. позволяет без всяких исправлений добавлять новые режимы, вписывая их перед OFF.
    Что-то кроме кнопки 1 может изменять (увеличивать) режим? Если нет, то логичнее это условие поместить в обработчик кнопок. Если же что-то еще влияет, тогда и в loop() и в обработчик кнопок.
     
  8. chudos

    chudos Нуб

    Попробовал исправленный Вами код...
    Изменения появились, но не те)))
    Теперь после загрузки скетча сразу включается режим OFF.
    И не какие действие (нажатие на кнопки) не помогают.
    Заново вставлю код(у меня там была ошибка):
    Код (C++):
    //Управление сказчиком

    //пины 6 и 3 это кнопки
    //пин 2 выход на насос
    //программа 1 - "город" - 2 капли в минуту (2 открытия в минуту)
    //программа 2 - "трасса" - 3-4 капли в минуту (3-4 открытия в минуту)
    //программа 3 - "дождь" - 10 капель в минуту (10 открытия в минуту)
    //кнопка 3 - выключает автосмажчик
    //!!!!количество открытий в минуту и время открытия пока ориентировочное!!!!

    //Вывод на экран
    //пины 4,5,10-13 для соединения с экраном
    //на экран выводится только информация какой режим сейчас включен
    //Подключаем стандартную библиотеку LiquidCrystal
    //--------------------------------------------------------------------------------------------------


    #include <math.h>
    #include <LiquidCrystal.h>               //библиотека экрана

    #define BUTTON_1                  6      //включает программу смазки 1 - "город" на второй ноге
    //каждое последующее нажатие включает следующую программу
    #define BUTTON_2                  3      //batton_2 - выключает смазчик на 3-й ноге
    #define MOTOR                     7      //транзистор управляющий насосом на 7-й ноге
    #define SPEED_SENSOR              2      //датчик скорости подключен к пину D2
    #define T                         A0     //датчик температуры подключен к А0
    #define SEC                       1000   //1секунда=период таймера(1мс)*коэффициет(1000)
    #define TIME_MEASURE_VOLTAGE      (1 * SEC)
    #define K_VOLT                    0.14   //0.184     //коэффициент делителя(для определения напряжения) (0.14 R1 = 13k, R2 = )
    #define V_MAX                     5
    #define VIN                       A1

    unsigned long speedLimit =        5;     //количество импульсов за один оборот колеса (при скорости примерно 7км/ч)
    //!!!!! ВНИМАНИЕ
    //ЭТО ЗНАЧЕНИЕ НУЖНО ПОЛУЧИТЬ НАТУРНО (ИЗМЕРИТЬ НА ДАТЧИКЕ ПРИ ВРАЩАЮЩЕМСЯ КОЛЕСЕ

    //int val_1 =                       0;     //переменная для хранения состояния кнопки1
    //int val_2 =                       0;     //переменная для хранения состояния кнопки2
    unsigned long sp=                 0;     //переменная для хранения данных с датчика скорости
    unsigned long T_speed =           1000;  //интервал времени для определения текущей скорости (1 секунда)
    unsigned long previousMillis_sp = 0;     //время последнего импульса
    unsigned long previousMillis =    0;     //храним время последнего переключения светодиода
    unsigned long interval_on =       3000;  //интервал между вкл/выкл насоса (3 секунда)
    unsigned long interval_7 =        7000;  //интервал между вкл/выкл насоса (7 секунда)
    unsigned long interval_17 =       17000; //интервал между вкл/выкл насоса (17 секунда)
    unsigned long interval_27 =       27000; //интервал между вкл/выкл насоса (27 секунда)
    boolean buttonWasUp_1 = true;  // была ли кнопка1 отпущена?
    boolean buttonWasUp_2 =          true;  // была ли кнопка2 отпущена?
    uint16_t voltage =               0;
    boolean fMeasureVoltage =        true;
    bool fOn =                       false;
    uint16_t tMeasureVoltage =       TIME_MEASURE_VOLTAGE;

    enum{
      GOROD, TRASSA, RAIN, OFF}
    Regim_t;
    byte regim, prevRegim;
    //enum Rregim = GOROD;

    LiquidCrystal lcd(4,5,10,11,12,13);

    //--------------------------------------------------------------------------------------------------

    void setup (){
       Serial.begin(9600);
      pinMode(MOTOR, OUTPUT);           //транзистор управляющий клапаном на 6-й ноге
      pinMode(BUTTON_1, INPUT_PULLUP);         //кнопка 1 - вход
      pinMode(BUTTON_2, INPUT_PULLUP);         //кнопка 2 - вход
      pinMode(SPEED_SENSOR, INPUT);
      attachInterrupt(0,SpeedSensor, FALLING);  //Подсчет импульсов
      voltage = analogRead(VIN);
      lcd.begin(20, 4);             //устанавливаем размер (количество столбцов и строк) экрана
      lcd.setCursor(0,1);             //устанавливаем курсор
    Serial.println("Smazka-");           //печатаем первую часть строки

      lcd.setCursor(1,2);             //устанавливаем курсор
      lcd.print("Voltage-");            //печатаем первую часть строки

      lcd.setCursor(1,3);             //устанавливаем курсор
      lcd.print("Temperature-");          //печатаем первую часть строки
    }


    //--------------------------------------------------------------------------------------------------

    void OutLCD(String s){           //функция печати на экран режима
      lcd.setCursor(8,1);           //устанавливаем курсор в первую строку, 8-я колонна
    Serial.println(s);
    }

    //--------------------------------------------------------------------------------------------------

    void On(){                //функция отвечающая за включение насоса
      digitalWrite(MOTOR, HIGH);
    }

    void Off(){               //функция отвечающая за выключение насоса
      digitalWrite(MOTOR, LOW);
    }

    //--------------------------------------------------------------------------------------------------

    void WorkPump(int delay){               //функция отвечающая за выбор режима
      unsigned long currentMillis = millis();
      if (fOn) {
        On();
        if(currentMillis - previousMillis > interval_on){ //проверяем не прошел ли нужный интервал,если прошел то
          Off();                      //закрыть клапан
          fOn = false;
          previousMillis = currentMillis;         //сохраняем время последнего переключения
        }
      }
      if (!fOn) {
        Off();
        if(currentMillis - previousMillis > delay){     //проверяем не прошел ли нужный интервал,если прошел то
          fOn = true;
          previousMillis = currentMillis;         //сохраняем время последнего переключения
        }
      }
    }

    //--------------------------------------------------------------------------------------------------

    byte SpeedSensorReturnRegim() {
      unsigned long currentMillis = millis();
      if ((currentMillis - previousMillis_sp > T_speed)&&sp++ <speedLimit){
        prevRegim = regim;
        regim = OFF;
        previousMillis_sp = currentMillis;        //сохраняем время последнего переключения
        lcd.setCursor(11,1);           //устанавливаем курсор в первую строку, 11-я колонна
        lcd.print("non active");
      }
      else{
        regim = prevRegim;
        return regim;
      }
    }

    //--------------------------------------------------------------------------------------------------
    void SpeedSensor(){                   //функция отвечающая за расчет  ограничителя
      unsigned long currentMillis = millis();
      sp++;
      if(((currentMillis - previousMillis_sp) > T_speed) && sp++ <speedLimit){
        regim = OFF;
        previousMillis_sp = currentMillis;        //сохраняем время последнего переключения
        sp=0;
      }
    }

    //--------------------------------------------------------------------------------------------------

    void SensorVolt() {
      int sensorValue;

      if (fMeasureVoltage)
      {
        sensorValue = analogRead(VIN);
        voltage = (int)(((sensorValue / 1023.0f * V_MAX) / K_VOLT) * 1000);
        fMeasureVoltage = false;
      }
      lcd.setCursor(9,2);
      lcd.print(voltage);
      delay(1000);
    }


    //--------------------------------------------------------------------------------------------------

    void Button_1(){
      boolean buttonIsUp_1 = digitalRead(BUTTON_1);

      if (buttonWasUp_1 && !buttonIsUp_1) {
       // delay(10);
        buttonIsUp_1 = digitalRead(BUTTON_1);
        if (!buttonIsUp_1) regim++;
        if (regim == OFF) regim = GOROD;
      }
      // запоминаем последнее состояние кнопки для новой итерации
      buttonWasUp_1 = buttonIsUp_1;
    }

    void Button_2(){
      boolean buttonIsUp_2 = digitalRead(BUTTON_2);

      if (buttonWasUp_2 && !buttonIsUp_2) {
      //  delay(10);
        buttonIsUp_2 = digitalRead(BUTTON_2);
        if (!buttonIsUp_2) regim = OFF;
      }
      // запоминаем последнее состояние кнопки для новой итерации
      buttonWasUp_2 = buttonIsUp_2;
    }


    //--------------------------------------------------------------------------------------------------
    double Thermister(int RawADC){
      double Temp;
      Temp = log(((10240000/RawADC) - 10000));
      Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
      Temp = Temp - 273.15;
      return Temp;
    }
    void SensorTemp(){
      int val;
      double temp;
      val=analogRead(T);
      temp=Thermister(val);
      long Temperature=temp;
      lcd.setCursor(13,3);
      lcd.print(Temperature);
      delay(1000);
    }
    //--------------------------------------------------------------------------------------------------

    void loop() {

    Button_1();
    Button_2();
      SpeedSensorReturnRegim();

      SensorTemp();

      SensorVolt();

      SpeedSensor();

      switch (regim){
      case GOROD:
        OutLCD("Gorod");
        WorkPump( interval_27 );
        break;

      case TRASSA:
        OutLCD("Trassa");
        WorkPump( interval_17 );
        break;

      case RAIN:
        OutLCD("RAIN");
        WorkPump( interval_7 );
        break;

      case OFF:
        OutLCD("OFF");
        Off();
        break;
      }

    }