Millis() на ESP32 не работает! (средство от переполнения millis())

Извините за название темы.

Работает, конечно же. Но не всегда.

Если вы делаете счетчик, который показывает, сколько времени прошло с такого-то момента, используя millis(), то не удивляйтесь, что счетчик обнулится через примерно 49 дней и ваш орешник улетит в небо: счетчик миллисекунд - 32 битный.

Вместо этого надо использовать секунды. Те же 32 бита секунд дают порядка 136 лет, у вас раньше плата сгниет, чем эта задержка вывалится.

Примечательно, что внутри millis() вызывается esp_timer_get_time(), который, вообще-то, 64 бита.

Поэтому :slight_smile:

#include  "Arduino.h"
#include  "esp_timer.h"

#define seconds() ((uint32_t)(esp_timer_get_time() / 1000000ULL))

Похожая проблема, кстати, и во FreeRTOS вообще: там почему-то принято задавать бесконечные задержки используя константу portMAX_DELAY. Которая дает те же самые 49 дней. Висел себе семафор или мутекс 49 дней, а на 50-1 улетел в небо черешник и дубовник.

2 лайка

Ещё бы найти такую задачу, чтобы надо было измерять период, длительностью в несколько дней, именно в миллисекундах))

Так ведь и на Нано/Уно миллис точно так же работает

И Вы тоже не удивляйтесь: счетчик продолжит исправно работать и выдавать адекватные показания. Вы же не будете утверждать, что стрелки часов показывают верное время лишь до тех пор, пока в первый раз не сойдутся в верхней точке циферблата, а потом - “улетят в небо”.

Спасибо, Кэп.

В юникстайм именно так и делают. Но это совсем не значит, что это единственно возможный способ.
То есть Ваше “надо” следовало бы заменить на “в некоторых случаях можно”.
А более универсальным решением является использовать 64-разрядный счетчик.

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

Можно переписать до 64, 128 или 256 бит. И в rtos тоже можно.

Можно. Но не в ардуино.

На 32-х битных системах 64битные операции эмулируются. К тому же держать счетчик в микросекундах неудобно. А раздел, тащем-та, для начинающих.

1 лайк

Ну, в Ардуино других способов нет. Вернее, они есть, но они не всегда будут работать. А миллис не зависит от текущего установленного системного времени. Поэтому измеряют в миллисах.

А что до периода в несколько дней - да хотя бы uptime. Или, если у вас софтина, которая переодически (на манер cron) запускает какой-то код раз в неделю - логи отослать\удалить, например. Или вот у нас тут в море стоит буй, который раз в неделю выходит в эфир и отсылает картинки на сервер. Да много можно напридумывать. Можно IP адрес выдать (представим что вы - Тов. DHCP сервер) на 60 дней, например, и ждать эти 60 дней, пока прокиснет IPшник.

И такой еще момент: даже если написать код, который будет учитывать обнуление счетчика по прошествии 49 дней, нет никакой возможности сказать сколько раз счетчик обнулился.

Все срочно переходим на seconds(). millis() - прошлый век

вот и восполняем пробел

вот легли вы спать. в 21:00. А проснулись в 22:00. Сколько вы спали? 1 час или 25?

PS: стрелки даже не работающих часов показывают точное время дважды в сутки, тоже мне пример, пфф

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

То же самое

При каждом обнулении инкрементируем счетчик, делов-то :wink:

:slight_smile:

Спящая красавица?

Ну, не знаю, коггда речь идёт о днях, обычно хватает “секундной” точности.

Вообще ты всё правильно про миллис написал, только это в описании функции описано, как бы “изобрёл велосипед”))
Возможно, надо было в раздел Wiki перенести…

1 лайк

С чего бы? Не знаю как на пердуине реализовано, но скорее всего что-то типа SysTick++ (32bit) Кто мешает сделать указатель на переменную любого размера (64 или 256 bit) , при этом функцию GetSysTick(32bit) можно и нужно оставить 32-х битную а остальную конструкцию написать на ASMe с любой битностью и ничего не эмулируя. Заодно дополнив функциями GetSysTick(64bit) или 256 бит и всё будет тип-топ) На 1хх с 72-мя мегагерцами или на 4хх с 100 мегагерцами натикает достаточно быстро.

Следить за обнулениями придется :wink:

Да, можно. Но это точно не для новичков.

Ну дак это было замечание к

Аа..

Знаешь , как проверяют?

uint32_t now = millis();
if (then >= now) {
// счетчик переполнился
...
...
} else
  interval = now - then;

Спасибо, КЭП ))

Ты тоже так же проверяешь? :)))

Нет. До сих пор такой нужды не было. Но если понадобится, то будет примерно так