Вопрос по использованию millis()
- Войдите на сайт для отправки комментариев
      Ср, 08/03/2017 - 03:26
          
      Здравствуйте
В основном цикле использую следующую типовую конструкцию:
if (millis()-lasttime > 1000) {
    // делаем что-то
    lasttime = millis();            
}Планируется, что устройство будет работать круглосуточно и очень долго.
В связи с этим есть вопросы:
1) Что случится при сбросе millis() через ~50 дней? Будет ли запинка?
2) Как правильно и красиво сбросить всю эту схему принудительно? Или совсем отвязать от каких-либо переполнений в принципе?
Заранее спасибо!
 
          
unsigned long current = millis(); static unsigned long previous = current; if (событие сброса ) {previous = current;} if (current - previous > 1000) {previous = current; // что-то делается }вся тема здесь класс титановый велосипед для delay без delay().
*слушай, ты только не обижайся - обычно тут ссаными тряпками гоняют по форуму свидетелей переполнения миллис, но ты на моём счету штук 12-й примерно и конца вам я не предвижу. пока в раздумиях, как бороться с этой напастью.
1) Что случится при сбросе millis() через ~50 дней? Будет ли запинка?
Ничего не случится.
2) Как правильно и красиво сбросить всю эту схему принудительно? Или совсем отвязать от каких-либо переполнений в принципе?
Никак не надо, ибо см. п. 1
До тех пор, пока Вы пишете так, как у Вас написано, можете спать спокойно. Главное - не верьте, что "от перестановки мест слагаемых ..." и никогда не пишите
if (millis() > lasttime + 1000) {А если не хотите получить "рваные отрезки времени" то писать надо не так как клапауций в часах делал, а так:
if (millis()-lasttime >= 1000) { lasttime = lasttime+1000; // делаем что-то }А если не хотите получить "рваные отрезки времени" то писать надо не так как клапауций в часах делал, а так:
if (millis()-lasttime >= 1000) { lasttime = lasttime+1000; // делаем что-то }Ну, это как раз зависит от задачи (хотелок).
А если не хотите получить "рваные отрезки времени" то писать надо не так как клапауций в часах делал, а так:
if (millis()-lasttime >= 1000) { lasttime = lasttime+1000; // делаем что-то }если ТС желает > 1000 , то значит он желает > 1000 , а не >= 1000 - не нужно, значит ему = 1000
*
если ты бредишь рваными отрезками времени, то заметь что выражение > 1000 равносильно выражению >= 1001
будут у тебя рваные отрезки если >= 1001 ? куда они волшебным образом пропадут?
ты можешь попытаться сделать == 1000, но тогда рискуешь пропускать это условие, если время исполнения кода больше 1 миллисекунды.
**
lasttime+1000 - сказано же было здесь #2 не делать так.
112, вопрос в другом.
Есть два варианта:
1. Проверяем, сравнивая с текущим millis(); выполняем; к текущему millis() прибавляем интервал.
2. Запоминаем текущее millis(); сравниваем с запомненной величиной; выполняем; прибавляем к запомненной величине.
В первом случае выдерживается интервал между концом предыдущего действия и началом следующего, а во втором - выдерживается средний период. И, как справедливо написал Евгений, выбор варианта осуществляется, исходя из задачи.
lasttime+1000 - сказано же было здесь #2 не делать так.
надеюсь я понимаю почему Евгений так сказал, конечный код зависит от компилятора, в простейшем случае
сказанное реализуется командой типа ADD lastime, 1000 и полученное значение будет хранится в переменной (регистре) lastime, посему правильней писать как в посте #2, хотя совсем правильным бы посмотреть ассемблерный код конструкции
lastime = millis() - Яркий образец ГОВНОКОДА
1. Проверяем, сравнивая с текущим millis(); выполняем; к текущему millis() прибавляем интервал.
точно прибавляем?
1. Проверяем, сравнивая с текущим millis(); выполняем; к текущему millis() прибавляем интервал.
точно прибавляем?
Именно так. Интервал в этом случае будет отсчитываться от последнего вызова millis(), т.е. следующее событие наступит не ранее "время послдеднего обращения к millis() + интервал".
lastime = millis() - Яркий образец ГОВНОКОДА
Разве. Говнокод это когда ничего нельзя добавить к программе или убрать, так как это приведет к краху программы. Программу надо писать так, что бы ее можно изменять или модифицировать, при этом не копаясь в ее структуре. Вот по этой причине .lastime = millis() самая что ни есть правильная запись.
Скорее у вас пованивающий код
if (millis()-lasttime >= 1000) { lasttime = lasttime+1000; // делаем что-то }правильнее так писать
const uint32_t interval = 1000; // здесь куча кодов if (millis()-lasttime >= interval) { lasttime = lasttime+interval; // делаем что-то }Но для демонстрашки вполне подойдет.
надеюсь я понимаю почему Евгений так сказал,
Если Вы о моих словах, что нельзя писать
if(millis() > lasttime + 1000) {то это было к тому, что при такой записи как раз возникает проблема переполнения - будет происходить сбой при переходе через 0.
lastime = millis() - Яркий образец ГОВНОКОДА
это ты кому сказал? - я не приводил такого кода.
================================
А если не хотите получить "рваные отрезки времени" то писать надо не так как клапауций в часах делал, а так:
if (millis()-lasttime >= 1000) { lasttime = lasttime+1000; // делаем что-то }А если не хотите получить "рваные отрезки времени" то писать надо не так как клапауций в часах делал, а так:
if (millis()-lasttime >= 1000) { lasttime = lasttime+1000; // делаем что-то }Не! я им точно не могу быть так как ни разу не кодер, я потомственный кузнец )))
Почему я считаю, что говнокод?
Между принятием решения в конструкции if и присвоением переменной последнего значения функцией миллис её приходится вызывать как минимум два раза, то-есть число тысяча, а правильней некая константа времени при таком подходе таковой не является, она может быть любой, может быть 1000, а может быть 1372 и никто не знает какова она, есть же у микропроцессора и аппаратные прерывания
Я так понимаю ты кодер, обоснуй свою позицию, чтобы человек для которого микропроцессор просто хобби с ней мог согласиться
lastime = millis() - Яркий образец ГОВНОКОДА
Разве. Говнокод это когда ничего нельзя добавить к программе или убрать, так как это приведет к краху программы. Программу надо писать так, что бы ее можно изменять или модифицировать, при этом не копаясь в ее структуре. Вот по этой причине .lastime = millis() самая что ни есть правильная запись.
Скорее у вас пованивающий код
if (millis()-lasttime >= 1000) { lasttime = lasttime+1000; // делаем что-то }правильнее так писать
const uint32_t interval = 1000; // здесь куча кодов if (millis()-lasttime >= interval) { lasttime = lasttime+interval; // делаем что-то }Но для демонстрашки вполне подойдет.
Не, он просто не кошерный
на асме я бы написал EQU )))
Тебе же сказали нельзя прибавлять к millis(). Вопрос "почему?" многократно обоссан здесь на форуме. Сам найдешь или тебе ссылку дать?
он не прибавляет к миллис - то у него отдельный счётчик, который всегда отстаёт от миллис на интервал, поэтому там всё корректно переползает через переполнение.
*сам вначале подумал, что то у него предыдущее значение миллис и наорал низачто.
и я о том же, в авторском варианте разбег будет уже через пару часов, в приведённом коде при хорошем кварце разбег не хуже чем в часах на DS1307
Это вообще ППЦ. Если основной цикл будет выполняться дольше 1 мС, его отдельный счетчик тупо отстанет и условие будет выполняться в каждом цикле.
если отстанет на интервал, то сломается в виде двух последовательных срабатываний и снова исправится.
проблема не в этом - он сломал себе мосг на писании точных часов на неточном дефолтном кварце и лепит теперь этот код везде. считает, что должно срабатывать каждые 1000, 2000, n000 миллисекунд, а не через 1000 миллисекунд.
UPD. ну, вот - о чём я и говорил: часы мерещатся там, где таймер.
и я о том же, в авторском варианте разбег будет уже через пару часов, в приведённом коде при хорошем кварце разбег не хуже чем в часах на DS1307
UPD. ну, вот - о чём я и говорил: часы мерещатся там, где таймер.
пионэры лепят таймера на D триггерах, юные электронщики на JK - разницу понимаете?
так и здесь, лепить таймер который в принципе не таймер, так как асинхронный
пионэры лепят таймера на D триггерах, юные электронщики на JK - разницу понимаете?
к чему этот поток сознания?
так и здесь, лепить таймер который в принципе не таймер, так как асинхронный
я тебе выше говорил, что если ты желаешь получить событие каждые 1000 миллисекунд процессорного времени, то тебе достаточно значения миллис().
например:
boolean nstate = (millis() / 1000) & 1; static boolean state = nstate; if (nstate != state) {state = nstate; // что-то делается каждые 1000 миллисекунд. }но... тебе нужен синхронный с миллис() метроном или таймер от события к событию? - это важно.
я тебе выше говорил, что если ты желаешь получить событие каждые 1000 миллисекунд процессорного времени, то тебе достаточно значения миллис().
например:
boolean nstate = (millis() / 1000) & 1; static boolean state = nstate; if (nstate != state) {state = nstate; // что-то делается каждые 1000 миллисекунд. }И как эта фиговина ведет себя при переполнении millis()?
И как эта фиговина ведет себя при переполнении millis()?
последних миллисекунд перед переполнением остаётся 1295 - затем снова считаем по 1000.
если критично, то интервал должен делить 4294967296 на целое чётное число.
*суть не в частном примере, а в концепции, что значения миллис() в принципе должно быть достаточно для решения задачи.
Началось в колхозе утро.
Здравствуйте
В основном цикле использую следующую типовую конструкцию:
if (millis()-lasttime > 1000) { // делаем что-то lasttime = millis(); }Планируется, что устройство будет работать круглосуточно и очень долго.
В связи с этим есть вопросы:
1) Что случится при сбросе millis() через ~50 дней? Будет ли запинка?
2) Как правильно и красиво сбросить всю эту схему принудительно? Или совсем отвязать от каких-либо переполнений в принципе?
Заранее спасибо!
Через 50 дней millis() сбросится, а в lasttime будет лежать, например, 4 294 966 295 и в это условие программа никогда больше не зайдет (при таком коде). Т.е. чтобы не было никаких ЗАПИНОК, нужно постоянно сравнивать lasttime с millis(). if (lasttime>millis()) lasttime = millis().
Через 50 дней millis() сбросится, а в lasttime будет лежать, например, 4 294 966 295 и в это условие программа никогда больше не зайдет (при таком коде). Т.е. чтобы не было никаких ЗАПИНОК, нужно постоянно сравнивать lasttime с millis(). if (lasttime>millis()) lasttime = millis().
О, Господи! Ещё один адепт секты Свидетелей Святого Переполнения!
Ща начнётся :)
Через 50 дней millis() сбросится, а в lasttime будет лежать, например, 4 294 966 295 и в это условие программа никогда больше не зайдет (при таком коде). Т.е. чтобы не было никаких ЗАПИНОК, нужно постоянно сравнивать lasttime с millis(). if (lasttime>millis()) lasttime = millis().
О, Господи! Ещё один адепт секты Свидетелей Святого Переполнения!
Ща начнётся :)
Человек спросил - я ему посоветовал. Что Вы можете предложить?
Человек спросил - я ему посоветовал. Что Вы можете предложить?
Я могу предложить не советовать того, в чём не разбираетесь. При таком коде, как у ТС через 50 дней НИЧЕГО не произойдёт - всё будет работать, как работало.
Можете провести эксперимент самостоятельно. Для этого не нужно ждать 50 дней. Достаточно полезть в файл wiring.c и зменить 0 на что-нибудь близкое к переполнению в иницализации переменной timer0_millis. Тогда millis начнёт считатья сразу с большого значения и переполнения наступит очень скоро.
Интересно. Не знал. Почему так происходит?
Через 50 дней millis() сбросится, а в lasttime будет лежать, например, 4 294 966 295 и в это условие программа никогда больше не зайдет (при таком коде). Т.е. чтобы не было никаких ЗАПИНОК, нужно постоянно сравнивать lasttime с millis(). if (lasttime>millis()) lasttime = millis().
О, Господи! Ещё один адепт секты Свидетелей Святого Переполнения!
Ща начнётся :)
Человек спросил - я ему посоветовал. Что Вы можете предложить?
Не советовать человеку херню!!!
1. Оставим за бортом разбор реализации говнокода программного счётчика, хотя нет, я, ни разу не программист, объясню на пальцах. ТС пытается использовать некую константу (у него это 1000) как тактовый генератор счётчика, вычисление длины тактового импульса реализует через разницу накопительного счетчика и счетчика миллис, а увеличивает накопительный счетчик - ТО-ЕСТЬ ТАКТИРУЕТ не длительностью константы, а накопительным счетчиком миллис.
2. Что можно посоветовать? Не заморачиваться вообще с миллис, а использовать аппаратные таймеры процессора, нам доступны 1 и 2-й. Для второго в сети есть библиотека TIMER2.h к примеру, по первому не искал.
С этой библиотекой тоже не всё очень прозрачно, по моим данным при использовании функции Serial.print гонит в порт периодически некий мусор, в чём проблема не разбирался, так вот - выделяем некий код который должен выполняться каждый отрезок времени и настраиваем таймер на вызов этой функции в соответствии с принятым отрезком времени.
Пара строк кода всего, ниже пример из библиотеки, всё просто, никаких извращений:
#include <MsTimer2.h> // Switch on LED on pin 13 each second void flash() { static boolean output = HIGH; digitalWrite(13, output); output = !output; } void setup() { pinMode(13, OUTPUT); MsTimer2::set(1000, flash); // 1000ms period MsTimer2::start(); } void loop() { }Эта музыка будет вечной)))
Коего хрена вобще там делают long int? Вам производительность жмет или проц 32-х битный?
перейдите на 16-битное целое, получите свое переполнение не через 50суток а через 65сек, за 10минут лично проверите в правильности реализации, код сократите, ОЗУ освободите и на форум отпишитесь мешает переполнение или нет.
ua6em Вы думаете прерывание будет проще, особенно челу который сам с милисами не разобрался? Зачем из пушки (да еще глюкавой, да еще и ценной т.к. тех таймеров всего ничего) по воробям.. Вы ж должны предугадать его следующий шаг - вызывать из обработчика шопопало как угодно долго, потом начнется таймер не тикает, сириал глючит шим кудато пропал...
belousovev, потому что выражение millis()-lasttime тоже подвергается переполнению, как и сама millis().
Эта музыка будет вечной)))
Коего хрена вобще там делают long int? Вам производительность жмет или проц 32-х битный?
перейдите на 16-битное целое, получите свое переполнение не через 50суток а через 65сек, за 10минут лично проверите в правильности реализации, код сократите, ОЗУ освободите и на форум отпишитесь мешает переполнение или нет.
ua6em Вы думаете прерывание будет проще, особенно челу который сам с милисами не разобрался? Зачем из пушки (да еще глюкавой, да еще и ценной т.к. тех таймеров всего ничего) по воробям.. Вы ж должны предугадать его следующий шаг - вызывать из обработчика шопопало как угодно долго, потом начнется таймер не тикает, сириал глючит шим кудато пропал...
Тут я должен вскричать - ОГЛАСИТЕ ВЕСЬ СПИСОК, это я о скетче )))
Вы же дали мне код цифрового фильтра и, ничё, одолел, с моими то 8 классами )))
А может у человека что-то большее за плечами...
Не боги горшки обжигают ..."но, политой обжиг это серьёзно" ))) ...по таймерам DIMAX точно поможет
Интересно. Не знал. Почему так происходит?
Ну, как бы, так устроена арифметика в дополнительном коде. Там же идёт просто переход через 0. Обратите внимание на мой пост №2 в этой теме и попробуйте понять разницу.
Ведь что происходит при переполнении. Давайте рассмотрим пример, только чтобы не таскать длинющщие числа, будем считать, что счётчик не 32, а 4 бита для простоты рассуждений. Т.е. переполнение выражается в том, что после 15 идёт 0.
Допустим, интервал 3, а последнее наше обращение было, при счётчике равном 14.
Итак lastMillis = 14. Что имеем:
millis стало 15: millis()-lastMillis === 15-14 === 1 < 3
millis стало 0: millis()-lastMillis === 0-14 === 2 < 3
millis стало 1: millis()-lastMillis === 1-14 === 3 < 3 - false - сработало!
Как видите, никакого сбоя.
Почему "0 - 14 равно 2" и "1 - 14 = 3" Вы знаете? Или надо объяснять?
belousovev, потому что выражение millis()-lasttime тоже подвергается переполнению, как и сама millis().
Не знал, спасибо. Какие здесь все злые))))
Не знал, спасибо. Какие здесь все злые))))
Просто эта тема с охренительной регулярностью всплывает здесь почти каждую неделю и уже до того всех достала, Вы себе представить не можете. Причём всплавет в обе стороны. И как у Вас, и наоборот "всё пофиг, проблемы нет вовсе", хотя она, конечно есть, если неправильно программировать (опять же см. мой пост №2).
Эта музыка будет вечной)))
Коего хрена вобще там делают long int? Вам производительность жмет или проц 32-х битный?
перейдите на 16-битное целое, получите свое переполнение не через 50суток а через 65сек, за 10минут лично проверите в правильности реализации, код сократите, ОЗУ освободите и на форум отпишитесь мешает переполнение или нет.
ua6em Вы думаете прерывание будет проще, особенно челу который сам с милисами не разобрался? Зачем из пушки (да еще глюкавой, да еще и ценной т.к. тех таймеров всего ничего) по воробям.. Вы ж должны предугадать его следующий шаг - вызывать из обработчика шопопало как угодно долго, потом начнется таймер не тикает, сириал глючит шим кудато пропал...
Тут я должен вскричать - ОГЛАСИТЕ ВЕСЬ СПИСОК, это я о скетче )))
Вы же дали мне код цифрового фильтра и, ничё, одолел, с моими то 8 классами )))
А может у человека что-то большее за плечами...
Не боги горшки обжигают ..."но, политой обжиг это серьёзно" ))) ...по таймерам DIMAX точно поможет
Та какой там список ))) Так делёж опытом по ходу.
И опыт говорит - "можеш делать без прерывания, делай без него" Это как пистолет, без нужды не бери, не свети попусту и по мелочам не доставай, достал - будь готов применить))) Прерывание слишком мощный аргумент.
А вобще интервалы от секунды и более для всякой неответственной фигни удобно делать так. Сразу на миллисе формируем небольшой но заведомо перекрывающий проход лупа интервал например 100, 200 или 250мсек и взводим флажок. Потом этот флажек считаем в приложении для всех нужных вещей. Все просто, и хоть сотню интервалов.
Не знал, спасибо. Какие здесь все злые))))
Просто эта тема с охренительной регулярностью всплывает здесь почти каждую неделю и уже до того всех достала, Вы себе представить не можете. Причём всплавет в обе стороны. И как у Вас, и наоборот "всё пофиг, проблемы нет вовсе", хотя она, конечно есть, если неправильно программировать (опять же см. мой пост №2).
Спасибо большое. Теперь и до меня дошло.
повторю свой вопрос ТС снова
*слушай, ты только не обижайся - обычно тут ссаными тряпками гоняют по форуму свидетелей переполнения миллис, но ты на моём счету штук 12-й примерно и конца вам я не предвижу. пока в раздумиях, как бороться с этой напастью.
Кроме меня. Я няша :3
belousovev, потому что выражение millis()-lasttime тоже подвергается переполнению, как и сама millis().
Не знал, спасибо. Какие здесь все злые))))
стоп! это нужно знать или это очевидно?
Интересно. Не знал. Почему так происходит?
Ну, как бы, так устроена арифметика в дополнительном коде. Там же идёт просто переход через 0. Обратите внимание на мой пост №2 в этой теме и попробуйте понять разницу.
Ведь что происходит при переполнении. Давайте рассмотрим пример, только чтобы не таскать длинющщие числа, будем считать, что счётчик не 32, а 4 бита для простоты рассуждений. Т.е. переполнение выражается в том, что после 15 идёт 0.
Допустим, интервал 3, а последнее наше обращение было, при счётчике равном 14.
Итак lastMillis = 14. Что имеем:
millis стало 15: millis()-lastMillis === 15-14 === 1 < 3
millis стало 0: millis()-lastMillis === 0-14 === 2 < 3
millis стало 1: millis()-lastMillis === 1-14 === 3 < 3 - false - сработало!
Как видите, никакого сбоя.
Почему "0 - 14 равно 2" и "1 - 14 = 3" Вы знаете? Или надо объяснять?
А мне надо. Это важнее для понимания чем то что показали. Я так понимаю, что "2-14" === 4?
А мне надо. Это важнее для понимания чем то что показали. Я так понимаю, что "2-14" === 4?
просто вычисли средствами контроллера и выведи в сериал или куда тебе удобней все свои непонятки арифметических действий с unsigned long.
примерно так:
А мне надо. Это важнее для понимания чем то что показали. Я так понимаю, что "2-14" === 4?
Да, конечно.
Тут важно знать два правила:
Правило №1
В данном процессоре (как и в большинстве (но не во всех!!!) промышленных процессорах сегодня) отрицательные числа хранятся в т.н. «дополнительном коде», т.е. вместо отрицательного числа хранится его «дополнение». Что это такое? Допустим, что мы работаем с n-битовыми числами, и у нас есть положительное число А. Тогда дополнением числа А будет называться число 2n-А.
Операция вычитания всегда заменяется на операцию «сложение с дополнением». Т.е. 10 – А на самом деле выполняется как 10 + (2n-А).
Правило №2
Вычисления над n-битовыми числами проводятся «по модулю 2n», т.е. если в результате операции получилось число большее или равное 2n, то результатом будет остаток от деления этого числа на 2n. Т.е. чисел равных или больших, чем 2n у нас получиться не может никогда – они просто не влазят в n бит.
В чём достоинства и недостатки такого способа хранения чисел, почитайте в сети. Там много интересного. Мы же вернёмся «к нашим баранам». В нашем примере n было равно 4 и lastMillis = 14. Потому мы вычитали 14 из всех чисел подряд. Давайте проделаем это вручную с учётом двух правил, приведённых выше.
Итак, мы везде вычитаем число 14. «Дополнение числа 14» = 24-14 = 16 – 14 = 2. Значит, в соответствии с правилом №1, везде, где надо вычесть 14, мы будем прибавлять 2.
Исходная операция
Правило
№1
Промежуточный
результат
Правило
№2
Результат
14 – 14
14 + 2
16
16 % 16
0
15 - 14
15 + 2
17
17 % 16
1
0 - 14
0 + 2
2
2 % 16
2
1 - 14
1 + 2
3
3 % 16
3
2 - 14
2 + 2
4
4 % 16
4
3 - 14
3 + 2
5
5 % 16
5
Как видите, переполнение проходит гладко безо всяких проблем. Можете также вручную посчитать для любых других чисел (в т.ч. «пограничные» случаи) – всё там получается нормально.
А вот если Вы будете не вычитать, а складывать, т.е. вместо
используете конструкцию
То получим «задницу». Например, при lastMillis = 14 и INTERVAL = 3 в правой части сразу же получается 17 % 16 = 1, а единица само собой меньше 14 или там 15, т.е. Ваше условие сработает сразу же безо всякого ожидания (не забываем, что для простоты мы работаем с 4-битными числами. С 32-битными тоже самое, только числа большие).
Скажите, а есть ли смысл использовать millis(), если я использую шилд-часы реального времени с батарейкой?
Использовать для чего? С шилда вы можете взять секунды/минуты/часы (а не миллисекунды), но потом их придется преобразовать в общую величину, что не мгновенно. Шилд может тупо отвалится или шина I2C (например) может быть занята другой перефирией в то время, когда вам срочно нужно будет узнать сколько натикало секунд.
Скажите, а есть ли смысл использовать millis(), если я использую шилд-часы реального времени с батарейкой?
ок. если у тебя есть автомобиль, то имеет смысл купить сыну велосипед?
*ракеты будут падать в Туву!
Скажите, а есть ли смысл использовать millis(), если я использую шилд-часы реального времени с батарейкой?
Например millis() используется для подавления дребезга кнопок. Или вы предлагаете подавлять дребезг с помощью модуля часов !!!
Нет, я исключительно про своё применение - выполнять что-либо раз в полсекунды-секунду-две