Форум программистов, компьютерный форум, киберфорум
Наши страницы
Arduino
Войти
Регистрация
Восстановить пароль
 
Jurboss
0 / 0 / 0
Регистрация: 10.09.2017
Сообщений: 11
#1

Таймер для отслеживания интервалов в скетче - Arduino

11.07.2018, 07:47. Просмотров 153. Ответов 18
Метки нет (Все метки)

Хочу представить на Ваше обсуждение скетч таймера, для отслеживания отрезков времени в скетче.

В примере Мигание светодиодом, двумя таймерами, время включено и время выключено.

Состояние таймера:
0 – не запущен
1 – идет отсчет
2 – время прошло


Узнать состояние таймера, без запуска.
dann = TimerSetAt.CheckTime(0);

Создать таймер: // TimerSetAt – имя нового таймера
Interval TimerSetAt;

Задать время (мс) таймеру = 1 мин:
TimerSetAt.interval = 60000;

Получение интервала (если таймер запущен, он не перезапустица, пока не отсчитает, принудительно остановить Interval.stat = 0:
if (TimerSetAt.CheckTime(1) == 2) // Запуск и проверка
{
// Время прошло
}


Во время отсчета, продлить на 1 мин с текущего времени (значение основного интервала таймера, при следующем запуске, не изменится):
TimerSetAt.outtime = millis() + 60000;

Мигание светодиодом, двумя таймерами, время включение и время выключено, в примере:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Interval   // Класс отсчета времени
{
  public:
    unsigned long int outtime;    // Время остановки (Мс)
    unsigned long int interval;   // Хранение интервала объекта (Мс)
    unsigned char stat = 0;       // Статус объекта таймера 0 - остановлено, 1 - идет отсчет, 2 - время прошло.
 
    unsigned char CheckTime(boolean zapusk)
    {
      unsigned long int corTime;
      if (stat == 0 && zapusk == 1)           // Если счетчик остановлен и разрешон запуск - то запустить
      {
        outtime = millis() + interval;        // Определение времени остановки
        corTime = millis();
        stat = 1;                             // Статус - таймер запущен
      }
      if (stat == 1)                          // Если статус = 1(Таймер запущен)
      {
        corTime = millis();                   // Берём текущее время
        if (corTime > outtime)                // Если текущее время превысило устаноленное
        {
          stat = 2;
          return 2;
        }
      }
      if (stat == 2)stat = 0;
    }
};
//-------------------------------------------------------------------------//
 
#define ledpin 13
 
Interval TimerOff;                    // Объект интевала выключено
Interval TimerOn;                     // Объект длительности включено
 
void setup() {
    TimerOff.interval = 3000;         // Интервал выключено
    TimerOn.interval = 1000;          // Интервал длительности включено
    
    pinMode(ledpin, OUTPUT);
}
 
void loop() {
  if(TimerOn.CheckTime(0) == 0 && TimerOff.CheckTime(0) == 0) // Если счетчики остановлены
      {
          digitalWrite(ledpin, HIGH);     // Включить
          TimerOn.CheckTime(1);                             // Включить отсчет времени включения
      }
      if(TimerOn.CheckTime(0) == 2)                         // Если счетчик включено остановлен
      {
          digitalWrite(ledpin, LOW);      // Выключить
          TimerOff.CheckTime(1);                            // Включить отсчет времени включения
      }
}

http://www.cyberforum.ru/arduino/thread1785052.html
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
11.07.2018, 07:47
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Таймер для отслеживания интервалов в скетче (Arduino):

таймер "для плюшек". продолжение.
начало тут:http://iosyitistromyss.ru/forum/mydivice/topys-1166 вот,...

Таймер для выпечки:) *мой первый девайс*
Ну что может быть банальней, не так ли? И впрямь... Тем не менее, делаю...

Отсчет интервалов миллисекундной точности
Здравствуйте! Помогите мне пожалуйста со скетчем, с апаратной я знаком. ...

Один таймер и 11 разных интервалов
Добрый день уважаемые форумчане. Имеется на данный момент 11 таймеров, в каждом...

Отличие доверительных интервалов от прогнозных интервалов
Всем доброго вермени года! Подскажите в чем разница между доверительными...

18
ValeryS
Модератор
7124 / 5392 / 669
Регистрация: 14.02.2011
Сообщений: 18,210
11.07.2018, 08:08 #2
Цитата Сообщение от Jurboss Посмотреть сообщение
unsigned char CheckTime(boolean zapusk)
и всего один выход
Цитата Сообщение от Jurboss Посмотреть сообщение
return 2;
а в других случаях что возвращает?
C++
1
TimerOn.CheckTime(0);
0
Jurboss
0 / 0 / 0
Регистрация: 10.09.2017
Сообщений: 11
11.07.2018, 08:34  [ТС] #3
Возвращает то, что записывает в переменную stat
Возвращать через return, скрипт не работает правильно. Функция CheckTime() присваивает значение переменной stat, тем самым и получается возвращаемое значение.
0
ValeryS
Модератор
7124 / 5392 / 669
Регистрация: 14.02.2011
Сообщений: 18,210
11.07.2018, 08:43 #4
Jurboss, как минимум не работоспособный
как максимум рухнет вся программа
Цитата Сообщение от Jurboss Посмотреть сообщение
Возвращает то, что записывает в переменную stat
покажи где?
0
Jurboss
0 / 0 / 0
Регистрация: 10.09.2017
Сообщений: 11
11.07.2018, 10:16  [ТС] #5
Я думаю так: Переменная stat находится вне функции CheckTime() и когда она записывает значение в переменную stat, она как-бы выводит значение из себя. Сам удивляюсь как такое происходит, поэтому и написал на форум.

Я понимаю, что скрипт не соответствует стандартам написания ООП.
Но факт, все работает отлично. Пишу скетч для автомобильной сигнализации на Arduino pro mini, там много отслеживаний промежутков времени, например, ожидание ответа, включать и выключать лампочки с определенным промежутком, завести двигатель на 10 минут, ожидание нажатия кнопки 2, после нажатия кнопки 1 и все это одновременно контролировать. Все промежутки контролирую через данный объект и всё работает без сбоев.

Попробуйте залить мой пример в Arduino, все работает.

Добавлено через 1 час 9 минут
Вот пример и итог работы демонстрации возвращаемого значения:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class Interval   // Класс отсчета времени
{
  public:
    unsigned long int outtime;    // Время остановки (Мс)
    unsigned long int interval;   // Хранение интервала объекта (Мс)
    unsigned char stat = 0;       // Статус объекта таймера 0 - остановлено, 1 - идет отсчет, 2 - время прошло.
 
    unsigned char CheckTime(boolean zapusk)
    {
      unsigned long int corTime;
      if (stat == 0 && zapusk == 1)           // Если счетчик остановлен и разрешон запуск - то запустить
      {
        outtime = millis() + interval;        // Определение времени остановки
        corTime = millis();
        stat = 1;                             // Статус - таймер запущен
      }
      if (stat == 1)                          // Если статус = 1(Таймер запущен)
      {
        corTime = millis();                   // Берём текущее время
        if (corTime > outtime)                // Если текущее время превысило устаноленное
        {
          stat = 2;
          return 2;
        }
      }
      if (stat == 2)stat = 0;
    }
};
//-------------------------------------------------------------------------//
#include <SoftwareSerial.h>
#define ledpin 13
 
Interval TimerOff;                    // Объект интевала выключено
Interval TimerOn;                     // Объект длительности включено
 
int onn = 0;
int off = 0;
 
void setup() {
    TimerOff.interval = 1000;         // Интервал выключено
    TimerOn.interval = 500;          // Интервал длительности включено
    pinMode(ledpin, OUTPUT);
    Serial.begin(57600);                           // Скорость обмена данными с компьютером
    Serial.println("START");
}
 
void loop() {
  onn = TimerOn.CheckTime(0);
  off = TimerOff.CheckTime(0);
  
  Serial.println("TimerOn = " + String(onn));
  Serial.println("TimerOff = " + String(off));
  Serial.println("--------------------------------------------");
  if(onn == 0 && off == 0) // Если счетчики остановлены
      {
          digitalWrite(ledpin, HIGH);     // Включить
          TimerOn.CheckTime(1);                             // Включить отсчет времени включения
      }
      if(onn == 2)                         // Если счетчик включено остановлен
      {
          digitalWrite(ledpin, LOW);      // Выключить
          TimerOff.CheckTime(1);                            // Включить отсчет времени выключения
      }
}
START
TimerOn = 0
TimerOff = 0
--------------------------------------------
TimerOn = 1
TimerOff = 0
--------------------------------------------
TimerOn = 1
TimerOff = 0
--------------------------------------------
TimerOn = 1
TimerOff = 0
--------------------------------------------
TimerOn = 1
TimerOff = 0
--------------------------------------------
TimerOn = 1
TimerOff = 0
--------------------------------------------
TimerOn = 2
TimerOff = 0
--------------------------------------------
TimerOn = 2
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 2
--------------------------------------------
TimerOn = 0
TimerOff = 2
--------------------------------------------
TimerOn = 0
TimerOff = 0
--------------------------------------------
TimerOn = 1
TimerOff = 0
--------------------------------------------
TimerOn = 1
TimerOff = 0
--------------------------------------------
TimerOn = 1
TimerOff = 0
--------------------------------------------
TimerOn = 1
TimerOff = 0
--------------------------------------------
TimerOn = 1
TimerOff = 0
--------------------------------------------
TimerOn = 2
TimerOff = 0
--------------------------------------------
TimerOn = 2
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
TimerOn = 0
TimerOff = 1
--------------------------------------------
0
Mirmik
techpriest
220 / 191 / 53
Регистрация: 27.02.2014
Сообщений: 1,018
11.07.2018, 10:18 #6
Проверка интервала будет работать неверно вблизи времени переполнения счетчика.

Правильный вариант. curtime - start >= interval;
0
Jurboss
0 / 0 / 0
Регистрация: 10.09.2017
Сообщений: 11
11.07.2018, 10:28  [ТС] #7
По подробнее пожалуйста об curtime - start >= interval;
Не понятно, что это значит и куда относится.
0
Mirmik
techpriest
220 / 191 / 53
Регистрация: 27.02.2014
Сообщений: 1,018
11.07.2018, 11:14 #8
Лучший ответ Сообщение было отмечено Jurboss как решение

Решение

Это к вопросу о методе проверки наступления времени срабатывания.
C++
1
if (corTime > outtime)
К сожалению, это не работает вблизи определенных значений времени, приближенных к максимальным.
У вас, конечно разрядность будь здоров и ошибку вы бы увидели раз в восемь лет, но есть проблема.

millis на ардуино 16-ти битный. Он сбрасывается каждый 50 суток.

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

Добавлено через 24 минуты
Наврал. Миллис 32-х битный... И да, он обнуляется каждые 49 с хвостиком суток. То есть раз в пятьдесят суток ваш алгоритм даст сбой.

Добавлено через 3 минуты
Если же сохранять не время завершения, а время старта, то используя проверку:
C++
1
if (corTime - starttime >= interval)
Ошибки можно избежать.
0
Jurboss
0 / 0 / 0
Регистрация: 10.09.2017
Сообщений: 11
11.07.2018, 11:27  [ТС] #9
Замечание справедливо. Для меня критично.
0
Mirmik
techpriest
220 / 191 / 53
Регистрация: 27.02.2014
Сообщений: 1,018
11.07.2018, 11:31 #10
Почему не изменит? Подумайте еще раз.
0
Jurboss
0 / 0 / 0
Регистрация: 10.09.2017
Сообщений: 11
11.07.2018, 11:35  [ТС] #11
[quote="Mirmik;12533311"]C++
C++
1
if (corTime - starttime >= interval)
Отличное решение. Я не смог придумать.
0
Mirmik
techpriest
220 / 191 / 53
Регистрация: 27.02.2014
Сообщений: 1,018
11.07.2018, 11:38 #12
Я его когда-то в коде ядра того же самого Ардуино подсмотрел. По-моему, раньше delay был так реализован. Прием этот стандартен, довольно часто используется.
1
Avazart
Эксперт С++
7674 / 5583 / 541
Регистрация: 10.12.2010
Сообщений: 25,046
Записей в блоге: 17
11.07.2018, 18:31 #13
На встроенном таймере/прерываниях слабо? Есть же либа ...
0
Mirmik
techpriest
220 / 191 / 53
Регистрация: 27.02.2014
Сообщений: 1,018
12.07.2018, 10:18 #14
Avazart. В целом, решение на прерываниях плохо масштабируется. Програмные таймеры предпочтительнее, если не требуется большой точности.
0
Jurboss
0 / 0 / 0
Регистрация: 10.09.2017
Сообщений: 11
12.07.2018, 13:06  [ТС] #15
Как заметил мою ошибку Mirmik, переделал класс
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Interval   // Класс отсчета времени
{
  public:
    unsigned long int starttime;    // Время запуска (Мс)
    unsigned long int interval;   // Хранение интервала объекта (Мс)
    unsigned char stat = 0;       // Статус объекта таймера 0 - остановлено, 1 - идет отсчет, 2 - время прошло.
 
    unsigned char CheckTime(boolean zapusk)
    {
      unsigned long int corTime;
      if (stat == 0 && zapusk == 1)           // Если счетчик остановлен и разрешон запуск - то запустить
      {
        starttime = millis();                 // Фиксируем время запуска
        stat = 1;                             // Статус - таймер запущен
      }
      if (stat == 1)                          // Если статус = 1(Таймер запущен)
      {
        corTime = millis();                   // Берём текущее время
        if (corTime - starttime >= interval)  // Если промежутор времени превысил интервал
        {
          stat = 2;
          return 2;
        }
      }
      if (stat == 2)stat = 0;
    }
};
//-------------------------------------------------------------------------//
Если во время выполнения отсчета таймера, нужно один раз изменить интервал то (но следующий запуск нужен с первичным интервалом)

C++
1
2
#define newSTOP 120000    // Новый интервал таймера 2 мин
TimerOn.starttime = millis() - TimerOn.interval + newSTOP;
0
Mirmik
techpriest
220 / 191 / 53
Регистрация: 27.02.2014
Сообщений: 1,018
12.07.2018, 13:36 #16
У ваших таймеров есть еще одна проблема.
Они уплывают при перезапуске в силу того, что каждый раз переинициализируются с новым временем.

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

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

Тоесть, вместо:
C++
1
TimerOn.CheckTime(1);
Можно писать что-то вроде:
C++
1
2
3
TimerOn.starttime = TimerOff.starttime + TimerOff.interval;
TimerOn.stat = 1;
TimerOn.CheckTime(0);
Добавлено через 8 минут
тут под точностью понимается то, чтобы ошибка не уплывала.
0
Jurboss
0 / 0 / 0
Регистрация: 10.09.2017
Сообщений: 11
12.07.2018, 13:52  [ТС] #17
Таймер не пойдет в перезагрузку, пока не отсчитает время. Остановить таймер принудительно
C++
1
TimerOn.stat = 0;
Можно постоянно его опрашивать с запуском и код будет выполнятся через заданные промежутки, а если в какой-то момент нужно изменить интервал (написал выше).
Насчет миллисекунд, да есть погрешность, но если нужно включать и выключать что-то с интервалом от 1 сек и больше, миллисекунды не имеют значения.

C++
1
2
3
4
if (TimerOn.CheckTime(1) == 2)
{
   // Здесь код по окончанию таймера и следующий запуск кода через заданный интервал
}
0
Mirmik
techpriest
220 / 191 / 53
Регистрация: 27.02.2014
Сообщений: 1,018
12.07.2018, 15:10 #18
Если что-то одно, то в целом два. А вот если вы две таких системы запустите паралельно, то вскоре можете удивиться. Потому как это кажется, что миллисекунда - это что-то незначительное. Они очень быстро накапливаются.
0
Jurboss
0 / 0 / 0
Регистрация: 10.09.2017
Сообщений: 11
12.07.2018, 16:01  [ТС] #19
Проверил, вы правы, получилась следующая картина
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <SoftwareSerial.h> 
 
Interval tim1;
Interval tim2;
Interval tim3;
Interval tim4;
Interval tim5;
 
unsigned int t;
 
void setup () {
 Serial.begin(9600);
 Serial.println("START");
 
tim1.interval = 1000;
tim2.interval = 2000;
tim3.interval = 3000;
tim4.interval = 4000;
tim5.interval = 5000;
 
}
 
void loop () {
    if (tim1.CheckTime(1) == 2){
    t = millis() - tim1.starttime;
        Serial.println("tim1 = " + String(t));
    }
  if (tim2.CheckTime(1) == 2){
    t = millis() - tim2.starttime;
   Serial.println("tim2 = " + String(t));
  }
  if (tim3.CheckTime(1) == 2){
    t = millis() - tim3.starttime;
    Serial.println("tim3 = " + String(t));
  }
  if (tim4.CheckTime(1) == 2){
    t = millis() - tim4.starttime;
    Serial.println("tim4 = " + String(t));
  }
  if (tim5.CheckTime(1) == 2){
    t = millis() - tim5.starttime;
    Serial.println("tim5 = " + String(t));
  }
}
Получаются непонятные сбои.
Хотя в моём скетче сигнализации все отрабатывает отлично. Буду искать решения.

START
tim1 = 1000
tim1 = 1000
tim1 = 1000
tim2 = 2000
tim1 = 1000
tim2 = 2000
tim3 = 3000
tim1 = 1000
tim3 = 3000
tim1 = 1000
tim4 = 4000
tim1 = 1000
tim2 = 2000
tim4 = 4000
tim1 = 1000
tim2 = 2001
tim5 = 5000
tim5 = 5000
tim1 = 1000
tim1 = 1000
tim3 = 3000
tim3 = 3000
tim1 = 1000
tim2 = 2000
tim1 = 1000
tim2 = 2000
tim1 = 1000
tim1 = 1000
tim1 = 1000
tim2 = 2000
tim4 = 4000
tim1 = 1000
tim2 = 2000
tim4 = 4001
tim3 = 3000
tim3 = 3000
tim1 = 1000
0
12.07.2018, 16:01
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.07.2018, 16:01
Привет! Вот еще темы с решениями:

Скрипт для nnCron для отслеживания появления новой папки в заданной директории
Доброго времени! Надеюсь пишу в нужной теме. Суть: нужно создать скрипт,...

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

Программа для отслеживания смартфона !
Доброго времени суток ! Уважаемые форумчане, подскажите пожалуйста какую...

программа для отслеживания проца
Есть кака это программа для просмотра какой процесс нагрузил ОЗУ на 100% или...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru