Переполнение millis(), как бороться?

Тема в разделе "Arduino & Shields", создана пользователем arssev1, 18 мар 2018.

  1. arssev1

    arssev1 Гик

    Есть следующий код:
    Код (C++):
    #include <Wire.h> //подключаем библиотеку для работы по I²C
    #include <LiquidCrystal.h> //подключаем библиотеку для ЖКИ
    #include <RTClib.h> //подключаем библиотеку для DS3231/DS1307
    #include <Adafruit_Sensor.h> //для нормальной работы библиотеки, что ниже
    #include <Adafruit_BMP280.h> //библиотека для BMP280
    #include <DHT.h> //подключаем библиотеку для DHT11

    #define SENSOR_UPDATE_TIME 5100 //время на обновление датчиков (опрашивать DHT11 не чаще 1 раза в 5 секунд)
    #define DEBOUNCE_TIME 200 //время на подавление дребезга кнопки
    #define DHT_PIN 8 //сигнальный провод DHT на 8 ноге дуины
    #define BUTTON_PIN 9 //кнопка подключена через подягивающий резистор к 9 пину
    #define BUZZER_PIN 10 //пищалка подключена к 10 пину

    LiquidCrystal lcd(7, 6, 5, 4, 3, 2); //подключаем ЖКИ 16x2
    RTC_DS1307 rtc; //DS1307 и DS3231 одинаковы в работе, так что можно подключать и то и то
    DHT dht(DHT_PIN, DHT11); //сигнальный пин DHT11 подключаем к 8 пину Arduino
    Adafruit_BMP280 bmp; //BMP280 подключен через аппаратный SPI и CS к 10 пину Arduino

    int temperature; //сюда пишем температуру
    int humidity; //сюда - влажность
    int pressure; //сюда - давление
    byte whatToDisplay = 0; //если 0 - то отображаем темп., если 1 - влажн., если 2 - то давл.
    unsigned long buttonReadCounter; //счетчик времени, нужен для подавления дребезга кнопки
    unsigned long sensorReadCounter = 5101; //счетчик времени, нужен для опроса сенсоров раз в 5.1 секунды (значение 5101 - костыль для обновления сразу после подачи питания)
    int currentButtonState; //сюда считываем состояние кнопки
    int previousButtonState; //а сюда будем записывать состояние кнопки в конце loop
    boolean needUpdateDisplay = true; //флаг для обновления дисплея
    char timeString[17]; //сюда форматируем строку в формате "ЧЧ:ММ" (16 символов + 1)
    char dateString[17]; //сюда форматируем строку в формате "дд.мм.гг" (16 символов + 1)
    char daysOfTheWeek[7][12] = {"\xB3oc\xBApec", "\xBEo\xBD""e\xE3""e\xBB", "\xB3\xBFop\xBD\xB8\xBA", "  cpe\xE3""a", "\xC0""e\xBF\xB3""ep\xB4", "\xBE\xC7\xBF\xBD\xB8\xE5""a", "cy\xB2\xB2o\xBF""a"};

    void setup() {
      lcd.begin(16, 2); //инициализируем ЖКИ
      rtc.begin(); //инициализируем часы
      dht.begin(); //инициализируем DHT11
      bmp.begin(); //инициализируем BMP280

      pinMode(BUTTON_PIN, INPUT); //кнопка на вход
      pinMode(BUZZER_PIN, OUTPUT); //пищалка на выход (хотя нужна ли эта строчка?)
    }

    void loop() {
      if (millis() - sensorReadCounter > SENSOR_UPDATE_TIME) {
        temperature = bmp.readTemperature(); //читаем из BMP280 температуру
        humidity = dht.readHumidity(); //читаем из DHT11 влажность
        pressure = bmp.readPressure() / 133.3224; //рассчитываем давление (переводим из Па в мм рт.ст.)
        needUpdateDisplay = true; //обновляем дисплей
        sensorReadCounter = millis();
      }

      currentButtonState = digitalRead(BUTTON_PIN); //читаем кнопку
      if (currentButtonState == HIGH && previousButtonState == LOW && millis() - buttonReadCounter > DEBOUNCE_TIME) {
        whatToDisplay++; //меняем то, что будем изображать
        if (whatToDisplay > 2) whatToDisplay = 0; //если досичтали до 3 - сбрасываем на 0
        needUpdateDisplay = true; //обновляем дисплей
        buttonReadCounter = millis();
        tone(BUZZER_PIN, 4200, 70); //пищим с частотой 4200Гц на протяжении 70мс
      }

      if (needUpdateDisplay) {
        lcd.clear(); //очищаем ЖКИ
        displayDateTime(); //отображаем время и дату
        if (whatToDisplay == 0) displayTemp(); //отображаем температуру и влажность
        else if (whatToDisplay == 1) displayHum();
        else if (whatToDisplay == 2) displayPressure(); //отображаем давление
        needUpdateDisplay = false; //обнуляем флаг
      }

      previousButtonState = currentButtonState; //записываем текущее состояние кнопки для последующего цикла
    }

    void displayDateTime() { //функция отображения даты и времени
      DateTime now = rtc.now(); //читаем из часов дату и время
      sprintf(timeString, "%02d:%02d", now.hour(), now.minute()); //форматируем строку "ЧЧ:ММ"
      sprintf(dateString, "%02d.%02d.%02d", now.day(), now.month(), now.year() - 2000);//форматируем строку "дд.мм.гг"

      lcd.setCursor(11, 0); //устанавливаем курсор в верхний правый угол
      lcd.print(timeString); //записываем строку времени
      lcd.setCursor(0, 1); //устанавливаем курсор в нижний левый угол
      lcd.print(dateString); //записываем строку даты
      lcd.setCursor(9, 1); //устанавливаем курсор в нижний правый угол
      lcd.print(daysOfTheWeek[now.dayOfTheWeek()]); //записываем строку дня недели
    }

    void displayTemp() { //функция вывода температуры и влажности
      lcd.home();
      lcd.print("Te\xBC\xBE="); //пишем "Темп="
      lcd.print(temperature); //отображаем температуру
      lcd.print("\x99""C"); //знак градуса и букву "С"
    }

    void displayHum() {
      lcd.home();
      lcd.print("B\xBB""a\xB6\xBD="); //пишем "Влажн="
      lcd.print(humidity); //отображаем влажность
      lcd.print("%"); //рисуем знак процента
    }

    void displayPressure() { //функция вывода давления
      lcd.home();
      lcd.print("\xE0""a\xB3\xBB="); //пишем "Давл="
      lcd.print(pressure); //отображаем давление
      lcd.print("p\xBF"); //пишем "рт"
    }
    Как победить неправильную работу скетча после ~40 суток аптайма?
    Проблема же с millis()?
    P.S. Если есть еще какие-нибудь замечания по коду - буду рад услышать что я делаю не так
     
  2. ostrov

    ostrov Гуру

    Было уже обсуждение тут и к выводам пришли.
     
  3. arssev1

    arssev1 Гик

    А можно ссылочку? Буду благодарен
    Похоже нашел. Вы про это говорили?
     
    Последнее редактирование: 18 мар 2018
  4. ostrov

    ostrov Гуру

  5. b707

    b707 Гуру

    Нетт никакой проблемы. Ваш код будет работать и до переполнения миллис, и после и даже во время.
     
  6. Damir20

    Damir20 Нерд

    Используйте вместо millis() переменную с типом DateTime
    Если новая дата минус период больше старой даты
     
  7. b707

    b707 Гуру

    Этот нестандартный тип требует дополнительных библиотек. И главное - он абсолютно не нужен для скетчей, где не используется реальное время
     
  8. Damir20

    Damir20 Нерд

    Вы его код видели?
     
  9. b707

    b707 Гуру

    нет, не видел. Хотите показать мне что-то интересноЕ? - я не против.
    Заодно подробнее остановитесь на том, какие преимущества дает использование DateTime вместо миллис()