2 Реле времени. Задержка включения и выключения.
- Войдите на сайт для отправки комментариев
Всем привет. Я не программист, но уже немного разобрался. Я больше хардверщик, но решил попробовать ардуину.
Вообщем задача банальна и проста, но вынесла мне мозг. Точнее я ее осилил, но потом дошел до mills и крыша поехала...
Реле времени 1! Нужно чтобы при нажатии кнопки и ее удержании через 5, предположим, секунд загорался светодиод и горел до отпускания кнопки.
Реле времени 2! Если кнопка нажата - светодиод горит. Как только кнопка отпущена - засекаем 10 секунд и выключаем светодиод.
Я все сделал с использованием delay(), и интервалом в 10мс. В целом это ОК, так как итераций много и успевает вылавливать оба "включения - выключения", но почитав мануалы решил переделать на mills.. вот тут прошу помощи.
//реле включения с задержкой и выключения с задержкой //версия 0.7 const int buttonPin1 = 8;//Контакт "генератор" const int buttonPin2 = 9;//Контакт "зажгание" // Это кнопки для Ардуины const int ledPin1 = 13; //Реле 1 - управление const int ledPin2 = 12; //Реле 2 - управление int offtimer =500; //Таймер выключения = 500 = 5 секунд. int ontimer = 0; // Таймер включения // переменные положения кнопок int buttonState1 = 0; //генератор int buttonState2 = 0; //зажигание void setup() { pinMode(ledPin1, OUTPUT); //этот пин выход pinMode(ledPin2, OUTPUT); //этот пин выход pinMode(buttonPin1, INPUT);//этот пин вход pinMode(buttonPin2, INPUT); //этот пин вход } void loop() { // читаем состояние пинов buttonState1 = digitalRead(buttonPin1); buttonState2 = digitalRead(buttonPin2); if (buttonState1 == HIGH) //если есть напряжение { // подаем сигнал на реле 1 digitalWrite(ledPin1, HIGH); offtimer = 500; //кончился таймер - перезаполняем его } //if1 else { //если питания пропало if (offtimer == 0) //если таймер еще не оработал (полный) { digitalWrite(ledPin1, LOW); //выключаем реле 1 }//if2 else { // Если не полный таймер offtimer = offtimer -1; //уменьшаем на 1 (1/10 секунды) delay (10); //ожидаие чтобы работал таймер }//else2 // }//else1 if (buttonState2 == HIGH) //если есть питание зажигания { if (ontimer == 300) //если уже прошло 3 секунды { digitalWrite(ledPin2, HIGH); //включаем реле 2 } else //если не прошло { // ontimer = 300; delay (10); ontimer = ontimer +1; //то добавляем 1 к таймеру }//else 3 //if 4 }//if 3 else //если нет питания { digitalWrite(ledPin2, LOW); //вырубаем ontimer = 0;//и обнуляем таймер. } }//loop
Примерно так (если я понял правильно)
Привет! 4ettik, спасибо большое!
Вот мой конечный результат, может кому пригодится. Когда сделаю финалку тоже выложу сюда.
Кнопки зависимы? Или их можно жать вместе, по отдельности и вообще по всякому? Если наэать на вторую кнопку в тот момент, когда вызванная ей процедура отсчёта 10 секунд работает, то что должно произойти: добавится ещё десять секунд, или ничего?
Привет Leshiy!
В целом это не кнопки аа вводы (+5 воль, но можно и кнопки).
Можно жать по всякому. Но если нажать кнопку в процессе отсчета, то таймер обнултся и начнет считать заново.
Для второго аналогично, если кнопку отпустить пойдет 5 секунд, нажать и отпустить - снова 5 секунд.
Кнопки могут работать параллельно, кроме кнокри Dimmer_led.
Она всязана с первым таймером: если таймер идет (пример 30 сек), то за 10 сек до конца начинает медленно гаснуть светодиот (5 секунд в сумме, а таймер дорабатывает. Если снова подать питание во вмеря 5и секунд угасания диода, угасание продолжится, не влияет на него. Но третей кнопкуй его можно снова включить.
Если что схема тут http://arduino.ru/forum/apparatnye-voprosy/pomogite-optimizirovat-skhemu
Пример далеко не перл программистского искусства, но я и сам тот ещё программист.
>Пример далеко не перл программистского искусства, но я и сам тот ещё программист.
Да че... все прилично выглядит.... прицепится можно ну уж "совсем из принципа". Цепляться, что тут еще можно "замшевой тряпкой полировку навести"?
А, там задержка на включение ещё нужна. Пропустил, прошу прощения, сутки уже без сна.
>Пример далеко не перл программистского искусства, но я и сам тот ещё программист.
Да че... все прилично выглядит.... прицепится можно ну уж "совсем из принципа". Цепляться, что тут еще можно "замшевой тряпкой полировку навести"?
Спасибо, приятно слышать.
Движок у форума наистраннейший. В моём 28 фаерфоксе его корёжит страшно. Через строку пишу не потому, что шибко умный, а потому, что нажатие на Ентер приводит к появлению неудаляемой пустой строки. А браузер ради форума менять не комильфо, поэтому пишу в блокноте, а потом переношу сюда, так всё работает красиво.
Поправил пример. Теперь светодиод по таймеру не гаснет, а инвертирует состояние. Таким образом если в вызывающей таймер процедуре зажечь светодиод, то по истечению времени он погаснет, а если погасить, то он наоборот зажжётся. Так сказать расширил функционал :)
Не, я говорил про "стилистику".
Вот смотрите... Первое. Проверки типа
i<=endcount
Которые заставляют вас отнимать "магическую единицу", вот тут:
Математически - все верно. Вопросов - нет :) Но... "так не принято". С такой привычкой и вам чужой код будет труднее читать, на ваш код другие будут морщится.
Делаем проверку
И магическая единица становится не нужна. Причем, само "endcount" у нас равно не "чему-то абстрактному" (последнему индексу), а ... количеству элементов массива. А эта цифра много где еще может пригодится (вывести пользователю и т.п.)
Возможно оно вам, сейчас, кажется "не интуитивным", но в будущем конструкция для "пробега по все элементам массива", выглядящая так:
будет казаться естественно и не требовать в головое "прикидывать по каким числам пробегается i". Одним взглядом будете распознавать "пробежались по всем элементам).
Не, я говорил про "стилистику".
Вот смотрите... Первое. Проверки типа
i<=endcount
Которые заставляют вас отнимать "магическую единицу", вот тут:
Математически - все верно. Вопросов - нет :) Но... "так не принято". С такой привычкой и вам чужой код будет труднее читать, на ваш код другие будут морщится.
Делаем проверку
И магическая единица становится не нужна. Причем, само "endcount" у нас равно не "чему-то абстрактному" (последнему индексу), а ... количеству элементов массива. А эта цифра много где еще может пригодится (вывести пользователю и т.п.)
Возможно оно вам, сейчас, кажется "не интуитивным", но в будущем конструкция для "пробега по все элементам массива", выглядящая так:
будет казаться естественно и не требовать в головое "прикидывать по каким числам пробегается i". Одним взглядом будете распознавать "пробежались по всем элементам).
Ясно. Ну я на "ардуино си" писать начал только когда ардуино купил, то есть полторы недели назад, так что я себя за эту ошибку прощаю. :)
Далее, конструкция вида:
(надеюсь на то что-бы убрать -1 я вас уже уговорил.
Что такое 2? Какая-то магическая цифра. Не... догадатся что это "размер одного элемента в байтах" - можно конечно. Но ведь это же мозг напрягать нужно :) Беглым взглядом "не ловится".
Тем более что оператор возвращающий размер "какой-нибудь фигни в байтах" - мы уже знаем. Поэтому и записать "размер массива поделить на размер элемета" мы можем практически буквально:
О... и уже не нужно листать справочник сколько же байт занимает int. Дуина это сама знает. Пусть она и "листает".
А если у нас будет там какой-то сложный тип, struct какой-нибудь, так руками вообще может очень заморочливо выяснять размер одного элемента. А так у нас "одна конструкция для массивов любого типа".
Кстати.... я бы inpin обозвал бы inpins , что-бы более явно было видно что это массив. множественное число - значит массив. можно даже в объявления не смотреть.
Ясно. Ну я на "ардуино си" писать начал только когда ардуино купил, то есть полторы недели назад, так что я себя за эту ошибку прощаю. :)
Да я же не корю вас. Я же сказал "все у вас нормально". Я просто рассказываю "как с моей точки зрения лучше сделать". Более того, все эти "правила" далеко не всегда выполняются.... у каждого, в итоге свой стиль. Просто рассказываю в чем можно проявить "перфекционизм".
Если не хотите, то в принципе могу остановится :)
Далее, в setup()
В принципе "спорный совет". Не ошибка. В какой-то степени даже "сам так люблю делать". Что-бы было явно видно, но....
Знайте что эти две строки не делают никакой полезной работы (кроме того что код чуть легче читается): по умолчанию, если ничего не далеть все пины уже включены как INPUT. И опять-таки, когда мы переключили кого-то на OUTPUT, то по умолочанию он уже LOW.
Вообщем делать так как сделали вы "можно", но делать нужно сознательно :) Типа "вот такая прихоть автора" ;)
То, что 2 это размер элемента в байтах для меня ясно как день, а вот то, что можно получить размерность типа - этта ваще! Я теперь себя как Колумб чувствую, правда Америку мне открыли вы. То есть сайзоф(инт) для меня невообразимая конструкция, про такое только читать, но не догадываться. Пока программки пишу больше на интуиции, нежели чем на энциклопедических знаниях.
Далее, в принципе вот этот endcount можно и не переменной делать.
Можно его тоже как define объявить...(сразу переименую его в TOTAL)
Что это дает? Так как на этапе компиляции и размер массива и размер int-та, уже известен. То компилятор сразу поделит одно на другое, и сразу подствит во все места где вы используете этот макрос: итоговую цифру.
Как будто вы руками написали
for(int i=0;i<2;i++)
Мы получим экономю в два байта (не будет выделения памяти для переменно) и экономию в пару тактов процессора на чтение этой переменной из памяти.
Далее, в setup()
В принципе "спорный совет". Не ошибка. В какой-то степени даже "сам так люблю делать". Что-бы было явно видно, но....
Знайте что эти две строки не делают никакой полезной работы (кроме того что код чуть легче читается): по умолчанию, если ничего не далеть все пины уже включены как INPUT. И опять-таки, когда мы переключили кого-то на OUTPUT, то по умолочанию он уже LOW.
Вообщем делать так как сделали вы "можно", но делать нужно сознательно :) Типа "вот такая прихоть автора" ;)
Я знаю, у меня на то тестер есть, но, блин, не могу себе отказать в удовольствии проинициализировать всё предварительно, чтобы потом не тупить "чо тут не так блин!?". А советы ваши полезны, поэтому продолжайте, если ТС не будет против.
Про #define узнал пару дней назад и ещё не приучил себя к ним. Переменные пока роднее.
Еще плюсом вычисления TOTAL с помощью #define состоит в том, что мы можем использовать его при объвялении других массивов.
Скажем писать:
Зачем это нужно? Зачем в явном виде говорить размер массива? А затем, что если мы вычилсли TOTAL на базе inpin массива, а потом попытаемся в oupin проинициализировать больше количество элементов, то компилятор на нас ругнется. Впихнуть в outpin элементов больше чем в inpin - мы уже не сможем. (меньше - к сожалению сможем. но хоть в одну сторону нас компилятор подстрахует).
Верно. Я хотел сделать проверку на размер, но решил, что в примере оно не надо. Хотел потому, что своём небольшом проекте, ради которого я и купил ардуино и начал учить язык, я допустил ошибку, внеся в мастер-массив элементов больше, чем с слейв-массив. И тут такооое началось! я часа полтора потратил, пока допёрло что и как (потому что ночью надо спать, а не быдлокодить).
То, что 2 это размер элемента в байтах для меня ясно как день, а вот то, что можно получить размерность типа - этта ваще! Я теперь себя как Колумб чувствую, правда Америку мне открыли вы. То есть сайзоф(инт) для меня невообразимая конструкция, про такое только читать, но не догадываться. Пока программки пишу больше на интуиции, нежели чем на энциклопедических знаниях.
Ну так все мы так осваиваем :) Все норм.
sizeof(int) имеет еще и один такой существенный плюс: вы увеличиваете переносимость.
На другом камне, с другим компилятором.... int может иметь размер совсем не 2-байта. Скорее 4-байта это более частая ситуация. Если вы "жестко забили делению на двойку", то на другой платформе "все пойдет лесом". И если программа большая то найти все эти деления на двойку, будет... ой как не просто.
А sizeof(int) - все продолжит работать как и планировалос. А "перейти на другую платформу" может оказаться не таким уже "фантастическим делом". Например будете писать какой-то уж слишком сложный алгоритм/фильтр/сортировку. На ардуине из-за отсуствия нормального дебагера - неудобно. Можно эту функцию написать отладить на большом компе, а потом просто сделать copy-pastе на ардуину.
Кстати про размер int-та. Два байта. Давайте привыкать экономить. Чай микроконтроллер у нас. Планку памяти просто так не доставишь.
Итак, какой у нас самый большой возможный номер пина? В случае меги 54. И отрицательных пинов у нас не бывает. Поэтому int - в даном случае "расточительство". Хватит обычного byte. Который от 0 до 255.
И для хранения номеров пинов, и для счетчиков циклов и т.п.
я часа полтора потратил, пока допёрло что и как (потому что ночью надо спать, а не быдлокодить).
О... ну значит вы уже "битый". Уже не нужно объяснять почему время потраченное на "выработку стиля" - окупается сторицей :)
Кстати постоянное привычка сознательно думать "какой тип тут лучше выбрать" - тоже уберегает (хотя и не 100%) от многочасовых поисков траблов. А если привык лепить "int" не думая, то где-то... в итоге... и таки напишешь int time=millis(); :(
Проблема в эпизодичности подобной работы. Сляпал и красотааа! Поэтому о выработке стиля говорить не приходится, хотя, конечно, он многое решает. Больше всего не люблю что-то делать ради самого процесса, поэтому "включаюсь" только если что-то надо изготовить, или изобрести этакое, тогда интересно. В остальное время предпочитаю сибаритствовать.
Нее, int к millis не моё. Оно ведь работать должно, а не коекакить. А вот переменные могу называть так, как мне удобнее в данном случае, тут я не придерживаюсь линии партии об именовании. Вот с миллис у меня небольшая нелюбовь, она, зараза, склонна к полноте и, даже, переполнению. А железка моя должна работать постоянно, RTC не хочу, батарейки фи, аккум можно, но тоже не вечен. Пока думаю ресетить дуину по прошествии 30 дней, при условии стабильного состояния устройства. Правда надо посмотреть, что по выходам при ресете происходит, а то меня 13 моргающий напрягает. Если и все остальные выходи не в выскоимпеданс уходят, а начинают дрыгать уровнями, то аяй.
А хочу ещё советов! Я уже их в папочку сложил, абсолютно серьёзно. Завтра зубрить буду. Про байт - замечательно, у меня вообще с типами проблемы, их надо решать.
Дальше... вы на горьком опыте познали как плохо когда массивы которые должны быть одного размера, "рассогласовались".
В сторону slave больше master - мы уже знаем как подстраховатся, но... "меньше" - нет у нас рецепта. И, поверте, если ошибка возможна - она случится.
А какая деталь не может сломаться? Правильно - та которой нет.
Значит нам нужно сделать так, что бы у нас небыло кучи разных массивов, за согласованием размеров которых нужно сделить.
Вот был-бы у нас всего один массив.... длина одиного всегда же равена своей собственно длине :) Сделать ошибку - шансов нет.
Как же нам запаковать разнородные данные в один массив?
А объеденить "что-то различное" в одну сущность нам позволяет конструкция языка struct.
Потом мы объявлем массив этих структур и... дело в шляпе.
Посмотреть пример структры можете тут (там объединят три числа r,g,b для одного светика в одну сущность)
Arduino Playground - Struct Resource
Попробуйте самостоятельно (возможно в справочничек заглянуть прийдется), переписать ваш пример на использование структр. Что-бы inpin,outpin и т.п. были полями структуры, а не отдельными массивами....
Если не получится - подскажем (но уже не сегодня :). Для новичка задача хоть и не тривиальна, но... подъемна. Тем более для такого который сам смог "маштабировать" использование millis() с помощью массивов :)
Ну так "стиль" он для того и нужен. Что-бы рутинные операции выполнялись без напряжения мозгов (больше времени на сибаритсво) и при этом качество не страдало (небыло кое-какерства).
Это сейчас вас очевидно что inpin - это массив.
А через пол-годига, когда стрехнете со скетча пыль - уже нужно лезть смотреть в объвления. А так сразу понятно - множественное число.
Опять-таки функцию какую-то захотите написать. У которйо будет параметр "входной пин". Как его обзовете? inpin. Хоп. Конфликт имен с массивом. И хорошо если компилятор завопит. А ведь бывают случае когда "все прошло тихо", только поменялась не та переменная которую хотели... Вернее другая переменная почему-то "начала менятся". И выяснить "какая падла ее меняет" это уже не часы, а дни и недели могут быть.
Так что имена переменных и функций это не "как хочу так и ворочу", а одно из самых важных (и кстати самых сложных). Именно от них зависит читаемость и сопровождаемость кода.
Всегда пишите код так, будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете.
— Martin Golding
>Пока думаю ресетить дуину по прошествии 30 дней
Фу...Фу.. Думать забудте.
Если спросите на форуме, то либо засмеют, либо в такие дебри заведут.... если не верите, то поищите ветку соотвествующую :) И того и другого там будет вдосталь. И смеха и дебрей... вплоть до шансов "а!!! теперь в ардуину не заливаются скетчи.." :)
С millis() проблема решается гораздо проще, примерно так как и с i<=encount, просто нужно привыкнуть к другой конструкции.
Которая "математически эквивалентна", но... не имеет проблем с переполнением.
Смотрите базовый пример Мигаем светодиодом без delay()
Смотрите как там делается проверка "нужный интервал времени прошел". Такой способ - через вычитание, а не суммирование... будет работать и через 50-т дней.
Почитал, более-менее понял, но возник вопрос: почему структура, а не многомерный массив? Структура более наглядна, меньше\столько же жрёт памяти, в этом причина?
>Пока думаю ресетить дуину по прошествии 30 дней
Фу...Фу.. Думать забудте.
Если спросите на форуме, то либо засмеют, либо в такие дебри заведут.... если не верите, то поищите ветку соотвествующую :) И того и другого там будет вдосталь. И смеха и дебрей... вплоть до шансов "а!!! теперь в ардуину не заливаются скетчи.." :)
С millis() проблема решается гораздо проще, примерно так как и с i<=encount, просто нужно привыкнуть к другой конструкции.
Которая "математически эквивалентна", но... не имеет проблем с переполнением.
Смотрите базовый пример Мигаем светодиодом без delay()
Смотрите как там делается проверка "нужный интервал времени прошел". Такой способ - через вычитание, а не суммирование... будет работать и через 50-т дней.
Пример гляну, спасибо, правда интересно, как обойти вычитание большего unsigned из меньшего. Пример с суммированием он только здесь, в моём случае вычитается.
Глянул, опять поморгаем светиком... Пусть они светиком 50 дней поморгают, при этом в проекте, в котором если светик не моргнёт в нужный момент, то разработчику сразу сапогом в табло прилетит, тогда и посмотрим... Запомнили мы ТЕКУЩЕЕ значение millis(), программа что-то там поделала и думает, надо бы нам посмотреть, сколько времени прошло-то, а то мож уже пора атомную бомбу отключать, чтоб не бахнула. Берёт она millis() и вычитает из неё предыдущее значение, тут кэээээк бабахнет! И абзац. А бабахнуло потому, что миллис у нас обнулится изволила, переполнилась и через края пошло. Поэтому она всё слила и теперь равна 10. А ПРЕДЫДУЩЕЕ значение было равно стомиллионмиллиардов миллисекунд.
Не вижу проблем с аппаратным ресетом "оборудованным" гистерезисом. То есть чтобы "нажать" можно было раз в минуту, например, это избавит от проблем неопределёности по портам в момент сброса и после него, нажало, отпустило и сидит себе, делая вид, что ничего не происходит, в следующий раз нажать можно будет через минуту, не раньше.
И может в общие разговоры какие уйти, а то ведь побьют за эти отвечённые эссе в теме.
Почитал, более-менее понял, но возник вопрос: почему структура, а не многомерный массив? Структура более наглядна, меньше\столько же жрёт памяти, в этом причина?
О :) Теперь у вас два "домашних задания" ;)
Сделать структурами и сделать многомерным массивом.
Кто памяти больше жрет... у вас уже есть "волшебный инструмент" sizeof()
Кто наглядней - вот выложите оба варианта, посмотрим/сравним/обсудим ;)
Берёт она millis() и вычитает из неё предыдущее значение, тут кэээээк бабахнет! И абзац. А бабахнуло потому, что миллис у нас обнулится изволила, переполнилась и через края пошло. Поэтому она всё слила и теперь равна 10. А ПРЕДЫДУЩЕЕ значение было равно стомиллионмиллиардов миллисекунд.
О... а вот и ваше третье домашние задание ;) Не теоретизировать а поставить эксперемент. Проверить "бабахнет или нет". Смодулируйте ситуацию. Сделайте три переменных unsigned long. В одну положите "текущие значение millis()" - 10. Во вторую, прошлое значение "стомиллионмиллиардов миллисекунд". Потом вычтите из первой вторую (аналог millis()-prevTime), поместитите в третью переменную разница (diff). Сделаейте Serial.println(diff).... и расскажите нам. Бабахнуло или, все-таки, нет :)
Бабахало уже. При старте дуины millis == 0, а код уже шустрить начал всякое, и первое вычитание происходит при millis == 100-200ms, а вычитается из них 15000мс, какая красота в терминале при этом образуется, просто неописуемо. Пока обошёл вводом переменной trumillis, которая всегда равна miillis()+60000. А третью домашку щаааа, это не со структурами ковыряться.
Ожидаемая дикая дичь.
Вывод:
Ожидаемая дикая дичь.
Почему ожидаемая? Что вы сейчас сэмулировали? Ну что за "пируэты на граблях"? :)
Зачем использовали millis(), когда сказанно было "положите в переменные".
Вам что нужно было? Проверить как произойдет вычисление интервала после переполнения. Правильно или нет.
1000 и простите "стомиллионов-миллисекунд" это слегка разные вещи.
Нужно было просто в две переменные, положить два значения. Отнять и вывсести. Один раз... что-бы понять "что происходит". Зачем это в loop() попало? Что-бы самому нельзя было "на пальцах" перепроверить верно ли сработало наше вычитание?
Раз мы воспроизводим ситуацию "переполнение", значит и значения для теста мы должны подбирать "близкие к правде". Предположим у нас last было записанно за "10-сек до переполнения". Это какое значение millis()? 4294967295-10000=4294957295
Вот его и пложите в last.
Теперь, предположим у на текущие время "2 секунды после переполнения". Значит ложим в current=2000;
Отнимаем одно от другого и выводим. Для проверки "считаем на пальцах". Сколько "взаправду прошло времени" от прошлого last? "10 сек до переполнения, 2 сек. после". Вместе получается 12сек. Если наш код насчитает при таких last и current что прошло "12 секунд" значит проблема переполнения его не затронула. Логично? (на самом деле 12 секунд и одна миллисекунда. само "переполнение" тоже одну миллисекунду занимает).
А то что вы "наэксперементировали", так это простите вы уже переполнились самими интервалами. Посчитайте "на пальцах" какой же временной интервал "взаправду" получился в вашем случае... и мог-ли он поместиться в unsigned long.
Вернее мог конечно, и вначале помещался... и даже верно выводился. Только вы этого - не поняли. Что вот эти "большие числа", а не бред, а именно то сколько времени прошло при данных вами входных параметрах. Просто ставя эксперимент нужно было прикинуть сколько же вы ожидаете в качестве "корректного результата".
Что вы ему дали? То что как был записан last , до переполнение прошло 49 девять с копейкой дней. После переполнения - пару секунд.
Ну... и какая должна быть разница? 49 девять с чем-то дней. Что-то близкое к максимального unsigned long. Что вообщем то мы и увидели в вашем выводе.
Вообщем "а вы чего ожидали"? ;)
Шото мне спать уже пора. Больше суток без сна плохо сказываются на производительности и понимании. Вон, уже не то не из того начал вычитать.
Поэтому я упаду спать, а завтра всё исправлю, ну или не исправлю. Спасибо и спокойной ночи.
Да, к вопросу о том, что мне нужно: мне нужно, чтобы оно работало. Выяснилось, что переполнение обрабатывается корректно, это хорошо, завтра буду думать, как красиво обойти проблему с уходом в псевдоотрицательные числа, потому как millis()+60000 это костыляка та ещё.
И я прекрасно понял, что большие числа не бред, я просто не понял, шо мне пока с ними делать, так как операция, от которой программа ожидает чего-то типа 0, возврашает ей 120938230498, ессно программа дичает и начинает плохо пахнуть. Но, собственно, это проблема не программы, а её написателя.
Вот теперь сон не идёт... В общем в моём случае при условии last>current, надо менять знак числа, которое вычитается из current. И всё, похоже.
Пример так, для иллюстрации идеи.
Пример так, для иллюстрации идеи.
Стремная какая-то идея. Какие-то попытки "угадать правильное заклинание". Никакие плюсы тут не нужны. Какой в плюсе реальный "физический смысл"?
Разница между currentTime-prevTime нам дает в результате "сколько времени прошло между prevTime и currentTime". Независимо от того "было-ли между ними переполнение" или нет. Независимо от того кто из них больше/меньше...
Естественно это работает только в случае когда currentTime, prevTime и разница - одного БЕЗЗНАКОГО тип. И переполнение было только одно. И если currentTime не "обгонял" prevTime (это то что произошло в вашем эксперименте через секунду и появились "маленькие цифры" - вот они и были "неправильными"). Если он "догнал prevTime", то действительно возникает неоднозначность. По разнице мы уже понять не можем мы "только что начали отсчет" или currenTime успел сделать круг (или несколько). Но... если он его "обогнал", это значит что сама разница "сколько прошло времени" уже не помещается в unsigned long. И нам нужно будет для вычисления "сколько прошло времени" пользоваться уже более вместительными типами. Или... если мы хотим делать часы или еще что-то подобное (при этом нас не колышит точность. плюс/минус километр устраивает), то нам нужно будет завести отдельную переменную, в которой мы будем засекать "сколько кругов прошел currentTime". Но круги мы, опять-таки, будем отсчитывать детектирую не "переполнение", а моменты когда currentTime сравнивается с prevTime.
Но... в 99% процентах задач. Нам не нужно ловить интервалы, мигать диодом с переодичностью в 50-т дней.
Практически всегда нам нужны интервалы в секунды/миллисекунды. Что совершенно спокойно помещается в unsigned long. А значит можно делать простое вычитаение стартового времени и текущего. И не переусложнять свой код.
Вообщем, что-бы было легче мысленно представить "почему же разница работает".
Вообразите себе 12-ти часовй циферблад (только вместо 12-ти у нас ноль). Вообщем имеет 12-ть "засечек" 0..11
Ситуация 1:
Первая стрелка у нас стоит на 10-ти часах. это prevTime
Вторая стрелка у нас стот на 11 часах. это currentTime
Третья на нуле - это "разница" (мы ее пока не высчитали).
Отнимаем currentTime-prevTime=11-10=1. Переполнение небыло. Все очевидно. Теперь просто крутим третью стрелку по часовому направлению на одно деление. Все наш "прибор" показал что между currentTime и prevTime прошел ровно один час (показание третьей стрелки).
Ситуация 2:
Возвращаем третью стрелку (diff) в нулевую позицию... (пока не выщитана разница). diff=0
prevTime тоже самое что и в прошлом примере prevTime=10
А вот currentTime у нас пошел "тикать" дальше.... прошел 0 (12ть часов), это случилось "переполнение", 1,2,3 и остановился на "трех часах". Мы опять делаем ТО ЖЕ САМОЕ
currentTime-prevTime=3-10=-7
Теперь нам нужно выставить третью стрелку, в "минус 7мь часов". Но.... у нас же нет на циферблате "отрицательных чисел" (как их нет и в unsigned long, поэтому нам важна беззнаковость типа куда мы разницу сохраняем). Но... абсолютно как и в прошлом случае, мы просто крутим diff-стрелку на нужное количество делений. Просто раз отрицательное число, крутим ее "против часовой стрелки". На семь делений.
11,10,9,8,7,6,5 - и остановились на 5-ти часах.
Итого наш прибор показал (показаниея третьей стрелки) что между 10-тью часами и тремя часами - прошло 5-ть часов. Что соотвествует правде (2 часа "до полуночи" плюс три часа "после полуночи").
И все у нас будет хорошо, пока currentTime не "дотикает" до 10-ти часов. До места где стоит "prevTime". В этот момент обнулиться diff.
Если же, мы хотя-бы раз, пока currentTime не догнал prevTime обновили саму prevTime на "свежее время", то.... у нас нет проблем.
Как еще более "понятней" рассказать - я не знаю... разве что "нарисовать", но сейчас точно на это нет времени :)
Вообщем весь фокус работает потому что "разница отрицательная", а когда мы пытаемся запихнуть "отрицательно" в беззнаковый тип unsigned long. Мы получаем "второе переполнение" в обратную сторону. Одно переполнение, компенсирует другое и на выходе: корректный результат.
Вот теперь сон не идёт... В общем в моём случае при условии last>current, надо менять знак числа, которое вычитается из current. И всё, похоже.
Пример так, для иллюстрации идеи.
вы сможете перевести на челЯзык - время абсолютное = 15 ч 75 мин 65 сек ? если сможете - то переложите это на МИЛЛИС :) , НО - миллис легко отследить при периоде засечки времени не более 1,9 ( например ) периода переполнения счётчика миллис.... при более длительных отрезков времени - придётся учитывать количество переполнений миллис...
по логике Лешака продолжу....
- в 23:00 засекли время
- в 23:59:59,999999999 и ещё чуть-чуть произошло переполнение миллис и стало =0
- в 01:00 фиксируем время
- diff = 01:00 - 23:00 = -22:00
- через if -> если ( diff < 0 ) то корректируем diff ! diff = diff + 24:00 = -22 + 24 = 2 часа
....от 23 до 01 - именно 2 часа
!!!!!!!!! если переполнения отследить, то нужно учесть их количество - ЧТО НЕ ТАК ?
ЦИКЛ переполнения миллиса - есть цикл ! мне кажется ( я уверен ), ( мине хочется верить ) - что при переполнении миллиса не добавляется никаких аппаратных тактов.... время не искажается.... счётчику - что переключиться с 16789 на 16789, что с 25678 на 0 - одно и тоже.... числа - не в тему - неохота вспоминать макс значение миллис :( , типа - 25678 = макс значение счётчика миллис ( только для этого поста ! )
итого, или как ещё рассудить-то ?
- миллис в ардуине - это абсолютное время
- если засечки времени относительного меньше периода переполнения счётчика миллис ( абсолютное время ) - то нет никаких проблем
- иначе - организуйте учёт колво переполнений ( N ) и скорректируйте время относительное на N циклов переполнения
......тема похожа на тему "1999 -> 2000", мир не рухнул же :)
Вообщем весь фокус работает потому что "разница отрицательная", а когда мы пытаемся запихнуть "отрицательно" в беззнаковый тип unsigned long. Мы получаем "второе переполнение" в обратную сторону. Одно переполнение, компенсирует другое и на выходе: корректный результат.
.......через IF - для таких как моя :) , фокус Лешака - от знаний представления чисел.... блиииин, действительно минус на минус = правильно :)
Во вы накрутили!!! :) Всё, кагбэ, уже давно исделано - проблема была только в несоответствии типов.
Если из unsigned long вычитать int, то есть millis=100, а мы делаем millis-1000, то выходят бока, "псевдоотрицательные" числа. А если мы объявим unsigned long diff=1000; unsigned long decrement=10000 и сделаем if (millis-decrement)>diff {}, то всё выходит как задумано.
То есть не if (millis-10000)>diff{}, а именно if (millis-decrement)>diff {}
Если точнее, то можно и инт вычитать, но не нужно.
зачем вы привязались к какой-то 10000 ? "...if (millis-10000)>diff{}..."
есть только мигЗафиксированный, и мигТекущий, нууууу, и разница вычисляемая....
миг-29 - это другое....
:)-
через фокусы Лешака ( знаковый / беззнаковый ) - это к Лешаку..... моя объяснить пытался через "если diff < 0", в итоге - это одно и тоже !!!!!!!!!!!!! .....в диапазоне одного переполнения !!!!!!!!!!!!!!!
Больше восклицательных знаков, боольше! :)
согласен.... колво !!!!!!!!!!!!!!!!!!!!! - просто эмоции.... лишнее т.е. ..... спасибо за критику :)
> А если мы объявим unsigned long diff=1000;
запутали.... зачем назначать diff=1000 ? это же ВЫЧИСЛЯЕМОЕ значение :( ....оно до первой засечки времени - неопределено
diff=1000 чисто для внесения в скушную нашу жизнь свежей струи!
Домучал я свой "проект", работает сносно вполне, то есть делает то, что нужно тогда когда нужно. Сейчас засел за его переработку в соответствии с высокими стандартами программирования - val, byte, diff и остальные страшные буквы. Тако же во имя Разума и Знаний приступил ко изучению Великих Структур. Так как Великие Структуры начал изучать... эээ... минут пять назад, ещё не понял, можно ли к членам структуры обращаться не по имени, а по нумеру их. А то с циклами печально как-то всё выходит. В общем жизнь идёт.
2 leshak
Ещё 5 минут поизучал. Структура дело нужное, только вот что она на даст в рассматриваемом случае с двумя таймерами? Объявим по структуре на каждую кнопку, которая будет управлять таймером? Или вы предлагаете создать структуру из массивов? Или многомерную структуру, если такое вообще возможно, я ваще не в кугсе, пацаны.
- в 23:59:59,999999999 и ещё чуть-чуть произошло переполнение миллис и стало =0
Шо вы накрутили? Вы мысленный эксперимент с циферблатами поставили? Какие 23:59:59?
Сказанно же было 12-ть засечек. От 0 до 11.
Никаких дробных. Целые числа.
У millis() - тоже "только целые".
Только положительные. Никаких дробных. Никаких отрицательных.
Зачем вы вначале "по простому" в голове уложите, а потом уже в сторону усложнений пойдете.
- в 23:59:59,999999999 и ещё чуть-чуть произошло переполнение миллис и стало =0
Шо вы накрутили? Вы мысленный эксперимент с циферблатами поставили? Какие 23:59:59?
Сказанно же было 12-ть засечек. От 0 до 11.
Никаких дробных. Целые числа.
У millis() - тоже "только целые".
Только положительные. Никаких дробных. Никаких отрицательных.
Зачем вы вначале "по простому" в голове уложите, а потом уже в сторону усложнений пойдете.
Я не то, что не поставил, я даже не читал. К тому же не припомню, где я про 23:59:59 писал.
Лучше про структуры расскажите, про конкретное применение в данном случае. Я не понимаю их смысла здесь, на каждую кнопку по структуре объявлять, вы это имели ввиду?
Жестяк ребята, я от вашей переписки узнал больше чем от 5и курсов иснтутиту...