"Переполнение" millis() для чайников" (очередной пост, надеюсь последний)
- Войдите на сайт для отправки комментариев
Судя по количеству подобных тем, и стабильного вайна в камментах этих тем, данный вопрос до сих пор считается актуальной, так как ни кто до сих пор не может внятно доходчиво осветить вопрос с позиции новичка. Дабы попытаться в очередной раз закрыть тему я решил предложить свою версию.
Не буду заострять внимание на millis(), описание функции есть в разделе "Программирование", а поговорим прежде сего об использовании данной функции. И логичнее всего использовать данную функцию для измерения абстрактных промежутков времени между какими либо событиями. Например, нам требуется рассчитать время между аппаратными прерываниями. Для наглядности воспользуемся примерном с тактовой:
Только пусть это будет некая важная кнопка, нажатие на которую ни в коем случае нельзя пропускать. По этому ради этого события мы будем прерывать программу, а время между прерываниями будем выводить через последовательный порт:
unsigned long interruptTime = 0; volatile boolean interrupt = false; void setup() { Serial.begin( 9600 ); //Назначаем прерывание на заземление прерывателя 0(Pin 2) attachInterrupt( 0, ifInterrupt, FALLING ); } void loop() { // Если значение переменной true if( interrupt ) { // Показываем разность между текущим временем и временем момента // предыдущего прерывания Serial.println( millis() - interruptTime ); // Записываем время момента прерывания interruptTime = millis(); interrupt = false; } } void ifInterrupt() { // Прерывание изменяет значение переменной. interrupt = true; }
Теперь попробуем представить ситуацию, когда вот-вот, в ближайшие миллисекунды, наступит этот страшный для многих момент! :) Когда произойдёт обнуление таймера. На самом деле с таймером ничего не случится конечно-же, просто произойдет переполнение переменной, в которую он записывает свое текущее значение, и отсчет опять начнется с нуля, но ни коим образом не остановится. Для примера подставим почти предельное значение переменной момента времени прерывания в скетч. После запуска программы таймер пойдёт от нуля, тем самым эмитируя ситуацию переполнения при нажатии на кнопку:
unsigned long interruptTime = 4294967290;
И, о чудо, ничего не произошло, контроллер на месте, не дымится, взрывов не слышно :) а на экране вполне корректное время прерывания от момента до переполнения. А все потому что, если попробовать записать в беззнаковую переменную отрицательное значение, оно будет вычтено из максимально возможно значения данного типа переменной.
Спасибо за внимание. Надеюсь, для кого-то этот пост будет полезен.
Больше объяснений, хороших и разных!
Хотя, боюсь, что коллеги правы :(((
А сколько переполнений выдерживает таймер?
Эт смотря чем ты его смазываешь и насколько регулярно проходишь ТО.
А сколько переполнений выдерживает таймер?
будет работать пока не переполнится счетчик переполнений. Вот тогда точно конец настанет.
Я бы в сетапе вставил чтобы не возиться с привязкой:
pinMode ( 2 , INPUT_PULLUP);
Пока затворы полевиков в триггерах регистров не протрутся :)))
Пока затворы ... :)))
Затворы клацают. В расчерченной на клетки,
Хуарес, ведомости делает отметки.
И попугай, весьма тропической расцветки,
Сидит на ветке и вот так поёт:
"Презренье к ближнему у нюхающих розы
ничуть не лучше,но честней гражданской позы..."
(с) И.Бродский
А если кнопку, например, нажимают раз в два месяца... то всёвыврёте)))
А если кнопку, например, нажимают раз в два месяца... то всёвыврёте)))
а, если не нажимать совсем, т.е. НИКОГДА, то у нас будет своё маленькое, домашнее Переполнение Шредингера.
У millis() есть очень важный секрет, если она переполнится, то в ней ничего нет.
Вот оно оказывается откуда японцы подчерпнули идею.
А если кнопку, например, нажимают раз в два месяца... то всёвыврёте)))
Если сильно нужно нажимать реже чем раз в 2 месяца, можно запустить счетчик обнулений разрядов, если это будет uint32_t, то этого должно хватить примерно на 500 - 600 миллионов лет :-)
Ну и как продвинутый вариант, сделать свой 8 байтный счетчик (uint64_t) :-)
Всё уже украдено до нас: https://www.faludi.com/itp/arduino/millis_rollover.pde
Этот дурдом никогда не закончится :(
Этот дурдом никогда не закончится :(
...без разговоров - в пропасть(с)
Всё уже украдено до нас: https://www.faludi.com/itp/arduino/millis_rollover.pde
Один вопрос - "зачем"? :-)
Ведь millis() это эффективный инструмент микротайма, позволяющий исключить блокирующие задержки, когда нужно, например, отфильтровать "дребезг", или посчитать время между импульсами. Для остальных вещей проще и точнее использовать часы реального времени, цена вопроса не больше 50-100р на Али.
Нужно создать на форуме раздел - "Переполнения таймера и борьба с ним". И каждый вошедший в него автоматом перекидывается на тему "вставка кода в форум". Польза будет стопудово.
Один вопрос - "зачем"? :-)
Действительно :)
Примерный аптайм девайса незамысловато посчитать без RTC, например.
Нужно создать на форуме раздел - "Переполнения таймера и борьба с ним". И каждый вошедший в него автоматом перекидывается на тему "вставка кода в форум". Польза будет стопудово.
Наверное в разделе "Программирование" не совсем доходчиво написано для многих, что таймер millis() НЕТОЧНЫЙ!!! :) И я не представляю, где такая погрешность устроит разработчика, если нужно будет отсчитать хотябы сутки.
Нужно создать на форуме раздел - "Переполнения таймера и борьба с ним". И каждый вошедший в него автоматом перекидывается на тему "вставка кода в форум". Польза будет стопудово.
Наверное в разделе "Программирование" не совсем доходчиво написано для многих, что таймер millis() НЕТОЧНЫЙ!!! :) И я не представляю, где такая погрешность устроит разработчика, если нужно будет отсчитать хотябы сутки.
дык, и секундный в RTC неточный - кого такая погрешность устроит, если нужно будет сосчитать хотя бы месяц.
Наверное в разделе "Программирование" не совсем доходчиво написано для многих, что таймер millis() НЕТОЧНЫЙ!!! :) И я не представляю, где такая погрешность устроит разработчика, если нужно будет отсчитать хотябы сутки.
А шо такое? Меня устраивает. Знавал я тут людей, которые тоже не жаловались. Конечно часики на атомах цезия поточней. Но дороже.
таймер millis() НЕТОЧНЫЙ!!!
А что в этом мире точно? Разве что то, что все мы когда-то умрём, а вера в Катастрофическое Великое Переполнение не умрёт никогда.
Мне вот, к примеру, нужно поймать внешним мониторингом ребут девайса. Событие определяется по факту простого уменьшения аптайма - было 41837849, стало 3345. Т.е. нужен монотонно нарастающий счетчик. Таковой уже есть в системе - millis(). Одна проблема - каждые 49 дней фиксируется ребут, которого не было, мониторинг начинает слать тревожные письма, считая, что случился вселенский пипец. С помощью несложного фокуса и фиксации rollover я могу эту проблему устранить. Поэтому точность в пределах любого неторопливого ухода счетчика в любую сторону меня вполне устраивает.
Зачем мне в этой задаче RTC, идущий с атомной точностью?
А шо такое? Меня устраивает. Знавал я тут людей, которые тоже не жаловались. Конечно часики на атомах цезия поточней. Но дороже.
Если единичный промежуток, то там обычно да, не важно, +/- час на месяце, ОК.)) Но я что-то слабо себе эту ситуацию представляю, ибо синхронность таких промежутков в процессах скорее всего приязана к реальному ("астрономическому") времени, и нужна гораздо большая точность. Но это всего лишь тема для дальнейшых филосовских рассуждений... :)
Одна проблема - каждые 49 дней фиксируется ребут, которого не было
Проблема надумана и высосана из пальца.
С помощью несложного фокуса и фиксации rollover я могу эту проблему устранить.
А если её (проблему) изначально не выдумывать, то и устранять бы не пришлось.
Зачем мне в этой задаче RTC, идущий с атомной точностью?
Потому что вы просто считываете разряды (ячейки памяти), и сравниваете между собой, и ни как не ограничиваетесь разрядностью какой либо велечины.
Одна проблема - каждые 49 дней фиксируется ребут, которого не было
Проблема надумана и высосана из пальца.
С чего вы так решили?
Ну, с Вашего описания проблемы.
1. Вам нужно слать сообщения при ребуте? Так поставьте в функцию setup отправку "я ребутнулся" и шлите на здоровье
2. Или Вам нужно звне спросить у контроллера "ты ребутнулся?". Ну, тогда заведите флаг "Да, ребутнулся", и при первом же опросе его сбрасывайте.
В обоих случаях при "штатном" ребуте (Вы типа руками включили питание) он пошлёт сообщение, но Вы в курсе что сами ребутнули, потому ничего страшного, а при любом нештатном ребуте, он пошлёт сообщение снова и Вы будете знать.
Ну, с Вашего описания проблемы.
...
Всё понятно. Вы полагаете, что мониторинг - это один опрашивающий сервер с заранее известным адресом и кучка девайсов (агентов). Однако нет, - опрашивающих серверов может быть более, чем один и они агенту могут быть неизвестны на момент запуска и вовсе находится в разных ip-подсетях, о которых агент даже не подозревает. По вашему алгоритму в первом случае сообщение нужно слать бродкастом по всему миру. Во втором же проблему заметит только первый сервер, опросивший агента после ребута. Для всех остальных флаг будет уже сброшен и ребута как бы не было.
Всё понятно. Вы полагаете, что мониторинг - это один опрашивающий сервер с заранее известным адресом...
Нормально задачу можете описать. Шлет вам хост флаг ребута, непонятно с какой сети, но знает адрес куда слать, так? И вам нужно посчитать что?
Шлет вам хост флаг ребута, непонятно с какой сети, но знает адрес куда слать, так? И вам нужно посчитать что?
это я его спамлю ребутами его серверов. О_О
По вашему алгоритму в первом случае сообщение нужно слать бродкастом по всему миру. Во втором же проблему заметит только первый сервер, опросивший агента после ребута. Для всех остальных флаг будет уже сброшен и ребута как бы не было.
А по-Вашему мониторинг, это когда кто попало опрашивает кого попало, когда попало и сколько попало раз? Хорошая системная архитектура.
Это, как раз тот случай о котором я и говорил: если не выдумывать себе проблем, то и решать их не придётся.
Нормально задачу можете описать. Шлет вам хост флаг ребута, непонятно с какой сети, но знает адрес куда слать, так? И вам нужно посчитать что?
Вот вам задача, если вы их любите:
Есть система мониторинга (Zabbix, если уж вам в деталях хочется знать). При работе агента в пассивном режиме сервер Zabbix опрашивает агентов, получая с них значения метрик. Опрашиваемым хостом может оказаться кто угодно - например коммутатор, сервер под управлением какой-либо ОС, дисковая полка и пр. и др. Необходимо при ребуте хоста послать сообщение администратору сети или техническому персоналу. Для этого существует механизм триггеров, которые срабатывают по изменению метрики. Сервер мониторинга может находится в одной ip-подсети, агенты - в другой. Даже на разных географических площадках они могут находится. Устройства (агенты) получают адреса по DHCP, сервера их находят по DNS. Про сервера агенты не знают, просто отдают значение метрики по запросу. Для обеспечения надежности введены избыточные сервера мониторинга.
Придумайте надежный способ определения факта ребута устройства, избегая ложных срабатываний при числе серверов мониторинга > 1 шт.
А по-Вашему мониторинг, это когда кто попало опрашивает кого попало, когда попало и сколько попало раз? Хорошая системная архитектура.
Вы придумываете какую-то ерунду, ей-богу.
Не кто попало, а несколько дублирующих серверов. Не кого попало, а агентов мониторинга. Не сколько попало, а с заданной периодичностью. Если вы считаете, что в кровавом энтерпрайзе оборудование повально имеет функцию "флаг ребута" и рассчитано на доступ исключительно с одного, жестко заданного хоста, а сервер мониторинга всегда один и заранее известен, то хочу вас разочаровать.
Да, в SNMP есть система трапов, с помощью которой можно уведомить сервер мониторинга о ребуте, но даже она поддерживается не всем брендовым оборудованием. А уж в мелкоардуину ее запихивать вместе с интерфейсом управление - занятие для безумцев.
Вот вам задача, если вы их любите:
...Необходимо при ребуте хоста послать сообщение администратору сети или техническому персоналу...
Если честно, не могу понять, причем здесь таймер вообще...
Вот вам задача, если вы их любите:
...Необходимо при ребуте хоста послать сообщение администратору сети или техническому персоналу...
Если честно, не могу понять, причем здесь таймер вообще...
анекдот про Ржевского, Наташу Ростову и весло знаешь?
...отож.
Вот вам задача, если вы их любите:
...Необходимо при ребуте хоста послать сообщение администратору сети или техническому персоналу...
Если честно, не могу понять, причем здесь таймер вообще...
Ну так вы задачку-то решили - как определить факт ребута агента в описанной выше конфигурации?
Если честно, не могу понять, причем здесь таймер вообще...
Ну так вы задачку-то решили - как определить факт ребута агента в описанной выше конфигурации?
не знаю, что там у тебя за конфигурация, но если в сетапе увеличивать значение счётчика, хранящееся в EEPROM на единицу, то этот вариант должен покрыть все возможные недоконфигурации - ты будешь знать, сколько раз запускалось устройство от начала времён до настоящего момента.
и, кстати, "да" - где-то я потерял в своём варианте переполнение и миллис
Ну так вы задачку-то решили - как определить факт ребута агента в описанной выше конфигурации?
а, т.е. это не агент, а пассивный узел, который отзывается на пинг? И нужно эти все узлы опрашивать, и если есть задержка между стандартной то выдавать что-то?
Мне задачи решать незачем, если хост должен послать, то должен, безо всяких millis()...
Придумайте надежный способ определения факта ребута устройства, избегая ложных срабатываний при числе серверов мониторинга > 1 шт.
Толи я Вас не понимаю, толи проблема - не проблема. Варианты.
1. Хост опосля ребута отправляет уведомление "я ребутнулсо" на некоторый сервер, рассылающий далее кому надо. Требование - хосты должны это уметь. Зато быстро и надежно.
2. Любой из серверов мониторинга (их>1) обнаружив факт ребута хоста при опросе рассылает уведомления кому надо. Тригер ребута сбрасывается. Недостаток - каждый сервер должен знать и уметь рассылать.
3.Любой из серверов мониторинга (их>1) обнаружив факт ребута хоста при опросе уведомления серверу рассылки (возможно это один из серверов мониторинга). Тригер сбрасывается. Сервер рассылки делает свое дело. Недостаток - не одноранговая сеть. Вариация на тему - сервер рассылки только хранит список адресатов рассылки, сервер мониторинга по нему рассылает уведомление.
4. Любой из серверов мониторинга при опросе запоминается на хосте и получает инфу о своем предыдущем заходе. Лучше сохраняет и получает кукис. При ребуте эта инфа сносится. Получается у каждого сервера индивидуальный тригер.
5. Гибрид варианта 4 и одного из 1-3. Тригер какбы один, но в зависимости от ID пришедшего сервера его значение разное за счет механизма из п.4
6. все сервера мониторят, но рассылает ошибки и сбрасывает тригер только один. Похоже на п.3 но без межсерверного обмена и медленее.
Как видите варианты есть, время вобще не при чем. Вопрос только что доковыривать можна: сервер, датчик или обоих.
а, т.е. это не агент, а пассивный узел, который отзывается на пинг? И нужно эти все узлы опрашивать, и если есть задержка между стандартной то выдавать что-то?
Допустим, что отзывается, но это необязательно, конечно. ICMP может быть перекрыт в разнообразных целях. Но агегт отдает значения метрик по SNMP, через JSON, XML API или как-то иначе. И, в третий раз повторяю, - нужно определить факт ребута, а не задержки или еще там что-то.
Мне задачи решать незачем, если хост должен послать, то должен, безо всяких millis()...
Вы хотели, цитирую, "Нормально задачу можете описать. " - я вам описал ее так, как она выглядит в реальности.
Если вам лень об этом думать или вы не представляете, какой в энтерпрайзе мониторинг и для чего он - так и напишите, тут нет ничего зазорного, это достаточно специфическая область.
И, еще раз повторю, хост никому ничего не должен. Не он следит за собой, за ним следят несколько серверов, заранее хосту неизвестных.
нужно всем, кому лень думать, проголосовать дабы демократическим большинством прекратить это бесполезное для общества занятие. О_О
...не представляете, какой в энтерпрайзе мониторинг и для чего он - так и напишите...
"Уважаемый", если вы так пишете, то зачем вам наш форум?
...не представляете, какой в энтерпрайзе мониторинг и для чего он - так и напишите...
"Уважаемый", если вы так пишете, то зачем вам наш форум?
ты анекдот про Ржевского, Наташу Ростову и весло знаешь?
...отож. О_О
И, в третий раз повторяю, - нужно определить факт ребута, а не задержки или еще там что-то.
Если вы пишете в данной ветке, то скорее всего вы лжоте...
И, еще раз повторю, хост никому ничего не должен. Не он следит за собой, за ним следят несколько серверов, заранее хосту неизвестных.
алё! аутист, ты когда прекратишь сам с собой разговаривать? - я тебе пердоставил решение #40
угомонись.
Казалось бы - при чём здесь ардуина? Клиенты на ней? О! Месье знает толк в извращениях!
1. Хост опосля ребута отправляет уведомление "я ребутнулсо" на некоторый сервер, рассылающий далее кому надо. Требование - хосты должны это уметь. Зато быстро и надежно.
Проигрышная тактика. Сервер отпал (сам или канал до него) - никто не узнал о ребуте.
2. Любой из серверов мониторинга (их>1) обнаружив факт ребута хоста при опросе рассылает уведомления кому надо. Тригер ребута сбрасывается. Недостаток - каждый сервер должен знать и уметь рассылать.
Более лучший вариант, но сложный по администрированию в плане выстраивания отношений между серверами. Как правило строят кластерную, синхронизирующуюся на уровне БД. Однако в случае географически распределенных серверов - синхронизация может превратится в беду.
Та же проблема, что и в п.1, но перенесена на сервер рассылки.
Как видите варианты есть, время вобще не при чем. Вопрос только что доковыривать можна: сервер, датчик или обоих.
Я вижу, что сценарии вы умеете проигрывать разные.
Однако, пользуясь тем, что практически каждый хост отдает uptime (даже сраный дешманский dlink имеет что-то тикающее и не обязательно точно), любая система мониторинга определит факт ребута по отрицательной разнице между текущим и предыдущим значением этой метрики. Способ более дешевый наврядли можно придумать. И вот эту бодягой с синхронизациями серверов, флагами, рассылками, записями в ЕЕПРОМ можно даже не заниматься. Любой из N серверов точно знает, что был ребут (конечно, если не раз в пятилетку запрашивает uptime). И это штатное решение систем мониторинга.
Надеюсь, что о связи uptime со счетчиком секунд/миллисекунд/чего угодно мне писать нет необходимости. В противном случае остается только прекратить эти бессмысленные разъяснения.