% (modulo) оператор и функция millis()

Beijo2908
Beijo2908 аватар
Offline
Зарегистрирован: 07.02.2019

Всем привет.

Заинтересовался данным оператором и хотел бы у нашего сообщества уточнить некоторую вещь. Буду очень признателен.

Начал рыться в интернете и выяснил как правильно пользоваться данной функцией и что она делает и как считает.

x=5%6    6x0+5
x=5
---
x1=6%5    5х1+1
x1=1

На данный момент использую функцию millis(), прекрасный заменитель delay(), в различных скетчах.

if (millis() - time > 1000){
//---//
time = millis();
}

Но недавно увидел выражение

if (millis()%1000 == 0){
//---//
}

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

Расскажите пожалуйста, как работает второй вариант. Ведь millis() постоянно нарастает, а функция постоянно выполняется раз в секунду. Получается при использовании millis() с % каким-то образом обнуляют счетчик или что? Бред конечно, но не могу просто понять.

И есть ли минусы у второго варианта? Переполнения вроде нет.

 

 

Komandir
Offline
Зарегистрирован: 18.08.2018

миллис растет и остаток от деления на 1000 растёт, до целой тысячи

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

ну и на границе uint32 100% будет один неверный интервал

rkit
Offline
Зарегистрирован: 23.11.2016

Второй вариант может отработать несколько раз подряд, а может и пропустить цикл. Не годится ни для чего серьезнее мигания светодиодами.

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

Beijo2908 пишет:

Получается при использовании millis() с % каким-то образом обнуляют счетчик или что?

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

Выражение millis()%1000 ничего не обнуляет, оно просто отбрасывает из значения счетчика все что больше тысячи. Для простоты можете считать, что в результате от числа просто отбрасываются все цифры левее третьей:

  1234 -> 234

  123456 ->  456

  5000 -> 0

 

Что касается использования конструкции

if (millis()%1000 == 0){
//---//
}

для замена delay и прочего измерения интервалов - то это плохая практика. не привыкайте к ней. Дело в том. что условие в скобках if срабатывет только при точном равенстве , которое длится только одну тысячную периода. Если ваша программа исполняется медленеее 1 миллисекунды - вы можете просткочить этот момент и интервал времени начнется заново, соответвенно ваша задержка уже будет не 1 сек. а две. А через две секунды оно может так же проскочить и так далее

 

Pyotr
Offline
Зарегистрирован: 12.03.2014

>> И есть ли минусы у второго варианта?
добавлю к сказанному - это еще и тормоза...

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Регулярно использую "%".
Но в основном для ограничения верхнего значения переменной, если нижний предел значения 0.
Выглядит примерно так:

int value;
if(//условие)value++;
if(//другое условие )value--;
value=(value+Max_value)%(Max_value+1);

Позволяет в одной строке зациклить значения при выборе значения переменной

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

Kakmyc пишет:
Регулярно использую "%". Но в основном для ограничения верхнего значения переменной, если нижний предел значения 0. Выглядит примерно так: int value; if(//условие)value++; if(//другое условие )value--; value=(value+Max_value)%(Max_value+1); Позволяет в одной строке зациклить значения при выборе значения переменной

для нижней границы работает. для верхней нет - то есть дает не Max_value, а Max_value-1

Kakmyc
Offline
Зарегистрирован: 15.01.2018

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

Kakmyc
Offline
Зарегистрирован: 15.01.2018

И действительно:
h=((h+24)-1)%24;
Вот так оно должно выглядеть.
Конкретно эта строка взята из часов, а точнее из установки времени.
Дальше идёт:
tm.Hour=h;
RTC.write(tm);

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

Kakmyc пишет:

h=((h+24)-1)%24;

Вот так оно должно выглядеть.

и опять что-то не то. Это выражение эквивалентно записи h = h-1; - что явно не то, что вы хотели сделать, никакого выравнивания по границе тут нет

Может просто вот так:

value=(value+Max_value)%(Max_value);

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

Дешевле на min/max проверять, чем остаток искать. В ассемблере первое будет простым джампом по условию, а второе, полагаю, - целой подпрограммой с делением, умножением, вычитанием...