Подсчет времени работы устройства

medved820

✩✩✩✩✩✩✩
25 Ноя 2020
10
0
Доброго дня!

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

Как в скетч прикрутить паузу/пуск?

C++:
#define BTN 3
#define LED 6
#define periodPIR 1500

boolean btnFlag = false ;
boolean btnFlag1 = false ;
boolean btnFlag2 = false ;
boolean led_flag = false ;

int timer1 = 0;
int timer2 = 0;
int timerRez1 = 0;

void setup() {
  Serial.begin(9600);

  pinMode(BTN, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
}
void loop() {
  bool btnState = !digitalRead(BTN);

  if (btnState && !btnFlag) {
     btnFlag = true;
    led_flag = !led_flag;
    timer1 = millis();
  }
  if (btnFlag && millis() -  timer1 >=  periodPIR) {        // задержка на вкл/откл светодиода
    digitalWrite(LED, led_flag);
    btnFlag1 = !btnFlag1;                                 //флаг о включ светодиода для подсчета времени
    btnFlag = false;
  }

  if (btnFlag1 && !btnFlag2) {                             //отсчет времени с момента включ светодиода
    timer2 = millis();
    btnFlag2 = true;
  }
  if (btnFlag1) {                                          //отсчет времени с момента включ светодиода
    timerRez1 = millis() -  timer2;   
    Serial.print("timerRez1_"); Serial.println (timerRez1);
  }
}
 

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

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
В общем виде так
в самом начале:
общеевремяработы=0
времявключениясветодиода=0

дальше,
если светодиод горит и времявключениясветодиода==0 то
{
времявключениясветодиода=millis()
}
если светодиод не горит и времявключениясветодиода!=0 то
{
общеевремяработы=общеевремяработы+millis()-времявключениясветодиода;
времявключениясветодиода=0;
}
 
  • Лойс +1
Реакции: medved820

medved820

✩✩✩✩✩✩✩
25 Ноя 2020
10
0
C++:
#define BTN 3
#define LED 6
#define periodPIR 1500

bool btnFlag = false ;
bool btnFlag1 = false ;
bool btnFlag2 = false ;
bool led_flag = false ;

uint32_t timer1 = 0;
uint32_t timerLED1 = 0;
uint32_t timerRezult1 = 0;

void setup() {
  Serial.begin(9600);

  pinMode(BTN, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
}
void loop() {
  bool btnState = !digitalRead(BTN);

  if (btnState && !btnFlag) {
    btnFlag = true;
    led_flag = !led_flag;
    timer1 = millis();
  }
  if (btnFlag && millis() -  timer1 >=  periodPIR) {         // задержка на вкл/откл светодиода
    digitalWrite(LED, led_flag);
    btnFlag1 = !btnFlag1;                                                 //флаг о включ светодиода для подсчета времени
    btnFlag = false;
  }

  if (btnFlag1 && timerLED1 == 0) {                              //отсчет времени с момента включ светодиода
    timerLED1 = millis();
  }

  if (!btnFlag1 && timerLED1 != 0) {
    timerRezult1 = timerRezult1 + millis() - timerLED1;             //РЕЗУЛЬТАТ
    timerLED1 = 0;
    Serial.print("timerRezult1_"); Serial.println (timerRezult1);
   }
}
Подсчет времени выполняется, но импульсно, в момент отключения устройства. Как сделать чтобы счёт шёл в режиме реального времени?

Ниже мои правки
C++:
#define BTN 3
#define LED 6
#define periodPIR 1500

bool btnFlag = false ;
bool btnFlag1 = false ;
bool btnFlag2 = false ;
bool led_flag = false ;

uint32_t timer1 = 0;
uint32_t timerLED1 = 0;
uint32_t timerRezult1 = 0;

void setup() {
  Serial.begin(9600);

  pinMode(BTN, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
}
void loop() {
  bool btnState = !digitalRead(BTN);

  if (btnState && !btnFlag) {
    btnFlag = true;
    led_flag = !led_flag;
    timer1 = millis();
  }
  if (btnFlag && millis() -  timer1 >=  periodPIR) {                      // задержка на вкл/откл светодиода
    digitalWrite(LED, led_flag);
    btnFlag1 = !btnFlag1;                                                                  //флаг о включ светодиода для подсчета времени
    btnFlag = false;
  }
 
  if (btnFlag1 && timerLED1 == 0) {                                               //отсчет времени с момента включ светодиода
    timerLED1 = millis();
  }

  if (btnFlag1) {                                                                                    //отсчет времени с момента включ светодиода
    timerRezult1 = timerRezult1  +  millis() - timerLED1;              //РЕЗУЛЬТАТ
    Serial.print("timerRezult1_"); Serial.println (timerRezult1);
  }

  if (!btnFlag1 && timerLED1 != 0) {
    timerLED1 = 0;
   }
}
👆Поправил код, но теперь timerRezult1 считает в режиме реального времени, но не корректно, с сильной прогрессией 😬. Помогите плз
 

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

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
Тогда так:

если светодиод горит и времявключениясветодиода==0 то
{
времявключениясветодиода=millis()
}
если светодиод горит и времявключениясветодиода!=0 то
{
текущее_время=millis()
общеевремяработы=общеевремяработы+текущее_время-времявключениясветодиода;
времявключениясветодиода=текущее_время
}
если светодиод не горит и времявключениясветодиода!=0 то
{
общеевремяработы=общеевремяработы+millis()-времявключениясветодиода;
времявключениясветодиода=0;
}

Если делать в режиме реального времени, то совсем реально не надо. Определитесь c нужным интервалом , скажем 0.1 секунды. Иначе будет очень точный подсчет, и на это будет тратиться все полезное время ардуины

Условие нужно подшаманить. Сделать с подусловиями как то так
если светодиод горит то
{
...
тут преобразованный код
...
}
иначе
{

если времявключениясветодиода!=0 то
{
общеевремяработы=общеевремяработы+millis()-времявключениясветодиода;
времявключениясветодиода=0;
}

}

ДОПОЛНЕНИЕ!
Вот подумалось, что подсчет то можно оставить такой же как был! Но! Ведь постоянно считать нужно для того что бы отображать ?
Тогда делать так
В коде ниже, отдельно (а можно и нет!)

если светодиод горит то
отобразить время горения millis()-время включения светодиода

пожалуй так будет самое точное и быстрое выполнение
 
Изменено:
  • Лойс +1
Реакции: medved820

poty

★★★★★★✩
19 Фев 2020
3,230
940
@medved820, если нет основного замысла, нет и правильного решения. Судя по коду, промежуточные значения времени не используются, тогда чем не устраивает "импульсный подсчёт"?
 

medved820

✩✩✩✩✩✩✩
25 Ноя 2020
10
0
@medved820, если нет основного замысла, нет и правильного решения. Судя по коду, промежуточные значения времени не используются, тогда чем не устраивает "импульсный подсчёт"?
Это часть скетча, само решение будет применяться в отоплении лоджии
 

poty

★★★★★★✩
19 Фев 2020
3,230
940
Это не объясняет то, каким образом применяется посчитаная наработка. У меня есть предположения, например, для контроля потребляемой мощности, но, извините, зачем это считать с точностью до миллисекунд? Как это сохраняется между выключениями электричества? И кто на это будет смотреть между циклами включения/выключения?
В принципе, перед любым использованием этого значения можно точно посчитать, сколько устройство находится онлайн, формула приведена в процедуре выключения, что ещё надо?
 

medved820

✩✩✩✩✩✩✩
25 Ноя 2020
10
0
Ну да, с миллисекундами точно перебор, буду думать дальше
 

medved820

✩✩✩✩✩✩✩
25 Ноя 2020
10
0
Да, дискретность замера 1 раз в 1 сек вполне бы устроила, только не пойму как это сделать.

if (millis() - timing > 1000) {
timing = millis();
...
тут преобразованный код
...
}
👆об этом речь? Только тогда не понятно за счет чего экономим ресурсы Ардуины, это же все тот же вызов миллиса или я чего-то не догоняю?
 

poty

★★★★★★✩
19 Фев 2020
3,230
940
@medved820, Вы упорно не желаете видеть, что подсчёт ради подсчёта бессмыслен. Если же Вы каждый раз, когда считаете, что-то делаете с этим значением, то разница в "расходуемом времени" будет весьма значительна.
Я хотел бы также отметить, что unsigned long хоть и большая величина, но не бесконечная. Значения millis() будут повторяться примерно через 49 дней, такое же предельное "время наработки" Вы соберёте в своём счётчике, дальше он попросту обнулится. Т.е., лучше собирать это в осмысленных переменных (типа дней, часов, минут, секунд), тогда это, во-первых, будет вполне "выводимо", а во вторых - устраняет переполнение счётчика.
 
Изменено:

medved820

✩✩✩✩✩✩✩
25 Ноя 2020
10
0
@poty,
Дружище, я правильно понял, что под "расходуемом времени" подразумевается набегающая погрешность на потраченные ресурсы Ардуины. Сильно не пинайте я тут новенький))
 

poty

★★★★★★✩
19 Фев 2020
3,230
940
Не совсем. Я хочу, чтобы Вы внимательно прочитали пост #4 от @Старик Похабыч . В отличие от меня он часто говорит сложные вещи простыми словами. Ресурсы Ардуино - это относительно бесплатная штука, но только если они есть! Т.е., если Вам нужно просто заставить светиться светодиод и подсчитать, сколько времени он будет светиться - это одно, тут экономить ресурсы не стоит. Результат этого скетча будет нулевой, поскольку Вы это число не сможете узнать, даже если бы захотели. (я сейчас не беру задачу подсчёта времени горения светодиода в принципе, понятно что она вырожденная и не отражает реального применения)
Другое дело - если это как-то используется. Поскольку Вы не хотите говорить для чего Вы это используете, давайте предположим, что Вы хотите посчитать потраченную на отопление лоджии электроэнергию. Вопрос: зачем осуществлять подсчёт "в реальном времени", а не "импульсно", как Вы написали ранее? Ведь до момента, когда Вы посмотрите на условный монитор затраченной электроэнергии, счётчик Вам вообще не понадобится! Вы вообще можете заставить Ардуино спать в период между снятием параметров или изменением статуса (включено/выключено). И давайте допустим, что вывод на монитор занимает... Ну, к примеру, 20мс.
Допустим, что у Вас присутствует некоторый интерактив. Например, Вы хотите в любой момент подойти к мониторчику, нажать кнопку и увидеть количество израсходованной энергии. Допустим, обогреватель всегда включается на полную мощность и Вы точно знаете, сколько он потребляет. Для подсчёта электроэнергии нужно помножить величину потребления в Ваттах на время, которое обогреватель был включен. Это время, хоть и небольшое. Плюс вспоминаем, что нам нужно вывести на монитор (те же 20мс). Мы можем сохранить "импульсный" характер подсчёта, но зафиксировать его моментом нажатия на кнопку (аналогично моменту выключения, только не переводить соответствующий флаг в выключено). Задача выполнена, Ардуино снова свободна.
Усложним задачу: кнопки нет, монитор постоянно включен и должен отображать текущую затраченную работу электричества. "Возникает два путя": отображать в кВт-ч или Вт-ч (тогда период отображения будет зависеть от мощности обогревателя; допустим, для 5кВт обогревателя это будет 12 минут в кВт-ч и 0,72 сек для Вт-ч) или выводить по мере доступности. По прежнему, наше время отображения (20мс + небольшое время для расчёта) по сравнению с периодом отображения в Вт-ч весьма мало. А второй путь будет приводить к тому, что мы будем выводить одно и то же число на монитор примерно 50 раз в секунду. Есть резон считать в реальном времени?
Ещё усложним задачу: сымитируем электросчётчик, для чего поставим два датчика (тока и напряжения) и будем мерить эти величины. Так как ток и напряжение меняются гораздо чаще, чем, допустим, количество Вт-ч, то определим период их измерения в 0,02с (1 период сетевого напряжения). Допустим, используем внешние датчики, измерение тока занимает 2мс, измерение напряжения - 2мс, расчёт также несколько усложняется: кВт-ч = ток * напряжение * время. Если результат каждого такого расчёта мы будем выводить на монитор (+20мс), то 20мс периода измерения нам уже не хватит. Если нам нужно делать что-то ещё (допустим, считывать датчик присутствия и как-то его обрабатывать), то "уходит" ещё часть времени. В результате мы приходим к тому, что времени нам уже не хватает на полную обработку всех данных и наш электросчётчик будет врать. Можно вынести вывод на монитор в отдельный временнОй цикл по смене кВт-ч, например. Тогда этот вывод будет осуществляться в худшем случае (для 5кВт обогревателя) раз в 12 минут и это не окажет существенного влияния на точность данных.
 
  • Лойс +1
Реакции: medved820