Вопрос по использованию millis()

ivpo
Offline
Зарегистрирован: 07.01.2014

Здравствуйте

В основном цикле использую следующую типовую конструкцию:

if (millis()-lasttime > 1000) {
    // делаем что-то
    lasttime = millis();            
}

Планируется, что устройство будет работать круглосуточно и очень долго.

В связи с этим есть вопросы:

1) Что случится при сбросе millis() через ~50 дней? Будет ли запинка?

2) Как правильно и красиво сбросить всю эту схему принудительно? Или совсем отвязать от каких-либо переполнений в принципе?

Заранее спасибо!

 

 

 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017
       unsigned long current  = millis();
static unsigned long previous = current;
if (событие сброса           ) {previous = current;}
if (current - previous > 1000) {previous = current;
// что-то делается
}

вся тема здесь класс титановый велосипед для delay без delay().

*слушай, ты только не обижайся - обычно тут ссаными тряпками гоняют по форуму свидетелей переполнения миллис, но ты на моём счету штук 12-й примерно и конца вам я не предвижу. пока в раздумиях, как бороться с этой напастью.

ответь честно на вопрос: 
вот эта вредная ересь про конец света после переполнения, она где зарождается? 
этому где-то обучают?
это где-то в тырнетах написано большими буквами?
дай пруф, пожалуйста - нужно сходить и кому-то ноги переломать.
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ivpo пишет:

1) Что случится при сбросе millis() через ~50 дней? Будет ли запинка?

Ничего не случится.

ivpo пишет:

2) Как правильно и красиво сбросить всю эту схему принудительно? Или совсем отвязать от каких-либо переполнений в принципе?

Никак не надо, ибо см. п. 1

До тех пор, пока Вы пишете так, как у Вас написано, можете спать спокойно. Главное - не верьте, что "от перестановки мест слагаемых ..." и никогда не пишите

if (millis() >  lasttime + 1000) {

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

А если не хотите получить "рваные отрезки времени" то писать надо не так как клапауций в часах делал, а так:
 

if (millis()-lasttime >= 1000) {
     lasttime =  lasttime+1000; 
   // делаем что-то           
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

А если не хотите получить "рваные отрезки времени" то писать надо не так как клапауций в часах делал, а так:
 

if (millis()-lasttime >= 1000) {
     lasttime =  lasttime+1000; 
   // делаем что-то           
}

 

Ну, это как раз зависит от задачи (хотелок).

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

ua6em пишет:

А если не хотите получить "рваные отрезки времени" то писать надо не так как клапауций в часах делал, а так:
 

if (millis()-lasttime >= 1000) {
     lasttime =  lasttime+1000; 
   // делаем что-то           
}

если ТС желает  > 1000 , то значит он желает  > 1000 , а не  >= 1000 - не нужно, значит ему  = 1000

*

если ты бредишь рваными отрезками времени, то заметь что выражение > 1000 равносильно выражению  >= 1001

будут у тебя рваные отрезки если  >= 1001 ? куда они волшебным образом пропадут?

ты можешь попытаться сделать  == 1000, но тогда рискуешь пропускать это условие, если время исполнения кода больше 1 миллисекунды.

**

lasttime+1000 - сказано же было здесь #2 не делать так.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

112, вопрос в другом.

Есть два варианта:

1. Проверяем, сравнивая с текущим millis(); выполняем; к текущему millis() прибавляем интервал.

2. Запоминаем текущее millis(); сравниваем с запомненной величиной; выполняем; прибавляем к запомненной величине.

В первом случае выдерживается интервал между концом предыдущего действия и началом следующего, а во втором - выдерживается средний период. И, как справедливо написал Евгений, выбор варианта осуществляется, исходя из задачи.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Клапауций 112 пишет:

lasttime+1000 - сказано же было здесь #2 не делать так.

надеюсь я понимаю почему Евгений так сказал, конечный код зависит от компилятора, в простейшем случае
сказанное реализуется командой типа ADD lastime, 1000 и полученное значение будет хранится в переменной (регистре) lastime, посему правильней писать как в посте #2, хотя совсем правильным бы посмотреть ассемблерный код конструкции

lastime = millis() - Яркий образец ГОВНОКОДА

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

andriano пишет:

1. Проверяем, сравнивая с текущим millis(); выполняем; к текущему millis() прибавляем интервал.

точно прибавляем?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Клапауций 112 пишет:

andriano пишет:

1. Проверяем, сравнивая с текущим millis(); выполняем; к текущему millis() прибавляем интервал.

точно прибавляем?

Именно так. Интервал в этом случае будет отсчитываться от последнего вызова millis(), т.е. следующее событие наступит не ранее "время послдеднего обращения к millis() + интервал".

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ua6em пишет:

lastime = millis() - Яркий образец ГОВНОКОДА

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

Скорее у вас пованивающий код

if (millis()-lasttime >= 1000) {
     lasttime =  lasttime+1000; 
   // делаем что-то           
}

правильнее так писать

 const uint32_t interval = 1000;
 // здесь куча кодов 
if (millis()-lasttime >= interval) {
     lasttime =  lasttime+interval; 
   // делаем что-то           
}

Но для демонстрашки вполне подойдет.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

надеюсь я понимаю почему Евгений так сказал, 

Если Вы о моих словах, что нельзя писать 

if (millis() >  lasttime + 1000) {

то это было к тому, что при такой записи как раз возникает проблема переполнения - будет происходить сбой при переходе через 0.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

ua6em пишет:

lastime = millis() - Яркий образец ГОВНОКОДА

это ты кому сказал? - я не приводил такого кода.

================================

ок.
давай определимся, что ты желаешь получить на выходе:
1. событие каждые 1000 миллисекунд с момента старта контроллера?
2. событие через 1000 миллисекунд с момента прошлого события?
 
мой код корректно отрабатывает 2-й вариант.
твой код - 1-й вариант.
 
но... твоё желание навязать именно 1-й вариант вызывает претензии не только по сути, но и по способу реализации - если известно значение millis(), то этого достаточно, что бы знать на сколько оно изменилось с момента чего-либо. 
если тебе хочется что-то делать каждые millis()/1000 - делай.
для этого не обязательно городить параллельные millis() счётчики.
 
*под 1000 здесь подразумевается любой разумный интервал.
 
 
Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

ua6em пишет:

А если не хотите получить "рваные отрезки времени" то писать надо не так как клапауций в часах делал, а так:
 

if (millis()-lasttime >= 1000) {
     lasttime =  lasttime+1000; 
   // делаем что-то           
}

Это и есть образец говнокода. Значит ua6em говнокодер.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Andy пишет:

ua6em пишет:

А если не хотите получить "рваные отрезки времени" то писать надо не так как клапауций в часах делал, а так:
 

if (millis()-lasttime >= 1000) {
     lasttime =  lasttime+1000; 
   // делаем что-то           
}

Это и есть образец говнокода. Значит ua6em говнокодер.


 

Не! я им точно не могу быть так как ни разу не кодер, я потомственный кузнец )))

Почему я считаю, что говнокод?
Между принятием решения в конструкции if и присвоением переменной последнего значения функцией миллис её приходится вызывать как минимум два раза, то-есть число тысяча, а правильней некая константа времени при таком подходе таковой не является, она может быть любой, может быть 1000, а может быть 1372 и никто не знает какова она, есть же у микропроцессора и аппаратные прерывания

Я так понимаю ты кодер,  обоснуй свою позицию, чтобы человек для которого микропроцессор просто хобби с ней мог согласиться

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

qwone пишет:

ua6em пишет:

lastime = millis() - Яркий образец ГОВНОКОДА

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

Скорее у вас пованивающий код

if (millis()-lasttime >= 1000) {
     lasttime =  lasttime+1000; 
   // делаем что-то           
}

правильнее так писать

 const uint32_t interval = 1000;
 // здесь куча кодов 
if (millis()-lasttime >= interval) {
     lasttime =  lasttime+interval; 
   // делаем что-то           
}

Но для демонстрашки вполне подойдет.

Не, он просто не кошерный
на асме я бы написал EQU )))

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

ua6em пишет:
обоснуй свою позицию, чтобы человек для которого микропроцессор просто хобби с ней мог согласиться
Тебе же сказали нельзя прибавлять к millis(). Вопрос "почему?" многократно обоссан здесь на форуме. Сам найдешь или тебе ссылку дать?

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

Andy пишет:

Тебе же сказали нельзя прибавлять к millis(). Вопрос "почему?" многократно обоссан здесь на форуме. Сам найдешь или тебе ссылку дать?

он не прибавляет к миллис - то у него отдельный счётчик, который всегда отстаёт от миллис на интервал, поэтому там всё корректно переползает через переполнение.

*сам вначале подумал, что то у него предыдущее значение миллис и наорал низачто.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Клапауций 112 пишет:
у него отдельный счётчик, который всегда отстаёт от миллис на интервал
Это вообще ППЦ. Если основной цикл будет выполняться дольше 1 мС, его отдельный счетчик тупо отстанет и условие будет выполняться в каждом цикле.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Andy пишет:

Клапауций 112 пишет:
у него отдельный счётчик, который всегда отстаёт от миллис на интервал
Это вообще ППЦ. Если основной цикл будет выполняться дольше 1 мС, его отдельный счетчик тупо отстанет и условие будет выполняться в каждом цикле.

и я о том же, в авторском варианте разбег будет уже через пару часов, в приведённом коде при хорошем кварце разбег не хуже чем в часах на DS1307

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

Andy пишет:

Это вообще ППЦ. Если основной цикл будет выполняться дольше 1 мС, его отдельный счетчик тупо отстанет и условие будет выполняться в каждом цикле.

если отстанет на интервал, то сломается в виде двух последовательных срабатываний и снова исправится.

проблема не в этом - он сломал себе мосг на писании точных часов на неточном дефолтном кварце и лепит теперь этот код везде. считает, что должно срабатывать каждые 1000, 2000, n000 миллисекунд, а не через 1000 миллисекунд.

UPD. ну, вот - о чём я и говорил: часы мерещатся там, где таймер.

ua6em пишет:

и я о том же, в авторском варианте разбег будет уже через пару часов, в приведённом коде при хорошем кварце разбег не хуже чем в часах на DS1307

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Клапауций 112 пишет:

UPD. ну, вот - о чём я и говорил: часы мерещатся там, где таймер.

пионэры лепят таймера на D триггерах, юные электронщики на JK - разницу понимаете?
так и здесь, лепить таймер который в принципе не таймер, так как асинхронный

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

ua6em пишет:

пионэры лепят таймера на D триггерах, юные электронщики на JK - разницу понимаете?

к чему этот поток сознания?

ua6em пишет:

так и здесь, лепить таймер который в принципе не таймер, так как асинхронный

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

например:

       boolean       nstate = (millis() / 1000) & 1;
static boolean        state = nstate;
if (nstate != state) {state = nstate;
// что-то делается каждые 1000 миллисекунд.
}

но... тебе нужен синхронный с миллис() метроном или таймер от события к событию? - это важно.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Клапауций 112 пишет:

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

например:

       boolean       nstate = (millis() / 1000) & 1;
static boolean        state = nstate;
if (nstate != state) {state = nstate;
// что-то делается каждые 1000 миллисекунд.
}

И как эта фиговина ведет себя при переполнении millis()?

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

andriano пишет:

И как эта фиговина ведет себя при переполнении millis()?

последних миллисекунд перед переполнением остаётся 1295 - затем снова считаем по 1000.

если критично, то интервал должен делить 4294967296 на целое чётное число.

*суть не в частном примере, а в концепции, что значения миллис() в принципе должно быть достаточно для решения задачи.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Началось в колхозе утро.

belousovev
Offline
Зарегистрирован: 14.02.2017

ivpo пишет:

Здравствуйте

В основном цикле использую следующую типовую конструкцию:

if (millis()-lasttime > 1000) {
    // делаем что-то
    lasttime = millis();            
}

Планируется, что устройство будет работать круглосуточно и очень долго.

В связи с этим есть вопросы:

1) Что случится при сбросе millis() через ~50 дней? Будет ли запинка?

2) Как правильно и красиво сбросить всю эту схему принудительно? Или совсем отвязать от каких-либо переполнений в принципе?

Заранее спасибо!

 

 

 

Через 50 дней millis() сбросится, а в lasttime будет лежать, например, 4 294 966 295 и в это условие программа никогда больше не зайдет (при таком коде). Т.е. чтобы не было никаких ЗАПИНОК, нужно постоянно сравнивать lasttime с millis(). if (lasttime>millis()) lasttime = millis().

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

belousovev пишет:

Через 50 дней millis() сбросится, а в lasttime будет лежать, например, 4 294 966 295 и в это условие программа никогда больше не зайдет (при таком коде). Т.е. чтобы не было никаких ЗАПИНОК, нужно постоянно сравнивать lasttime с millis(). if (lasttime>millis()) lasttime = millis().

О, Господи! Ещё один адепт секты Свидетелей Святого Переполнения! 

Ща начнётся :)

belousovev
Offline
Зарегистрирован: 14.02.2017

ЕвгенийП пишет:

belousovev пишет:

Через 50 дней millis() сбросится, а в lasttime будет лежать, например, 4 294 966 295 и в это условие программа никогда больше не зайдет (при таком коде). Т.е. чтобы не было никаких ЗАПИНОК, нужно постоянно сравнивать lasttime с millis(). if (lasttime>millis()) lasttime = millis().

О, Господи! Ещё один адепт секты Свидетелей Святого Переполнения! 

Ща начнётся :)

Человек спросил - я ему посоветовал. Что Вы можете предложить?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

belousovev пишет:

Человек спросил - я ему посоветовал. Что Вы можете предложить?

Я могу предложить не советовать того, в чём не разбираетесь. При таком коде, как у ТС через 50 дней НИЧЕГО не произойдёт - всё будет работать, как работало.

Можете провести эксперимент самостоятельно. Для этого не нужно ждать 50 дней. Достаточно полезть в файл wiring.c и зменить 0 на что-нибудь близкое к переполнению в иницализации переменной timer0_millis. Тогда millis начнёт считатья сразу с большого значения и переполнения наступит очень скоро.

belousovev
Offline
Зарегистрирован: 14.02.2017

Интересно. Не знал. Почему так происходит?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

belousovev пишет:

ЕвгенийП пишет:

belousovev пишет:

Через 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() {
}

 

Logik
Offline
Зарегистрирован: 05.08.2014

Эта музыка будет вечной)))

Коего хрена вобще там делают long int? Вам производительность жмет или проц 32-х битный?

перейдите на 16-битное целое, получите свое переполнение не через 50суток а через 65сек, за 10минут лично проверите в правильности реализации, код сократите, ОЗУ освободите и на форум отпишитесь мешает переполнение или нет.

ua6em Вы думаете прерывание будет проще, особенно челу который сам с милисами не разобрался? Зачем из пушки (да еще глюкавой, да еще и ценной т.к. тех таймеров всего ничего) по воробям.. Вы ж должны предугадать его следующий шаг - вызывать из обработчика шопопало как угодно долго, потом начнется таймер не тикает, сириал глючит шим кудато пропал...

 

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

belousovev, потому что выражение millis()-lasttime тоже подвергается переполнению, как и сама millis().

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Logik пишет:

Эта музыка будет вечной)))

Коего хрена вобще там делают long int? Вам производительность жмет или проц 32-х битный?

перейдите на 16-битное целое, получите свое переполнение не через 50суток а через 65сек, за 10минут лично проверите в правильности реализации, код сократите, ОЗУ освободите и на форум отпишитесь мешает переполнение или нет.

ua6em Вы думаете прерывание будет проще, особенно челу который сам с милисами не разобрался? Зачем из пушки (да еще глюкавой, да еще и ценной т.к. тех таймеров всего ничего) по воробям.. Вы ж должны предугадать его следующий шаг - вызывать из обработчика шопопало как угодно долго, потом начнется таймер не тикает, сириал глючит шим кудато пропал...

Тут я должен вскричать - ОГЛАСИТЕ ВЕСЬ СПИСОК, это я о скетче )))
Вы же дали мне код цифрового фильтра и, ничё, одолел, с моими то 8 классами )))
А может у человека что-то большее за плечами...

Не боги горшки обжигают ..."но, политой обжиг это серьёзно" ))) ...по таймерам DIMAX точно поможет

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

belousovev пишет:

Интересно. Не знал. Почему так происходит?

Ну, как бы, так устроена арифметика в дополнительном коде. Там же идёт просто переход через 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
Offline
Зарегистрирован: 14.02.2017

Voodoo Doll пишет:

belousovev, потому что выражение millis()-lasttime тоже подвергается переполнению, как и сама millis().

Не знал, спасибо. Какие здесь все злые))))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

belousovev пишет:

Не знал, спасибо. Какие здесь все злые))))

Просто эта тема с охренительной регулярностью всплывает здесь почти каждую неделю и уже до того всех достала, Вы себе представить не можете. Причём всплавет в обе стороны. И как у Вас, и наоборот "всё пофиг, проблемы нет вовсе", хотя она, конечно есть, если неправильно программировать (опять же см. мой пост №2).

Logik
Offline
Зарегистрирован: 05.08.2014

ua6em пишет:

Logik пишет:

Эта музыка будет вечной)))

Коего хрена вобще там делают long int? Вам производительность жмет или проц 32-х битный?

перейдите на 16-битное целое, получите свое переполнение не через 50суток а через 65сек, за 10минут лично проверите в правильности реализации, код сократите, ОЗУ освободите и на форум отпишитесь мешает переполнение или нет.

ua6em Вы думаете прерывание будет проще, особенно челу который сам с милисами не разобрался? Зачем из пушки (да еще глюкавой, да еще и ценной т.к. тех таймеров всего ничего) по воробям.. Вы ж должны предугадать его следующий шаг - вызывать из обработчика шопопало как угодно долго, потом начнется таймер не тикает, сириал глючит шим кудато пропал...

Тут я должен вскричать - ОГЛАСИТЕ ВЕСЬ СПИСОК, это я о скетче )))
Вы же дали мне код цифрового фильтра и, ничё, одолел, с моими то 8 классами )))
А может у человека что-то большее за плечами...

Не боги горшки обжигают ..."но, политой обжиг это серьёзно" ))) ...по таймерам DIMAX точно поможет

Та какой там список ))) Так делёж опытом по ходу.

И опыт говорит - "можеш делать без прерывания, делай без него" Это как пистолет, без нужды не бери, не свети попусту и по мелочам не доставай, достал - будь готов применить))) Прерывание слишком мощный аргумент.

А вобще интервалы от секунды и более для всякой неответственной фигни удобно делать так. Сразу на миллисе формируем небольшой но заведомо перекрывающий проход лупа интервал например 100, 200 или 250мсек и взводим флажок. Потом этот флажек считаем в приложении для всех нужных вещей. Все просто, и хоть сотню интервалов.

belousovev
Offline
Зарегистрирован: 14.02.2017

ЕвгенийП пишет:

belousovev пишет:

Не знал, спасибо. Какие здесь все злые))))

Просто эта тема с охренительной регулярностью всплывает здесь почти каждую неделю и уже до того всех достала, Вы себе представить не можете. Причём всплавет в обе стороны. И как у Вас, и наоборот "всё пофиг, проблемы нет вовсе", хотя она, конечно есть, если неправильно программировать (опять же см. мой пост №2).

Спасибо большое. Теперь и до меня дошло.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

повторю свой вопрос ТС снова

Клапауций 112 пишет:

*слушай, ты только не обижайся - обычно тут ссаными тряпками гоняют по форуму свидетелей переполнения миллис, но ты на моём счету штук 12-й примерно и конца вам я не предвижу. пока в раздумиях, как бороться с этой напастью.

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

 

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

belousovev пишет:
Какие здесь все злые

Кроме меня. Я няша :3

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

belousovev пишет:

Voodoo Doll пишет:

belousovev, потому что выражение millis()-lasttime тоже подвергается переполнению, как и сама millis().

Не знал, спасибо. Какие здесь все злые))))

стоп! это нужно знать или это очевидно?

uragan
Offline
Зарегистрирован: 23.02.2015

ЕвгенийП пишет:

belousovev пишет:

Интересно. Не знал. Почему так происходит?

 

Ну, как бы, так устроена арифметика в дополнительном коде. Там же идёт просто переход через 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?

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

uragan пишет:

А мне надо. Это важнее для понимания чем то что показали. Я так понимаю, что "2-14" === 4?

просто вычисли средствами контроллера и выведи в сериал или куда тебе удобней все свои непонятки арифметических действий с unsigned long.

примерно так:

// 4294967294 - 4294967284 = 10
// 4294967295 - 4294967285 = 10
// 0          - 4294967286 = 10
// 1          - 4294967287 = 10
// 2          - 4294967288 = 10
// 3          - 4294967289 = 10
// 4          - 4294967290 = 10
// 5          - 4294967291 = 10
// 6          - 4294967292 = 10
// 7          - 4294967293 = 10
// 8          - 4294967294 = 10
// 9          - 4294967295 = 10
// 10         - 0          = 10
// 11         - 1          = 10

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

uragan пишет:

А мне надо. Это важнее для понимания чем то что показали. Я так понимаю, что "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

Как видите, переполнение проходит гладко безо всяких проблем. Можете также вручную посчитать для любых других чисел (в т.ч. «пограничные» случаи) – всё там получается нормально.

А вот если Вы будете не вычитать, а складывать, т.е. вместо

If (millis() – lastMillis >= INTERVAL)

используете конструкцию

If (millis() >=  lastMillis + INTERVAL)

То получим «задницу». Например, при lastMillis = 14 и INTERVAL = 3 в правой части сразу же получается 17 % 16 = 1, а единица само собой меньше 14 или там 15, т.е. Ваше условие сработает сразу же безо всякого ожидания (не забываем, что для простоты мы работаем с 4-битными числами. С 32-битными тоже самое, только числа большие).

ivpo
Offline
Зарегистрирован: 07.01.2014

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

sadman41
Offline
Зарегистрирован: 19.10.2016

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

Использовать для чего? С шилда вы можете взять секунды/минуты/часы (а не миллисекунды), но потом их придется преобразовать в общую величину, что не мгновенно. Шилд может тупо отвалится или шина I2C (например) может быть занята другой перефирией в то время, когда вам срочно нужно будет узнать сколько натикало секунд.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

ivpo пишет:

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

ок. если у тебя есть автомобиль, то имеет смысл купить сыну велосипед?

*ракеты будут падать в Туву!

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ivpo пишет:

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

Например millis() используется для подавления дребезга кнопок. Или вы предлагаете подавлять дребезг с помощью модуля часов !!!

ivpo
Offline
Зарегистрирован: 07.01.2014

Нет, я исключительно про своё применение - выполнять что-либо раз в полсекунды-секунду-две