вопрос по таймингу

Михаил Бурко

✩✩✩✩✩✩✩
16 Апр 2021
30
0
доброго времени суток , прошу обьясните мне как на миллис сделать последовательное включение с задержкой , задача следующая: имеется 3 реле которые нужно включать с задержкой например в 1сек последовательно. На включение реле завел переменные f0,f9,f10, включение происходит по условию.
C++:
  if ( FUNK1 == 1) {
    static uint32_t tmr = 0;
    if (millis() - tmr > 1000) {
      f0 = 0;
    }
    if (millis() - tmr > 2000) {
      f9 = 0;
    }
    if (millis() - tmr > 3000) {
      tmr = millis();
      f10 = 0;
    }
  }
помогите с кодом плиз!
 

Михаил Бурко

✩✩✩✩✩✩✩
16 Апр 2021
30
0
@Эдуард Анисимов,я пробывал ,работает также как и мой код
C++:
  if ( FUNK1 == 1) {
  if (myTimer.isReady())   f0 = 0   ;
  if (myTimer2.isReady())  f9 = 0  ;
   if (myTimer3.isReady())  f10 = 0  ;
по нажатию кнопки в процессинге , переменная FUNK0 меняет своё значение на FUNK1 и срабатывает данное условие , реле включаются с задаными промежутками но не последовательно , а как попало.... Кстати управление реле идет через расширитель портов на PCF8575 , может в этом проблема?хотя непохоже... незнаю как сделать последовательное включение ,помогите плиз

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

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,412
978
58
Марий-Эл
Как напишешь, так и будет работать.
таймеры вроде как работают вне условия и при включении получается что может гореть сразу 3 реле , или 2 сразу и 3 через секунду , незнаю как исправить...
Вводных данных мало. Нужно чётко расписать что нужно делать.
 

Михаил Бурко

✩✩✩✩✩✩✩
16 Апр 2021
30
0
@Эдуард Анисимов, задача вроде не сложная , при срабатывании условия , нужно включить реле 1, через секунду реле 2, и через секунду реле 3. это вся задача

но @Эдуард Анисимов, данные скетчи вроде срабатывают по времени ,но в зависимости когда сработает условие , те реле и сработают ,тоесть можно попасть что всё сработает корректно как и задумано , можно попасть что будут включены сразу два реле а потом через секунду сработает 3. а мне нужно чтобы всегда включение происходило последовательно ....
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,412
978
58
Марий-Эл

poty

★★★★★★✩
19 Фев 2020
3,262
949
@Михаил Бурко, в Вашей интерпретации (с millis и tmr), почему при выполнении условия FUNK1 == 1 переменная tmr становится равной нулю? Таймер так не работает! tmr нужно присваивать millis() в первый момент соблюдения условия. Так как переменная эта у Вас локальная в рамках выделенного блока кода, то повторное срабатывание FUNK1 == 1 будет работать неправильно, так как инициализация tmr происходит только один раз - первый. Это - вторая ошибка.
В примере с таймерами Гайвера ошибка та же самая. Для того, чтобы таймеры отсчитывали интервалы, их нужно "запустить" в момент выполнения условия FUNK1 == 1. Для этого их нужно инициализировать (объявить) правильно в первую очередь.
При создании таймера можно ничего не указывать: GTimer myTimer;, тогда таймер будет сконфигурирован как миллисекундный и не запустится
Таймаут. Запуск – метод setTimeout(время) с указанием времени. В режиме таймаута таймер срабатывает (метод isReady() возвращает true) только один раз при достижении указанного периода и автоматически отключается. Для повторного запуска нужно вызвать .setTimeout() с указанием периода, или просто .start() – запустит таймер на новый круг с прежним периодом
 
Изменено:

Михаил Бурко

✩✩✩✩✩✩✩
16 Апр 2021
30
0
@poty, мне на получается , кручу верчу кодом уже 5 ч и не могу врубиться ? инициализирую таймер вот так

C++:
GTimer myTimer;   
GTimer myTimer2;  
GTimer myTimer3;
таким образом он будет сконфигурирован но не запустится (значит нужно будет его запустить при старте условия FUNK1 == 1 ) , дальше в
C++:
 void setup() 
 myTimer.setTimeout (1000) ;// задаю таймаут работы            
 myTimer2.setTimeout (2000) ;
 myTimer3.setTimeout (3000) ;
Здесь много вариантов пробовал никак не получается запустить таймер в начале условия
C++:
if ( FUNK1 == 1) {  
   if (myTimer.isReady())   f0 = 0  ;         
   if (myTimer2.isReady())  f9 = 0  ;     
   if (myTimer3.isReady())  f10 = 0  ;           
  }
 

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

★★★★★★★
14 Авг 2019
4,271
1,303
Москва
Тут главное понимать логику. Вообще программирование это перевод своих желаний на язык понятный электронному мозгу.
Рассмотрим вариант включения логически:

Если возникло нужное событие, то надо включить 3 реле с интервалом в 1(2,3,15..) секунду.
Алгоритм:
1) Событие было ?
Если да - выставляем флаг срабатывания события в ИСТИНА (f=true) и запоминаем время срабатывания события (t1=millis()). Тут еще надо учесть , что за 3 секунды событие может возникнуть второй раз. Поэтому ВОЗМОЖНО! надо проверить что при возникновении события флаг был в ФАЛЬШЬ
Если нет, то идем дальше.

2) Если флаг выставлен то
{
Со времени начала прошло больше 1 сек ? Если да, то включить 1-ое реле.
Со времени начала прошло больше 2 сек ? Если да, то включить 2-ое реле.
Со времени начала прошло больше 3 сек ? Если да, то включить 3-ое реле и сбросить флаг в ФАЛЬШЬ
}

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


Как сделать включение реле только один раз, один из вариантов:
Внутри скобок завести статическую переменную типа байт (static byte b=0)
Условия делать такие:
если со времени начала события прошло больше 1 сек и b<1 то включить 1 реле и b=1;
если со времени начала события прошло больше 2 сек и b<2 то включить 2 реле и b=2;
если со времени начала события прошло больше 3 сек и b<3 то включить 2 реле , флаг события в ФАЛЬШЬ и b=0;
Еще можно для каждого реле завести свой таймер и флаг, но это расточительно. Еще можно проверять состояние выходного пина.
 

Михаил Бурко

✩✩✩✩✩✩✩
16 Апр 2021
30
0
вот рабочий код по данной теме , решил скинуть может кому нужно будет
C++:
boolean f_vk1 = false;      флаги включения и отключения                       
boolean f_otk1 = false;
unsigned long t1 ; //переменная таймера
int FUNK1 = 0;  //переменная функции
C++:
if ( FUNK1 == 1 && f_vk1 == false) {     
   t1 = millis(); // Запишем время срабатывания  в t1
   f_vk1 = true;    //устанавливаем флаг flag включения в true
} 
  if ( f_vk1 == true)  //если флаг установлен то выполняем действия в скобках
  {
   FUNK1 = 2; // сброс FUNK1  
if (millis() - t1 > 1000) {  //если текущее время (-) время которое
      f0 = 0;               //запомнили с момента услов FUNK1 больше 1с
    }                       // включаем реле1 (f0 = 0)
if (millis() - t1 > 2000) {
      f9 = 0;
    }
  if (millis() - t1 > 3000) {
      f10 = 0;
    f_vk1 = false; //после запуска 3 реле сбрасываем флаг
    }  }     
      if ( FUNK1 == 0  ) {
   t1 = millis(); // Запишем время срабатывания (FUNK1) в t1
   f_otk1 = true;    //устанавливаем флаг отключения f_otk1 в true
      }
     if ( f_otk1 == true)  //если флаг установлен то выполняем действия в скобках
  {
   FUNK1 = 2; // сброс FUNK1
if (millis() - t1 > 1000) {  //если текущее время (-) время которое
      f10 = 1;               //запомнили с момента услов FUNK1 больше 1с
    }                       // отключаем реле (f0 = 1)
if (millis() - t1 > 2000) {
      f9 = 1;
    }
  if (millis() - t1 > 3000) {
      f0 = 1;
    f_otk1 = false; //после отключения 3 реле сбрасываем флаг
    }  }
 

bort707

★★★★★★✩
21 Сен 2020
3,069
916
Правильно я понял, что теперь у вас будет два режима на выбор - либо включения (строка 1) либо выключение со строки 18? Причем выбрать можно только один при прошивке, но не оба сразу?

Обрати е внимание на различие строчек 1 и 18 - думаю, в 18 вы что-то позабыли
 

Михаил Бурко

✩✩✩✩✩✩✩
16 Апр 2021
30
0
@bort707,да , флаг забыл , спасибо , вы очень внимательны. Здесть есть один неприятный сюрприз , программа не работает сразу , а нужно подождать пока таймер дойдет до определенного времени , в данном случае , у меня код заработает только через 4 сек..... а если я поставлю включение реле через 30сек то придется ждать целых 30 секунд чтобы сработал код.... может вам известно как поправить код или "подогнать" таймер чтобы он запускался сразу со100 секунд например
 

bort707

★★★★★★✩
21 Сен 2020
3,069
916
Не понимаю вашей проблемы, вы же сами написали код, где нагрузки включаются по таймерам. Если надо, что включались сразу - уберите таймеры из ветки включения, оставте толь при выключении.
Или я неверно понял? Тогда поясните
 

Михаил Бурко

✩✩✩✩✩✩✩
16 Апр 2021
30
0
@bort707,по нажатию на кнопку у меня должны включится последовательно , с задержкой реле , реле включаются по таймеру , отщет таймера начинается со старта программы .при выполнении условия первое реле должно запустится (допустим) через 10сек после того как я нажму на кнопку и выполнится условие FUNK1 . НО ничего не произойдет , если я нажму на кнопку раньше 10 сек , так как со старта программы прошло меньше времени и таймер пока не досчитал как я понимаю, или в чёмто другом проблема . я пока не понимаю как это исправить.... приходится ждать 10сек чтобы скетч заработал
 

bort707

★★★★★★✩
21 Сен 2020
3,069
916
@Михаил Бурко, что-то вы не то пишете, в вашем коде никакого ожидания после старта нет, кнопку можно нажимать сразу. Если это не так - значит вы что-то намудрили с кодом
 

Михаил Бурко

✩✩✩✩✩✩✩
16 Апр 2021
30
0
да , но почему-то происходит то что происходит , если запустить программу то сразу FUNK1 не срабатывает....
 

bort707

★★★★★★✩
21 Сен 2020
3,069
916
показывайте полный код, а не отдельные куски
 

Михаил Бурко

✩✩✩✩✩✩✩
16 Апр 2021
30
0
посмотрите пожалуйста , корректно работает только после 6 сек после старта программы
C++:
#include "Parser.h"       // библиотека парсера
#include "AsyncStream.h"  // асинхронное чтение сериал
AsyncStream<50> serial(&Serial, ';');   // указываем обработчик и стоп символ
#include <Wire.h>
#include "PCF8575.h"
PCF8575 expander20;
PCF8575 expander21;

boolean f0 = 1;
boolean f1 = 1;
boolean f2 = 1;
boolean f3 = 1;
boolean f4 = 1;
boolean f5 = 1;
boolean f6 = 1;
boolean f7 = 1;
boolean f8 = 1;
boolean f9 = 1;
boolean f10 = 1;
boolean f11 = 1;
boolean f12 = 1; //флаги еспандеров
boolean f13 = 1;
boolean f14 = 1;
boolean f15 = 1;
boolean f16 = 1;
boolean f17 = 1;
boolean f18 = 1;
boolean f19 = 1;
boolean f20 = 1;



boolean f_vk1 = false;
boolean f_vk2 = false;
boolean f_vk3 = false;
boolean f_vk4 = false;
boolean f_vk5 = false;
boolean f_vk6 = false;
boolean f_vk7 = false;
boolean f_vk8 = false;
boolean f_vk9 = false;
boolean f_vk10 = false;
boolean f_vk11 = false;
boolean f_vk12 = false; //флаги ВКЛючения функций (FNK)
boolean f_vk13 = false;
boolean f_vk14 = false;
boolean f_vk15 = false;
boolean f_vk16 = false;

boolean f_otk1 = false;
boolean f_otk2 = false;
boolean f_otk3 = false;
boolean f_otk4 = false;
boolean f_otk5 = false;
boolean f_otk6 = false;
boolean f_otk7 = false;
boolean f_otk8 = false;
boolean f_otk9 = false;
boolean f_otk10 = false;
boolean f_otk11 = false;
boolean f_otk12 = false; //флаги ВЫКЛлючения функций (FNK)
boolean f_otk13 = false;
boolean f_otk14 = false;
boolean f_otk15 = false;
boolean f_otk16 = false;






unsigned long t2 ; //переменная таймера
unsigned long t1 ; //переменная таймера

int St_Kin1 = 0;
int St_Kin2 = 0;
int St_Kin3 = 0;
int St_Kin4 = 0;
int St_Kin5 = 0;
int St_Kin6 = 0;  //состояние концевиков
int St_Kin7 = 0;
int St_Kin8 = 0;
int St_Kin9 = 0;
int St_Kin10 = 0;
int St_Kin11 = 0;
int St_Kin12 = 0;
int St_Kin13 = 0;
int St_Kin14 = 0;
int St_Kin15 = 0;
int St_Kin16 = 0;

int FUNK1 = 0;
int FUNK2 = 0;
int FUNK3 = 0;
int FUNK4 = 0;
int FUNK5 = 0;
int FUNK6 = 0;
int FUNK7 = 0;
int FUNK8 = 0;
int FUNK9 = 0;
int FUNK10 = 0;
int FUNK11 = 0;
int FUNK12 = 0;
int FUNK13 = 0;
int FUNK14 = 0;
int FUNK15 = 0;
int FUNK16 = 0;

void setup() {
  Serial.begin(9600);
  expander20.begin(0x20);
  expander21.begin(0x21);
 
  expander20.pinMode(0, OUTPUT);
  expander20.pinMode(1, OUTPUT);
  expander20.pinMode(2, OUTPUT);
  expander20.pinMode(3, OUTPUT);
  expander20.pinMode(4, OUTPUT);
  expander20.pinMode(5, OUTPUT);
  expander20.pinMode(6, OUTPUT);
  expander20.pinMode(7, OUTPUT);
  expander20.pinMode(8, OUTPUT);
  expander20.pinMode(9, OUTPUT);
  expander20.pinMode(10, OUTPUT);
  expander20.pinMode(11, OUTPUT);
  expander20.pinMode(12, OUTPUT);
  expander20.pinMode(13, OUTPUT);
  expander20.pinMode(14, OUTPUT);
  expander20.pinMode(15, OUTPUT);

  expander21.pinMode(0, INPUT_PULLUP);
  expander21.pinMode(1, INPUT_PULLUP);
  expander21.pinMode(2, INPUT_PULLUP);
  expander21.pinMode(3, INPUT_PULLUP);
  expander21.pinMode(4, INPUT_PULLUP);
  expander21.pinMode(5, INPUT_PULLUP);
  expander21.pinMode(6, INPUT_PULLUP);
  expander21.pinMode(7, INPUT_PULLUP);
  expander21.pinMode(8, INPUT_PULLUP);
  expander21.pinMode(9, INPUT_PULLUP);
  expander21.pinMode(10, INPUT_PULLUP);
  expander21.pinMode(11, INPUT_PULLUP);
  expander21.pinMode(12, INPUT_PULLUP);
  expander21.pinMode(13, INPUT_PULLUP);
  expander21.pinMode(14, INPUT_PULLUP);
  expander21.pinMode(15, INPUT_PULLUP);
}
void loop() {
  parsing();
  St_Kin1 =  expander21.digitalRead(0);
  St_Kin2 =  expander21.digitalRead(1);
  St_Kin3 =  expander21.digitalRead(2);
  St_Kin4 =  expander21.digitalRead(3);
  St_Kin5 =  expander21.digitalRead(4);
  St_Kin6 =  expander21.digitalRead(5);
  St_Kin7 =  expander21.digitalRead(6);
  St_Kin8 =  expander21.digitalRead(7);
  St_Kin9 =  expander21.digitalRead(8);
  St_Kin10 = expander21.digitalRead(9);
  St_Kin11 = expander21.digitalRead(10);
  St_Kin12 = expander21.digitalRead(11);
  St_Kin13 = expander21.digitalRead(12);
  St_Kin14 = expander21.digitalRead(13);
  St_Kin15 = expander21.digitalRead(14);
  St_Kin16 = expander21.digitalRead(15);

  expander20.digitalWrite(0, f0);
  expander20.digitalWrite(1, f1);
  expander20.digitalWrite(2, f2);
  expander20.digitalWrite(3, f3);
  expander20.digitalWrite(4, f4);
  expander20.digitalWrite(5, f5);
  expander20.digitalWrite(6, f6);
  expander20.digitalWrite(7, f7);
  expander20.digitalWrite(8, f8);
  expander20.digitalWrite(9, f9);
  expander20.digitalWrite(10, f10);
  expander20.digitalWrite(11, f11);
  expander20.digitalWrite(12, f12);
  expander20.digitalWrite(13, f13);
  expander20.digitalWrite(14, f14);
  expander20.digitalWrite(15, f15);
  //========================================================================== відправка стану кінцевиків
  static uint32_t tmr = 0;
  if (millis() - tmr > 500) {            //отправка по таймеру
    tmr = millis();                      //отправка данных концевиков
    int packet[12];                     //количество в пакете !!!
    packet[0] = !St_Kin1;
    packet[1] = !St_Kin2;
    packet[2] = !St_Kin3;
    packet[3] = !St_Kin4;
    packet[4] = !St_Kin5;
    packet[5] = !St_Kin6;
    packet[6] = !St_Kin7;
    packet[7] = !St_Kin8;
    packet[8] = !St_Kin9;
    packet[9] = !St_Kin10;
    packet[10] = !St_Kin11;
    packet[11] = !St_Kin12;
    sendPacket(0, packet, 12);         
  }
  //=============================РАБОТА C ФУНКЦИЯМИ FUNK==================================================
  
   if ( FUNK1 == 1 && f_vk1 == false) {     
   t1 = millis(); // Запишем время срабатывания  в t1
   f_vk1 = true;    //устанавливаем флаг flag включения в true

} 
  if ( f_vk1 == true)  //если флаг установлен то выполняем действия в скобках
  {
   FUNK1 = 2; // сброс FUNK1
  
if (millis() - t1 > 1000) {  //если текущее время (-) время которое
      f0 = 0;               //запомнили с момента услов FUNK1 больше 1с
    }                       // включаем реле1 (f0 = 0)
if (millis() - t1 > 2000) {
      f9 = 0;
    }
  if (millis() - t1 > 6000) {
      f10 = 0;
    f_vk1 = false; //после запуска 3 реле сбрасываем флаг
    }
  }
      
      if ( FUNK1 == 0 && f_otk1 == false  ) {
   t2 = millis(); // Запишем время срабатывания (FUNK1) в t1
   f_otk1 = true;    //устанавливаем флаг отключения f_otk1 в true
      }
     if ( f_otk1 == true)  //если флаг установлен то выполняем действия в скобках
  {
   FUNK1 = 2; // сброс FUNK1
if (millis() - t2 > 1000) {  //если текущее время (-) время которое
      f0 = 1;               //запомнили с момента услов FUNK1 больше 1с
    }                       // отключаем реле1 (f0 = 1)
if (millis() - t2 > 2000) {
      f9 = 1;
    }
  if (millis() - t2 > 6000) {
      f10 = 1;
    f_otk1 = false; //после отключения 3 реле сбрасываем флаг
    }
  }
      
 

      
      
      
      
      
      
      
      
      
      
//      if (FUNK2 == 1 && St_Kin3 == 0 && St_Kin5  == 0 && St_Kin7  == 0  ){
//    digitalWrite(8, 0);                                                   
//      }
//  if ( FUNK2 == 1) {
//    f1 = 0;
//        if (FUNK3 == 1 && St_Kin3 == 0 && St_Kin5  == 0 && St_Kin8  == 0  ){
//    digitalWrite(8, 0);
//        }
//  }
//  if ( FUNK2 == 0) {                                                       
//    f1 = 1;
//  }
//  if ( FUNK3 == 1) {
//    f2 = 0;
//    //    if (FUNK4 == 1 && St_Kin6 == 0 && St_Kin3  == 0  ){
//    //  digitalWrite(8, 0);
//    //    }
//  }
//  if ( FUNK3 == 0) {                                                       
//    f2 = 1;
//  }
//  if ( FUNK4 == 1) {
//    expander20.digitalWrite(3, LOW);
//    //    if (FUNK4 == 1 && St_Kin6 == 0 && St_Kin3  == 0  ){
//    //  digitalWrite(8, 0);
//    //    }
//  }
//  if ( FUNK5 == 1) {
//    expander20.digitalWrite(4, LOW);
//    //    if (FUNK4 == 1 && St_Kin6 == 0 && St_Kin3  == 0  ){
//    //  digitalWrite(8, 0);
//    //    }
//  }
//  if ( FUNK6 == 1) {
//    expander20.digitalWrite(5, LOW);
//    //    if (FUNK4 == 1 && St_Kin6 == 0 && St_Kin3  == 0  ){
//    //  digitalWrite(8, 0);
//    //    }
  }

//===============================================================================
// функция для отправки пакета на ПК
void sendPacket(int key, int* data, int amount) {
  Serial.print(key);
  Serial.print(',');
  for (int i = 0; i < amount; i++) {
    Serial.print(data[i]);
    if (i != amount - 1) Serial.print(',');
  }
  Serial.print('\n');
}

// функция парсинга, опрашивать в лупе
void parsing() {
  if (serial.available()) {
    Parser data(serial.buf, ',');  // отдаём парсеру
    int ints[30];           // массив для численных данных
    data.parseInts(ints);   // парсим в него

    switch (ints[0]) {      // свитч по ключу
      case 0:
        break;
      case 1:  FUNK1 =  ints[1];
        break;
      case 2:  FUNK2 =  ints[1];
        break;
      case 3:  FUNK3 =  ints[1];
        break;
      case 4:  FUNK4 =  ints[1];
        break;
      case 5:  FUNK5 =  ints[1];
        break;
      case 6:  FUNK6 =  ints[1];
        break;
    }
  }
}
 

bort707

★★★★★★✩
21 Сен 2020
3,069
916
у вас условие в строке 225 срабатывает сразу же после старта без всяких команд... а поскольку при срабатывании условия программа начинает выдерживать задержки - никакие другие команды не принимаются.
Выберите для функций отключения какое-то другое значение FUNK1. не ноль
 

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

★★★★★★★
14 Авг 2019
4,271
1,303
Москва
Вот это все безобразие
expander20.pinMode(0, OUTPUT);
expander20.pinMode(1, OUTPUT);
expander20.pinMode(2, OUTPUT);
expander20.pinMode(3, OUTPUT);
...
Делается циклом.
for (int i=0;i<15;i++)
{
expander20.pinMode(i, OUTPUT);
expander21.pinMode(i,INPUT_PULLUP);
}