Вопрос по нестандартному использованию millis()

Green
Offline
Зарегистрирован: 01.10.2015

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

Green пишет:
 

#define EVERY_MS(X) for (static uint32_t T = millis(); millis() - T >= (X); T += (X))
 

здесь, с виду, всё нормально.
За исключением того, что первое выполнение произойдёт сразу, а не через Х.

Почему?


Не, извиняюсь, ошибся.
С виду, всё нормально.)

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

спасибо, щас переделаю сразу в проекте, пока их не так много.

Green
Offline
Зарегистрирован: 01.10.2015

Для тех кто экономит и для соответствующих интервалов:

#define every_ms(x) for (static uint16_t t = millis(); (uint16_t)millis() - t >= (x); t += (x))

Или даже uint8_t.)

Green
Offline
Зарегистрирован: 01.10.2015

DetSimen пишет:

Но, люди, призываю вас, забудьте про дефайны и макросы вместе с Си, как страшный сон, в 80% случаев они работают не так, как вы планировали.  А у новичков - в 146% случаев.


Не нужно так категорично. Если есть средство, значит можно (и нужно) его использовать. А все эти перестраховки зачастую лишние. Это и к goto относится также.

Green
Offline
Зарегистрирован: 01.10.2015

Datak пишет:

От себя могу предложить такую версию макроса

#define EVERY_MS(X) for( static uint32_t T = millis( ); millis( ) - T >= (X); T += (X) )

Молодец Datak! Многие не додумались до такой конструкции. Хотя, как известно, всё изобретено до нас. Вот есть подобное: https://forum.arduino.cc/index.php?topic=124974.0
 

Datak
Offline
Зарегистрирован: 09.10.2014

Green пишет:
Вот есть подобное: https://forum.arduino.cc/index.php?topic=124974.0

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

---------

И ещё, сам собирался покаяться и извиниться. Зря я переменную в for'е назвал таким простым и общепринятым именем. Оно легко может совпасть с какой-нибудь переменной какого-нибудь ардуинопрограммера - и, понятное дело, ничего хорошего из этого не выйдет.

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

b707
Offline
Зарегистрирован: 26.05.2017

Datak пишет:

И ещё, сам собирался покаяться и извиниться. Зря я переменную в for'е назвал таким простым и общепринятым именем. Оно легко может совпасть с какой-нибудь переменной какого-нибудь ардуинопрограммера - и, понятное дело, ничего хорошего из этого не выйдет.

этим извинением вы сразу опустили себя ниже плинтуса :)

Почитайте что-нить про область видимости переменных :)

Green
Offline
Зарегистрирован: 01.10.2015

ОК. Переменная в for-е может иметь любое имя, т.к. это локальная переменная. Она видна только в самом for-е, в цикле то бишь, и нигде больше. Но это уже за рамками данной темы.)

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

b707 пишет:

Datak пишет:

Должны ли мы пропустить несколько интервалов, из-за того что какое-нибудь, допустим, чтение даллас-температуры провисело неизвестно сколько времени, не возвращая управление в основной loop( )? Или всё же лучше эти интервалы приплюсовать, хоть и с опозданием?

Нет, это фича, однозначно. И очень полезная, кстати - она позволяет отсчитывать интервалы без накопления погрешности. То есть, видите сами - погрешность для каждого отдельного интервала есть - а накопления нет.  И в среднем, за время выполнения программы (1 секунда) мы имеем ожидаемые десять 100-миллисекундных тиков.

про "фичу" это вы Гайверу расскажите... он любит прикрывать свои косяки подобными росказнями

У него есть замечательная библиотека GyverTimer. В первой версии он отсчитывал интервалы вот этим способом:

  static uint32_t tmr = millis();
  bool flag = millis() - tmr >=interval;
  if (flag) tmr = millis();\

но так как писать код у него не очень получается, нередко выходило, что выполнения кода в ЛУП длилось больше интервала и таймер начинал отставать. Это особенно забавно, когда Алекс использует эту библиотеку для отсчета времени в часах (проект "Часы-метеостанция") - народ массово начал жаловаться. что часы почему-то отстают на несколько минут в сутки.

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


  if (flag) tmr +=x:

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

Что характерно - после исправления GyverTimer-а с первой версии на вторую Алексу не пришло в голову заменить библиотеку в старых проектах - поэтому "Часы-метеостанция" как отставали. так и отстают. Почему - да потому что Гайвер не имеет  понятия о принципах повторного использования кода и в каждый свой проект вкладывает копии всех используемых библиотек, вместо того чтоб включать только ссылки. Таким образом, отслеживать акутуальность кода библиотекв каждом проекте становится невероятно сложно - вот он и не отслеживает...

а всего то надо было одну строку изменить...тема заезженная, Клапауций в своих часиках такую же как Гайвер ахинею написал и, помню это была моя первая БОЕВАЯ тема на этом сайте, ошибка то детская )))
 

static uint32_t tmr = millis();
 bool flag = millis() - tmr >=interval;
 if (flag) tmr =  tmr + interval;\

 

b707
Offline
Зарегистрирован: 26.05.2017

Green пишет:

Молодец Datak! Многие не додумались до такой конструкции. Хотя, как известно, всё изобретено до нас. Вот есть подобное: https://forum.arduino.cc/index.php?topic=124974.0
 

Грин, ты прикалываешься?

Этот метод отсчета интервалов известен каждому, он тут в форуме обсуждался раз пять, он даже у неумехи Гайвера в либе есть - о чем я писал выше. В чем новизна-то?

Или речь о том, что Datak догадался его в макрос засунуть?

Datak
Offline
Зарегистрирован: 09.10.2014

ЕвгенийП пишет:
Пассажа про накопление погрешности я не понял вовсе. Каким там боком накопление ... это выходит за рамки моей понималки.

Очень жаль, хреновый, значит, из меня объясняльщик.

Но попробую ещё раз, на примере Вашего же кода, без всяких изменений.

Вы подразумевали, что задача этого скетча - сгенерить 10 временных интервалов, длиной не менее 100ms. И в этом смысле, да, получилась полная фигня, поскольку первые пять интервалов получились практически нулевой длины, и только потом появилось что-то похожее на 100ms.

А я предложил взглянуть на тот же код с другой стороны, и считать что наша задача - сгенерировать 10 интервалов со средней длиной 100ms. И тогда сразу станет понятно, почему мы получили нулевые интервалы - это код обнаружил, что он сильно отстал от счётчика millis() - на целые 500 миллисекунд! - и срочно кинулся этот счётчик догонять. А как только догнал - всё, успокоился и начал выдавать уже правильные 100-миллисекундные интервалы.

В общем, чувствую, всем всё и так уже понятно. Замолкаю. ))

 

b707
Offline
Зарегистрирован: 26.05.2017

Datak пишет:

В общем, чувствую, всем всё и так уже понятно. Замолкаю. ))

 

на самом деле, оба варианта отсчета интервалов тут уже  обсуждались много раз

Green
Offline
Зарегистрирован: 01.10.2015

.

Green
Offline
Зарегистрирован: 01.10.2015

b707 пишет:

Green пишет:

Молодец Datak! Многие не додумались до такой конструкции. Хотя, как известно, всё изобретено до нас. Вот есть подобное: https://forum.arduino.cc/index.php?topic=124974.0
 

Грин, ты прикалываешься?

Этот метод отсчета интервалов известен каждому, он тут в форуме обсуждался раз пять, он даже у неумехи Гайвера в либе есть - о чем я писал выше. В чем новизна-то?

Или речь о том, что Datak догадался его в макрос засунуть?

Нет, наверно я что то пропустил, просто не видел что бы кто то втулил эту конструкцию в for.)

Datak
Offline
Зарегистрирован: 09.10.2014

b707 пишет:

этим извинением вы сразу опустили себя ниже плинтуса :)

Почитайте что-нить про область видимости переменных :)

1. Я не боюсь опустить себя ниже плинтуса. ))

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

Green
Offline
Зарегистрирован: 01.10.2015

Помнится, в юности нашел баг в z80 инструкции. Ну ни фига се, подумалось.) Когда, через какое то время, прочёл об этом в каком то репорте от японского спеца по z80.))) Ну, то есть, сейчас что то изобрести - невозможно.)

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

Green пишет:

Помнится, в юности нашел баг в z80 инструкции. Ну ни фига се, подумалось.) Когда, через какое то время, прочёл об этом в каком то репорте от японского спеца по z80.))) Ну, то есть, сейчас что то изобрести - невозможно.)

...вспоминая те времена, когда программатор можно было написать на бейсике с использованием ИК55 )))

Green
Offline
Зарегистрирован: 01.10.2015

Я могу написать оперу.... Как всё собиралось с нуля! Жаль, никому нах. не надо.)))

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

Green пишет:

Я могу написать оперу.... 

Напишите лучше кому-нибудь другому, хоть нам.

Green
Offline
Зарегистрирован: 01.10.2015

Сейчас это уже никому не интересно. Сейчас уже всё готово. Модули, скетчи...
А вот когда берёшь сам процессор, без ничего... И что с этим делать!)))

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

Green пишет:

Сейчас это уже никому не интересно. 

А опер-то тут причём? Ему что ли интересно?

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

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

Green пишет:

Сейчас это уже никому не интересно. 

А опер-то тут причём? Ему что ли интересно?

Евгений Петрович, не отвлекайтесь, Вы озвучивали, что для софтового сериала можно использовать и в программе PCINT если делать это аккуратно, может пнёте в нужном направлении

Green
Offline
Зарегистрирован: 01.10.2015

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

А опер-то тут причём? Ему что ли интересно?


А оперу всё интересно. Не дай бог вам с ним столкнуться.(

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

ua6em, точно не сегодня. День был тяжёлый, я уже никакущий. Не ложусь спать ... сам не знаю почему, но никакущий.

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

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

ua6em, точно не сегодня. День был тяжёлый, я уже никакущий. Не ложусь спать ... сам не знаю почему, но никакущий.

хорошо!

Green
Offline
Зарегистрирован: 01.10.2015

Datak пишет:

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


Так пойдёт?)

#define every_ms(x) for (static uint16_t _##__LINE__ = millis(); (uint16_t)millis() - _##__LINE__ >= (x); _##__LINE__ += (x))

 

Datak
Offline
Зарегистрирован: 09.10.2014

Green пишет:

Так пойдёт?)

#define every_ms(x) for (static uint16_t _##__LINE__ = millis(); (uint16_t)millis() - _##__LINE__ >= (x); _##__LINE__ += (x))

Вот да, наверно так достаточно. Хитровычурнее уже не стОит. ))

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

Никак не может быть достаточным! Мы же знаем, что переменная может быть не только uint16_t, но и uint8_t, правда же Green, уже знаем!? ;) А иногда и uint32_t нужна. Макрос сам должен определятся с её типом в зависимости от значения заданного  интервала. Вот тогда нирваны достигнём.

Green
Offline
Зарегистрирован: 01.10.2015

Без уже! А это возможно, в рамках С++? Auto напрашивается, а тогда как быть с ограничением разрядности 32-битной millis()? Что то фантазия кончилась.( Наверное, можно замутить с sizeof(), не?
 

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

Ну как жеж без уже;) Пробовал мутить любимым методом местной свиньи. Не то оно. Не совсем правильно. На  sizeof не пробовал. Не думаю что оно так не получится.

Green
Offline
Зарегистрирован: 01.10.2015

Считаю что писать нужно максимально просто и наглядно, без наворотов на ровном месте. К тому же, С++ часто отсутствует. Не удобно, но деваться некуда.)

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

Green пишет:

А это возможно, в рамках С++? 

А то!

Green
Offline
Зарегистрирован: 01.10.2015

ЕвгенийП, если не в тягость.)

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

Green пишет:

ЕвгенийП, если не в тягость.)

Да, не в тягость, конечно, но попробуйте сами-то. Могу только сделать замечание/подсказку. Вы спрашивали "в рамках С++", так вот в С++ то это делается просто - там есть шаблоны, специализации и прочие вкусняшки. Гораздо интереснее сделать это в Си, где всего этого добра нет. Там потребуется некая built-in функция __builtin_choose_expr - аналог тернарного оператора, но без преобразований типов выходного значения. Она вроде нестандартная, но это меня не напрягает. Во-первых, она есть в GCC, а больше, в силу тематики нашего форума, нас ничего не интересует. Ну, и, во-вторых, на самом деле она есть во многих реализациях (у майкрософта и интеля точно есть).

Green
Offline
Зарегистрирован: 01.10.2015

ОК, Евгений, спасибо! Да, есть варианты, посмотрел слегка. В GCC есть так же и __builtin_types_compatible_p для простого сравнения. Смущает завязка на компилятор всё ж таки... А хотелось бы каких то стандартных решений.(

Green
Offline
Зарегистрирован: 01.10.2015

Тут, как обычно, приходится выбирать между накрученностью (но зато авто) и простым (тупым) ручным выбором. И неизвестно что лучше (проще. понятнее)!

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

Стандартно это можно сделать на шаблонах и специализации. А вот на Си - это да, тяжко. Могу показать. Причём на голом тернарном операторе не работает, т.к. он результат преобразует, а эта функция - нет.

А что до функции, так тут два момента: 1) она много где есть; 2) сама по себе задача извращенская и реально делать это просто не нужно :-)

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Коллеги! Вы всё ещё every_ms в каких либо реализациях обсуждаете?

Но самое тупое решение на классе С++ с лямбдой в качестве нагрузки, дает удобное, простое, масштабируемое  и т.п. решение. Пишется любым получайником за полчаса. Вот Квон наш - спец по лямбдам - напишет точно, а его уровень знаний известен ;))). Нахера вам нужны эти странные макросы? Причем я - любитель Си, и плюсы и ООП использую редко, но макросы - для управления компиляцией в в основном следует использовать, ИМХО.

Хотя ваше дело, конечно.

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

wdrakula пишет:
решение на классе С++ с лямбдой в качестве нагрузки, дает удобное, простое, масштабируемое  и т.п. решение.
+100500!