Функция Millis () не работает в течение длительного периода времени

Я использую функцию millis() для управления таймером моего светодиода. Это очень простой код, который я использовал из примеров библиотек. Код работал хорошо в течение 6 часов (включен в течение 6 часов, выключен в течение следующих 6 часов и так далее), однако, когда я установил его на 12 часов, свет не выключился, когда я проверил его. Расчетное время должно было уместиться в 2 ^ 32 бита для unsigned long, которые я определил заранее. Может ли кто-нибудь помочь в этом вопросе? Спасибо!

/*
Мигать без задержки

Включает и выключает светоизлучающий диод (LED), подключенный к цифровому контакту,
без использования функции delay(). Это означает, что другой код может выполняться одновременно с
в то же время, не прерываясь кодом светодиода.

Схема:
- Используйте встроенный светодиод.
- Примечание. Большинство плат Arduino имеют встроенный светодиод, которым вы можете управлять. На УНО, МЕГА
и ZERO подключается к цифровому пину 13, на MKR1000 к пину 6. LED_BUILTIN
устанавливается на правильный вывод светодиода, независимо от того, какая плата используется.
Если вы хотите узнать, к какому контакту подключен встроенный светодиод на вашем
Модель Arduino, проверьте технические характеристики вашей платы по адресу:
https://www.arduino.cc/en/Main/Продукты

создан в 2005 г.
Дэвид А. Меллис
изменено 8 февраля 2010 г.
Пол Штоффреген
изменено 11 ноября 2013 г.
Скотт Фицджеральд
изменено 9 января 2017 г.
Артуро Гуадалупи

Этот пример кода находится в общественном достоянии.

http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
*/

// константы не изменятся. Используется здесь для установки вывода:
const int ledPin =  7;// номер вывода светодиода

// Переменные изменятся:
int ledState = LOW;             // ledState используется для установки светодиода

// Как правило, вы должны использовать "unsigned long" для переменных, которые содержат время
// Значение быстро станет слишком большим для хранения в int
unsigned long previousMillis = 0;        // запомним время последнего обновления светодиода

// константы не изменятся:
unsigned long interval = 12*60*60*1000UL;           // интервал мигания (миллисекунды)

void setup() {
  // устанавливаем цифровой вывод в качестве выхода:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // здесь вы бы разместили код, который должен выполняться все время.

  // проверяем, не пора ли мигнуть светодиодом; то есть если разница
  // между текущим временем и последним временем, когда вы моргнули, светодиод больше, чем
  // интервал, с которым вы хотите мигать светодиодом.
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // сохранить время последнего мигания светодиодом
    previousMillis = currentMillis;

    // если светодиод выключен, включить его и наоборот:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // устанавливаем светодиод с помощью переменной ledState:
    digitalWrite(ledPin, ledState);
  }
}

, 👍1

Обсуждение

пожалуйста, посмотрите на свой пост ... листинг программы выглядит так, как вы предполагали? ... пожалуйста, отформатируйте код... используйте кнопку {}, @jsotola

используйте длинный интервал без знака = 1000UL*12*60*60*; , @Juraj


2 ответа


0

Вы пытались изменить свои переменные, чтобы расчеты производились в секундах, а не в миллисекундах? IOW добавьте "/1000" после millis() и соответственно уменьшите ваши константы.

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

,

Не добавляйте /1000 после millis(), иначе у вас возникнут проблемы, когда millis() перевернется., @Edgar Bonet


1

В C++ оператор умножения является «левоассоциативным». Это означает что выражение

12*60*60*1000UL

интерпретируется как

((12*60)*60)*1000UL

Левый множитель, а именно (12*60)*60, вычисляется с использованием данных int тип, но результат выходит за рамки этого формата, что приводит к проблеме, которую вы см.

Простое решение – сделать один из факторов первого продукта быть unsigned long. Например

1000UL*60*60*12

Затем вычисляется 1000UL*60 с типом данных unsigned long. С результат сам по себе является unsigned long, следующее умножение также делается как unsigned long и аналогично для последнего.

Если вы находите этот метод несколько непонятным, вы также можете добавить UL суффикс к каждому фактору. Это позволит избежать неявных преобразований компилятор, делая все типы явными.

,

Проблема раскрыта! Спасибо, сэр! Программирование вообще не моя область и поэтому у меня явно нет базы. Ваш комментарий очень полезен и высоко ценится., @syuen