На простом скейче спустя время лагает функция millis()

jeka744
Offline
Зарегистрирован: 06.10.2019

Сижу уже месяц над одним проектом. Собираю можно сказать умный террариум.

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

Собралось 5 переменных для функции millis() искал способ разгрузить ардуинку, а то выходит рез в секунду количество ее действий подскакивает к примеру с 10 до 100. когда можно было бы распределить на всю секунду. Связано с тем что много операций выполняется раз в секунду. И тут написал для теста и столкнулся с глюком.

При запуске контроллера все работает четко но спустя пол часа или час. передача в Serial становиться примерно отправил "1" спустя примерно 0.4 секунды отправил "2" спустя так же 0.4 секунды "3" и тд. что я недопонимаю? из за чего такое происходит? плата китайская нана 328Р атмегой. 

unsigned long startLOOP;                            
unsigned long startLOOP1;
unsigned long startLOOP2;
unsigned long startLOOP3;
unsigned long startLOOP4;
void setup() {
  Serial.begin(9600);

}

void loop() {
  if (millis() - startLOOP > 5000) {
    startLOOP = millis();
    Serial.println("1");
  }
   if (millis() - startLOOP1 > 5001) {
    startLOOP1 = millis();
    Serial.println("2");
  }
   if (millis() - startLOOP2 > 5002) {
    startLOOP2 = millis();
    Serial.println("3");
  }
   if (millis() - startLOOP3 > 5003) {
    startLOOP3 = millis();
    Serial.println("4");
  }
   if (millis() - startLOOP4 > 5004) {
    startLOOP4 = millis();
    Serial.println("5");
  }
}

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

Клапауций 003
Offline
Зарегистрирован: 20.07.2019

jeka744 пишет:

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

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

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

каждый следующий цикл длинее предыдущего на 1 мс.  За полчаса эти циклы исполняются примерно 600 раз - сл-но набегает разница в 0.6 секунды.

Хотите чтобы разница не накапливалась - задайте один общий интервал на все пять условий

jeka744
Offline
Зарегистрирован: 06.10.2019

Тут не все так просто. Днем температура одна, ночью другая. В вентиляции есть спираль для того что бы подогревать воздух, с термошнуром это быстрее пример. Там все горазда сложнее. Есть кулер от компьютера в фоновом режиме он крутиться 300 оборотов в минуту. С обогревом он выбирает оптимальную скорость так чтоб быстрее согреть террариум. Так же на эту спираль я подаю ШИМ сигнал, в Зависимости от разнице температуры между комнатой и внутри террариума. Это в 1 очередь позволит экономить электроэнергию. Есть другая сторона этого. К примеру попала солнце на террариум. Стенки вроде холодные шнур вроде тоже, термостат запустил подогрев не смотря на то что в террариуме как в парнике. В моей задумке все иначе, Датчик dht22 определил температуру. В моем случаи это 2 датчика dht22 один стоит с низу другой с верху, и в расчет берётся среднее значение. Увидел что температура большая из за тех же лучей солнца. не стал включать подогрев(по сколько не прислонен к стеклу которое в любом случаи на полу будет прохладное) А добавил обороты вентилятора выронив температуру до нужной, не затратив при этом лишний электроэнергии.

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

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

Но опять же, похвасться я люблю идеями, пусть и путь к ним долог. Я думаю продвинутые ардуиншики эти циклы написали за пару дней а не как я месяц копчу проверяя все по отдельности. НО ГЛАВНЫЙ ВОПРОС В ТОМ ПОЧЕМУ ЭТО ПРОИСХОДИТ?  от куда взялся глюк? И может это быть из за того что плата ардуина нана слишком слабая? На нане я проверяю каждый режим в отдельности потом это все дела перемешается на мегу. По сколько из бюджетных у меге хватает памяти это все исполнять. У наны кончалась память уже после подключения часов ОЛЕД дисплея и 2х датчиков dht22.

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

jeka744
Offline
Зарегистрирован: 06.10.2019

b707 пишет:

каждый следующий цикл длинее предыдущего на 1 мс.  За полчаса эти циклы исполняются примерно 600 раз - сл-но набегает разница в 0.6 секунды.

Хотите чтобы разница не накапливалась - задайте один общий интервал на все пять условий

Немного не понял. Да я понимаю на примере этого цикла проще одним условиям все сделать. Но исходя из того что уже много написано и я давал милис специально разные переменные чтоб в каждой функции был свой милис. И переделать это все под одну переменую мне пока кажется нереальным. 

Или я снова что то не так понял? Как вы вычислили 0.6 секунды?  и почему получается каждый новый цыкал длине? если постоянно идет приравнивание переменной к милес? немного не понял. Можете пояснить по проще на пальцах?

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

unsigned long startLOOP;                            
unsigned long startLOOP1;
unsigned long startLOOP2;
unsigned long startLOOP3;
unsigned long startLOOP4;
void setup() {
  Serial.begin(9600);

}

void loop() {
  if (millis() - startLOOP > 1000) {
    startLOOP = millis();
    Serial.println("1");
  }
   if (millis() - startLOOP1 > 1000) {
    startLOOP1 = millis();
    Serial.println("2");
  }
   if (millis() - startLOOP2 > 1000) {
    startLOOP2 = millis();
    Serial.println("3");
  }
   if (millis() - startLOOP3 > 1000) {
    startLOOP3 = millis();
    Serial.println("4");
  }
   if (millis() - startLOOP4 > 1000) {
    startLOOP4 = millis();
    Serial.println("5");
  }
}

Повторюсь обледенить в 1 милис их нельзя по сколько то где это нужно там разные функции. Можно как то сделать чтоб это выполнялась на протяжение секунды а не раз в секунду все 5 действия? хотелось немного оптимизировать работу.

Это мой первый большой проект и в первые я использую милис. Не ругайте сильно за тупые вопросы. 

vvadim
Offline
Зарегистрирован: 23.05.2012

вы на марс летите или климатом в банке занимаетесь ?

нафига такие точности ?

да ещё и DHT22.

Вы себе просто голову ерундой забиваете.

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

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

ТС, тебе запятых отсыпать?  У мня есть, полно.  И разные другие есть препинания.

Komandir
Offline
Зарегистрирован: 18.08.2018

Хорошим тоном считается задание начальных значений переменных.

В крайнем скетче задайте им значения от 0 до 800 с шагом в 200.

 

Гриша
Offline
Зарегистрирован: 27.04.2014

jeka744 пишет:

Это мой первый большой проект и в первые я использую милис. Не ругайте сильно за тупые вопросы. 

мои первые проекты еще хуже, хоть и проще. Клапауций писал класс титановый велосипед для delay без delay(). можно использовать как библиотеку, завести переменную и выполнять какие-либо действий по новому счетчику.

т.е. когда переменная счетчика станет равной заданной, а в конце ее скидывать и начинать цикл заново. Можно вообще календарь или "RTC" использовать. 

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

jeka744 пишет:

 Как вы вычислили 0.6 секунды?  и почему получается каждый новый цыкал длине? если постоянно идет приравнивание переменной к милес? немного не понял. Можете пояснить по проще на пальцах?

Я там выше немного обсчитался, не 0.6 сек, а 0.4. Но суть та же.

Каждый следующий цикл длиннее, потому что вы их так задали. Вот смотрите - в первом у вас интервал 5000 мс, во втором - 5001. То есть выполнение второго цикла длинеее на 1мс, и с каждым запуском второй цикл все больше отстает от первого. 5000 мс - это 5 сек, значит за минуту циклы запускаются 12 раз и между первым и вторым циклом накопится расхождение в 12 мс. За 30 минут - 30*12 = 360мс, то есть примерно 0.4 секунды

Цитата:
ГЛАВНЫЙ ВОПРОС В ТОМ ПОЧЕМУ ЭТО ПРОИСХОДИТ?  от куда взялся глюк? И может это быть из за того что плата ардуина нана слишком слабая?

Не пишите ерунды, ардуина тут совершенно не причем - причина исключительно в вашем коде. Код работает ровно так, как вы его написали.

jeka744
Offline
Зарегистрирован: 06.10.2019

b707 пишет:

Не пишите ерунды, ардуина тут совершенно не причем - причина исключительно в вашем коде. Код работает ровно так, как вы его написали.

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

 

Еще такой вопросик из куска кода. Не будит тут не каких глюков? попробую собрать код как можно проще. 

unsigned long startVlaga;                           // для функции милис увлажнения
float h1 = 0;                                       // для влажности с датчика 1 верхний
float h2 = 0;                                       // для влажности с датчика 2 нижний
int vlagaON = 0;                                    // изменения режима увлажнения
int vlagaConstant = 0;                              // перебирает значения переменную vlagaHour
int vlMin = 0;                                      // Минимальное значение влаги
int vlagaAUTO = 3;                                  // время на которое будет включатся увлажнитель когда уровень влажности будет меньше заданного. в минутах
int vlagaPRIN = 10;                                 // время на сколько будет включаться ежедневное увлажнения(выпала роса) в минутах
int vlagaHour[] {10, 16, 22};                       // в какой час будет включаться принудительное увлажнение часы через запятую в {} скобках
int vlagaN = 3;                                     // сколько раз будет включаться принудительное увлажнения (сколько интервалов задано в vlagaHour[] )
int pinPawerV = 12;                                 // пин к которому подключена реле для замыкания кнопки вкл выкл увлажнитель
int pinIntensivV = 11;                              // пин к которому подключено реле замыкающие кнопку регулировки интенсивности увлажнения
int pinHetV = 10;                                   // пин к которому подключено реле для замыкания кнопки нагрев увлажнения
int pinION = 9;                                     // пин к которому подключено реле для замыкания кнопки ионизация увлажнения
int hour ;                                          // для хранения  часов с часов реального времени 
int minut ;                                         // для хранения минут с часов реального времени 

void setup() {
  digitalWrite(pinPawerV, HIGH);                    // реле включается если подтянуть вывод к минусу.  
  digitalWrite(pinIntensivV, HIGH);
  digitalWrite(pinHetV, HIGH);
  digitalWrite(pinION, HIGH);
}



void loop() {
 vlagas ();
}


void vlagas () {                                    // функция увлажнения. 
  if ((h1 + h2) / 2 < vlMin && vlagaON == 0 && h1 > 0 && h2 > 0) {  // сравниваем уровень влажности в террариуме с минимальным значением, проверяем все ли датчики подключены  
    vlagaON = 1;
    startVlaga = millis(); 
  }
  if ( vlagaConstant < vlagaN) {                    // перебираем значения часов когда будет выпадать раса 
    vlagaConstant++;
  }
  else {
    vlagaConstant = 0;
  }
  if (hour == vlagaHour[ vlagaConstant] && vlagaON == 0 &&  minut - 1 < vlagaPRIN) {  // сравниваем часы с часами когда должна выпасть раса 
    vlagaON = 2;
    startVlaga = millis();
  }
  if (vlagaON == 1) {                               // сценарий включения увлажнения в случаи низкого уровня влаги (без ионизации) 

    if (millis() - startVlaga > 300 && millis() - startVlaga < 600) {
      digitalWrite(pinPawerV, LOW);
    }
    if (millis() - startVlaga > 600 && millis() - startVlaga < 900 ) {
      digitalWrite(pinPawerV, HIGH);
    }
    if (millis() - startVlaga > 900 && millis() - startVlaga < 1200) {
      digitalWrite(pinIntensivV, LOW);
    }
    if (millis() - startVlaga > 1200  && millis() - startVlaga < 1500) {
      digitalWrite(pinIntensivV, HIGH);
    }
    if (millis() - startVlaga > 1500 && millis() - startVlaga < 1800) {
      digitalWrite(pinIntensivV, LOW);
    }
    if (millis() - startVlaga > 1800 && millis() - startVlaga < 2100 ) {
      digitalWrite(pinIntensivV, HIGH);
    }
    if (millis() - startVlaga > 2100 && millis() - startVlaga < 2400) {
      digitalWrite(pinHetV, LOW);
    }
    if (millis() - startVlaga > 2400  && millis() - startVlaga < 2700) {
      digitalWrite(pinHetV, HIGH);
    }
    if (millis() - startVlaga > 60000 * vlagaAUTO  && millis() - startVlaga < 60000 * vlagaAUTO + 300) {
      digitalWrite(pinPawerV, LOW);
    }
    if (millis() - startVlaga > 60000 * vlagaAUTO + 300  && millis() - startVlaga < 60000 * vlagaAUTO + 600) {
      digitalWrite(pinPawerV, HIGH);
    }
    if (millis() - startVlaga > 60000 * vlagaAUTO + 700) {
      startVlaga = millis();
      vlagaON = 0;

    }
  }
  if (vlagaON == 2) {                             // сценарий включения увлажнения по часам (с ионизацией)
    if (millis() - startVlaga > 300 && millis() - startVlaga < 600) {
      digitalWrite(pinPawerV, LOW);
    }
    if (millis() - startVlaga > 600 && millis() - startVlaga < 900 ) {
      digitalWrite(pinPawerV, HIGH);
    }
    if (millis() - startVlaga > 900 && millis() - startVlaga < 1200) {
      digitalWrite(pinIntensivV, LOW);
    }
    if (millis() - startVlaga > 1200  && millis() - startVlaga < 1500) {
      digitalWrite(pinIntensivV, HIGH);
    }
    if (millis() - startVlaga > 1500 && millis() - startVlaga < 1800) {
      digitalWrite(pinIntensivV, LOW);
    }
    if (millis() - startVlaga > 1800 && millis() - startVlaga < 2100 ) {
      digitalWrite(pinIntensivV, HIGH);
    }
    if (millis() - startVlaga > 2100 && millis() - startVlaga < 2400) {
      digitalWrite(pinHetV, LOW);
    }
    if (millis() - startVlaga > 2400  && millis() - startVlaga < 2700) {
      digitalWrite(pinHetV, HIGH);
    }
    if (millis() - startVlaga > 2700  && millis() - startVlaga < 3000) {
      digitalWrite(pinION, LOW);
    }
    if (millis() - startVlaga > 3000  && millis() - startVlaga < 3300) {
      digitalWrite(pinION, HIGH);
    }
    if (millis() - startVlaga > 60000 * vlagaPRIN  && millis() - startVlaga < 60000 * vlagaPRIN + 300) {
      digitalWrite(pinPawerV, LOW);
    }
    if (millis() - startVlaga > 60000 * vlagaPRIN + 300  && millis() - startVlaga < 60000 * vlagaPRIN + 600) {
      digitalWrite(pinPawerV, HIGH);
    }
    if (millis() - startVlaga > 60000 * vlagaPRIN + 700) {
      startVlaga = millis();
      vlagaON = 0;

    }
  }
}

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

Увлажнения по часам нужно для того чтобы на стеклах собрались капли. Странная привычка питомца пить не из поилки, или фонтанчика, а слизывать влагу со стекал.

Вопрос в том что будут ли тут глюки со временим?

При тесте были глюки. Но они были связаны с тем что реле не успевала выключиться или включиться. пока не подобрал оптимальное количество миллисекунд. причем глюк был хаотичный. тестил минут 10. Но все равно бывает какое то реле во включенном состояние дольше какое то меньше. С накоплением Милис  проблем не будет? не появиться какая-нибудь разница? Просто прошу проверить)))) дабы не вышло того что я снова тупанул))))       

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

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Первое, что заметил - есть в скетче отсыл к часам реального времени, но работы с ними я не наблюдаю. Следовательно, проверить в "режиме vlagaON == 2" никогда не представится.

ЗЫ: Может быть это вообще для вас и не нужно, но есть много вопросов по написанию кода. Самый первый вопрос - зачем в loop() вызывать всего одну функцию vlaga()? Суть функций в другом. Чаще всего - вынести повторяющийся код в функцию.

jeka744
Offline
Зарегистрирован: 06.10.2019

BOOM пишет:

Первое, что заметил - есть в скетче отсыл к часам реального времени, но работы с ними я не наблюдаю. Следовательно, проверить в "режиме vlagaON == 2" никогда не представится.

ЗЫ: Может быть это вообще для вас и не нужно, но есть много вопросов по написанию кода. Самый первый вопрос - зачем в loop() вызывать всего одну функцию vlaga()? Суть функций в другом. Чаще всего - вынести повторяющийся код в функцию.

Первое что надо сделать это прочитать полностью. В идеале пробежаться по всей теме. 

Объясняю! в данном коде нет библиотеки, и кода работы с часами реального времени, по сколько это часть кода вернее 1 функция вырванная из большого скейча. В скейче этих функций достаточно. Но чтоб не объяснять длинный код я взял всего его кусочек. По этому отсутствует библиотека работы с часами реального времени. к данной библиотеке вопросов не каких. А поместив ее суда, пришлось бы прикреплять саму библиотеку и грузить людей лишней информацией. Вопрос весь связан функцией милес. Я с ней работаю в 1 раз и какие то нюансы упускаю. По этому прощу подсказать гуру в этой теме точно ли я не получу лагов через день или другой. как в шапке темы.

Почему в loop() я вызываю только эту функцию как сказана выше первое это часть кода в остальное вникать бессмысленно и большинство людей пройдет мимо увидев 30-40 переменных и 300-400 строк кода. Также в дальнейшем в цикле loop() будут прописаны ворожения. К примеру если температура в террариуме ниже заданной то к функции vlaga() орошаться не нужно. Так же если температура в комнате это t3 которого тут нету выше заданной температуре обрушаться и уж точно выполнять функцию обогрева и тратить на нее ресурс контролёра не нужно, а еще просто удобно. Я писал каждый цикл отдельно испытывая на ардуине нано. Далее просто капиравал в общий скейч и из цикла делал функцию зная что данный кусок кода рабочий. И когда Я все помещу в ардуину мегу меньше будет проблем!           

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Я спросил это все не просто так. Если есть часы реального времени, не проще ли работать с ними по "всем пунктам логики программы"?

По типу как у вас сделано вот тут:

  if (hour == vlagaHour[ vlagaConstant] && vlagaON == 0 &&  minut - 1 < vlagaPRIN) {  // сравниваем часы с часами когда должна выпасть раса 
    vlagaON = 2;
    startVlaga = millis();
  }

В библиотеке (по типу такой) есть все что нужно для реализации ваших хотелок. Скеч упростится. Но может я чего-то не знаю/не понимаю в вашей логике... Не исключаю этого.