По нажатию кнопки моргнуть 3 раза диодом (без delay)
- Войдите на сайт для отправки комментариев
День добрый, форумчане!
Никак не могу понять, сам принцип как реализовать следующую задачу:
На нажатие кнопки светодиод должен моргнуть 3 раза (скажем 1 сек горит, 1 сек не горит... и так 3 раза). При наличии delay всё получается. Но как только заменяю delay на схему с millis и циклами, то выходит одно из двух: или светодиод начинает мигать без остановки, или моргает только один раз.
Вот пример кода:
---------------------------------------------
#define BUTT_PIN 2
#define RELE1_PIN 10
#define INTERVAL_RELE1 1000
#include "GyverButton.h"
GButton butt2(BUTT_PIN);
uint32_t rs01 = 0;
//----------------------
void setup() {
Serial.begin(9600);
pinMode(BUTT_PIN,INPUT_PULLUP);
pinMode(RELE1_PIN,OUTPUT);
butt2.setDebounce(90); // настройка антидребезга (по умолчанию 80 мс)
butt2.setTimeout(300); // настройка таймаута на удержание (по умолчанию 500 мс)
butt2.setType(HIGH_PULL);
butt2.setDirection(NORM_OPEN);
//----------------------
void loop() {
butt2.tick();
LED ();}
//----------------------
void LED (){
for (int i=0; i<3; i++) {
if (butt2.isPress()) {
digitalWrite(RELE1_PIN, HIGH);
rs01 = millis();
// Serial.println ("1");
}
if( rs01 > 0 && (millis() - rs01 >= INTERVAL_RELE1)) {
digitalWrite(RELE1_PIN, LOW);
rs01 = 0;
// Serial.println ("2");
}
}
}
------------------------------
Если отследить при помощи SERIAL то, как работает цикл, то становится понятно, что цикл работает... но диод моргает только один раз... Никак не пойму что не так в коде.
Помогите, кто может. Если есть у кого-нибудь ссылки на подобное решение - буду благодарен.
1. Код, естественно, не смотрел (почему "естественно" - читайте правила форума).
2. Для мигания заводится переменная состояния, принимающая, скажем, следующие значения:
- 0 - начальное состояние, при нажатии кнопки - переводим в состояние 1,
- 1 - светодиод горит, по истечении интервала времени переводим в 2,
- 2 - светодиод не горит, по истечении интервала времени переводим в 3,
- 3 - светодиод горит, по истечении интервала времени переводим в 4,
- 4 - светодиод не горит, по истечении интервала времени переводим в 5,
- 5 - светодиод горит, по истечении интервала времени переводим в 0.
Логически я это понимаю.... Т. е. вы предлагаете не цикл сделать, а раз надо 3 раза моргнуть, то создать 6 разных задач, которые будут вызываться через установленный интервал друг за другом?
1. Цикл всегда один - loop(). Других циклов не нужно.
2. Задача - одна. В этой задаче используется переменная состояния, которая может принимать одно из 6 значений: на нечетные светодиод горит, на четные - нет.
Советуете воспользоваться:
ТС, вы задаете вопросы но ответы не читаете. Вас же попросили код оформить правильно. По сути, своими действиями вы хамите тем кто хочет вам помочь.
Зачем вам эти тухлые библиотеки в решении элементарной задачи ?
2. Для мигания заводится переменная состояния, принимающая, скажем, следующие значения:
- 0 - начальное состояние, при нажатии кнопки - переводим в состояние 1,
-.........
- 5 - светодиод горит, по истечении интервала времени переводим в 0.
Спасибо вам за подсказку! Попробовал. Реализовал...
Затем мысленный процесс пошёл по пути оптимизации и в результате получилось следующее:
1) Простите, извините... #5 Я ничего такого не хотел сделать... Это всё - мой первый опыт программирования на Ардуино... А сейчас даже не могу поменять свой первый пост: нет кнопки "Редактировать" или "Изменить"... Ещё раз прошу прощения у вас и других членов форума.
2) и ещё раз: спасибо за направление.
Это сложно назвать оптимизацией.
Давайте посмотрим, что вы делаете. Вы вешаете на таймер некое действие, которое по сработке этого таймера выполняется. Ладно... Тут вроде все норм...
А что же за действие вы вешаете ? А вот тут облом. Вы написали блокирующую процедуру. Она выполняется в цикле долго-долго, пока не истечет некоторое время. По сути вы написали тот же delay.
То есть запутались еще больше. Сделаете это не используя while, loop и goto. Тогда у вас все получится.
Это сложно назвать оптимизацией.
.... Вы написали блокирующую процедуру. Она выполняется в цикле долго-долго, пока не истечет некоторое время. По сути вы написали тот же delay.
То есть запутались еще больше. Сделаете это не используя while, loop и goto. Тогда у вас все получится.
Так, теперь вот я точно запутался...(( (ну это и не удивительно, исходя из моего опыта) Дык, я так понимаю, что в том и смысл любого цикла...
И если "всё плохо", то тогда возникает главный вопрос любого новичка к учителю: А как надо было?
И если вам не трудно - подправьте код (тот что созданный мною делей) так, как должно быть с точки зрения вас как профи. Как сделать то это без while?
Ну написал же brokly в #5. Хотя и его можно "оптимизировать").
Тада я сначала пошёл читать мануалы на тему: чем while отличается от if с точки зрения блокировок и долгого выполнения...
А чего тут читать то !? Чем отличается операция сравнения от цикла ?! Вы зацикливаете свой код, зацикливание - блокирующая операция. Пока процессор в цикле выполняет действия одной задачи, вторую он решить не может. Правильно это сначала сделать немножко от одной задачи, потом немножко от другой, вернуться к первой и так далее. Таким образом вы гарантировано выполните все задачи, ну или по крайней мере они все будут выполняться.
Ну написал же brokly в #5. Хотя и его можно "оптимизировать").
Покажешь ? :)
Благодарю за разъяснение. Смысл ваших объяснений мне понятен. Но их сутью ещё не проникся... Не прочувствовал как оно так на самом деле... Нужно помозговать.
Ну написал же brokly в #5. Хотя и его можно "оптимизировать").
Покажешь ? :)
Да, тяжело оптимизировать нерабочий скетч. )
А вот эта оптимизация , она что сделала ? Теперь код стал оптимальнее в чем, ну не считая "нерабочести" ? В том что стал еще больше нерабочий ? Стал сложнее читаем ? Стал занимать больше места после компиляции? Стал медленее работать ? :)
Меньше букв, лаконичнее. Только и всего.
За-то оно дважды читает порт и делает лишнюю операцию инвертирования. В конечном итоге бумажная лаконичность выливается в лишний код и время. Компилятор точно будет обрабатывать два чтения порта, как две разные операции, а учитывая, что они, в нашей среде дико кривые и медленные получаем "фиасо братан".
Братан, пудри мозги новичкам.)
А чего я сказал неправильного ? В следующий раз, когда будешь без апеляционно рассказывать про оптимизацию, подумай, может ты термин понимаешь не правильно.
Знаю несколько библиотек, которые написаны красиво на си, но тупо сишным программером, который про процессоры знает очень мало. Так вот они работают, но места занимают столько, что становятся бессмысленными. Они так же, как ты говорили, когда им рассказывали об экономии ресурсов :)
И еще один момент, я в форум пишу не тебе одному. Новички, тут тоже читают.
Уважаемые знатоки!
Заранее прошу прощения, если что не так скажу или сделаю, у обоих: и у brokly, и у Green... но я проверил на Nano код brokly:
Он просто моргает раз в секунду светодиодом и на кнопку никак не реагирует.
Код же от Green:
работает как надо, т. е. при нажатии на кнопку мигает три раза.
Но это была просто ремарка ( я никого не хотел обидеть, просто констатировал факты).
-----------------------------------------------
Вот теперь то я понял, в чём я никак не могу разобраться, а именно:
1) если сделать так (т. е. код разместить прямо внутри главного цикла):
то всё прекрасно работает (я о многозадачности). 2 кнопки управляют 2-я светодиодами независимо друг от друга и даже одновременно (я специально в коде сделал разные интервалы, указываю напрямую пины и т. п. - для ясности таким как я)...
2) А вот если сделать так (т. е. тот же функционал, но сделать через вызов функции в главном цикле):
то не работает вообще: при нажатии кнопок нет никакой реакции...
Вроде бы, всё одно и то же. Но похоже, это именно то, чего я и не понимаю: в чём тут разница?
Пожалуйста, "пните" меня в нужном направлении... Моя цель - разобраться в том, чего я не понимаю и не знаю и понять, как в таком случае надо правильно поступать чтоб и delay не было, и многозадачность сохранялась... Ну и чтоб работало.))
[/quote]
Проверку кнопок надо делать в основном цикле и вызвать функции моргания по результатам.
Так разве главный цикл не вызывает функцию, которая всё и должна выполнить? Такая же логика?
Нужно же понимать что вы делаете. void-ы уберите из лупа. И закрывающие фигурные скобки ставьте где положено - смотреть невозможно.
Убрал void-ы из лупа. Блин, действительно ужасно лопухнулся... Как я проглядел. Опробую - отпишусь. Запроста не работало из-за моего ляпа. И прога при компиляции не ругнулась... Надо ж...
А скобки перенёс - чтоб сократить размер простыни кода.... Извините, буду впредь писать как обычно..
Что бы размер простыни уменьшить оформляйте классом. Тогда и ошибок меньше будет.
Исправил.
Вот так всегда....(( Начинается с "да это ж плёвая задача! Зачем вам.....", а заканчивается классами, которые, как пелось в песне, "это мы не проходили" (в прямом смысле слова - ещё предстоит поизучать)) А моя сегодняшняя задача не разобраться в классах, а понять сам принцип многозадачности. А понимать его лучше на примерах, причём рабочих. А их то и нет нигде...( Казалось бы, что может быть проще задачи: есть 2 кнопки и 2 светодиода. При нажатии 1-й кнопки нужно моргнуть 1-м диодом 3 раза за секунду и перстать моргать, а при нажатии 2-й кнопки - моргнуть 4 раза за секунду вторым диодом и перстать моргать.... и без использования delay.
А по факту выходит: разбирать и разбираться - не чего и не в чем. А без понимания, что ты сделал не так - и обучения нет никакого... Цикл замыкается.
А у меня есть мнооого многозадачности, но разобраться тебе в ней задача не стоит, она вся состоит из классов.
Спасибо, я понял, что щенкам рядом с вами не место. Отошёл в сторону.
А по факту выходит: разбирать и разбираться - не чего и не в чем. А без понимания, что ты сделал не так - и обучения нет никакого... Цикл замыкается.
А кто тебя обманул, сказав, что здесь обучающая площадка?
А ещё я слышал, что есть FreeRTOS.... Тоже надо будет посмотреть чего это такое.
А зачем нужен дискуссионный клуб, коим является любой форум, дабы не разъяснить собравшимся свою правоту и не показать остальным правильный путь решения проблем? Форум что, нужен чтоб выяснить - кто круче, а то более всех остальных является недоучкой? А заодно и почесать своё эго, считающее самого себя гуру?
Прочитайте правила форума, что бы у Вас не было заблуждений. http://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/pesochnitsa-dlya-vsekh-novichkov . Форумы разные. Цели и задачи форума определяются создателями. Они могут совершенно не соответствовать Вашим представлениям. Форум не коммерческий. Без рекламы. Вы не платите денег. Ваша плата - следование правилам форума. Если Вам что то не нравиться, то просто уйдите.
GREEN же написал, что мой код с ошибкой. Я же в онлайне от руки набросал, могу и ошибиться. Вы же пытаетесь понять, так не списывайте тупо, а анализируйте, что делаете.
20 строка :
Обратите внимание на расстановку круглых скобок.
Насчет FreeRTOS. Она есть, но использовать ее при решении вашей задачи, все равно, что стрелять из пушки по воробьям. И "глянуть" просто так не получится. Сначала нужно понять что такое критические секции, семафоры, потоки, а уже потом пытаться глядеть :)
1) Извините меня. Но вы не так поняли. Я ещё раз говорю: моя задача не списать, а разобраться и понять. Понять почему МОЙ код не работает; понять то, что через while я сделал тот же deley (кстати, после вашего объяснения я понял мою ошибку с while); понять и "прочувствовать" многозадачность и главное способы её реализации... И тут сильно "открыли мне глаза" (лично мне) 2 поста (первый - ваш, кстати): http://arduino.ru/forum/programmirovanie/mnogozadachnost-s-vyvodom-na-displei#comment-174839 и http://arduino.ru/forum/programmirovanie/mnogozadachnost-s-vyvodom-na-displei#comment-174874
Но я, увы пока, не умею так, как вы: глянуть беглым взглядом на код и понять, что расстановка скобок не в том месте... Мне нужно сесть, чтоб за душой не было "тянущих" дел, собрать в кучу все "исходники", "разложить всё по полочкам", протестировать в живую... И я проконстатировал просто факты: один код работает, согласно поставленной задачи, а другой - нет. Никакой цели другой у меня не было.
А ошибиться, тем более ненароком (как я с void-ами), может каждый. Главное вовремя осознать и исправить ошибку.
2) Вот, опять же вам огромное спасибо про краткое резюме о FreeRTOS... Отзыв профи, краткий и по сути - это очень важно. Особенно для того, кто только название слышал....
Теперь о главном:
Нужно же понимать что вы делаете. void-ы уберите из лупа. И закрывающие фигурные скобки ставьте где положено - смотреть невозможно.
И действительно, убрав void-ы всё заработало как надо, то есть:
Значит, я на правильном пути и предыдущие "темы уроков" я" выучил". ))
И это хорошо.
Подходим к итогу...
И снова я хочу высказать благодарность: вам, brokly, за http://arduino.ru/forum/programmirovanie/po-nazhatiyu-knopki-morgnut-3-raza-diodom-bez-delay#comment-576771 и http://arduino.ru/forum/programmirovanie/mnogozadachnost-s-vyvodom-na-displei#comment-174839 2) вам, Green за http://arduino.ru/forum/programmirovanie/po-nazhatiyu-knopki-morgnut-3-raza-diodom-bez-delay#comment-576966 и http://arduino.ru/forum/programmirovanie/po-nazhatiyu-knopki-morgnut-3-raza-diodom-bez-delay#comment-576778 и 3) вам, nik182, за
Это я отметил те "вехи", что помогли мне понять происходящее и достичь таки поставленной перед самим собой же цели.
Итог.
Теперь к поставленной мною задаче " По нажатию кнопки моргнуть 3 раза диодом (без delay)" добавим следующие условия:
1) чтоб система реагировала только на нажатие кнопки (не на удержание, не на нажатие-отпускание, не на отпускание) и учесть дребезг контактов;
2) чтоб система работала в нужном временном интервале, скажем с 13-00 до 15-00,
3) чтоб в системе был индикатор, работющий круглосуточно при наступлении и до окончания некоего события;
4) чтоб количество морганий светодиодов и интервал морганий были бы произвольно настраиваемыми;
5) чтоб система сама себя контроллировала бы от зависания (WhatchDog; но эту функцию я не реализовал по причине того, что пока не разобрался с темой как и чем перепрошить загрузчик NANO) и
6) чтоб была "многозадачность", т.е. выполнение одних функций системы не должны блокировать остальные.
Я применяя свои, пусть и крохотные, знания а так же благодаря вышеупомянутых (в предыдущем посте) товарищей, в итоге получил следующий код (проверил - работает всё так, как надо на Nano):
Посему, считаю тему закрытой, так как нужный результат был достигнут.
По сути мы решали и решили задачу автоматической маслёнки для автоцентра для двух рабочих мест автослесарей. А так же я многое понял и разъяснил для себя с точки зрения "многозадачности", а так же как организовать цикл без "зависания" системы.
Кому нужен этот код - пользуйтесь на здоровье.
И ещё раз: благодарю всех за помощь и кооперацию.
125 строка порадовала ;)) защита от переполнения millis().
Улучшения - приветствуются! И да... ну а чё бы и не защититься? Пожалуй нужно вставить и в работу реле.... :-)
Так вам надо изучать как организованы и как Вы сможете написать классы в Си++.
Вот так вот будет с защитой от переполнения millis() во всех функциях. Думаю, что для профи эта инфа не актуальна, а студентам - в самый раз. ;-)
Да, я и не против в принципе... Но в моей жизни вряд ли уже это понадобится, увы.... Время уходит, а мои последние "научные" достижения остались в 95-м... на защите диплома...
А сегодня - так, по мелочи, решаем повседневные надоедливые задачи.... Упрощаем себе жись...
Вот так вот будет с защитой от переполнения millis() во всех функциях. Думаю, что для профи эта инфа не актуальна, а студентам - в самый раз. ;-)
студентам эта информация только навредит, потому что она неправильная. Ну а профи сами знают, что в правильно написанной программе "защита от переполнения" - лишняя.
b707, всё великое начинается с малого... Я говорю про то, что "занимаюсь тесанием камня" только последние полгода, а вы мне - про то, как "не правильно построена пирамида Гизы"....
Не, конечно в итоге вы правы... Но студент сначала использует delay, затем преполнение millis и предохранение от него, ну а уж потом становится как вы: класс для delay без delay()... Всё это разные этапы и разные уровни...
Нельзя просто так сесть и не зная нот родить симфонию Бетховена...
Ну а за ссылку на титановый велосипед Клапауций 9999 - огромная благодарность!
b707, всё великое начинается с малого... Я говорю про то, что "занимаюсь тесанием камня" только последние полгода, а вы мне - про то, как "не правильно построена пирамида Гизы"....
Не, конечно в итоге вы правы... Но студент сначала использует delay, затем преполнение millis и предохранение от него, ну а уж потом становится как вы: класс для delay без delay()... Всё это разные этапы и разные уровни...
Нельзя просто так сесть и не зная нот родить симфонию Бетховена...
Видите ли, на Вершину всегда более одного пути. И чем раньше Вы освободитесь от delay(), тем Ваш путь будет короче, разнообразнее и интереснее. И, хотя на первый взгляд кажется, что повторение уже освоенного проще, на самом деле, чем раньше будет произведен переход к новому, тем безболезненнее это произойдет.
Да... Философии тоже разными бывают. ))) Что единственно верно - так это то, что у каждого свой путь к вершине (да и понятие вершины тоже).
короче, хочешь моргать без delay(), разбирайся
https://github.com/DetSimen/Arduino_TimerList
А я пацкажу, когда трезвый.