Проверка выполнения условий

Доброго времени дня. Помогите пжл новичку. Есть эл. шаровый кран с “обратной” связью, т.е. логика такая - дал команду на открытие (закр.) крана, при достижении крайних положений крана на пинах “обратной” связи high или low сигнал. Пытаюсь сделать проверку на “залипание” крана. Допустим, дал команду на открытие крана, если в течении 2 мин пин “обратной” связи изменил своё состояние, все в порядке, пин “обратной” связи не изменил своего состояния за 2 мин-кран залип “Авария”… Вот код, вроде логично, но не работает…

...

#define BUTTON_MANUAL_PIN 4  // Пин, к которому подключена кнопка для ручного управления клапаном
#define VALVE_PIN 5  // Пин, к которому подключен клапан
#define FEEDBACK_PIN 6  // Пин, к которому подключен сигнал обратной связи

bool valveState = false;  // Изначальное состояние клапана - закрыт
bool mode = false;  // Изначальный режим работы - автоматический
uint32_t valveChangeTime;  // Время последнего изменения состояния клапана

void setup() {
...

  pinMode(BUTTON_MANUAL_PIN, INPUT_PULLUP);  // Кнопка для ручного вкл(выкл) клапана - вход
  pinMode(VALVE_PIN, OUTPUT);  // Клапан - выход
  pinMode(FEEDBACK_PIN, INPUT_PULLUP);  // Сигнал обратной связи - вход
}
...

// Функция для проверки аварийной сигнализации
void checkEmergency() {
  // Если состояние клапана не соответствует состоянию обратной связи и прошло больше 2 минут, то включаем аварийную сигнализацию
  if (valveState != digitalRead(FEEDBACK_PIN) && millis() - valveChangeTime > 120000) {  // Если состояние клапана не соответствует состоянию обратной связи и прошло больше 2 минут...    
    lcd.setCursor(0, 3);  // Устанавливаем курсор на начало четвертой строки
    lcd.print("EMERGENCY!!!");  // Выводим на LCD дисплей надпись "EMERGENCY!!!"
  } else {  // Если состояние клапана соответствует состоянию обратной связи или прошло меньше 2 минут...
    lcd.setCursor(0, 3);  // Устанавливаем курсор на начало четвертой строки
    lcd.print("                ");  // Очищаем четвертую строку
  }
}
...
void loop() {
...
  // Управляем клапаном
  digitalWrite(VALVE_PIN, valveState ? HIGH : LOW);  // Если клапан должен быть открыт, то подаем на пин клапана высокий уровень, иначе - низкий
...

P/S LCD и др. обвязку убрал из кода…

1.Откуда вызывается функция checkEmergency()?
2. Где сохраняется значение valveChangeTime?

Уберите из кода так, чтобы код таки работал, безо всяких многоточий, а то вопросы, как у @Дим-мычъ будут возникать постоянно. Просто сделайте работающий код, который любой может запустить и увидеть Вашу проблему.

1.Откуда вызывается функция checkEmergency()?

void loop() {
....
  // Проверяем состояние аварийной сигнализации
  checkEmergency();  // Вызываем функцию для проверки аварийной сигнализации
....
}
  1. Где сохраняется значение valveChangeTime?
uint32_t valveChangeTime;

Или это не то и не там?

Сейчас исправлю.

Это лишь объявление переменной.

// Подключаем библиотеки
#include <Wire.h>  // Библиотека для работы с I2C
#include <OneWire.h>  // Библиотека для работы с 1-Wire устройствами (например, DS18B20)
#include <DallasTemperature.h>  // Библиотека для работы с датчиками температуры Dallas
#include <LiquidCrystal.h>  // Библиотека для работы с LCD дисплеем

// подключение дисплея
/*
 The LCD circuit:
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
*/
#define D7_PIN    19    // пин LCD D7
#define D6_PIN    18    // пин LCD D6
#define D5_PIN    17    // пин LCD D5
#define D4_PIN    16    // пин LCD D4
#define EN_PIN    15    // пин LCD Enable
#define RS_PIN    14    // пин LCD RS

// Определяем пины и устройства
#define ONE_WIRE_BUS 2  // Пин, к которому подключен датчик температуры
#define BUTTON_PIN 3  // Пин, к которому подключена кнопка переключения режима
#define BUTTON_MANUAL_PIN 4  // Пин, к которому подключена кнопка для ручного управления клапаном
#define VALVE_PIN 5  // Пин, к которому подключен клапан
#define FEEDBACK_PIN 6  // Пин, к которому подключен сигнал обратной связи
#define EMERGENCY_LED_PIN 7  // Пин, к которому подключен светодиод аварийного сигнала
#define LED_STATE_PIN 8  // Пин, к которому подключен светодиод, указывающий на состояние клапана
#define LED_PROCESS_PIN 10  // Пин, к которому подключен светодиод, указывающий на процесс открытия/закрытия клапана

// Создаем объекты для работы с температурным датчиком и LCD дисплеем
OneWire oneWire(ONE_WIRE_BUS);  // Создаем объект OneWire для работы с 1-Wire устройствами
DallasTemperature sensors(&oneWire);  // Создаем объект для работы с датчиками температуры Dallas
LiquidCrystal lcd(RS_PIN, EN_PIN, D4_PIN, D5_PIN, D6_PIN, D7_PIN);  // Создаем объект для работы с LCD дисплеем

// Глобальные переменные для состояния клапана, режима работы и времени последнего изменения состояния клапана
boolean butt_flag = 0; // Последнее состояние кнопки на вкл(выкл) клапана
boolean butt; // Текущее состояние кнопки на вкл(выкл) клапана
bool valveState = false;  // Изначальное состояние клапана - закрыт
bool mode = false;  // Изначальный режим работы - автоматический
uint32_t valveChangeTime;  // Время последнего изменения состояния клапана

void setup() {
  // Устанавливаем пины в нужный режим
  pinMode(BUTTON_PIN, INPUT_PULLUP);  // Кнопка переключения режима - вход
  pinMode(BUTTON_MANUAL_PIN, INPUT_PULLUP);  // Кнопка для ручного вкл(выкл) клапана - вход
  pinMode(VALVE_PIN, OUTPUT);  // Клапан - выход
  pinMode(FEEDBACK_PIN, INPUT_PULLUP);  // Сигнал обратной связи - вход
  pinMode(EMERGENCY_LED_PIN, OUTPUT);  // Светодиод аварийного сигнала - выход
  pinMode(LED_STATE_PIN, OUTPUT);  // Светодиод, указывающий на состояние клапана - выход
  pinMode(LED_PROCESS_PIN, OUTPUT);  // Светодиод, указывающий на процесс открытия/закрытия клапана - выход

  // Запускаем датчик и LCD дисплей
  sensors.begin();  // Запускаем датчик температуры
  lcd.begin(20, 4);  // Инициализируем LCD дисплей

  // Запуск серийного порта для отладочных сообщений
  Serial.begin(9600);
}

void checkEmergency() {
  // Если состояние клапана не соответствует состоянию обратной связи и прошло больше 2 минут, то включаем аварийную сигнализацию
  if (valveState != digitalRead(FEEDBACK_PIN) && millis() - valveChangeTime > 120000) {  // Если состояние клапана не соответствует состоянию обратной связи и прошло больше 2 минут...
    digitalWrite(EMERGENCY_LED_PIN, HIGH);  // ... то включаем светодиод аварийного сигнала
    lcd.setCursor(0, 3);  // Устанавливаем курсор на начало четвертой строки
    lcd.blink();  // Включаем мигание курсора
    lcd.print("EMERGENCY!!!");  // Выводим на LCD дисплей надпись "EMERGENCY!!!"
  } else {  // Если состояние клапана соответствует состоянию обратной связи или прошло меньше 2 минут...
    digitalWrite(EMERGENCY_LED_PIN, LOW);  // ... то выключаем светодиод аварийного сигнала
    lcd.noBlink();  // Выключаем мигание курсора
    lcd.setCursor(0, 3);  // Устанавливаем курсор на начало четвертой строки
    lcd.print("                ");  // Очищаем четвертую строку
  }
}
// Функция для управления сигнальными лампами
void controlLeds() {
  // Если состояние клапана изменилось...
  if (valveState != digitalRead(FEEDBACK_PIN)) {
    digitalWrite(LED_STATE_PIN, LOW);
    digitalWrite(LED_PROCESS_PIN, HIGH);  // ... то включаем светодиод, указывающий на процесс открытия/закрытия клапана
  } else {  // Если состояние клапана не изменилось...
    digitalWrite(LED_PROCESS_PIN, LOW);  // ... то выключаем светодиод, указывающий на процесс открытия/закрытия клапана
    digitalWrite(LED_STATE_PIN, HIGH);  
  }
}

void loop() {
   // Считываем текущее состояние кнопки на вкл(выкл) клапана
  butt = !digitalRead(BUTTON_MANUAL_PIN);
  
  // Запрашиваем данные с датчика и выводим температуру на LCD дисплей
  sensors.requestTemperatures();  // Запрашиваем данные с датчика температуры
  float temperature = sensors.getTempCByIndex(0);  // Получаем температуру первого датчика в градусах Цельсия

  lcd.setCursor(0, 0);  // Устанавливаем курсор на начало первой строки
  lcd.print("\240AK \244A\250O\247. HA-");  // Выводим на LCD дисплей надпись "БАК ЗАПОЛ. НА -"
  lcd.setCursor(15, 0);
  lcd.print(temperature,0);  // Выводим на LCD дисплей значение температуры
  lcd.setCursor(19, 0);
  lcd.print("%"); // Выводим на LCD дисплей знак %
  
  // Проверяем состояние кнопки для переключения режима
  if (digitalRead(BUTTON_PIN)) {  // Если кнопка нажата...
    mode = false;  // ... то режим работы ручной
    delay(200);  // Пауза для исключения дребезга контактов кнопки
  } else {  // Если кнопка отжата...
    mode = true;  // ... то режим работы автоматический
    delay(200);  // Пауза для исключения дребезга контактов кнопки
  }
  // Выводим текущий режим на LCD дисплей
  lcd.setCursor(0, 1);  // Устанавливаем курсор на начало второй строки
  lcd.print("PE\243\245M PA\240OT\256 -");  // Выводим на LCD дисплей надпись "РЕЖИМ -"
  lcd.print(mode ? " P\251\253H." : " ABTO");  // Выводим на LCD дисплей текущий режим работы

  // В автоматическом режиме открываем и закрываем клапан в зависимости от температуры
  if (mode == false) {  // Если режим работы - автоматический...
    if (temperature >= 20.0 && valveState == false) {  // ... и температура больше или равна 20 градусам, а клапан закрыт...
      valveState = true;  // ... то открываем клапан
    } else if (temperature < 19.0 && valveState == true) {  // ... и температура меньше 19 градусов, а клапан открыт...
      valveState = false;  // ... то закрываем клапан
    }
  }
  // В ручном режиме открываем и закрываем клапан по нажатию кнопки
  if (mode == true && butt == true && butt_flag == false) {  // Если режим работы - ручной и нажата кнопка для ручного управления клапаном...
    valveState = !valveState;  // ... то меняем состояние клапана на противоположное
    delay(200);  // Пауза для исключения дребезга контактов кнопки
    butt_flag = 1;
    Serial.println ("Button pressed");
  }
  if (mode == true && butt == false && butt_flag == true) { // Если режим работы - ручной и отжата кнопка для ручного управления клапаном...
     butt_flag = 0; 
     Serial.println ("Button released");
  }     
  
  // Управляем клапаном
  digitalWrite(VALVE_PIN, valveState ? HIGH : LOW);  // Если клапан должен быть открыт, то подаем на пин клапана высокий уровень, иначе - низкий
  
  // Выводим состояние клапана на LCD дисплей
  lcd.setCursor(0, 2);  // Устанавливаем курсор на начало третьей строки
  lcd.print("KPAH         -");  // Выводим на LCD дисплей надпись "KPAH         -"
  if (digitalRead(VALVE_PIN) == HIGH) {
    lcd.print(" OTKP.");
  }
  if (digitalRead(VALVE_PIN) == LOW) {
    lcd.print(" \244AKP.");
  }  
  

  // Проверяем состояние аварийной сигнализации
  checkEmergency();  // Вызываем функцию для проверки аварийной сигнализации

  // Управляем сигнальными лампами
  controlLeds();  // Вызываем функцию для управления сигнальными лампами
}

@mixxx

уточните, что означает “не работает” в этом случае.
Сигнализация не срабатывает вообще или срабатывает не так или не тогда, как вы планировали?
Поподробнее

Принудительно моделирую режим “авария”. Т.е. нажал кн для открытия (закрытия) крана, а состояние пина “обратной” связи не меняю более 2 мин и ничего на LCD не меняется.

Как исправить ситуацию?

Посмотрите примеры работы с миллис
https://forum.arduino.ru/t/primer-blink-migaem-svetodiodom/9361

так вы время начала переключения не запоминаете нигде.

Единственное, я правда не понимаю, почему у вас тревога не включается. На самом деле она у вас должна всегда гореть - работает кран или нет.

Спасибо изучу тему.

Потому что новичок, для меня это и так титаническая работа))))) Не пинайте сильно)

А эта функция

правильно работает?
Светодиод переключения клапана зажигается на время поворота и гаснет, когда клапан повернулся?

Физически еще пока не проверял, т.к. схему собрал “на коленках” и не полную, и затуп у меня с “аварией”

начните с проверки этой функции. Она проще, зато вы будете знать, что у вас фидбеки на клапанах правильно работают.

Понял, по результатам отпишусь… Очень сильно грешу на

millis();

как-то у меня все просто с ними)

Я вам про controlLeds() посоветовал не в связи с вашей проблемой , а отдельно. То что вам надо разобраться с миллис - это само собой.

Вот здесь ещё посмотреть можно
https://forum.arduino.ru/t/zaderzhka-v-funkczii/8783/17

https://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/vypolnenie-koda-vo-vremya-zaderzhki#comment-667325