Таймер в таймере.... Или мигание диодом с регулируемой задержкой

Dubolom

✩✩✩✩✩✩✩
2 Фев 2021
77
0
Хай.
Дело не сложное вроде)
Если простыми словами, то нужно так:
раз в минуту опрашиваем датчик, и

if(temperatureC > 29) {
digitalWrite(13, 1);
Но нужно не просто Включить, а НА 10сек.

Придумал такую тему -
Опрашивать по таймеру на millis
Тут проблем не возникло.

Потом решил в этом таймере, в условии if развернуть еще один таймер для работы диода.
Но что то не канает)

Подскажите как правильно

C++:
    int sensorPin = 0; //аналоговый ввод для выхода датчика TMP36
    //разрешение 10 мВ / градус цельсия со смещением на 500 мВ
    //для отрицательной температуры
#define PERIOD 5*1000  
#define PERIODB 10*1000

uint32_t timerA = 0;
uint32_t timerB = 0;

unsigned long currentTime;


void setup()
    {
    Serial.begin(9600);
        pinMode(13, OUTPUT);

    }




void ttt2() {

    if (millis() - timerB >= PERIODB) {
     
     
//считываем напряжение датчика
    int reading = analogRead(sensorPin);
    // преобразуем показания в напряжение, для 3.3v используйте значение 3.3
    float voltage = reading * 5.0;
    voltage /= 1024.0;
    // выводим напряжение
    Serial.print(voltage); Serial.println(" volts");
    // теперь выводим температуру
    float temperatureC = (voltage - 0.5) * 100 ; //исходя из 10 мВ на градус со смещением 500 мВ
    Serial.print(temperatureC); Serial.println(" degrees C");
    // в фаренгейтах
    float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
    Serial.print(temperatureF); Serial.println(" degrees F");
       
     
           if(temperatureC > 29){
     
       digitalWrite(13, 1);
       Serial.println("  ON ");
      currentTime = millis();
           
             //////////////////////// таймер Ц
                // Таймер опроса и выполнения (Период настраиваем вверху - #define PERIOD)
  if (millis() - timerA >= PERIOD) {

   
            digitalWrite(13, 0);
       Serial.println("  Off ");
   //     currentTime = millis();

          do {
      timerA += PERIOD;
      if (timerA < PERIOD) break;        // переполнение uint32_t
      }
     while (timerA < millis() - PERIOD); // защита от пропуска шага
     }
   }

     
          do {
      timerB += PERIODB;
      if (timerB < PERIODB) break;        // переполнение uint32_t
      }
     while (timerB < millis() - PERIODB); // защита от пропуска шага
  }
    }
  /////////////////////////////////////////////////////////


    void loop()
    {
 
     ttt2();
    }
Или может знаешь другие варианты опрашивать раз в период и включать диод на определённое время?
 

Fleshdeck

★★★✩✩✩✩
19 Янв 2019
349
176
Киев
библиотека gyvertimer, просто используй timer.setTimeout(10000); таймаут всегда можно ввести какой нужно
 

bort707

★★★★★★✩
21 Сен 2020
3,067
916
Потом решил в этом таймере, в условии if развернуть еще один таймер для работы диода.
Но что то не канает)
твой таймер в условии ничем не отличается от delay, он блокирует работу остального кода.

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

Dubolom

✩✩✩✩✩✩✩
2 Фев 2021
77
0
@Александр Симонов,
Спасибо. Посмотрел. Почитал. Но победить так и не смог как хочу - хочу мерить темп раз в 5 мин. включать диод при t>29, а при включении диода запускать таймер, и по истечении таймера выключать этот диод. Помогите с кодом и пояснениями, кому скучно)

А победил я только таким примитивным способом:
1 таймер опрашивает датчик и включает диод если t>29
А второй таймер пробегает выключает, если включено.
Но как то это так себе...
 

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

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
Т.е. запуск на включение диода будет 1-ое превышение температуры 29 градусов ?
Если так, то примерно так:
В сетапе.
Взяли температуру, Запомнили время взятия.
в лупе
если текущее время - время взятия температуры (Берилина) больше 5 минут, то взять температуру и запомнить время.
Это что касается измерения раз в 5 минуту.
На второй цикл.
В сетапе.
Запомним температуру 28 градусов в доп. переменной. (температура которую запоминаем должна быть любой, но ниже чем температура сигнала)

В лупе.
проверяем: если температура из доп переменной ниже 29, а запомненная температура выше, то
{
в доп переменную запоминаем новую температуру.
Запускаем светодиод. Для этого: 1) запоминаем время включения, 2) включаем светодиод.
}

Следующая проверка:
Если светодиод включен и с момента включения прошло больше 10 сек - выключаем его.

В принципе все.
 
  • Лойс +1
Реакции: Dubolom

Dubolom

✩✩✩✩✩✩✩
2 Фев 2021
77
0
Спасибо за ответ, но результата я так и не добился. Затуп в том, что не понимаю как посчитать время включенного диода..
Хотя у меня в скетче даже Реальное Время присутствует)
Ну ладно..
Во так ведь тоже нормально:?

1 таймер срабатывает раз в минуту - опрашивает датчик и - если t>29 - включает диод.
2 таймер срабатывает раз в 10 секунд - если включен диод - выключает
 

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

★★★★✩✩✩
2 Авг 2018
727
208
@Dubolom,
1 если t>29 - включает диод, стартует таймер2, поднимает флаг диодЗажжен
2 если поднят флаг диодЗажжен и с начала таймера2 прошло 10 секунд -- погасить диод, опустить флаг диодЗажжен
 
  • Лойс +1
Реакции: Dubolom

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

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
uint32_t vremia_dioda=millis();
digitalWrite(diod_PIN,HIGH);

Вот в 1-ой переменной оно и будет , время включения диода.

if (digitalRead(diod_PIN)) {
// тут диод горит
}
 
  • Лойс +1
Реакции: Dubolom

Dubolom

✩✩✩✩✩✩✩
2 Фев 2021
77
0
поднимает флаг диодЗажжен
Не получается) Видос ещё раз посмотрел кусками - зачем мне флаг не понимаю...
и с начала таймера2 прошло 10 секунд -- погасить диод
Тут вообще не работает у меня... как только не пробовал))

uint32_t vremia_dioda=millis();
digitalWrite(diod_PIN,HIGH);

Вот в 1-ой переменной оно и будет , время включения диода.

if (digitalRead(diod_PIN)) {
// тут диод горит
}
Вы извините конечно, но вроде просто, а до конца не понятно.
Эти таймеры пфффф...

Уже <GyverOS.h> тестирую)
А как в условии таймер запустить хз... Да и ладно.... хрен с ним.

Вы скажите, есть ли несостыковки в этом варианте?

C++:
    int sensorPin = 0; //аналоговый ввод для выхода датчика TMP36
    //разрешение 10 мВ / градус цельсия со смещением на 500 мВ
    //для отрицательной температуры
#define PERIOD 5*1000  
#define PERIODB 10*1000

uint32_t timerA = 0;
uint32_t timerB = 0;

float temperatureC;

void setup()
    {
    Serial.begin(9600);
        pinMode(13, OUTPUT);
     }

void ttt2() {
    if (millis() - timerB >= PERIODB) {
     
//считываем напряжение датчика
    int reading = analogRead(sensorPin);
    // преобразуем показания в напряжение, для 3.3v используйте значение 3.3
    float voltage = reading * 5.0;
    voltage /= 1024.0;
    // выводим напряжение
    Serial.print(voltage); Serial.println(" volts");
    // теперь выводим температуру
    temperatureC = (voltage - 0.5) * 100 ; //исходя из 10 мВ на градус со смещением 500 мВ
    Serial.print(temperatureC); Serial.println(" degrees C");
    // в фаренгейтах
    float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
    Serial.print(temperatureF); Serial.println(" degrees F");
       
           if(temperatureC > 29){
     
       digitalWrite(13, 1);
       Serial.println("  ON ");
           }
 
          do {
      timerB += PERIODB;
      if (timerB < PERIODB) break;        // переполнение uint32_t
      }
     while (timerB < millis() - PERIODB); // защита от пропуска шага
  }
}

void ttt() {

    if (millis() - timerA < PERIOD) return; 
    
    if (digitalRead(13) == 1) {
       digitalWrite(13, 0);
       Serial.println("  Off ");
     }
  }

    void loop()
    {
     ttt();
     ttt2();
    }
 
Изменено:

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

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
Я уже раз 500 писал, что вот такая конструкция:
C++:
  if (millis() - tm < TEST_LT_PER) return;
  tm = millis();
ни как не зависит от переполнения.
допустим считаем до 255 (что бы было проще), период 5
если миллис выдваст 200, а tm было 199, то будет выход, т.е. разница 1. и она меньне 5

Допустим время срабатывания было 254, таймер перешел через 255 и стал 2, будет 2-254=-252, но, т.к. число без знака, то оно не может быть отрицательным, и оно будет 4 , и опять будет return - выход.

Что бы выключить светодиод не нужно обновлять таймерА, он должен обновиться, когда светодиод включается. если делать так, то время свечения светодиодом может быть разное, будет зависеть от кратности перидаА периодуБ
 
  • Лойс +1
Реакции: Dubolom

Dubolom

✩✩✩✩✩✩✩
2 Фев 2021
77
0
Я уже раз 500 писал, что вот такая конструкция:
Не ругайтесь)

Вроде что то заработало. А правильно ли?
C++:
    int sensorPin = 0; //аналоговый ввод для выхода датчика TMP36
    //разрешение 10 мВ / градус цельсия со смещением на 500 мВ
    //для отрицательной температуры
#define PERIOD 5*1000   
#define PERIODB 10*1000 

uint32_t timerB = 0;
uint32_t timerA = 0;
float temperatureC;

void setup()
    {
    Serial.begin(9600);
        pinMode(13, OUTPUT);
     }
 
void ttt2() {

    if (millis() - timerB >= PERIODB) {
                
//считываем напряжение датчика
    int reading = analogRead(sensorPin);
    // преобразуем показания в напряжение, для 3.3v используйте значение 3.3
    float voltage = reading * 5.0;
    voltage /= 1024.0;
    // выводим напряжение
    Serial.print(voltage); Serial.println(" volts");
    // теперь выводим температуру
    temperatureC = (voltage - 0.5) * 100 ; //исходя из 10 мВ на градус со смещением 500 мВ
    Serial.print(temperatureC); Serial.println(" degrees C");
    // в фаренгейтах
    float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
    Serial.print(temperatureF); Serial.println(" degrees F");
              
           if(temperatureC > 29){

       digitalWrite(13, 1);
        Serial.println("  ON ");
      
       timerA = millis();
  
           }
  
          do {
      timerB += PERIODB;
      if (timerB < PERIODB) break;        // переполнение uint32_t
      }
     while (timerB < millis() - PERIODB); // защита от пропуска шага
  }
}
    
void ttt() {

    if (millis() - timerA < PERIOD) return;
    
    if (digitalRead(13) == 1) {
       digitalWrite(13, 0);
       Serial.println("  Off ");
     }
  }

    void loop()
    {
     ttt2();
      ttt();
    }
 

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

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
Что бы знать правильно, надо знать как должно.
Учтите, что по этому коду если температура будет выше 29 градусов. то светодиод будет включаться на 10 сек каждую минуту. Так и задумано ?
 
  • Лойс +1
Реакции: Dubolom

Dubolom

✩✩✩✩✩✩✩
2 Фев 2021
77
0
если температура будет выше 29 градусов. то светодиод будет включаться на 10 сек каждую минуту. Так и задумано ?
угу
Если простыми словами, то нужно так:
раз в минуту опрашиваем датчик, и

if(temperatureC > 29) {
digitalWrite(13, 1);
Но нужно не просто Включить, а НА 10сек.
но в коде сейчас цифры 10 сек и 5 сек

#define PERIOD 5*1000
#define PERIODB 10*1000

т.е. опрос датчиков раз в 10 сек
и если температура будет выше 29 градусов. то светодиод будет включаться на 5 сек

То что надо. Респект Вам огромный.

Что бы знать правильно, надо знать как должно.
я Вроде доПонял)

timerA = millis(); // эта строчка в условии if обновляtт таймерА

if (millis() - timerA < PERIOD) return; // это сам таймер
 

Dubolom

✩✩✩✩✩✩✩
2 Фев 2021
77
0
Я тут ещё один момент додумал - подскажите, что почитать на эту тему?

Вопрос такой:

Хочу добавить -
Если последние, например 5 опросов (те опросы - которые 1 раз в минуту) температура ни разу не опускалась ниже 25,
то digitalWrite(14, HIGH);

Это надо городить какой то счетчик опроса датчиков?

что хоть гуглить то? намекните)
 

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

★★★★✩✩✩
2 Авг 2018
727
208
Самое простое это счётчик опусканий ниже 25 подряд. Если температура ниже 25, увеличил счетчик, иначе сбросил счетчик в ноль.
Если счетчик больше 5 подал высокий сигнал на пин 14.
 
  • Лойс +1
Реакции: Dubolom

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

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
Да, нужен счетчик. Примерно так
если температура выше 25, то счетчик увеличить на 1, иначе счетчик уменьшить на 1
Если счетчик больше 5, то счетчик равен 5
Если счетчик меньше 0, то счетчик равен 0
Если счетчик равен 5, то digitalWrite(14, HIGH); иначе digitalWrite(14, LOW);
 
  • Лойс +1
Реакции: Dubolom

bort707

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

В следуший раз попытайтесь сначала написать хоть какой-то код сами, прежде чем спрашивать.
 
  • Лойс +1
Реакции: Dubolom

Dubolom

✩✩✩✩✩✩✩
2 Фев 2021
77
0
понял) вот попробовал.
Немного изменил логику - Сейчас так -
Если за последние, например 3 опроса (те опросы - которые 1 раз в минуту - включают диод по температуре), диод включался 3 раза
то digitalWrite(8, 1);

Ну в смысле если 3 раза подряд диод включался - то - digitalWrite(8, 1);
А если был опрос, и он не включился, - т.е. температура была в норме, то - сбрасываем счетчик.

Эти 3 раза подряд подряд будут сообщать что прибор не справляется с охлаждением например...
вот код. вроде работает)
C++:
    int sensorPin = 0; //аналоговый ввод для выхода датчика TMP36
    //разрешение 10 мВ / градус цельсия со смещением на 500 мВ
    //для отрицательной температуры
#define PERIOD 3*1000   
#define PERIODB 5*1000 

uint32_t timerB = 0;
uint32_t timerA = 0;
float temperatureC;

int kol_A;   //количество включений
bool f_A = 0;  // флаг включения



void setup()
    {
    Serial.begin(9600);
        pinMode(13, OUTPUT);
     }

 
void ttt2() {

    if (millis() - timerB >= PERIODB) {
      
          
//считываем напряжение датчика
    int reading = analogRead(sensorPin);
    // преобразуем показания в напряжение, для 3.3v используйте значение 3.3
    float voltage = reading * 5.0;
    voltage /= 1024.0;
    // выводим напряжение
    Serial.print(voltage); Serial.println(" volts");
    // теперь выводим температуру
    temperatureC = (voltage - 0.5) * 100 ; //исходя из 10 мВ на градус со смещением 500 мВ
    Serial.print(temperatureC); Serial.println(" degrees C");
    // в фаренгейтах
    float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
    Serial.print(temperatureF); Serial.println(" degrees F");
        
      
           if(temperatureC > 29 && f_A == 0){

       digitalWrite(13, 1);
        
        Serial.println("  ON ");
      
       timerA = millis();
    
       f_A = 1; // меняем флаг
       kol_A++;  // добаляем кол-во
      
    Serial.print("kol_A  ");
  Serial.println(kol_A);

  }
 
  else  if (f_A == 0) {

  kol_A = 0; // обнуляем счетчик
    
      Serial.print("kol_A  ");
  Serial.println(kol_A);
  }

 if(kol_A > 2){
     kol_A = 3;
     }

    
      if (kol_A == 3) {
        digitalWrite(8, 1);
        Serial.println("  Уже 3 раза подряд ON ");
     }
 
               do {
      timerB += PERIODB;
      if (timerB < PERIODB) break;        // переполнение uint32_t
      }
     while (timerB < millis() - PERIODB); // защита от пропуска шага
  }
    
}
 

void ttt() {

    if (millis() - timerA < PERIOD) return;
    
    if (digitalRead(13) == 1) {
       digitalWrite(13, 0);
       Serial.println("  Off ");
      
        f_A = 0; // меняем флаг
     }
  }


    void loop()
    {
     ttt2();
      ttt();
    }
 

bort707

★★★★★★✩
21 Сен 2020
3,067
916
Старайтесь писать логичнее. Код просто переполнен бессмысленными переменными и операторами.
Зачем какой-то флаг? Зачем нужны дублирующие условия в строке 67и 72, почему не обойтись одним?
Вам изложили простейшую логику - превышена температура - увеличиваем счетчик, понизилась - обнуляем. Вся логика укладывается в 5 строк, а вы нагородили...
 
  • Лойс +1
Реакции: Dubolom

Dubolom

✩✩✩✩✩✩✩
2 Фев 2021
77
0
Зачем какой-то флаг?
Согласен. Нагородил. Убрал щас вот) - работает.
Зачем нужны дублирующие условия в строке 67и 72, почему не обойтись одним?
Если счетчик больше 5, то счетчик равен 5
Если счетчик меньше 0, то счетчик равен 0
Если счетчик равен 5, то digitalWrite(14, HIGH); иначе digitalWrite(14, LOW);
Вдруг тройку сДуру проскочет))
 

bort707

★★★★★★✩
21 Сен 2020
3,067
916
Счетчик можно менять уже условии измерения температуры, никакие иные условия не нужны:

If(темп > 29)
{if (счетчик <5) счетчик ++;}
else счетчик =0;

Вот и все , никакие флаги и условия больше не нужны
 
  • Лойс +1
Реакции: Dubolom

poty

★★★★★★✩
19 Фев 2020
3,263
949
Эххх, @bort707 как всегда прав! Вот разложить бы алгоритм в виде событий, состояний и переходов между ними - не потребовалось бы никаких повторов. Состояний-то всего семь получается:
  • <25 LED1, LED2 выключены;
  • 25-29 LED1, LED2 выключены;
  • 25-29 LED1 включен, LED2 выключен;
  • >29 LED1 выключен, LED2 выключен;
  • >29 LED1 включен, LED2 выключен;
  • >29 LED1 выключен, LED2 включен;
  • >29 LED1 включен, LED2 включен.
Переходы тоже определены. Время нахождения - определено. Бери и пиши.