Применение millis для нескольких процессов

restiv
Offline
Зарегистрирован: 03.01.2016

Добрый вечер!

Подкажите пожалуйста как с помощью каманды millis управлять несколькими процессами? Есть такой кусок коды:

 static bool state1;
  static unsigned long time;
  if((millis() - time) > (state1 ? 10000 : 20000)) // первое число отображает время одного положения в мск, второе число отображает длительность второго состояния реле
 {
  state1 = !state1;
  digitalWrite(relay1, state1);
  time = millis();

Данный кусочек кода управляет включением и отключением реле через определенный интервал времени. Есть необходимость управлять таким же образом еще двумя реле. Подскажите пожалуйста как можно это организовать, никак не получается самому допереть?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Опишите класс для управления процессом и содайте по экземпляру на каждый процесс. Тогда сложно будет такая же, как для одного процесса. А если Вы будете пытаться всё описать в одной простыне - свихнётесь и всё равно что-то будет вылазить.

restiv
Offline
Зарегистрирован: 03.01.2016

ЕвгенийП пишет:

Опишите класс для управления процессом и содайте по экземпляру на каждый процесс. Тогда сложно будет такая же, как для одного процесса. А если Вы будете пытаться всё описать в одной простыне - свихнётесь и всё равно что-то будет вылазить.

Подскажите пожалуйста, что значит "описать класс"? Я только учусь и это пока для меня сложновато. Может есть пример?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

http://arduino.ru/forum/programmirovanie/klassy-arduino-po-qwone-dlya-ch...

Если конечно не свихнетесь читать.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

restiv пишет:

Подскажите пожалуйста, что значит "описать класс"? Я только учусь и это пока для меня сложновато. Может есть пример?

Примеров миллион. Открываюте почти любую библиотеку и смотрите. Они почти вес состоят из описаний классов.

А вообще, прочтите книгу Страуструпа по С++, там всё написано. Найдёте. 

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

ЕвгенийП пишет:

А вообще, прочтите книгу Страуструпа по С++, там всё написано. Найдёте. 

если человек не может в логике работы разобраться, то cкорее всего ТрупСтрауса не осилит :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Хочет разобраться - осилит. Будет не просто читать, а реально запускать примеры оттуда, смотреть как работают, пробовать осмысленно менять, и в каком-нибудь объёме осилит. ООП вообще штука непростая, и всех тонкостей его не знают процентов 90 реально работающих программистов (а "прогеров" - так все 100%). Но на каком-то уровне осилить вполне можно.

restiv
Offline
Зарегистрирован: 03.01.2016

Очень хочу осилить и буду потихоньку читать, изучать, пробовать, вам вопросы задавать, но проблемка в том, что на это уйдет время и не мало, поскольку я не могу все свое свободное время тратить на изучение. А решение задачки нужно найти в ближайшие пару дней, потом уеду на вахту и не смогу в течении месяца решить задачку... (((

Efim
Offline
Зарегистрирован: 04.05.2018

restiv

Полностью код выложите.

andryn
Offline
Зарегистрирован: 08.06.2018

restiv пишет:

Подкажите пожалуйста как с помощью каманды millis управлять несколькими процессами? 

А что мешает завести еще 2 переменные для времени и для state?

Типа такого:

static bool state2;
static unsigned long time2;
if((millis() - time2) > (state2 ? 10000 : 20000))
 {
    state2 = !state2;
    time2 = mills();
    ....
}

Или я что-то в попросе недопонимаю?

 

b707
Offline
Зарегистрирован: 26.05.2017

andryn пишет:

Или я что-то в попросе недопонимаю?

можно и так, хотя это плохой стиль. Всякий раз, когда вам приходится размножать куски кода копированием - это означает, что вы неэффективно спроектировали программу.

triac
triac аватар
Offline
Зарегистрирован: 03.05.2018

restiv пишет:

Подкажите пожалуйста как с помощью каманды millis управлять несколькими процессами?

Берете библиотеку coos, описываете каждый процесс как самостоятельную  задачу, регистрируете задачи и запускаете шедулер. Там в примере показано как двумя задачами мигать светодиодом, а вообще задач можно довольно много наплодить.

После этого у вас все задачи исполняются одновременно. Надо только обязательно в каждой задаче хотя бы раз вызывать задержку COOS_DELAY(x), причем именно в теле самой задачи, а не в функции, которую вызывает задача.

 

 

restiv
Offline
Зарегистрирован: 03.01.2016

Я так пробовал делать. Но не работает так.

restiv
Offline
Зарегистрирован: 03.01.2016

Пожалуйста! Вот весь код.

#include <Wire.h>                                                                           //Подключаем библиотеку для использования I2C интерфейса с модулем RTC 
#include <RTClib.h>                                                                         //Подключаем библиотеку для использования модуля часов реального времени RTC

#define relay1 5
#define RelayChn1 8

unsigned long prevMillis;

#define PWM_MIN 0                                                                            //Если необходим ток покоя на LED - изменить эту константу
#define PWM_MAX 200                                                                          //Если необходимо ограничить максимальную яркость - уменьшить значение
#define PWM_PIN 6                                                                            //Пин порта, где будет ШИМ

#define mn 60UL                                                                              //Дополнительные константы для удобства
#define hr 3600UL                                                                            //Отражают соответствующие количества секунд 
#define d 86400UL

//------------------------------------------------------------------
class time{
public:
        time(unsigned char h=0, unsigned char m=0, unsigned char s=0){
            set_time(h, m, s);
        }
        time&   operator = (time &t){hour = t.hour; min = t.min; sec = t.sec; seconds = t.seconds; return *this;}
        boolean operator ==(time &t){return seconds==t.get_time();}
        boolean operator !=(time &t){return !(*this==t);}
        boolean operator > (time &t){return seconds>t.get_time();}
        boolean operator < (time &t){return seconds<t.get_time();}
        boolean operator >=(time &t){return seconds>=t.get_time();}
        boolean operator <=(time &t){return seconds<=t.get_time();}
        void set_time(unsigned char h, unsigned char m, unsigned char s){
            hour=h; min=m; sec=s;
            seconds=(unsigned long)h*1440 + (unsigned long)m*60 + s;
        }
        unsigned long get_time(){return seconds;};
        void print()    {Serial.print(hour); Serial.print(':');Serial.print(min); Serial.print(':');Serial.println(sec);}
private:
        unsigned char   hour;
        unsigned char   min;
        unsigned char   sec;
        unsigned long   seconds;
};
//------------------------------------------------------------------
class relay{
public:
    relay(unsigned char pin){
        pin_num = pin;
        pinMode(pin_num, OUTPUT);
        digitalWrite(pin_num, 1); 
        state=0;
    }
    void operator =(boolean val) {digitalWrite(pin_num, !val); state=val;}
    operator boolean()  {return state;}
private:
    unsigned char   pin_num;
    boolean         state;
};                    
//------------------------------------------------------------------

RTC_DS1307 RTC;     

//------------------------------------------------------------------
time    cur_time;
time    relay_1_on(07, 00, 00);          // Время включения 1-ого реле
time    relay_1_off(22, 00, 00);        // Время отключения 1-ого реле  
relay   relay_1(RelayChn1);             // Реле 1 
//------------------------------------------------------------------

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

long sunrise_start = 07*hr+05*mn;                                                             //Начало восхода в 9 - 45 
long sunrise_duration = 55*mn;                                                                //Длительность восхода 30 минут     
long sunset_start = 21*hr+00*mn;                                                              //начало заката в 21-15
long sunset_duration = 55*mn;                                                                 //Длительность заката 30 минут 
//********************************************************************************************
void setup(){
  pinMode(relay1, OUTPUT); 
  //pinMode(relay2, OUTPUT);   
  Wire.begin();                                                                               //Инициируем I2C интерфейс
  RTC.begin();                                                                                //Инициирум RTC модуль
  analogWrite(PWM_PIN, PWM_MIN);                                                              //Пишем в порт минимальное значение 
  Serial.begin(9600);                                                                         //Запускаем сом-порт
  delay(3000);                                                                                //Ожидаем открытия консоли

  if (! RTC.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

    RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));                                         //Текущая строка выводит дату и время компиляции скетча. После заливки скетча нужно закомментировать. 
    //RTC.adjust(DateTime(2018, 4, 30, 16, 36, 0));                                           //Текущая строка предназначена для ручного ввода даты и времени в формате: Мес. день, год часы, минуты, секунды. 
    
}                                                                                             // КОНЕЦ ИНИЦИАЛИЗАЦИИ

//********************************************************************************************
void loop()                                                                                   // ПРОГРАММЫй безусловный ЦИКЛ 
{
  
    long pwm; 
    DateTime myTime = RTC.now();                                                              //Читаем данные времени из RTC при каждом выполнении цикла
    long Day_time = myTime.unixtime() % 86400;                                                //сохраняем в переменную - время в формате UNIX
//*********************************************************************************************
//           обработка интервала до восхода и после заката
//*********************************************************************************************
    if ((Day_time<sunrise_start) ||                                                           //Если с начала суток меньше чем начало восхода 
        (Day_time>=sunset_start+sunset_duration)) {                                           //Или больше чем начало заката + длительность
            pwm = PWM_MIN;                                                                    //Величина для записи в порт равна минимуму  

//*********************************************************************************************
//           обработка интервала восхода 
//*********************************************************************************************
    }else if ((Day_time>=sunrise_start) &&                                                    //Если с начала суток больше чем начало восхода
              (Day_time<sunrise_start+sunrise_duration)){                                     //И меньше чем начало восхода + длительность 
                  pwm =  ((Day_time - sunrise_start)*(PWM_MAX-PWM_MIN)) / sunrise_duration;   //Вычисляем для рассвета величину для записи в порт ШИМ

//*********************************************************************************************
//           обработка интервала заката 
//*********************************************************************************************
    }else if ((Day_time>=sunset_start) &&                                                     //Если  начала суток больше чем начало заката и меньше чем  
              (Day_time<sunset_start+sunset_duration)){                                       //начало заката плюс длительность
      pwm = ((sunset_start+sunset_duration - Day_time)*(PWM_MAX-PWM_MIN)) / sunrise_duration; //Вычисляем для заката величину для записи в порт ШИМ
 
//********************************************************************************************
//           обработка интервала от конца рассвета и до начала заката,
//           когда свет должен быть включен на максимальную яркость 
//********************************************************************************************
    }else {
                  pwm = PWM_MAX;                                                              //Устанавливаем максимальную величину для записи в порт ШИМ 
    }
    analogWrite(PWM_PIN, pwm);                                                                //Пишем в порт вычисленное значение           
  
    DateTime now = RTC.now();
    
    Serial.print(now.day(), DEC);
    Serial.print('.');
    Serial.print(now.month(), DEC);
    Serial.print('.');
    Serial.print(now.year(), DEC);
    Serial.print(" (");
    Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.print(") ");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.print("  ");
    Serial.print("PWM=");
    Serial.print(pwm);
    Serial.println();
    delay(1000);

  static bool state1;
  static unsigned long time;
  if((millis() - time) > (state1 ? 1800000 : 20000)) // первое число отображает время одного положения в мск, второе число отображает длительность второго состояния реле
 {
  state1 = !state1;
  digitalWrite(relay1, state1);
  time = millis();
 }
 
    cur_time.set_time(myTime.hour(), myTime.minute(), myTime.second());  // Устанавливаем часы, минут, секунды в cur_tim
//------------КАНАЛ 1 (Контроль температуры по времени) -------
//    sensors.requestTemperatures();

    relay_1 = (cur_time>=relay_1_on) && (cur_time<relay_1_off);     // Состояние реле 1 = нахождение текущего времени в диапазоне от relay_1_on до relay_1_off и в диапазоне заданных температур 
}//------------Конец ЦИКЛА-----------------------------

 

restiv
Offline
Зарегистрирован: 03.01.2016

[/quote]

А что мешает завести еще 2 переменные для времени и для state?

Типа такого:

static bool state2;
static unsigned long time2;
if((millis() - time2) > (state2 ? 10000 : 20000))
 {
    state2 = !state2;
    time2 = mills();
    ....
}

Или я что-то в попросе недопонимаю?

 

[/quote]

Я так пробовал. Не работает код.

andryn
Offline
Зарегистрирован: 08.06.2018

restiv пишет:

Я так пробовал. Не работает код.

Вот так работает(убрал все не относящиеся к реле):

#define relay1 5
#define relay2 6 //Например реле 2 на 6-м пине

void setup(){
  pinMode(relay1, OUTPUT); 

  Serial.begin(115200);          //Запускаем сом-порт
  Serial.println("Test start");
    
}                               // КОНЕЦ ИНИЦИАЛИЗАЦИИ

void loop()                     // ПРОГРАММЫй безусловный ЦИКЛ 
{
   static bool state1;
   static unsigned long time;
   if((millis() - time) > (state1 ? 1800 : 20)) // уменьшил цифры на 3 порядка, чтобы не ждать сутки :)
   {
      state1 = !state1;
      digitalWrite(relay1, state1);
      Serial.print("relay1:");
      Serial.println(state1);
      
      time = millis();
   }
   //Для второго реле
   static bool state2;
   static unsigned long time2;
   if((millis() - time2) > (state2 ? 1800 : 20)) // уменьшил цифры на 3 порядка, чтобы не ждать сутки :)
   {
      state2 = !state2;
      digitalWrite(relay2, state2);
      Serial.print("relay2:");
      Serial.println(state2);
      
      time2 = millis();
   }
}

Или я что-то всетаки недопонимаю?

restiv
Offline
Зарегистрирован: 03.01.2016

andryn пишет:

restiv пишет:

Я так пробовал. Не работает код.

Вот так работает(убрал все не относящиеся к реле):

#define relay1 5
#define relay2 6 //Например реле 2 на 6-м пине

void setup(){
  pinMode(relay1, OUTPUT); 

  Serial.begin(115200);          //Запускаем сом-порт
  Serial.println("Test start");
    
}                               // КОНЕЦ ИНИЦИАЛИЗАЦИИ

void loop()                     // ПРОГРАММЫй безусловный ЦИКЛ 
{
   static bool state1;
   static unsigned long time;
   if((millis() - time) > (state1 ? 1800 : 20)) // уменьшил цифры на 3 порядка, чтобы не ждать сутки :)
   {
      state1 = !state1;
      digitalWrite(relay1, state1);
      Serial.print("relay1:");
      Serial.println(state1);
      
      time = millis();
   }
   //Для второго реле
   static bool state2;
   static unsigned long time2;
   if((millis() - time2) > (state2 ? 1800 : 20)) // уменьшил цифры на 3 порядка, чтобы не ждать сутки :)
   {
      state2 = !state2;
      digitalWrite(relay2, state2);
      Serial.print("relay2:");
      Serial.println(state2);
      
      time2 = millis();
   }
}

Или я что-то всетаки недопонимаю?

Да, данный код работает, но не совсем корректно. Как и в вашем случае я забыл проинициализировать выход второго реле как OUTPUT. Поэтому код не работал. Но когда я подправил данный косяк код заработал, но как то странно. Время запуска первого и второго реле не совпадали. Я не знаю почему. Первое реле запускается и отрабатывает как положенно, а втрое реле сразу не запускается, а запускается только через какое то время и получается, что два реле работают в разнобой. А мне нужно, чтобы они запускались одновременно, а отключались в разное время.

restiv
Offline
Зарегистрирован: 03.01.2016

restiv]</p> <p>[quote=andryn пишет:

   if((millis() - time) > (state1 ? 1800 : 20)) // уменьшил цифры на 3 порядка, чтобы не ждать сутки :)
  

А почему речь идет о сутках? 1800000 мск - это же всего 15 минут. Или я что то не понимаю?

sadman41
Offline
Зарегистрирован: 19.10.2016

Можете ли вы сделать две вещи: определить событие, по которому начинается отсчет и произвести действие по истечению временного интервала? Если две этих задачи сумеете решить раздельно, то масштабировать свой скетч сумеете хоть до ста независимых выдержек.

restiv
Offline
Зарегистрирован: 03.01.2016

sadman41 пишет:

Можете ли вы сделать две вещи: определить событие, по которому начинается отсчет и произвести действие по истечению временного интервала? Если две этих задачи сумеете решить раздельно, то масштабировать свой скетч сумеете хоть до ста независимых выдержек.

Я бы с радостью "определить событие, по которому начинается отсчет", но не знаю как. Знаний пока не достаточно.

andryn
Offline
Зарегистрирован: 08.06.2018

Если нужна синхронная работа, то напишите digitalWrite(relay2, state1); после digitalWrite(relay1, state1);

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

b707 пишет:
можно и так, хотя это плохой стиль.

А у меня стойкое убеждение что классы - это автоматически подразумевает "не жалко памяти". Так что лично я лучше уж покопирую лишний раз, но возможно, однажды меня и переубедят. Пока не знаю, избегаю пользоваться классами. Исключение - библиотечные, типа LCD и RF24.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Voodoo Doll пишет:
А у меня стойкое убеждение что классы - это автоматически подразумевает "не жалко памяти". Так что лично я лучше уж покопирую лишний раз, но возможно, однажды меня и переубедят.
В корне не верное представление. Вот вы заказываете в Китае компоненты. они приходят в бумажных коробочках с сильной упаковкой. А зачем. Если грузить навалом, как песок, то можно загрузить раз в 10 больше. А значит и пересылка дешевле. Но почему нет. Скорее потому что придет 100% лом, который никому не нужен.  Так и с классами. Это упаковка для того что бы в программе не получился фарш из-за похожих названий и взаимного перекрывания. И да классы позволяют работать не в час по чайной ложке, а грузить сразу большими упаковками. Это экономит человеческие усилия.

Logik
Offline
Зарегистрирован: 05.08.2014

много раз уже проверяли, переход к ООП это + 10-20% к ОЗУ и - 5-10% к производительности. qwone, вам уже десяток людей писали что ваше представление о классах - такое  https://www.youtube.com/watch?v=J-_tf-XULUM . Не в упаковках дело, а в более высоком уровне абстрагирования. Разумеется там где он нужен.

sadman41
Offline
Зарегистрирован: 19.10.2016

restiv пишет:

Я бы с радостью "определить событие, по которому начинается отсчет", но не знаю как. Знаний пока не достаточно.

Если вы не знаете, с какого момента нужно выдерживать временной интервал, то ваша задача не имеет осмысленного решения (или имеет миллиарды равнозначно бессмысленных). Механизм формирования кода из неоформившихся ощущений пользователя в ардуину пока что не встроен.

restiv
Offline
Зарегистрирован: 03.01.2016

sadman41 пишет:

Если вы не знаете, с какого момента нужно выдерживать временной интервал, то ваша задача не имеет осмысленного решения (или имеет миллиарды равнозначно бессмысленных). Механизм формирования кода из неоформившихся ощущений пользователя в ардуину пока что не встроен.

В принципе можно и с начала запуска работы МК запускать эти процессы или через минуту после включения МК. Мне не столь важно начало процесса, главное, чтобы они начинались одновременно.

sadman41
Offline
Зарегистрирован: 19.10.2016

Представьте, что перед вами секундомер. Вам нужно одновременно включить настольную лампу, верхний свет и фонарик. Настольная лампа должна гореть 15сек, верхний - 35сек, фонарик - 43сек. Как в реальной жизни эту задачу бы решали?

restiv
Offline
Зарегистрирован: 03.01.2016

andryn пишет:
Если нужна синхронная работа, то напишите digitalWrite(relay2, state1); после digitalWrite(relay1, state1);

А что есть разница, где писать digitalWrite(relay2, state1); после digitalWrite(relay1, state1)??? Неужели если они будут расписанны как в скетче - это может привести к разнице в задержке запусков реле в несколько минут???

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Logik, специально для узбеков говорю. Если вы думаете , упаковка в классы и упаковка архивы это одно и тоже.То это две большие разницы. Опять же  абстрагироваться можно по разному. И потерей ОЗУ и с потерей производителености и вообще самому потеряться в абстракциях. Так что вы завязыватете с тяжелыми астракциями.

restiv
Offline
Зарегистрирован: 03.01.2016

sadman41 пишет:

Представьте, что перед вами секундомер. Вам нужно одновременно включить настольную лампу, верхний свет и фонарик. Настольная лампа должна гореть 15сек, верхний - 35сек, фонарик - 43сек. Как в реальной жизни эту задачу бы решали?

включал бы по очереди... Т.е. вы предлагаете привязаться к запуску первого реле и от этого вести отсчет времени работы второго реле?

sadman41
Offline
Зарегистрирован: 19.10.2016

restiv пишет:

sadman41 пишет:

Представьте, что перед вами секундомер. Вам нужно одновременно включить настольную лампу, верхний свет и фонарик. Настольная лампа должна гореть 15сек, верхний - 35сек, фонарик - 43сек. Как в реальной жизни эту задачу бы решали?

включал бы по очереди... Т.е. вы предлагаете привязаться к запуску первого реле и от этого вести отсчет времени работы второго реле?

Не включал, а выключал бы, наверное? Но идею пока что правильно ловите - имеется одна точка запуска (отсчета) и три интервала. Хорошо точка отсчета, скажем, имеет значение N сек. Как определить, что пора выключать верхний свет?

restiv
Offline
Зарегистрирован: 03.01.2016

sadman41 пишет:

Не включал, а выключал бы, наверное? Но идею пока что правильно ловите - имеется одна точка запуска (отсчета) и три интервала. Хорошо точку отсчета, скажем, имеет значение N сек. Как определить, что пора выключать верхний свет?

[/quote]

Нет, у меня то проблема не с отключением реле. Отключаются они как часики по тому врмени которое я закладываю. К меня проблема, что я не могу из одновременно включать. Первое реле запуска сразу же с включением МК, а второе включается через какое то ему одному известное время.

sadman41
Offline
Зарегистрирован: 19.10.2016

Т.е. сейчас вам нужно вообще не то, о чем спрашивалось в первом посте? Так что же вам надо - можете написать русским языком без квестов?

restiv
Offline
Зарегистрирован: 03.01.2016

sadman41 пишет:

Т.е. сейчас вам нужно вообще не то, о чем спрашивалось в первом посте? Так что же вам надо - можете написать русским языком без квестов?

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

Andryn в посте #9 подсказал как это сделать. Я попробовал. Реле стали включаться, но не одновременно, а сначала одно реле, а через какое то время - второе реле.

Efim
Offline
Зарегистрирован: 04.05.2018

restiv

Странно, тернарный оператор умеете использовать, а такой простой код не можете написать.

sadman41
Offline
Зарегистрирован: 19.10.2016

Если у вас нет проблем с отключением после заданного интервала, то что вам мешает все интервалы отсчитывать от одной точки, например нуля по millis(). Вы же поняли, как вычисляется интервал для выключения?

restiv
Offline
Зарегистрирован: 03.01.2016

Efim пишет:

restiv

Странно, тернарный оператор умеете использовать, а такой простой код не можете написать.

К сожалению этот код не весь я писал сам. Большую его часть я позаимствовал у кого то здесь на форуме. И просто корректирую под свои нужды.

Efim
Offline
Зарегистрирован: 04.05.2018

restiv

Правильно я понимаю что  реле должны включится одновременно, а выключались каждая через определенный интервал? Опишите весь процесс.

restiv
Offline
Зарегистрирован: 03.01.2016

Efim пишет:

restiv

Правильно я понимаю что  реле должны включится одновременно, а выключались каждая через определенный интервал? Опишите весь процесс.

Да, вы все поняли правильно. два реле должны запускаться одновременно, через 20 сек одно реле должно отключаться, а через 60 секунд должно отключаться второе реле. Затем ждем 15 или 20 минут (нужно будет подобрать время) снова одновременно включаются 2 реле: одно на 20 сек, второе на 60 сек. Затем ждем 15 минут и снова включаем 2 реле и так по кругу в течении 12 часов. Потом третье реле полностью отключает питание и через 12 часов третье реле снова подключает питание и снова должен запуститья цикл отключения включения на 20 сек и 60 сек через каждые 15-20 минут.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ну так включайте их в одном месте - соседними строчками в коде.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Voodoo Doll пишет:

Исключение - библиотечные, типа LCD и RF24.

А также, Serial, LiquidCristalI2C, ... и ещё 100500 примерно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

Logik, специально для узбеков говорю. 

Любо Logic - узбек, либо Вы - нацист.

andryn
Offline
Зарегистрирован: 08.06.2018

В моем примере объявление переменных перенесите в общую часть, перед setup.

Efim
Offline
Зарегистрирован: 04.05.2018

restiv

А модуль часов будет использоватся?

restiv
Offline
Зарегистрирован: 03.01.2016

Efim пишет:

restiv

А модуль часов будет использоватся?

Да, он у меня стоит. По нему включается и отключается третье реле.

Logik
Offline
Зарегистрирован: 05.08.2014

qwone пишет:

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

Я такое думаю?! Отличные манеры, самому выдумать фигню и  приписать её другому. И тем более говорить это специально узбекам. А что мордва и буряты, ничего от нацика так и не услышат?

Efim
Offline
Зарегистрирован: 04.05.2018

restiv

Ну вот набросал кодик, проверяй.

#include <Wire.h>
#include <RTClib.h>

#define PinRelay1 5         // Тут указываем на каком пине реле 1
#define PinRelay2 6         // Тут указываем на каком пине реле 2
#define PinRelay3 7         // Тут указываем на каком пине реле 3
RTC_DS1307 RTC;

const byte hht = 7;       //Тут устанавливаем час начала 12 часового цикла от 0...23
byte mmi = 15;            //Тут устанавливаем интервал между включениями реле 1 и  2 в минутах
byte hhh = 0;             
boolean f1 = false;        //Флаг сброса таймера
boolean r1 = false;        //Состояние реле 1
boolean r2 = false;        //Состояние реле 2
boolean r3 = false;        //Состояние реле 3
unsigned long timer;

void setup()
{
	Serial.begin(9600);
	Wire.begin();
	RTC.begin();
	if (! RTC.isrunning()) RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
	pinMode(PinRelay1, OUTPUT);
	pinMode(PinRelay2, OUTPUT);
	pinMode(PinRelay3, OUTPUT);
	digitalWrite(PinRelay1, LOW);
	digitalWrite(PinRelay2, LOW);
	digitalWrite(PinRelay3, LOW);	
	if (hht>=12) hhh = hht-12;
	else hhh = hht + 12;	
}                                                                                             

void loop()                                                                                   
{  
   DateTime now = RTC.now();
   digitalWrite(PinRelay1, r1);
   digitalWrite(PinRelay2, r2);
   digitalWrite(PinRelay3, r3);
   if (hht>=12)
   {
    if (now.hour()>=hht || now.hour()<hhh) r1 = true; //Смотрим поподает ли текущий час в диапазон активности реле1
    else r1 = false;	   
   }
   if (hht<12)                                        //Можно использовать else, но так нагляднее 
   {
	if (now.hour()>=hht && now.hour()<hhh) r1 = true; //Смотрим поподает ли текущий час в диапазон активности реле1
    else r1 = false;	
   }
   if (!r1)                                           //Если реле1 не активно то оключаем остальные реле 
   {
	 r2 = false;
     r3 = false;
     f1 = false;
   }
   if (r1&&!f1)                                       //Если реле 1 активно и флаг сброшен то включаем реле 2 и 3
   {
	 r2 = true;
     r3 = true;
     f1 = true;
     timer = millis();	 
   }
   if ((f1)&&(millis()-timer>=20000)) r2 = false;    //Если с момента включения реле 2 прошло 20 сек. то отключаем его
   if ((f1)&&(millis()-timer>=60000)) r3 = false;    //Если с момента включения реле 3 прошло 60 сек. то отключаем его
   if ((f1)&&(millis()-timer>=(mmi*60000))) f1 = false;  //Если с момента включения реле 2 и 3 прошло интервальное время то сбрасываем флаг 
}

 

restiv
Offline
Зарегистрирован: 03.01.2016

Вчера до поздна сидел с этим кодом. Залил эмуляцию в Протеус и долго наблюдал за работой скетча. И до меня дошло, что при такой стурктуре скетча моя задача просто никогда не будет выполняться.

#define relay1 5
#define relay2 9 //Например реле 2 на 6-м пине

void setup(){
  pinMode(relay1, OUTPUT); 
  pinMode(relay2, OUTPUT);

  Serial.begin(115200);          //Запускаем сом-порт
  Serial.println("Test start");
    
}                               // КОНЕЦ ИНИЦИАЛИЗАЦИИ

void loop()                     // ПРОГРАММЫй безусловный ЦИКЛ 
{
   static bool state1;
   static unsigned long time;
   if((millis() - time) > (state1 ? 1000 : 5000)) // уменьшил цифры на 3 порядка, чтобы не ждать сутки :)
   {
      state1 = !state1;
      digitalWrite(relay1, state1);
      Serial.print("relay1:");
      Serial.println(state1);
      
      time = millis();
   }
   //Для второго реле
   static bool state2;
   static unsigned long time2;
   if((millis() - time2) > (state2 ? 3000 : 5000)) // уменьшил цифры на 3 порядка, чтобы не ждать сутки :)
   {
      state2 = !state2;
      digitalWrite(relay2, state2);
      Serial.print("relay2:");
      Serial.println(state2);
      
      time2 = millis();
   }
}

Поскольку постоянно будет происходить сдвиг в запуске реле на величину разницы в отключении первого и второго реле.

И по этой причине возникает вопрос. Как можно изменить код, чтобы реле одновременно включались, но отключались в разное время и через определенный интервал, снова 2 реле одновременно запускались и отключались в разное время и т.д.??? Получается я должен отсчитывать время запуска реле посредсвом команды millis, но вот для отсчета времени их отключения нужно использовать какой то другой таймер времени. Который будет только отсчитывать время с момента включения и до момента когда реле нужно отключить.

restiv
Offline
Зарегистрирован: 03.01.2016

Efim пишет:

restiv

Ну вот набросал кодик, проверяй.

#include <Wire.h>
#include <RTClib.h>

#define PinRelay1 5         // Тут указываем на каком пине реле 1
#define PinRelay2 6         // Тут указываем на каком пине реле 2
#define PinRelay3 7         // Тут указываем на каком пине реле 3
RTC_DS1307 RTC;

const byte hht = 7;       //Тут устанавливаем час начала 12 часового цикла от 0...23
byte mmi = 15;            //Тут устанавливаем интервал между включениями реле 1 и  2 в минутах
byte hhh = 0;             
boolean f1 = false;        //Флаг сброса таймера
boolean r1 = false;        //Состояние реле 1
boolean r2 = false;        //Состояние реле 2
boolean r3 = false;        //Состояние реле 3
unsigned long timer;

void setup()
{
	Serial.begin(9600);
	Wire.begin();
	RTC.begin();
	if (! RTC.isrunning()) RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
	pinMode(PinRelay1, OUTPUT);
	pinMode(PinRelay2, OUTPUT);
	pinMode(PinRelay3, OUTPUT);
	digitalWrite(PinRelay1, LOW);
	digitalWrite(PinRelay2, LOW);
	digitalWrite(PinRelay3, LOW);	
	if (hht>=12) hhh = hht-12;
	else hhh = hht + 12;	
}                                                                                             

void loop()                                                                                   
{  
   DateTime now = RTC.now();
   digitalWrite(PinRelay1, r1);
   digitalWrite(PinRelay2, r2);
   digitalWrite(PinRelay3, r3);
   if (hht>=12)
   {
    if (now.hour()>=hht || now.hour()<hhh) r1 = true; //Смотрим поподает ли текущий час в диапазон активности реле1
    else r1 = false;	   
   }
   if (hht<12)                                        //Можно использовать else, но так нагляднее 
   {
	if (now.hour()>=hht && now.hour()<hhh) r1 = true; //Смотрим поподает ли текущий час в диапазон активности реле1
    else r1 = false;	
   }
   if (!r1)                                           //Если реле1 не активно то оключаем остальные реле 
   {
	 r2 = false;
     r3 = false;
     f1 = false;
   }
   if (r1&&!f1)                                       //Если реле 1 активно и флаг сброшен то включаем реле 2 и 3
   {
	 r2 = true;
     r3 = true;
     f1 = true;
     timer = millis();	 
   }
   if ((f1)&&(millis()-timer>=20000)) r2 = false;    //Если с момента включения реле 2 прошло 20 сек. то отключаем его
   if ((f1)&&(millis()-timer>=60000)) r3 = false;    //Если с момента включения реле 3 прошло 60 сек. то отключаем его
   if ((f1)&&(millis()-timer>=(mmi*60000))) f1 = false;  //Если с момента включения реле 2 и 3 прошло интервальное время то сбрасываем флаг 
}

 

Спасибо за скетч, завтра попробую. Сегодня в отъезде.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Попробуйте еще и так

#define relay1 5
#define relay2 9 //Например реле 2 на 6-м пине
uint32_t time;
uint32_t period = 120000;// Период для ВК 1го и 2го-реле
uint8_t myVar = 0;

void setup() {
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  Serial.begin(115200);          //Запускаем сом-порт
  Serial.println("Test start");
}                               // КОНЕЦ ИНИЦИАЛИЗАЦИИ

void loop()                     // ПРОГРАММЫй безусловный ЦИКЛ
{
  if ((millis() - time) >= period)
  {
    switch (myVar) {
      case 0:
        digitalWrite(relay1, HIGH );
        digitalWrite(relay2, HIGH );
        Serial.print("relay1:");
        Serial.println(digitalRead(relay1));
        Serial.print("relay2:");
        Serial.println(digitalRead(relay2));
        period = 20000; // Период для ВЫК 1го-реле
        myVar++;
	time = millis();
        break;
      case 1:
        digitalWrite(relay1, LOW);
        myVar++;
        period = 60000;// Период для ВЫК 2го-реле
        time = millis();
        break;
      case 2:
        digitalWrite(relay2, LOW);
        myVar = 0;
        period = 120000;// Период для ВК 1го и 2го-реле
        time = millis();
        break;
    }
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

vosara,поправил ваш скетч

/***/
#define RelPin1 5
#define RelPin2 9 //Например реле 2 на 6-м пине

enum {sRel_12ON = 0, sRel_1OFF, sRel_2OFF};
uint32_t time = 0;
uint8_t state = sRel_12ON;
uint32_t period = 0;// Период для ВК 1го и 2го-реле

//------------------------------
void setup() {
  pinMode(RelPin1, OUTPUT);
  pinMode(RelPin2, OUTPUT);
  Serial.begin(115200);          
  Serial.println("Test start");
}                               
void loop() {                 
  if ((millis() - time) >= period)  {
    time = millis();
    switch (state) {
      case sRel_12ON:
        state = sRel_1OFF;
        digitalWrite(RelPin1, HIGH );
        digitalWrite(RelPin2, HIGH );
        period = 20000; // Период для ВЫК 1го-реле
        break;
      case sRel_1OFF:
        state = sRel_2OFF;
        digitalWrite(RelPin1, LOW);
        period = 60000;// Период для ВЫК 2го-реле
        break;
      case sRel_2OFF:
        state = sRel_12ON;
        digitalWrite(RelPin2, LOW);
        period = 120000;// Период для ВК 1го и 2го-реле
        break;
    }
  }
}
/**/