Прошу помочь с выполнением действия в заданном интервале времени

bablja

✩✩✩✩✩✩✩
17 Июл 2019
15
0
Всем привет. Делаю контроллер для аквариума чтобы в нужное время кормил, освещал и проч.
Из железа ардуина уно, шаговый двиг и модуль реле на 4 канала.
Для выполнения действия по времени делаю так:

if (time.Hours == 4 && time.minutes == 00 && time.seconds == 00 )//Включение лампы подсветки растений
{
digitalWrite(4, LOW);
}
if (time.Hours == 22 && time.minutes == 00 && time.seconds == 00 )//Выключение лампы подсветки растений
{
digitalWrite(4, HIGH);
}
Но вот в чем засада. Действие выполняется в заданное время, а не в заданный интервал времени. Как задать интервал времени, в котором будет срабатывать реле?


Мой скетч:
#include <Stepper.h>
#define STEPS 200
#include <iarduino_RTC.h>
#define pin_SW_SDA 4
#define pin_SW_SCL 5
iarduino_RTC time(RTC_DS3231);
Stepper motor(STEPS, 8, 9, 10, 11);
void setup()
{
  motor.setSpeed(60);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  delay(300);
  Serial.begin(9600);
  time.begin();
  //time.settime(0,05,19,14,04,20,2);  //   сек,  мин,  час, число, месяц, год, вторник
  digitalWrite(3, HIGH);  //Фильтр нижняя розетка
  digitalWrite(4, HIGH);  //Лампа верхняя розетка
  digitalWrite(5, HIGH);  //красные светодиоды
  digitalWrite(6, HIGH); // белые светодиоды
}
void stopen()
{
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
}
void loop()
{
  if (millis() % 1000 == 0) { // если прошла 1 секунда
    Serial.println(time.gettime("d-m-Y, H:i:s, D")); // выводим время
    if (time.Hours == 7 && time.minutes == 20 && time.seconds == 0 )// ВРЕМЯ 1 КОРМЛЕНИЯ
    {
      motor.step(256);
      stopen();
    }
    if (time.Hours == 20 && time.minutes == 00 && time.seconds == 0 )// ВРЕМЯ 2 КОРМЛЕНИЯ
    {
      motor.step(256);
      stopen();
    }
       if (time.Hours == 8 && time.minutes == 00 && time.seconds == 00 )//включение фильтра после кормления
    {
      digitalWrite(3, LOW);
    }
    if (time.Hours == 19 && time.minutes == 59 && time.seconds == 30 )//выключение фильтра перед 2 кормлением
    {
      digitalWrite(3, HIGH);
    }
    if (time.Hours == 20 && time.minutes == 15 && time.seconds == 00 )//включение фильтра после 2 кормления
    {
      digitalWrite(3, LOW);
    }
     if (time.Hours == 21 && time.minutes == 30 && time.seconds == 0 )//выключение фильтра на ночь
    {
      digitalWrite(3, HIGH);
    }
    if (time.Hours == 4 && time.minutes == 00 && time.seconds == 00 )//Включение лампы подсветки растений
    {
     digitalWrite(4, LOW);
    }
   if (time.Hours == 22 && time.minutes == 00 && time.seconds == 00 )//Выключение лампы подсветки растений
    {
    digitalWrite(4, HIGH);
    }

        // настройки включения лент светодиодов
    if (time.Hours == 6 && time.minutes == 30 && time.seconds == 00 )//Включение рассвета
    {
     digitalWrite(5, LOW);
    }
    if (time.Hours == 18 && time.minutes == 00 && time.seconds == 00 )//Включение подсветки белой
    {
    digitalWrite(6, LOW);
    }
     if (time.Hours == 9 && time.minutes == 30 && time.seconds == 00 )//ВЫключение рассвета
    {
    digitalWrite(5, HIGH);
    }
   if (time.Hours == 19 && time.minutes == 55 && time.seconds == 00 )//Выключение подсветки белой перед 2 кормлением
    {
   digitalWrite(6, HIGH);
    }
     if (time.Hours == 19 && time.minutes == 00 && time.seconds == 00 )//Включение заката вечером
    {
     digitalWrite(5, LOW);
    }
   // if (time.Hours == 20 && time.minutes == 00 && time.seconds == 00 )//Включение подсветки вечером
    {
    // digitalWrite(6, LOW);
    }
     if (time.Hours == 21 && time.minutes == 30 && time.seconds == 30 )//Выключение заката вечером
    {
      digitalWrite(5, HIGH);
    }
    //if (time.Hours == 20 && time.minutes == 30 && time.seconds == 00 )//Выключение подсветки вечером
    {
    //digitalWrite(6, HIGH);
    }
  }
}
// подключение шагового двигателя
// ардуино----------драйвер
// пин 8--------------пин in 1
// пин 9--------------пин in 3
// пин 10-------------пин in 2
// пин 11-------------пин in 4
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
есть время начало работы и есть время конца работы.
Берем произвольное время. и начинаем его проверять. Как ? Вот так:
Если произвольное время больше времени начала работы и меньше времени конца работы то:
{
если лампа выключена, то включить и запомнить, что включили.
}
иначе // это иначе к 1-ому словию по времени!
{
если лампа включена, то вЫключить и запомнить, что вЫключили.
}

в принципе внутренние условия можно не использовать, а просто включать лампу все это время, пока должна быть включена, включить включенное не выйдет еще раз, так же как и выключить выключенное
 
  • Лойс +1
Реакции: bablja

bort707

★★★★★★✩
21 Сен 2020
3,067
916
Как задать интервал времени, в котором будет срабатывать реле?
Для реле интервал вам не нужен. Реле срабатывает моментально, а не в "интервале".
Попытайтесь сформулировать задачу для интервала - может тогда сами поймете, как ее решить.
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
Как я понимаю, если устройство включить в интервале (время включения; время выключения), то реле не сработает, прям задача из соседней ветки, https://community.alexgyver.ru/threads/perevod-chasov-v-minuty-dlja-raboty-tajmera-rele.4412/

Либо вот тут могут быть проблемы
if (millis() % 1000 == 0) { // если прошла 1 секунда
так как во время цикла много опросов модуля часов, можно перескочить миллисекунду, что не даст сработать действиям внутри этого условия, чтобы ускорить программу и снизить количество опросов модуля, можно сразу после входа в это условие один раз присвоить значение часов в временные переменные и потом уже их подставлять в условия.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
@bort707, Наверное Вы немного не поняли автора. Или я не понял.
Но сейчас в его алгоритме включение идет тлько при достижении определенного момента, если этот момент пролюбить (не важно почему, хоть включить устройство на 2 сек. позже) то лампа не включится. А должна. Т.е. включать лампу надо в любой момент времени из интервала, если она выключена.То же самое с выключением
 
  • Лойс +1
Реакции: bablja и bort707

bort707

★★★★★★✩
21 Сен 2020
3,067
916
Изменено:
  • Лойс +1
Реакции: bablja

bablja

✩✩✩✩✩✩✩
17 Июл 2019
15
0
@bort707,
Если у меня условие задано так, то все работает
Работает:
if (time.Hours >= 20)
      if (time.Hours <= 21)
        digitalWrite(LED_BUILTIN, HIGH);
      else
        digitalWrite(LED_BUILTIN, LOW);
А если добавить минуты, секунды
не работает:
if (time.Hours >= 20 && time.minutes == 30 && time.seconds == 0 )
      if (time.Hours <= 21 && time.minutes == 30 && time.seconds == 0 )
        digitalWrite(LED_BUILTIN, HIGH);
      else
        digitalWrite(LED_BUILTIN, LOW);
то не работает нифига.
то же самое с конструкцией
C++:
if ((time.Hours >= 20) & (time.Hours <= 21))
        digitalWrite(LED_BUILTIN, HIGH);
      else
        digitalWrite(LED_BUILTIN, LOW);
 
Изменено:

Старик Похабыч

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
Потому что неверное понимание условия. 30 минут есть в любом часа. Для однозначности идентификации времени переведите все в минуты. И 20 асов 30 минут у вас будет 1230 минут. И условие будет (время >1230) . Если же Вам нужно светить с секундной точность, то переводите в секунды. Но , на мой взгляд, это уже лишнее.
 
  • Лойс +1
Реакции: bablja

SUPERNYAMSTER

✩✩✩✩✩✩✩
19 Дек 2020
27
1
C++:
if (time.Hours >= 20 && time.minutes == 30 && time.seconds == 0 )
      if (time.Hours <= 21 && time.minutes == 30 && time.seconds == 0 )
        digitalWrite(LED_BUILTIN, HIGH);
я вот сидел и читал прям интепритированный перевод этих слов.
C++:
если ( час>=20 и минуты = 30 и секунды = 0) // если да то следующий шаг
    если ( час<=21 и минуты = 30 и секунды = 0)
         то (записать что то куда то)
упрощенно: в 20:30 будет время 21:30
time.seconds=0 можно не указывать.
если тебе опеределенно точно важно работать именно с часом и минутой. то надо переводить время в минуты. а если не критичны минут, то проще работать только с часом как у меня в соседней ветке.
если где то там используеш реле, то не делай в него digitalWrite. дай ему flag и дергай его по инверсии
 

poty

★★★★★★✩
19 Фев 2020
3,261
949
Последняя конструкция написана неверно, вместо && - логическое И - написано & - побитовое умножение. Не уверен, что в данном случае это имеет значение
А если добавить минуты, секунды
Попробуйте найти условие, при котором это выполняется. Первый интервал длиной в 1 секунду будет выполняться каждый час, начиная с 20:30 включительно до 23:30 включительно. Второй интервал - не вводит никаких дополнительных ограничений по минутам и секундам, но вводит ограничение по часам (меньше или равно 21). Т.е. единственный раз, когда "сойдутся" оба условия - 20:30 (и переведут порт в HIGH). Как сказал @Старик Похабыч , если "пролюбить" этот интервал размером в секунду, то больше внутрь условия HIGH мы не попадём.
Теперь про условие LOW: ну вот никак не хочется Вам, видимо, читать! В соседней ветке, на которую давали ссылку, уже разбирали вложенный if. Фактически, мы в условие LOW попадём только на секунду в 21:30, 22:30 и 23:30.
Вывод: никакого интервала эта запись не определяет, лишь некоторые точки.
то же самое с конструкцией
Замените "&" на "&&".
 
Изменено:

bablja

✩✩✩✩✩✩✩
17 Июл 2019
15
0
Спасибо вам всем за то что помогаете начинающим. Заработал вот этот вариант.
C++:
int a = ((time.Hours * 60) + time.minutes);  // пересчитываем время в минуты
    if ((a >= 1218) && (a <= 1226)) // задаю интервал в минутах
        digitalWrite(LED_BUILTIN, HIGH);
      else
        digitalWrite(LED_BUILTIN, LOW);
Только неудобно вручную пересчитывать время в минуты, при установке периодов. Может есть способ задать его в нормальном виде, а программа чтобы сама пересчитала в минуты и использовала в дальнейшем.
 

poty

★★★★★★✩
19 Фев 2020
3,261
949
Оформите эти числа в виде макроса или, если заморачиваться не хотите, просто сделайте несколько define:
C++:
#define hour 60
#define min 1

if (a>=21*hour+30*min) ...
 

Александр Симонов

★★★★✩✩✩
2 Авг 2018
727
208
Для удобочитаемости можно часы умножать на 100.

Допустим, если включаем в 9:30, выключаем в 12:15, получается такой код:
C++:
int a = ((time.Hours * 100) + time.minutes); 
if ((a >= 930) && (a <= 1215))
    digitalWrite(LED_BUILTIN, HIGH);
else
    digitalWrite(LED_BUILTIN, LOW);
Так удобней писать условия, время получается человекочитаемое.

И кстати, подобные условия (если выполняется, то включить, если нет, то выключить) можно ещё сократить, до такого вида:
C++:
int a = time.Hours * 100 + time.minutes; 
digitalWrite(LED_BUILTIN, a >= 930 && a <= 1215);
 
  • Лойс +1
Реакции: bablja и DAK

bablja

✩✩✩✩✩✩✩
17 Июл 2019
15
0
@Александр Симонов, сокращенная запись просто супер! На этом форуме каждый ответ приводит меня к дополнительным вопросам. Заметил что если задать 2 условия включения
C++:
int a = ((time.Hours * 100) + time.minutes);
    digitalWrite(LED_BUILTIN, a >= 1927 && a <= 1928);
    digitalWrite(LED_BUILTIN, a >= 1930 && a <= 1931);
то срабатывает только последнее. Почему так?
 

SUPERNYAMSTER

✩✩✩✩✩✩✩
19 Дек 2020
27
1
потому что программа идет сверху вниз. так то и первое включается, но на 1 микросекунду