По нажатию кнопки моргнуть 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 значений: на нечетные светодиод горит, на четные - нет.
Советуете воспользоваться:
switch (mode) { case 0: task_0(); break; case 1: task_1(); break; case 2: task_2(); break; case 3: task_3(); break; case 4: task_4(); break; case 5: task_5(); break; }ТС, вы задаете вопросы но ответы не читаете. Вас же попросили код оформить правильно. По сути, своими действиями вы хамите тем кто хочет вам помочь.
Зачем вам эти тухлые библиотеки в решении элементарной задачи ?
#define LED_PIN LED_BUILTIN #define BUTTON_PIN 5 void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { static uint32_t timer=0; static uint8_t counter=0; if(counter && millis()-timer>1000){ timer=millis(); if(digitalRead(LED_PIN)){ digitalWrite(LED_PIN,LOW); counter--; } else { digitalWrite(LED_PIN,HIGH); } } else if(digitalRead(BUTTON_PIN==LOW)){ //если кнопка нажата counter=3; // мигнуть 3 раза } }2. Для мигания заводится переменная состояния, принимающая, скажем, следующие значения:
- 0 - начальное состояние, при нажатии кнопки - переводим в состояние 1,
-.........
- 5 - светодиод горит, по истечении интервала времени переводим в 0.
Спасибо вам за подсказку! Попробовал. Реализовал...
Затем мысленный процесс пошёл по пути оптимизации и в результате получилось следующее:
// --------Начальные установки здесь---------- #define DATCHIK1_PIN 2 #define RELE1_PIN 10 #define LED_LOW_OIL_PIN 13 #define INTERVAL_RELE1 250 #define MODE1 3 // количество срабатываний (миганий) реле1 (от 1 до указанного) //-----Подключаем библилтеки, объявляем переменные-------- #include "GyverButton.h" GButton D1(DATCHIK1_PIN); uint32_t RS1 = 0; bool RELE1flag = false; //================================================= void setup() { // Serial.begin(9600); pinMode(DATCHIK1_PIN,INPUT_PULLUP); pinMode(RELE1_PIN,OUTPUT); digitalWrite(RELE1_PIN, LOW); D1.setDebounce(90); D1.setTimeout(300); D1.setType(HIGH_PULL); D1.setDirection(NORM_OPEN); //--------------------------------------------------- void loop() { D1.tick(); if (D1.isPress()) {run_rele1();}; } } //========================================================== //--------Работа 1-го реле---------- void run_rele1() { // Serial.println("Task 1"); int i=0; while (i < MODE1 * 2){ if (millis() - RS1 >= INTERVAL_RELE1) { RS1 = millis(); // сбросить таймер digitalWrite(RELE1_PIN, !RELE1flag); // вкл/выкл RELE1flag = !RELE1flag; // инвертировать флаг i++; }}}1) Простите, извините... #5 Я ничего такого не хотел сделать... Это всё - мой первый опыт программирования на Ардуино... А сейчас даже не могу поменять свой первый пост: нет кнопки "Редактировать" или "Изменить"... Ещё раз прошу прощения у вас и других членов форума.
2) и ещё раз: спасибо за направление.
Это сложно назвать оптимизацией.
Давайте посмотрим, что вы делаете. Вы вешаете на таймер некое действие, которое по сработке этого таймера выполняется. Ладно... Тут вроде все норм...
А что же за действие вы вешаете ? А вот тут облом. Вы написали блокирующую процедуру. Она выполняется в цикле долго-долго, пока не истечет некоторое время. По сути вы написали тот же delay.
То есть запутались еще больше. Сделаете это не используя while, loop и goto. Тогда у вас все получится.
Это сложно назвать оптимизацией.
.... Вы написали блокирующую процедуру. Она выполняется в цикле долго-долго, пока не истечет некоторое время. По сути вы написали тот же delay.
То есть запутались еще больше. Сделаете это не используя while, loop и goto. Тогда у вас все получится.
Так, теперь вот я точно запутался...(( (ну это и не удивительно, исходя из моего опыта) Дык, я так понимаю, что в том и смысл любого цикла...
И если "всё плохо", то тогда возникает главный вопрос любого новичка к учителю: А как надо было?
И если вам не трудно - подправьте код (тот что созданный мною делей) так, как должно быть с точки зрения вас как профи. Как сделать то это без while?
Ну написал же brokly в #5. Хотя и его можно "оптимизировать").
Тада я сначала пошёл читать мануалы на тему: чем while отличается от if с точки зрения блокировок и долгого выполнения...
А чего тут читать то !? Чем отличается операция сравнения от цикла ?! Вы зацикливаете свой код, зацикливание - блокирующая операция. Пока процессор в цикле выполняет действия одной задачи, вторую он решить не может. Правильно это сначала сделать немножко от одной задачи, потом немножко от другой, вернуться к первой и так далее. Таким образом вы гарантировано выполните все задачи, ну или по крайней мере они все будут выполняться.
Ну написал же brokly в #5. Хотя и его можно "оптимизировать").
Покажешь ? :)
Благодарю за разъяснение. Смысл ваших объяснений мне понятен. Но их сутью ещё не проникся... Не прочувствовал как оно так на самом деле... Нужно помозговать.
Ну написал же brokly в #5. Хотя и его можно "оптимизировать").
Покажешь ? :)
Да, тяжело оптимизировать нерабочий скетч. )
#define LED_PIN LED_BUILTIN #define BUTTON_PIN 5 void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { static uint32_t timer; static uint8_t counter; if (counter) { if (millis() - timer > 1000) { timer = millis(); if (digitalRead(LED_PIN)) counter--; digitalWrite(LED_PIN, !digitalRead(LED_PIN)); } } else if (digitalRead(BUTTON_PIN) == LOW) counter = 3; }А вот эта оптимизация , она что сделала ? Теперь код стал оптимальнее в чем, ну не считая "нерабочести" ? В том что стал еще больше нерабочий ? Стал сложнее читаем ? Стал занимать больше места после компиляции? Стал медленее работать ? :)
Меньше букв, лаконичнее. Только и всего.
За-то оно дважды читает порт и делает лишнюю операцию инвертирования. В конечном итоге бумажная лаконичность выливается в лишний код и время. Компилятор точно будет обрабатывать два чтения порта, как две разные операции, а учитывая, что они, в нашей среде дико кривые и медленные получаем "фиасо братан".
Братан, пудри мозги новичкам.)
А чего я сказал неправильного ? В следующий раз, когда будешь без апеляционно рассказывать про оптимизацию, подумай, может ты термин понимаешь не правильно.
Знаю несколько библиотек, которые написаны красиво на си, но тупо сишным программером, который про процессоры знает очень мало. Так вот они работают, но места занимают столько, что становятся бессмысленными. Они так же, как ты говорили, когда им рассказывали об экономии ресурсов :)
И еще один момент, я в форум пишу не тебе одному. Новички, тут тоже читают.
Уважаемые знатоки!
Заранее прошу прощения, если что не так скажу или сделаю, у обоих: и у brokly, и у Green... но я проверил на Nano код brokly:
#define LED_PIN LED_BUILTIN #define BUTTON_PIN 5 void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { static uint32_t timer=0; static uint8_t counter=0; if(counter && millis()-timer>1000){ timer=millis(); if(digitalRead(LED_PIN)){ digitalWrite(LED_PIN,LOW); counter--; } else { digitalWrite(LED_PIN,HIGH); } } else if(digitalRead(BUTTON_PIN==LOW)){ //если кнопка нажата counter=3; // мигнуть 3 раза } }Он просто моргает раз в секунду светодиодом и на кнопку никак не реагирует.
Код же от Green:
#define LED_PIN LED_BUILTIN #define BUTTON_PIN 5 void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { static uint32_t timer; static uint8_t counter; if (counter) { if (millis() - timer > 1000) { timer = millis(); if (digitalRead(LED_PIN)) counter--; digitalWrite(LED_PIN, !digitalRead(LED_PIN)); } } else if (digitalRead(BUTTON_PIN) == LOW) counter = 3; }работает как надо, т. е. при нажатии на кнопку мигает три раза.
Но это была просто ремарка ( я никого не хотел обидеть, просто констатировал факты).
-----------------------------------------------
Вот теперь то я понял, в чём я никак не могу разобраться, а именно:
1) если сделать так (т. е. код разместить прямо внутри главного цикла):
void setup() { pinMode(10, OUTPUT); pinMode(12, OUTPUT); pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP);} static uint32_t timer1, timer2; static uint8_t counter1, counter2; void loop() { //Работа 1-й кнопки 1-го реле if (counter1) { if (millis() - timer1 > 1000) { timer1 = millis(); if (digitalRead(10)) counter1--; digitalWrite(10, !digitalRead(10)); } } else if (digitalRead(2) == LOW) counter1 = 2; // Работа 2-й кнопки и 2-го реле if (counter2) { if (millis() - timer2 > 500) { timer2 = millis(); if (digitalRead(12)) counter2--; digitalWrite(12, !digitalRead(12)); } } else if (digitalRead(3) == LOW) counter2 = 4; }то всё прекрасно работает (я о многозадачности). 2 кнопки управляют 2-я светодиодами независимо друг от друга и даже одновременно (я специально в коде сделал разные интервалы, указываю напрямую пины и т. п. - для ясности таким как я)...
2) А вот если сделать так (т. е. тот же функционал, но сделать через вызов функции в главном цикле):
void setup() { pinMode(10, OUTPUT); pinMode(12, OUTPUT); pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP);} static uint32_t timer1, timer2; static uint8_t counter1, counter2; void loop() { void run_rele1(); void run_rele2();} //Работа 1-й кнопки 1-го реле void run_rele1() { if (counter1) { if (millis() - timer1 > 1000) { timer1 = millis(); if (digitalRead(10)) counter1--; digitalWrite(10, !digitalRead(10)); } } else if (digitalRead(2) == LOW) counter1 = 2;} //Работа 2-й кнопки 2-го реле void run_rele2() { if (counter2) { if (millis() - timer2 > 500) { timer2 = millis(); if (digitalRead(12)) counter2--; digitalWrite(12, !digitalRead(12)); } } else if (digitalRead(3) == LOW) counter2 = 4;}то не работает вообще: при нажатии кнопок нет никакой реакции...
Вроде бы, всё одно и то же. Но похоже, это именно то, чего я и не понимаю: в чём тут разница?
Пожалуйста, "пните" меня в нужном направлении... Моя цель - разобраться в том, чего я не понимаю и не знаю и понять, как в таком случае надо правильно поступать чтоб и 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 . Форумы разные. Цели и задачи форума определяются создателями. Они могут совершенно не соответствовать Вашим представлениям. Форум не коммерческий. Без рекламы. Вы не платите денег. Ваша плата - следование правилам форума. Если Вам что то не нравиться, то просто уйдите.
#define LED_PIN LED_BUILTIN #define BUTTON_PIN 5 void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { static uint32_t timer=0; static uint8_t counter=0; if(counter && millis()-timer>1000){ timer=millis(); if(digitalRead(LED_PIN)){ digitalWrite(LED_PIN,LOW); counter--; } else { digitalWrite(LED_PIN,HIGH); } } else if(digitalRead(BUTTON_PIN==LOW)){ //если кнопка нажата counter=3; // мигнуть 3 раза } }GREEN же написал, что мой код с ошибкой. Я же в онлайне от руки набросал, могу и ошибиться. Вы же пытаетесь понять, так не списывайте тупо, а анализируйте, что делаете.
20 строка :
} else if(digitalRead(BUTTON_PIN)==LOW){ //если кнопка нажатаОбратите внимание на расстановку круглых скобок.
Насчет 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-ы всё заработало как надо, то есть:
void setup() { pinMode(10, OUTPUT); pinMode(12, OUTPUT); pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP); } static uint32_t timer1, timer2; static uint8_t counter1, counter2; void loop() { run_rele1(); run_rele2(); } //Работа 1-й кнопки 1-го реле void run_rele1() { if (counter1) { if (millis() - timer1 > 1000) { timer1 = millis(); if (digitalRead(10)) counter1--; digitalWrite(10, !digitalRead(10)); } } else if (digitalRead(2) == LOW) counter1 = 3; } //Работа 2-й кнопки 2-го реле void run_rele2() { if (counter2) { if (millis() - timer2 > 300) { timer2 = millis(); if (digitalRead(12)) counter2--; digitalWrite(12, !digitalRead(12)); } } else if (digitalRead(3) == LOW) counter2 = 4; }Значит, я на правильном пути и предыдущие "темы уроков" я" выучил". ))
И это хорошо.
Подходим к итогу...
И снова я хочу высказать благодарность: вам, 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):
// --------Начальные установки здесь---------- #define DATCHIK1_PIN 2 // Первый датчик цепи #define DATCHIK2_PIN 3 // Второй датчик цепи #define DATCHIK_LOW_OIL_PIN 6 // Пин датчика уровня масла #define RELE1_PIN 10 #define RELE2_PIN 12 #define LED_LOW_OIL_PIN 13 // Пин cветодиода низкого уровня масла #define INTERVAL_LED 333 // Частота моргания сетодиода низкого уровня масла #define INTERVAL_RELE1 500 // Интервал между всасываниями масла в реле 1 #define INTERVAL_RELE2 150 // Интервал между всасываниями масла в реле 2 #define MODE1 3 // количество срабатываний (миганий) реле1 (от 1 до указанного) #define MODE2 10 // количество срабатываний (миганий) реле2 (от 1 до указанного) //-----Подключаем библиотеки, объявляем переменные-------- #include <microDS3231.h> // Библиотека часов RTC MicroDS3231 rtc; #include "GyverButton.h" // Библиотека датчиков(кнопок) уровня масла и релюх GButton LO(DATCHIK_LOW_OIL_PIN); GButton D1(DATCHIK1_PIN); GButton D2(DATCHIK2_PIN); //#include "GyverWDT.h" // Библиотека WatchDog против зависания uint32_t LS = 0, RS1 = 0, RS2 = 0; bool led_stat = true; bool RELE1flag = false; bool RELE2flag = false; static uint8_t count1, count2; //--- Настройка временного интервала работы клапанов-------- int H_start = 17; // Старт работы контроллёра - ЧАСЫ. //int M_start = 0; // Старт работы контроллёра - МИНУТЫ. (всегда должно быть = 0) //int S_start = 0; // Старт работы контроллёра - Секунды. int H_finish = 20; // Окончание работы контроллёра - ЧАСЫ. //int M_finish = 30; // Окончание работы контроллёра - МИНУТЫ. //int S_finish = 1; // Окончание работы контроллёра - Секунды. //================================================= void setup() { Serial.begin(9600); //rtc.setTime(10,25,01,21,12,2020); //rtc.setTime(SEC, MIN, HOUR, DAY, MONTH, YEAR); // устанвока времени вручную //if (rtc.lostPower()) { // при потере питания //rtc.setTime(COMPILE_TIME); // установить время компиляции //} pinMode(DATCHIK1_PIN,INPUT_PULLUP); pinMode(DATCHIK2_PIN,INPUT_PULLUP); pinMode(DATCHIK_LOW_OIL_PIN,INPUT_PULLUP); pinMode(RELE1_PIN,OUTPUT); digitalWrite(RELE1_PIN, LOW); pinMode(RELE2_PIN,OUTPUT); digitalWrite(RELE2_PIN, LOW); pinMode(LED_LOW_OIL_PIN, OUTPUT); digitalWrite(LED_LOW_OIL_PIN, LOW); // HIGH_PULL - кнопка подключена к GND, пин подтянут к VCC (PIN --- КНОПКА --- GND) // LOW_PULL - кнопка подключена к VCC, пин подтянут к GND // NORM_OPEN - нормально-разомкнутая кнопка // NORM_CLOSE - нормально-замкнутая кнопка LO.setDebounce(90); // настройка антидребезга (по умолчанию 80 мс) LO.setTimeout(300); // настройка таймаута на удержание (по умолчанию 500 мс) LO.setType(HIGH_PULL); LO.setDirection(NORM_OPEN); D1.setDebounce(90); // настройка антидребезга (по умолчанию 80 мс) D1.setTimeout(300); // настройка таймаута на удержание (по умолчанию 500 мс) D1.setType(HIGH_PULL); D1.setDirection(NORM_OPEN); D2.setDebounce(90); // настройка антидребезга (по умолчанию 80 мс) D2.setTimeout(300); // настройка таймаута на удержание (по умолчанию 500 мс) D2.setType(HIGH_PULL); D2.setDirection(NORM_OPEN); //Watchdog.enable(RESET_MODE, WDT_PRESCALER_512); // Режим сторжевого сброса , таймаут ~4с } //====================================================== void loop() { // printTime(); // проверка внутреннего времени по RTC int H = rtc.getHours(); // int M = rtc.getMinutes(); LO.tick(); D1.tick(); D2.tick(); run_oil(); if (H >= H_start && H < H_finish) { run_rele1(); run_rele2(); } //Watchdog.reset(); // Переодический сброс watchdog, означающий, что устройство не зависло } //======================================================= //--------Работа 1-го реле---------- void run_rele1() { if (count1) { if (millis() - RS1 >= INTERVAL_RELE1) { RS1 = millis(); if (digitalRead(RELE1_PIN)) count1--; digitalWrite(RELE1_PIN, !digitalRead(RELE1_PIN)); } } else if (D1.isPress()) count1 = MODE1; } //-------Работа 2-го реле--------- void run_rele2() { if (count2) { if (millis() - RS2 >= INTERVAL_RELE2) { RS2 = millis(); if (digitalRead(RELE2_PIN)) count2--; digitalWrite(RELE2_PIN, !digitalRead(RELE2_PIN)); } } else if (D2.isPress()) count2 = MODE2; } //------Раздел работы индикаторв LED_LOW OIL----------- void run_oil(){ if (LO.isHold()) {led_oil();} else digitalWrite(LED_LOW_OIL_PIN, LOW); } void led_oil(){ if( ( millis() - LS ) > INTERVAL_LED || millis() < LS ){ LS = millis(); digitalWrite(LED_LOW_OIL_PIN, led_stat); led_stat = !led_stat; } } // --- Вывод внутреннего времени с RTC в COM-порт для контроля void printTime() { Serial.print(rtc.getHours()); Serial.print(":"); Serial.print(rtc.getMinutes()); Serial.print(":"); Serial.print(rtc.getSeconds()); Serial.print(" "); Serial.print(rtc.getDay()); Serial.print(" "); Serial.print(rtc.getDate()); Serial.print("/"); Serial.print(rtc.getMonth()); Serial.print("/"); Serial.println(rtc.getYear()); }Посему, считаю тему закрытой, так как нужный результат был достигнут.
По сути мы решали и решили задачу автоматической маслёнки для автоцентра для двух рабочих мест автослесарей. А так же я многое понял и разъяснил для себя с точки зрения "многозадачности", а так же как организовать цикл без "зависания" системы.
Кому нужен этот код - пользуйтесь на здоровье.
И ещё раз: благодарю всех за помощь и кооперацию.
125 строка порадовала ;)) защита от переполнения millis().
Улучшения - приветствуются! И да... ну а чё бы и не защититься? Пожалуй нужно вставить и в работу реле.... :-)
Так вам надо изучать как организованы и как Вы сможете написать классы в Си++.
Вот так вот будет с защитой от переполнения millis() во всех функциях. Думаю, что для профи эта инфа не актуальна, а студентам - в самый раз. ;-)
// --------Начальные установки здесь---------- #define DATCHIK1_PIN 2 // Первый датчик цепи #define DATCHIK2_PIN 3 // Второй датчик цепи #define DATCHIK_LOW_OIL_PIN 6 // Пин датчика уровня масла #define RELE1_PIN 10 #define RELE2_PIN 12 #define LED_LOW_OIL_PIN 13 // Пин cветодиода низкого уровня масла #define INTERVAL_LED 333 // Частота моргания сетодиода низкого уровня масла #define INTERVAL_RELE1 500 // Интервал между всасываниями масла в реле 1 #define INTERVAL_RELE2 150 // Интервал между всасываниями масла в реле 2 #define MODE1 3 // количество срабатываний (миганий) реле1 (от 1 до указанного) #define MODE2 10 // количество срабатываний (миганий) реле2 (от 1 до указанного) //-----Подключаем библиотеки, объявляем переменные-------- #include <microDS3231.h> // Библиотека часов RTC MicroDS3231 rtc; #include "GyverButton.h" // Библиотека датчиков(кнопок) уровня масла и релюх GButton LO(DATCHIK_LOW_OIL_PIN); GButton D1(DATCHIK1_PIN); GButton D2(DATCHIK2_PIN); //#include "GyverWDT.h" // Библиотека WatchDog против зависания uint32_t LS = 0, RS1 = 0, RS2 = 0; bool led_stat = true; bool RELE1flag = false; bool RELE2flag = false; static uint8_t count1, count2; //--- Настройка временного интервала работы клапанов-------- int H_start = 17; // Старт работы контроллёра - ЧАСЫ. //int M_start = 0; // Старт работы контроллёра - МИНУТЫ. (всегда должно быть = 0) //int S_start = 0; // Старт работы контроллёра - Секунды. int H_finish = 20; // Окончание работы контроллёра - ЧАСЫ. //int M_finish = 30; // Окончание работы контроллёра - МИНУТЫ. //int S_finish = 1; // Окончание работы контроллёра - Секунды. //================================================= void setup() { Serial.begin(9600); //rtc.setTime(10,25,01,21,12,2020); //rtc.setTime(SEC, MIN, HOUR, DAY, MONTH, YEAR); // устанвока времени вручную //if (rtc.lostPower()) { // при потере питания //rtc.setTime(COMPILE_TIME); // установить время компиляции //} pinMode(DATCHIK1_PIN,INPUT_PULLUP); pinMode(DATCHIK2_PIN,INPUT_PULLUP); pinMode(DATCHIK_LOW_OIL_PIN,INPUT_PULLUP); pinMode(RELE1_PIN,OUTPUT); digitalWrite(RELE1_PIN, LOW); pinMode(RELE2_PIN,OUTPUT); digitalWrite(RELE2_PIN, LOW); pinMode(LED_LOW_OIL_PIN, OUTPUT); digitalWrite(LED_LOW_OIL_PIN, LOW); // HIGH_PULL - кнопка подключена к GND, пин подтянут к VCC (PIN --- КНОПКА --- GND) // LOW_PULL - кнопка подключена к VCC, пин подтянут к GND // NORM_OPEN - нормально-разомкнутая кнопка // NORM_CLOSE - нормально-замкнутая кнопка LO.setDebounce(90); // настройка антидребезга (по умолчанию 80 мс) LO.setTimeout(300); // настройка таймаута на удержание (по умолчанию 500 мс) LO.setType(HIGH_PULL); LO.setDirection(NORM_OPEN); D1.setDebounce(90); // настройка антидребезга (по умолчанию 80 мс) D1.setTimeout(300); // настройка таймаута на удержание (по умолчанию 500 мс) D1.setType(HIGH_PULL); D1.setDirection(NORM_OPEN); D2.setDebounce(90); // настройка антидребезга (по умолчанию 80 мс) D2.setTimeout(300); // настройка таймаута на удержание (по умолчанию 500 мс) D2.setType(HIGH_PULL); D2.setDirection(NORM_OPEN); //Watchdog.enable(RESET_MODE, WDT_PRESCALER_512); // Режим сторжевого сброса , таймаут ~4с } //====================================================== void loop() { // printTime(); // проверка внутреннего времени по RTC int H = rtc.getHours(); // int M = rtc.getMinutes(); LO.tick(); D1.tick(); D2.tick(); run_oil(); if (H >= H_start && H < H_finish) { run_rele1(); run_rele2(); } //Watchdog.reset(); // Переодический сброс watchdog, означающий, что устройство не зависло } //======================================================= //--------Работа 1-го реле---------- void run_rele1() { if (count1) { if ( ( millis() - RS1 ) >= INTERVAL_RELE1 || millis() < RS1 ) { RS1 = millis(); if (digitalRead(RELE1_PIN)) count1--; digitalWrite(RELE1_PIN, !digitalRead(RELE1_PIN)); } } else if (D1.isPress()) count1 = MODE1; } //-------Работа 2-го реле--------- void run_rele2() { if (count2) { if ( ( millis() - RS2 ) >= INTERVAL_RELE2 || millis() < RS2 ) { RS2 = millis(); if (digitalRead(RELE2_PIN)) count2--; digitalWrite(RELE2_PIN, !digitalRead(RELE2_PIN)); } } else if (D2.isPress()) count2 = MODE2; } //------Раздел работы индикаторв LED_LOW OIL----------- void run_oil(){ if (LO.isHold()) {led_oil();} else digitalWrite(LED_LOW_OIL_PIN, LOW); } void led_oil(){ if( ( millis() - LS ) > INTERVAL_LED || millis() < LS ){ LS = millis(); digitalWrite(LED_LOW_OIL_PIN, led_stat); led_stat = !led_stat; } } // --- Вывод внутреннего времени с RTC в COM-порт для контроля void printTime() { Serial.print(rtc.getHours()); Serial.print(":"); Serial.print(rtc.getMinutes()); Serial.print(":"); Serial.print(rtc.getSeconds()); Serial.print(" "); Serial.print(rtc.getDay()); Serial.print(" "); Serial.print(rtc.getDate()); Serial.print("/"); Serial.print(rtc.getMonth()); Serial.print("/"); Serial.println(rtc.getYear()); }Да, я и не против в принципе... Но в моей жизни вряд ли уже это понадобится, увы.... Время уходит, а мои последние "научные" достижения остались в 95-м... на защите диплома...
А сегодня - так, по мелочи, решаем повседневные надоедливые задачи.... Упрощаем себе жись...
Вот так вот будет с защитой от переполнения millis() во всех функциях. Думаю, что для профи эта инфа не актуальна, а студентам - в самый раз. ;-)
студентам эта информация только навредит, потому что она неправильная. Ну а профи сами знают, что в правильно написанной программе "защита от переполнения" - лишняя.
b707, всё великое начинается с малого... Я говорю про то, что "занимаюсь тесанием камня" только последние полгода, а вы мне - про то, как "не правильно построена пирамида Гизы"....
Не, конечно в итоге вы правы... Но студент сначала использует delay, затем преполнение millis и предохранение от него, ну а уж потом становится как вы: класс для delay без delay()... Всё это разные этапы и разные уровни...
Нельзя просто так сесть и не зная нот родить симфонию Бетховена...
Ну а за ссылку на титановый велосипед Клапауций 9999 - огромная благодарность!
b707, всё великое начинается с малого... Я говорю про то, что "занимаюсь тесанием камня" только последние полгода, а вы мне - про то, как "не правильно построена пирамида Гизы"....
Не, конечно в итоге вы правы... Но студент сначала использует delay, затем преполнение millis и предохранение от него, ну а уж потом становится как вы: класс для delay без delay()... Всё это разные этапы и разные уровни...
Нельзя просто так сесть и не зная нот родить симфонию Бетховена...
Видите ли, на Вершину всегда более одного пути. И чем раньше Вы освободитесь от delay(), тем Ваш путь будет короче, разнообразнее и интереснее. И, хотя на первый взгляд кажется, что повторение уже освоенного проще, на самом деле, чем раньше будет произведен переход к новому, тем безболезненнее это произойдет.
Да... Философии тоже разными бывают. ))) Что единственно верно - так это то, что у каждого свой путь к вершине (да и понятие вершины тоже).
короче, хочешь моргать без delay(), разбирайся
https://github.com/DetSimen/Arduino_TimerList
А я пацкажу, когда трезвый.