Великое переполнение millis()

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

Данный пост имеет своей целью положить конец бессмертной как Вечный Жид теме «переполнения millis()», которая только и норовит переполниться настолько, что того и гляди лопнет и из неё во все стороны полезут непомещающиеся биты. Не знаю, как millis(), но моё терпение точно переполнилось и я твёрдо решил таки прихлопнуть её.

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

Часть первая. Для тех, кто хочет знать как

Если Вам надо пользоваться millis() и при этом не думать о переполнении, пользуйтесь и не думайте. Главное, всегда вычитайте из текущего значения millis() стартовое значение, и результат сравнивайте с заданным интервалом. И никогда не делайте наоборот – никогда не складывайте стартовое значение с интервалом, чтобы потом сравнить с текущим значением.

Для демонстрации правильной и неправильной работы с millis() я сделал два скетча. В них используется тот факт, что внутренний счётчик миллисекунд хранится во вполне себе доступной нам переменной timer0_millis, которая при запуске Ардуино устанавливается в 0. Я подкрутил её, чтобы переполнение наступало не через два месяца, а через пять секунд после старта и благодаря этому появилась возможность просто проверить как поведёт себя программа при переполнении.

Итак, правильный скетч

//////////////////////////////////////////////////////////////////////
//
// ПРАВИЛЬНОЕ использование millis() - плевать на переполнение
//
// Сделано так, чтобы millis() переполнился через 5 секунд после старта
// программа же отсчитывает двухсекундные интревалы (в функции make2SecondsInterval)
// Так что переполнение millis  придётся на середину интервала
// Запускаем и смотрим на происходящую "катастрофу"
//
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }
extern volatile unsigned long timer0_millis;

static void make2SecondsInterval(void) {
	uint32_t startTime = millis(), currentMillis;
	while ((currentMillis = millis()) - startTime < 2000ul); // ТАК НАДО !!!
	Serial << " start: " << startTime << "\nmillis: " << currentMillis <<
	        "\ndiffer: " << (currentMillis - startTime) << "\n---\n";
}

void setup (void) {
	Serial.begin(115200);
	//
	// Устанавливаем счётчик millis так, чтобы он переполнился через 5 секунд
	timer0_millis = UINT32_MAX - 5000ul;
	//
	// Отсчитываем 5 двухсекундных интервалов
	for (int i=0; i < 5; i++) make2SecondsInterval();
}

void loop(void) {}
//
// РЕЗУЛЬТАТ - всё отлично работает, несмотря на переполнение
//
//	 start: 4294962295
//	millis: 4294964295
//	differ: 2000
//	---
//	 start: 4294964296
//	millis: 4294966296
//	differ: 2000
//	---
//	 start: 4294966297
//	millis: 1001
//	differ: 2000
//	---
//	 start: 1002
//	millis: 3002
//	differ: 2000
//	---
//	 start: 3002
//	millis: 5002
//	differ: 2000
//	---

как видите, переполнение происходит, но интервалы прекрасно отрабатываются

Неправильный скетч

//////////////////////////////////////////////////////////////////////
//
// НЕПРАВИЛЬНОЕ использование millis() - переполнение создаёт проблемы
//
// Сделано так, чтобы millis() переполнился через 5 секунд после старта
// программа же отсчитывает двухсекундные интревалы (в функции make2SecondsInterval)
// Так что переполнение millis  придётся на середину интервала
// Запускаем и смотрим на происходящую катастрофу
//
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }
extern volatile unsigned long timer0_millis;

static void make2SecondsInterval(void) {
	uint32_t startTime = millis(), currentMillis;
	while (startTime + 2000ul > (currentMillis = millis())); // ТАК НЕЛЬЗЯ !!!
	Serial << " start: " << startTime << "\nmillis: " << currentMillis <<
	        "\ndiffer: " << (currentMillis - startTime) << "\n---\n";
}

void setup (void) {
	Serial.begin(115200);
	//
	// Устанавливаем счётчик millis так, чтобы он переполнился через 5 секунд
	timer0_millis = UINT32_MAX - 5000ul;
	//
	// Отсчитываем 5 двухсекундных интервалов
	for (int i=0; i < 5; i++) make2SecondsInterval();
}

void loop(void) {}

//
// РЕЗУЛЬТАТ - всё сломалось на третьем проходе
//
//	 start: 4294962295
//	millis: 4294964295
//	differ: 2000
//	---
//	 start: 4294964296
//	millis: 4294966296
//	differ: 2000
//	---
//	 start: 4294966297
//	millis: 4294966297
//	differ: 0
//	---
//	 start: 4294966299
//	millis: 4294966299
//	differ: 0
//	---
//	 start: 4294966303
//	millis: 4294966303
//	differ: 0
//	---

а здесь всё ломается

Разница между правильным и неправильным скетчами ТОЛЬКО в строке 15. И состоит она именно в том, о чём я говорил чуть выше – используйте вычитание и не используйте сложение.

Делайте всегда, как написано в первом скетче и забудьте о перхоти переполнении millis().

Часть вторая. Для тех, кто хочет понимать почему

Если Вы хотите понимать как это происходит, Вам необходимо:

№1 Внимательно изучить арифметику в дополнительном коде

№2 Для проверки усвоения материала попытаться устно решить две задачи, приведённые ниже. Если задачи устно решить не удалось, обязательно вернуться к п.1 и так, пока задачи не покажутся очевидными, и не решатся устно.

Часть третья. Задачи для проверки понимания работы арифметики

В обеих задачах требуется в обозначенное в коде место подставить число такое, чтобы получался приведённый результат. Обе задачи решаются устно теми, кто действительно понимает работу арифметики в дополнительном коде.

Задача №1

Найти такое целое, отличное от нуля  число, которое равно самому себе с обратным знаком.

void setup (void) {
	Serial.begin(115200);
	int a = <вставьте сюда число>;
	if (a != 0 && a == -a) Serial.println("What the fuck?!?");
	Serial.println("That's all! No more fun!");
}

void loop(void) {}
//
//	РЕЗУЛЬТАТ
//
//	What the fuck?!?
//	That's all! No more fun!

Задача №2.

Найти такое целое беззнаковое, отличное от нуля число, чтобы оно же умноженное на 2 равнялось нулю.

void setup (void) {
	Serial.begin(115200);
	unsigned a = <вставьте сюда число>;
	if ((a != 0) && (a * 2 == 0)) Serial.println("What the fuck?!?");
	Serial.println("That's all! No more fun!");
}

void loop(void) {}
//
//	РЕЗУЛЬТАТ
//
//	What the fuck?!?
//	That's all! No more fun!

Надеюсь, у тех, кто исполнил алгоритм из части второй до конца, больше никаких вопросов о переполнении millis() не возникает. Если же таки остались, то, даже не знаю, попробуйте написать в «Спортлото».

Часть последняя. Для тех, кто «как математик не может согласиться»

Ребята, задолбали! Если бы вы действительно были математиками, то легко заметили бы, что множество целых чисел в математике и множество всех возможных значений целочисленного типа в нашей системе – суть принципиально разные вещи. Первое – абелева группа, а второе – не является группой вообще. Так какого хрена Вы пытаетесь распространять свойство одного на другое?

bwn
Offline
Зарегистрирован: 25.08.2014

Глас вопиющего в пустыне. И снова придет неофит, и снова у него все переполнится, и все случится сначала. Ибо для неофита: во многая знания, многая печали, преумножающий знания, преумножает печали. Аминь.))))
Это я типа на тему подписался.))))

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

bwn пишет:

И снова придет неофит

Я предлагаю использовать метод Эдуарда Овечкина - ничего не объяснять и не ввязываться в холивары (по Овечкину "в моральные противостояния"). Сам по себе метод просто замечательный. Он настолько же прост и эффективен, насколько краток и понятен. Полное изложение метода состоит из одной единственной фразы из рассказа "Мичман Тоня". Начинается она со слов: "Я вообще человек неконфликтный", легко найдёте поиском :)))

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Фигня ваши примеры. Запустил на компиляцию - выдало ошибку в строке после знака равно:

unsigned a = <<strong>вставьте сюда число</strong>>

Что я сделал не так? Может версия ИДЕ не та? :-)

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

Arhat109-2, решили поиграть в тупого нуба? В другой раз, ладно, у меня сегодня нет настроения, извините.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Просто показал Вам какого рода вопросы будут в этой теме, если её прикрепить. Придут новички, и это будет первое что они сделают. Далее будут попытки вставить число в тег strong "как есть" (новички с какого-нить ПХП) и т.д. Если человек не разбирается с дополнительным кодом, то в "сях" ему делать в общем-то нечего.

Кстати, задал сыну ваш второй вопрос в таком виде: имеем байтовую целочисленную беззнаковую переменную. Какое положить в неё чиселко, чтобы при умножении на 2 получился ноль? Не с первого раза, но сообразил таки. :)

Мне кажется что такая запись примера ближе к "сионистам":

unsigned a = "замените этот комментарий на число";

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

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

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

кстати, что об этом всём думал не математик, не учёный и даже не программист, а обычный гуманитарий и философ:

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

«Путешествие первое А, или Электрибальд Трурля» Станислав Лем 1964 год

arduinec
Offline
Зарегистрирован: 01.09.2015

ЕвгенийП в правильном и неправильном примерах применил сложные конструкции, которые усложняют понимание новичками данных примеров, поэтому им остаётся верить в переполнение миллис.

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

Що знову?

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

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

Що знову?

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

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

Без обид новых ОК? Пока Евгений занят.

...Смотри вот шаблон

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

Это обозначает,что на этапе компиляции, для каждого использованияконструкции вида:

Serial << " start: ";

будет порождено описание, в котором  T будет заменено на то, что есть:

const char * inline Print & operator << (Print &s, const char* n) { s.print(n); return s; }

для  Serial << 5;

будет порождена строка:

int inline Print & operator << (Print &s, int n) { s.print(n); return s; }

Условно можешь считать, что все этистроки будут помещены ВМЕСТО строки с шаблоном.

-------------------------------------

Еще остались вопросы?

То есть шаблон равен описанию функции (в данном случае оператора) для РАЗНЫХ типов операндов. Написание такогошаблона, как у Евгения, все равно,  что написать пять - семь строк для все типов. ОК? И для компилятора тоже все равно.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

wdrakula пишет:

Без обид новых ОК? Пока Евгений занят.

...Смотри вот шаблон

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

Это обозначает,что на этапе компиляции, для каждого использованияконструкции вида:

Serial << " start: ";

будет порождено описание, в котором  T будет заменено на то, что есть:

const char * inline Print & operator << (Print &s, const char* n) { s.print(n); return s; }

для  Serial << 5;

будет порождена строка:

int inline Print & operator << (Print &s, int n) { s.print(n); return s; }

Условно можешь считать, что все этистроки будут помещены ВМЕСТО строки с шаблоном.

-------------------------------------

Еще остались вопросы?

То есть шаблон равен описанию функции (в данном случае оператора) для РАЗНЫХ типов операндов. Написание такогошаблона, как у Евгения, все равно,  что написать пять - семь строк для все типов. ОК? И для компилятора тоже все равно.

Блин, я это знаю :) Молодеж не знает. Им нужно объяснить. Ты дал объяснения для данного конкретного случая, а примененеий дохрена. Нужно раскрыть вопрос. Я вот не смогу. Всегда в таких случаях вспоминаю как я пытался младшему сыну про двоичное и шестнадцетиричное счисление рассказать :) Ну учитель был хуже меня, весь класс не знал, а я за ДВА (!!) дня все же вдолбил. 

Тут , в примере, нужно еще как то объяснить, что эта конструкция бесконечна, потому что каждое ее звено возвращает указатель на Serial для следующего звена.

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

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

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

arduinec пишет:

ЕвгенийП в правильном и неправильном примерах применил сложные конструкции, которые усложняют понимание новичками данных примеров, поэтому им остаётся верить в переполнение миллис.

а, я шо говорил - без разговоров сбрасывать в пропасть.

arduinec
Offline
Зарегистрирован: 01.09.2015

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

arduinec пишет:

ЕвгенийП в правильном и неправильном примерах применил сложные конструкции, которые усложняют понимание новичками данных примеров, поэтому им остаётся верить в переполнение миллис.

а, я шо говорил - без разговоров сбрасывать в пропасть.

Так он и сбросил, попросив модераторов удалить не нравящиеся ему высказывания: http://arduino.ru/forum/obshchii/chistim-forum-ot-spama-vmeste?page=4#co...

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

Прошу, по возможности, убрать политоту и срач из темы про переполнение. Начиная с поста #9, и до конца темы там можно всё спокойно выбросить.

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

arduinec пишет:
удалить не нравящиеся ему высказывания:
Да, политота, взаимные оскорбления, а особенно высеры одного участника о начале войны мне никогда не нравились и не понравятся.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

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

arduinec пишет:
удалить не нравящиеся ему высказывания:
Да, политота, взаимные оскорбления, а особенно высеры одного участника о начале войны мне никогда не нравились и не понравятся.

Если это про меня, то я не девочка, что бы кому то нравится. 

И так, на всякий случай, по хорошему, претендовать на роль учителя, при этом еще более запутывая потенциальных "учеников", по крайней мере глупо. Да еще потом упираться рогом, мня себя мессией. Сами разводите тут цирк с конями, а потом подтираетесь.

Попробуйте объяснить , в чем я не прав ?

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

brokly пишет:

Если это про меня, то я не дквочка, что бы кому то нравится. 

Я в курсе, что Вы не дквочка, но высеров про начало войны, политоту и оскорблений от Вас я не видел. Прошу прощения, если пропустил, но это было не про Вас.

brokly пишет:

претендовать на роль учителя

Так не претендуйте! Зачем Вы постоянно пытаетесь учить меня что мне писать, а что - нет? Пишите сами, что считаете нужным, а я буду писать то, что я считаю нужным.

И да, если мои опусы не нужны этому форуму, я могу их не писать, в том, что я пишу новой для меня информации нет.

brokly пишет:

еще более запутывая потенциальных "учеников"

Я уже говорил Вам, что про потоковый вывод у меня есть отдельный пост, кому надо прочитает, кому не надо - тому не надо.

brokly пишет:

по крайней мере глупо

Ну, вот такой я человек, каким Бог создал.

brokly пишет:

Да еще потом упираться рогом

Вот тут не понял. Во что я упёрся рогом? Отказываюь написать то, чего хотите Вы? Так ... я не отказываюсь, готов обсудить стоимость этой этой работы. А бесплатно я пишу то, что считаю нужным сам и не пишу то, чего не считаю нужным. Если же Вы хотите, чтобы я писал что-то по Вашему заказу, так заказывайте! Я ведь тоже, как Вы изволили выразиться не дквочка, чтобы всем нравится, а Вы не мой работодатель, чтобы требовать от меня написать что-то, что сам я писать не планировал. 

brokly пишет:

мня себя мессией

Не знаю, кем Вы себя мните - это не моё дело.

brokly пишет:

а потом подтираетесь.

Что-то я не припомню каких-то срачей между нами. Давайте избегать такого рода лексики, ладно? Мне это неприятно и не думаю, что это приятно Вам.

brokly пишет:

Попробуйте объяснить , в чем я не прав ?

Вы во всём правы.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Просто я тут писал, что это война между тупоконечниками и остроконечниками , пытаясь показать ее безсмысленность ( https://dic.academic.ru/dic.nsf/ruwiki/374980 ), потому и принял на свой счет.

Евгений, стеб ни к чему. У меня и в мыслях не было гнать вас с форума. Да и ваши статьи тут очень даже радуют. Да , видимо я погорячился, приняв все на свой счет. Оскорбить не хотел, просто видимо эхо "прошедшей войны", был тут инцидент :( Правда , не обижайтесь, нервы... 

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

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

Ну, разобрались, и слава Богу.

mir12
Offline
Зарегистрирован: 11.09.2016

Иначе говоря правильно будет так

unsigned long currentMillis = 1UL;
unsigned long previousMillis = 1UL;

void setup() {

}

void loop() {
    currentMillis = millis();
    
    if ( currentMillis - previousMillis >= 500UL ){
        previousMillis = currentMillis;
        
        //этот код повторяться каждые 500 мсек

    }


}

так будет НЕ правильно

unsigned long currentMillis = 1UL;
unsigned long previousMillis = 1UL;

void setup() {

}

void loop() {
    currentMillis = millis();
    
    if ( previousMillis + 500UL <= currentMillis ){
        previousMillis = currentMillis;
        
        //этот код повторяться каждые 500 мсек

    }


}

 

maxvalin
Offline
Зарегистрирован: 22.02.2016

а такой метод имеет право на существование?



if (nextTime <=millis())
  {
    //делаю что-то свое
    nextTime = millis() + 5000;
    }

 

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

maxvalin пишет:

а такой метод имеет право на существование?

Право имеют все.

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

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

Кусочек из библиотеки tinyFAT

uint8_t mmc::initialize(uint8_t speed) 
{
	uint16_t t0 = (uint16_t)millis();
	uint32_t arg;
	uint8_t status_;

	P_SS	= portOutputRegister(digitalPinToPort(_SS));
	B_SS	= digitalPinToBitMask(_SS);
	P_MISO	= portOutputRegister(digitalPinToPort(_MISO));
	B_MISO	= digitalPinToBitMask(_MISO);
	P_MOSI	= portOutputRegister(digitalPinToPort(_MOSI));
	B_MOSI	= digitalPinToBitMask(_MOSI);
	P_SCK	= portOutputRegister(digitalPinToPort(_SCK));
	B_SCK	= digitalPinToBitMask(_SCK);

	sbi(P_SS, B_SS);
	sbi(P_SCK, B_SCK);
	sbi(P_MISO, B_MISO);
	pinMode(_SS, OUTPUT);
	pinMode(_MOSI, OUTPUT);
	pinMode(_SCK, OUTPUT);
	pinMode(_MISO, INPUT);
	pinMode(_SS_HW, OUTPUT);
	digitalWrite(_SS_HW, HIGH); // disable any SPI device using hardware SS pin

	sbi(P_SS, B_SS);

	// Enable SPI, Master, clock rate f_osc/128
	SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
	// clear double speed
	SPSR &= ~(1 << SPI2X);

	for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);

	cbi(P_SS, B_SS);

	while ((status_ = cardCommand(GO_IDLE_STATE, 0)) != STATUS_IN_IDLE) 
	{
		if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) 
		{
			_errorCode = SD_CARD_ERROR_CMD0;
			goto fail;
		}
	}

	// check SD version
	if ((cardCommand(SEND_IF_COND, 0x1AA) & STATUS_ILLEGAL_COMMAND)) 
	{
		_card_type = SD_CARD_TYPE_SD1;
	} 
	else 
	{
		// only need last byte of r7 response
		for (uint8_t i = 0; i < 4; i++)	status_ = spiRec();
		if (status_ != 0XAA) 
		{
			_errorCode = SD_CARD_ERROR_CMD8;
			goto fail;
		}
		_card_type = SD_CARD_TYPE_SD2;
	}

строки 3 и 39 :)

 

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

А что за проблема? Я не понял, мне кажется, что нормально всё. Что-то не так?

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

просто улыбнуло, ищу проблему зависания без sd карты по таймауту, но хороший вариант, ждать всего 65 секунд до великого переполнения

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

Так там поди SD_INIT_TIMEOUT меньше. Если так, то всё должно быть нормально.

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

да там по умолчанию 2000 стоит, но не отрабатывает

maxvalin
Offline
Зарегистрирован: 22.02.2016
Valera19701
скорее всего имел ввиду что взял на заметку:
timer0_millis = UINT32_MAX - 5000ul;

 

тоисть как ускорить "конец света" ))

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

maxvalin пишет:

Valera19701
скорее всего имел ввиду что взял на заметку:
timer0_millis = UINT32_MAX - 5000ul;

 

тоисть как ускорить "конец света" ))

ничего я на заметку не брал, я знаю как работает millis(), и что переполнения не будет если правильно его использовать

infyniti
Offline
Зарегистрирован: 15.07.2017

 

[/quote]

 и что переполнения не будет если правильно его использовать

[/quote]

а что будет если не правильно??

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

infyniti пишет:

Valera19701 пишет:

 и что переполнения не будет если правильно его использовать

а что будет если не правильно??

Ну, понятное дело - переполнение :)

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

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

infyniti пишет:

Valera19701 пишет:

 и что переполнения не будет если правильно его использовать

а что будет если не правильно??

Ну, понятное дело - переполнение :)

Петрович, эта тема вечная).

Ещё бывают "великие переполнения" суток в году, часов в сутках и т. д.
Все решают по разному. 
Я применяю такой подход.

#define TOTAL_MIN 1440u //всего мин в сутках
word carrMin, prevMin, intervalMin = 3;//все в минутах

void setup(){ 
  Serial.begin(9600);
}
void loop(){
  carrMin = getTotMin();
  if((carrMin + TOTAL_MIN - prevMin) % TOTAL_MIN >= intervalMin){
    prevMin = carrMin;
    // что-то делаем каждые 3 мин
    Serial.println(carrMin); //это для проверки работы скетча 
  }
}
word getTotMin(){
  //функция возвращает количество мин с начала суток
  return millis() / 10;//это просто для проверки работы скетча 
       //при переходе через полночь=1440 мин от начала суток
}

 

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

Pyotr пишет:

Ещё бывают "великие переполнения" суток в году, часов в сутках и т. д.
Все решают по разному. 

 

вспомните "проблему 2000"   :)

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

b707 пишет:

вспомните "проблему 2000"   :)

Уже не так далеко и переполнение UNIX-time

maxvalin
Offline
Зарегистрирован: 22.02.2016

Евгений, вы можете самый первый Правильный пример расписать на уровне 


    long previousMillis = 0; 
     
 void setup()    
 { 
       
 } 

 void loop() 

 { 
      if (millis() -previousMillis >500)    
     { 
        previousMillis = millis();     
        //тут выполняется задача
     }       
 } 

 

все у вас превосходно конечно описано но уж больно заумно для дятлов вроде меня))) пожалуйста,  по-народному, к примеру мигалки можете расписать?

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

maxvalin пишет:

все у вас превосходно конечно описано но уж больно заумно для дятлов вроде меня))) пожалуйста,  по-народному, к примеру мигалки можете расписать?

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

(С) Задорнов

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

maxvalin пишет:

все у вас превосходно конечно описано но уж больно заумно для дятлов вроде меня))) пожалуйста,  по-народному, к примеру мигалки можете расписать?

Каждому дятлу по новой обьяснять - жизни не хватит. Не Евгений должен опускаться до дятлов - а вы пытаться расти вслед ему. Так что обучайтесь. Все данные в посте Евгения есть. Как разберетесь в беззнаковой арифметике - так и все остальное в этой теме перестанет быть "заумным".

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

maxvalin пишет:
но уж больно заумно

Вас смутила запись Serial << ... ?

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

maxvalin
Offline
Зарегистрирован: 22.02.2016

Все что угодно но только не по-делу. Да что я один такой?! Это один раз написать всего надо. Как раз таки для развития. Ну не в силах допустим новичку сразу разобраться.  Я допустим полностью код понимаю,  очем речь,  но куча примеров с этими миллисами и все написаны в простой форме.  А здесь написанно еще и правильно но в сложной форме для первого понимания.  Зачем?!  Зачем сразу на вилы сажать ? Ну черкони ты раз для тебя это уж совсем просто. Не,  давайте демагогию разводить... 

За Задорнова спасибо! -приятный момент.  Даже если в свой адрес

 

Евгений,  спасибо!  Это не в ваш адрес

maxvalin
Offline
Зарегистрирован: 22.02.2016

Плюс

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

maxvalin пишет:

Все что угодно но только не по-делу. Да что я один такой?! Это один раз написать всего надо.

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

Собственно, это в инете уже обьяснено десятки раз. Да и на этом форуме. тема-то и создана. чтобы раз и навсегда пресечь дурацие вопросы. Не помогает.

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

maxvalin пишет:

Зачем?!

что бы ты оценил уровень своего интеллектального развития и свалил бухать вотку.

maxvalin
Offline
Зарегистрирован: 22.02.2016

Понеслось... 

Ладно,  обозвите меня как хотите(в л.с),  только перестаньте срать в тему. 

Пожалуйста.  Я сюда прихожу за знаниями 

Иван_123
Offline
Зарегистрирован: 17.01.2018

Судя по ответам Ув. Гуру форума, сюда за знаниями приходить н-н-не стоит. 

Страуструп более лоялен, пожалуй.

Ну и Ув. Гугл.

Так что...

Привыкайте.

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

Иван_123 пишет:
сюда за знаниями приходить н-н-не стоит.
Вот, прямо не в бровь, а в глаз! За знаниями надо приходить в школу (в любом её виде) и в библиотеку (также в любом её виде). А сюда стоит приходить, чтобы поговорить с теми, кому интересно тоже, что и Вам.

maxvalin
Offline
Зарегистрирован: 22.02.2016

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

 

maxvalin пишет:
но уж больно заумно

 

Вас смутила запись Serial << ... ?

 

 

Фокусировка вопроса именно на 

uint32_t startTime = millis(), currentMillis;

15

    while ((currentMillis = millis()) - startTime < 2000ul); // ТАК НАДО !!!

start time равен миллисам,  дальше почему current millis через запятую?  Ему тоже присваивается значение millis?  Дальше цикл пошел причем while

Для вас тут естественно все чисто и просто.  Ок.  Но что тяжелого составило бы написать в самой простой форме.? Для нуб использования. Вот вам глобальная переменная,  вот сетап вот в лупе арифметика и место где что-то исполняется,  если вставить.  И новичек тогда пойдет дальше,  ведь все примеры начинаются именно так.  Никтож блинк не написал сразу отдельной функцией.  Все то хорошо конечно что вы делаете ребята ибо вы это делаете просто так в первую очередь. Возможно и есть такие кто в виду своей жизненной немощи пытается выглядеть хоть где-то богом,  но я думаю не здесь уж точно.  Это ближе к мастерам стиралок относится.... Тама клан просто и непосвященные уже есть говно ибо предстали перед ними.  Здесь нормальная атмосфера и я лично очень много вынес конкретно для себя,  для своей головы,  не для цель продаж там и. Т. Д.  

Спасибо всем за терпение.  Жаль только что сам форум построен на дерьмовом движке без нормальных привычных опциях(удаление,  шапки и. Т. Д)  все свалкой.  По этому прошу извинения что мой категорически -поперечный вопрос,  прозьба стала причиной ненужных пол-десятка сообщений.  Ссори с телефона коряво пишется))) 

Иван_123
Offline
Зарегистрирован: 17.01.2018

maxvalin пишет:

Для нуб использования  .....  И новичек тогда пойдет дальше,  ведь все примеры начинаются именно так.

Прикол в том, что  ардуино - это, цитата: "забавная игрушка ДЛЯ ПРОГРАММИСТОВ" (-wdrakula). Поэтому синтаксис и т.п. тут не разжевывают.(На собственном опыте выявленно)

maxvalin пишет:

start time равен миллисам,  дальше почему current millis через запятую?  Ему тоже присваивается значение millis?

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

maxvalin пишет:

 Все то хорошо конечно что вы делаете ребята ибо вы это делаете просто так в первую очередь. 

+

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

Иван_123, ваня иди погуляй. Миру не нужен такой программист.Здесь не ясельки и не садик, куда мамочки приводят своих деточек, что бы они голову по свой дурости не разбили. Да и не гуманитарий Вы, а банальный пиз**ол. 

Olej
Olej аватар
Offline
Зарегистрирован: 05.03.2018

maxvalin пишет:

Для вас тут естественно все чисто и просто.  Ок.  Но что тяжелого составило бы написать в самой простой форме.? Для нуб использования.

А для нуб-использования нужно начинать с вот этой небольшой книжки - Брайан Керниган, Денис М. Ритчи  "Язык программирования Си"

По ссылке выше скачивайте и читайте. Эта книга - классика, основы языка C, от которого производным будет и C++.

И всё станет надолго и гораздо понятнее. 

 

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

Иван_123,

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