Некорректно отрабатывает задержка на millis()

Доброго времени суток!
Начал знакомиться с миром ардуино. Заимел Uno на CH340G, датчик DHT22, дисплей LCD2004.
Набросал скетч, но столкнулся с тем, что он работает не так, как я задумывал. Задержка между итерациями цикла меньше, чем задана.

#include <DHT.h>
#include <LiquidCrystal_1602_RUS.h>

LiquidCrystal_1602_RUS lcd(2, 3, 4, 5, 6, 7);
#define DHTPIN 8
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.begin(20, 4);
  lcd.setCursor(0, 0);
  lcd.print(F("Влажность: "));
  lcd.setCursor(0, 2);
  lcd.print(F("Температура: "));
}

void loop() {
  static unsigned long lastLoop = 0;
  unsigned long now = millis();
  if (lastLoop > now) {
    lastLoop = 0;
  }
  if (now > (lastLoop+5000)) {
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  if (isnan(h) || isnan(t)) {
    Serial.println(F("ERROR READING"));
  }
  if (!isnan(h)) {
    lcd.setCursor(11, 0);
    lcd.print(h);
    lcd.print(F("%"));
  }
  if (!isnan(t)) {
    lcd.setCursor(13, 2);
    lcd.print(t);
    lcd.print(F("°C"));
  }
  Serial.println(h);
  Serial.println(t);
  lastLoop = now;
  }
}

В выводе порта получаю

00:25:01.517 -> 34.80
00:25:01.517 -> 26.10
00:25:02.102 -> 34.80
00:25:02.102 -> 26.10
00:25:05.692 -> 34.60
00:25:05.692 -> 26.20

43 строку переместите между 25 и 26…

Не помогло, в выводе порта так же

00:35:10.968 -> 35.30
00:35:10.968 -> 25.90
00:35:12.426 -> 35.30
00:35:12.426 -> 25.90
00:35:18.467 -> 35.20
00:35:18.467 -> 25.80
00:35:24.298 -> 35.00
00:35:24.298 -> 25.80
00:35:25.440 -> 35.00
00:35:25.440 -> 25.80
00:35:26.639 -> 35.20
00:35:26.639 -> 25.90
00:35:27.363 -> 35.20
00:35:27.363 -> 25.90
00:35:28.616 -> 35.20

Пробовал реализовать через delay() - такая же ситуация.
То выводит данные каждую секунду, то 20 секунд не выводит ничего.

Dht не сразу выдает видимо…
У него по паспорту 2 секунды !!!

Плюс вы переврали алгоритм с millis !!!

да не, если даже все вычистить

Переписал на delay() с задержкой между запросом данных с DHT и выводом данных, стало работать корректно

00:44:09.850 -> 35.20
00:44:09.850 -> 25.80
00:44:14.870 -> 35.20
00:44:14.870 -> 25.80
00:44:19.858 -> 35.50
00:44:19.901 -> 25.80
00:44:24.876 -> 35.60
00:44:24.915 -> 25.80
00:44:29.920 -> 35.40
00:44:29.920 -> 25.80
#include <DHT.h>
#include <DHT_U.h>
#include <LiquidCrystal_1602_RUS.h>

LiquidCrystal_1602_RUS lcd(2, 3, 4, 5, 6, 7);
#define DHTPIN 8
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.begin(20, 4);
  lcd.setCursor(0, 0);
  lcd.print(F("Влажность: "));
  lcd.setCursor(0, 2);
  lcd.print(F("Температура: "));
}

void loop() {
  float h = dht.readHumidity();
  delay(3000);
  float t = dht.readTemperature();
  delay(3000);
  if (isnan(h) || isnan(t)) {
    Serial.println(F("ERROR READING"));
  }
  if (!isnan(h)) {
    lcd.setCursor(11, 0);
    lcd.print(h);
    lcd.print(F("%"));
  }
  if (!isnan(t)) {
    lcd.setCursor(13, 2);
    lcd.print(t);
    lcd.print(F("°C"));
  }
  Serial.println(h);
  Serial.println(t);
}

и что?
теперь у тебя корректно “отрабатывает задержка на millis()” ?

Нет, некорректно
С таким скетчем ситуация следующая

#include <DHT.h>
#include <DHT_U.h>
#include <LiquidCrystal_1602_RUS.h>

LiquidCrystal_1602_RUS lcd(2, 3, 4, 5, 6, 7);
#define DHTPIN 8
#define DHTTYPE DHT22
DHT_Unified dht(DHTPIN, DHTTYPE);

uint32_t delayMS;

void setup() {
  Serial.begin(9600);
  dht.begin();
  sensor_t sensor;
  dht.temperature().getSensor(&sensor);
  dht.humidity().getSensor(&sensor);
  delayMS = sensor.min_delay / 1000;
  lcd.begin(20, 4);
  lcd.setCursor(0, 0);
  lcd.print(F("Влажность: "));
  lcd.setCursor(0, 2);
  lcd.print(F("Температура: "));
}

void loop() {
  static unsigned long lastLoop = 0;
  unsigned long now = millis();
  if (lastLoop > now) {
    lastLoop = 0;
  }
  if (now > (lastLoop+delayMS)) {
  lastLoop = now;
  sensors_event_t humidityEvent;
  sensors_event_t temperatureEvent;
  dht.temperature().getEvent(&temperatureEvent);
  dht.humidity().getEvent(&humidityEvent);
  if (isnan(humidityEvent.relative_humidity) || isnan(temperatureEvent.temperature)) {
    Serial.println(F("ERROR READING"));
  } else {
    lcd.setCursor(11, 0);
    lcd.print(humidityEvent.relative_humidity);
    lcd.print(F("%"));
    lcd.setCursor(13, 2);
    lcd.print(temperatureEvent.temperature);
    lcd.print(F("°C"));
    Serial.println(humidityEvent.relative_humidity);
    Serial.println(temperatureEvent.temperature);
  }
  }
}
01:32:53.977 -> 37.80
01:32:53.977 -> 25.00
01:32:54.877 -> 37.80

Далее с порта информация перестала приходить

А может всё-таки стоит посмотреть пример BlinkWithoutDelay - как с миллисом обращаться?

Отвецтвуй мне, отрок, в чём сакральный смысл строк 22-24 исходного скейча?

А вы тут такие тёмные, что даже про переполнения не слышали? :slight_smile:

а вот интересно, что ИИ про переполнение думает?

Ахтунг ахтунг. Секта свидетелей переполнения детектед !!!

Спросил. Думает уже 10 минут. Наверное, Гиверу звонит, консультируется. Когда и если ответит, выложу.

1 лайк

Может у него обед, если это рассейский ИИ.

Думаю, обед у Гивера. Или ещё по какой причине трубку не берёт. Но думает уже долго, гляньте на метку времени (это @GPT4Telegrambot ):

ИИ переполнился …

Ответил. Я потом ещё вопрос задал, вот результат:

Что такое переполнение millis в Arduino?

Переполнение millis в Arduino происходит, когда переменная millis, которая хранит количество миллисекунд, прошедших с момента запуска программы, достигает максимального значения (примерно 50 дней). После этого происходит переполнение переменной и она начинает считать время с нуля. Это может привести к неправильной работе программы, если она основана на точном измерении времени. Для решения этой проблемы можно использовать специальные функции и библиотеки, которые учитывают переполнение millis.

Как бороться с переполнением millis в Arduino?

  1. Использовать таймеры высокого разрешения - вместо использования функции delay() можно использовать таймеры высокого разрешения, такие как millis(). Они позволяют управлять временем более точно и предотвращать переполнение.
  2. Использовать библиотеку TimeLib - библиотека TimeLib позволяет работать с временем в Arduino, предотвращая переполнение millis и обеспечивая удобную работу с временем.
  3. Использовать функцию масштабирования времени - можно использовать специальную функцию, которая масштабирует время и позволяет увеличить его длительность до максимального значения переменной millis.
  4. Периодически проверять и перезапускать таймер - можно периодически проверять значение переменной millis и перезапускать таймер, чтобы избежать переполнения.
  5. Использовать библиотеки реального времени - существуют специальные библиотеки реального времени для Arduino, которые позволяют работать с временем более эффективно, предотвращая переполнение millis.

Наврядли у Гувера спрашивал - ни одна библиотека Gyver* в рекомендованный список не вошла.

Думаю, что на какой-нить Амперке пошлялся или, даже, по нашему форуму порыскал.