Выполнение кода во время задержки
- Войдите на сайт для отправки комментариев
Доброго времени суток! Наверняка я не первый тут с таким вопросом, но всё же.
Есть следующее железо: ардуино нано, реле (питает помпу) и датчик хола (у меня пока в место него обычная кнопка, для теста)
Задача следующая: вкл реле, дать ему поработать 25 сек, в это время считать количество срабатывания датчика хола (кнопки) и записывать его в переменную, затем выключить реле
Собственно вопрос: как сделать несколько процессов одновременно? Тот же delay "тормозит" мозги и паралельно ничего не сделать. То есть держать цифровой пин активным, считать инфу с датчика и записывать в переменную? Как сделать всё отдельно - знаю, а одновременно - увы.
Вот пример из того что сейчас работает просто через delay(), там нет работы с датчиком и тд. только вкл/выкл пин по таймеру. Не судите строго по качеству кода. Второй вечер разбираюсь что тут и как.
void start_filling() {
digitalWrite(PIN_RELAY, HIGH);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Помпа ВКЛ.");
delay(25000);
// (тут нужно пыполнить другой код пока идут 25 сек)
digitalWrite(PIN_RELAY, LOW);
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Помпа ВЫКЛ.");
}
Благодарю!
Сравните blink и blink without delay.
Второй делает именно то, что Вам нужно.
Нашел примеры в которых в цикле мигают лампочкой. Но мне не нужен цикл. Эта часть кода - один из void`ов, которые запускаются при определённых условиях и должен выполниться лишь раз
Если уж прям-прям с точностью до миллисекунд - смотри в сторону RtOs. Для AVR они есть. :))
Та не) +- трамвайная остановка тоже подойдёт. там супер точность не важна. главное сам момент одноразового выполнения кода во время работы таймера
Нашел примеры в которых в цикле мигают лампочкой. Но мне не нужен цикл. Эта часть кода - один из void`ов, которые запускаются при определённых условиях и должен выполниться лишь раз
Очень просто: после выполнения нужного Вам участка кода, поднимаете флаг. А в цикле loop() проверяете, поднят ли флаг. Если да - пропускаете, если нет - выполняете.
Нашел примеры в которых в цикле мигают лампочкой. Но мне не нужен цикл. Эта часть кода - один из void`ов, которые запускаются при определённых условиях и должен выполниться лишь раз
Очень просто: после выполнения нужного Вам участка кода, поднимаете флаг. А в цикле loop() проверяете, поднят ли флаг. Если да - пропускаете, если нет - выполняете.
Не совсем понимаю как завязать это дело на времени.
Не могли бы вы показать пример на основе того кода что я оставил? Благодарю
Объявляешь две булевых переменных флаги времени и выполнения. Флаги опускаешь - false. Ждёшь команды включения помпы. Вкючил помпу, поднял флаг -true помпа включена, запомнил время. Делаешь что нужно если флаг времени поднят, флаг выполнено опущен, в конце ставиш флаг выполено. Если флаг времени поднят проверяешь сколько времени прошло. Если (IF) меньше чем надо и не надо ещё раз что то делать то просто идёшь в начало цика. Если больше, выключаешь помпу, снимаешь флаги, ждёшь следующей команды включения помпы.
Про идею с флагами всё понял, спасибо. Но как описать это в коде - не хватает опыта. Второй день постигаю всё это. Пожалуйста, дайте пример. Спасибо!
Доброго времени суток! Наверняка я не первый тут с таким вопросом, но всё же.
Есть следующее железо: ардуино нано, реле (питает помпу) и датчик хола (у меня пока в место него обычная кнопка, для теста)
Задача следующая: вкл реле, дать ему поработать 25 сек, в это время считать количество срабатывания датчика хола (кнопки) и записывать его в переменную, затем выключить реле
Собственно вопрос: как сделать несколько процессов одновременно? Тот же delay "тормозит" мозги и паралельно ничего не сделать. То есть держать цифровой пин активным, считать инфу с датчика и записывать в переменную? Как сделать всё отдельно - знаю, а одновременно - увы.
Вот пример из того что сейчас работает просто через delay(), там нет работы с датчиком и тд. только вкл/выкл пин по таймеру. Не судите строго по качеству кода. Второй вечер разбираюсь что тут и как.
void start_filling() { digitalWrite(PIN_RELAY, HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Помпа ВКЛ."); delay(25000); // (тут нужно пыполнить другой код пока идут 25 сек) digitalWrite(PIN_RELAY, LOW); lcd.clear(); lcd.setCursor(0, 1); lcd.print("Помпа ВЫКЛ."); } Благодарю!Ну если по ТЗ ТС то проще всего так :-)
uint16_t Counter; void start_filling() { Counter=0; digitalWrite(PIN_RELAY, HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Помпа ВКЛ."); delay(25000); // (тут выпоняется другой код пока идут 25 сек) if (Counter <= 25) { //делаем что то } digitalWrite(PIN_RELAY, LOW); lcd.clear(); lcd.setCursor(0, 1); lcd.print("Помпа ВЫКЛ."); } void yield() // (тут выпоняется другой код пока идут 25 сек) { if( ) // если кнопка нажата { Counter++; } }Я так понимаю в yield (знаю как он работает) у нас идёт таймер который раз в секунду добавляет +1 к значению, а в 11 строке условие по которому если меньше, или равно 25, то делаем нужный код. И таким образом через yield "обходим" ограничение работы с обычным "delay". Я верно понял? Просто хочу для себя понять, а не просто готовый код взять
Нет.
yield() крутится как loop() пока delay(25000) отсчитывает свои 25 секунд и тормозит весь последующий код.
Если в в yield() нужен секундный таймер он делается на millis()
То есть в 13 строке я пишу код и он будет исполнятся только пока идут те 25 сек, или нужный мне код нужно писать в yield? Если нужно писать в yield, то будет ли работать код написанный в 13 строке, или он будет ждать окончания delay?
Код в строке 13 выполнится после выхода из delay(25000) - то есть через 25 секунд.
Пока идут эти 25 секунд буде постоянно вызываться yield() и в yield() уже тормозить нельзя. НИКАКИХ delay() там быть не должно.
Если в yield нужно что то проверять раз в секунду нужно использовать millis()
Примерно так:
void yield() { static unsigned long previousMillis = 0; if ( millis() - previousMillis >= 1000) { previousMillis = millis(); // делаем тут что то раз в секунду но без delay() } }Не надо delay. вместо него взять код из yield()
if ( millis() - previousMillis >= 1000) { previousMillis = millis(); // делаем тут что то раз в секунду но без delay() }digitalWrite(PIN_RELAY, HIGH); TimeStartPomp=previousMillis= millis(); do if ( millis() - previousMillis >= 1000) { previousMillis = millis(); // делаем тут что то раз в секунду но без delay() } while ( millis() - TimeStartPomp <=25000); digitalWrite(PIN_RELAY, LOW);Не проверял, только идея.
сделал так:
void start_test() { digitalWrite(PIN_RELAY, HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Помпа ВКЛ."); delay(25000); if (Counter <= 25) { digitalWrite(PIN_RELAY, LOW); lcd.clear(); lcd.setCursor(0, 1); lcd.print("Помпа ВЫКЛ.");} } void yield() { static unsigned long previousMillis1 = 0; if ( millis() - previousMillis1 >= 1000) { previousMillis1 = millis(); Counter++; } static unsigned long previousMillis2 = 0; if ( millis() - previousMillis2 >= 10) { previousMillis2 = millis(); btn2.tick(); if (btn2.click()) {return_counter++;} } }Но весь процесс останавливается на lcd.print("Помпа ВКЛ."); и всё. Больше на дисплее информация не появляется
ругается на
и
error: 'previousMillis' was not declared in this scope TimeStartPomp=previousMillis= millis(); ^~~~~~~~~~~~~~сам код следующий:
void start_test() { digitalWrite(PIN_RELAY, HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Помпа ВКЛ."); digitalWrite(PIN_RELAY, HIGH); TimeStartPomp=previousMillis= millis(); do if ( millis() - previousMillis >= 10) { previousMillis = millis(); btn2.tick(); if (btn2.click()) {return_counter++;} } while ( millis() - TimeStartPomp <=25000); digitalWrite(PIN_RELAY, LOW); oborotu(); }ругается на
и
error: 'previousMillis' was not declared in this scope TimeStartPomp=previousMillis= millis(); ^~~~~~~~~~~~~~сам код следующий:
void start_test() { digitalWrite(PIN_RELAY, HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Помпа ВКЛ."); digitalWrite(PIN_RELAY, HIGH); TimeStartPomp=previousMillis= millis(); do if ( millis() - previousMillis >= 10) { previousMillis = millis(); btn2.tick(); if (btn2.click()) {return_counter++;} } while ( millis() - TimeStartPomp <=25000); digitalWrite(PIN_RELAY, LOW); oborotu(); }конечно ругается. таймеры то в 0 не выставил. сейчас код выглядит так:
void start_test() { digitalWrite(PIN_RELAY, HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Помпа ВКЛ."); digitalWrite(PIN_RELAY, HIGH); static unsigned long TimeStartPomp = 0; static unsigned long previousMillis = 0; TimeStartPomp=previousMillis= millis(); do if ( millis() - previousMillis >= 10) { previousMillis = millis(); btn2.tick(); if (btn2.click()) {return_counter++;} } while ( millis() - TimeStartPomp <=25000); digitalWrite(PIN_RELAY, LOW); oborotu(); }Переменные надо описывать до использования. Для кнопки взял титановый велосипед.
https://github.com/Klapautsiy/titanium-bicycle-for-button/releases/tag/B...
#include <Button.h> #define PIN_RELAY 5 unsigned long TimeStartPomp, previousMillis; Button test; void setup() { pinMode( PIN_RELAY, OUTPUT); test.NO(); // N.O. Normal Open test.pullUp(); test.duration_bounce ( 50); unsigned long duration_check = 200; test.duration_click_Db (duration_check); test.duration_inactivity_Up(duration_check); test.duration_press ( 500); test.button(18); // arduino pins connected to button } void loop() { if (test.event_click_Up (0) == 1) { //При отпускании кнопки после нажатия начинается цикл digitalWrite(PIN_RELAY, HIGH); TimeStartPomp = previousMillis = millis(); do if ( millis() - previousMillis >= 1000) { previousMillis = millis(); // делаем тут что то раз в секунду но без delay() } while ( millis() - TimeStartPomp <= 25000); digitalWrite(PIN_RELAY, LOW); } }Сильно палками не стукайте, но сейчас код такой:
#define _LCD_TYPE 1 #define PIN_RELAY 7 #include <EncButton.h> EncButton<EB_TICK, 9> btn4(INPUT_PULLUP); // yes EncButton<EB_TICK, 8> btn3(INPUT_PULLUP); // no EncButton<EB_TICK, 2> btn2(INPUT_PULLUP); EncButton<EB_TICK, 3> btn1(INPUT_PULLUP); // enter #include <LCD_1602_RUS_ALL.h> LCD_1602_RUS lcd(0x20, 16, 2); uint16_t return_counter; void setup() { pinMode(PIN_RELAY, OUTPUT); lcd.init(); // инициализация lcd.backlight(); // включить подсветку lcd.setCursor(0, 0); lcd.print("Тестер турбинок"); delay(500); lcd.setCursor(0, 1); lcd.print("и редуктора ЗУ"); delay(1000); lcd.clear(); lcd.setCursor(2, 0); lcd.print("тут что-то будет"); lcd.setCursor(1, 1); lcd.print("Версия ПО: 1.0"); delay(3000); lcd.clear(); lcd.setCursor(2, 0); lcd.print("Начать тест?"); } void loop() { btn1.tick(); if (btn1.click()) {start_test_info();} } void start_test_info() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Заполнение..."); delay(1000); lcd.setCursor(0, 1); lcd.print("Ожидайте..."); delay(500); start_filling(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Готово"); lcd.write(33); delay(1000); lcd.setCursor(0, 1); lcd.print("Начинаем тест..."); delay(2000); start_test(); } void start_test() { digitalWrite(PIN_RELAY, HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Помпа ВКЛ."); digitalWrite(PIN_RELAY, HIGH); static unsigned long TimeStartPomp = 0; static unsigned long previousMillis = 0; TimeStartPomp=previousMillis= millis(); do if ( millis() - previousMillis >= 10) { previousMillis = millis(); btn2.tick(); if (btn2.click()) {return_counter++;} } while ( millis() - TimeStartPomp <=25000); digitalWrite(PIN_RELAY, LOW); oborotu(); } void start_filling() { digitalWrite(PIN_RELAY, HIGH); delay(15000); digitalWrite(PIN_RELAY, LOW); } void oborotu() { lcd.clear(); lcd.setCursor(1, 0); lcd.print("Оборотов: "); lcd.write(return_counter); }И оно работает! И я даже понимаю почему! (сам удивлён)
Всем огромное спасибо!
74 строка как задумано?
она выключается на 77. на самом деле +- немного это не важно. главное что бы всегда было одинаково
Не понятно зачем. Раз в секунду за 25 секунд будет 25. Или тут будет что то другое?
74 строка как задумано?
по факту там не кнопка, а будет датчик хола. кнопка там для удобного теста в протеусе
(железо ещё не доехало)
там раз в 10 мс опрашивается кнопка (которая датчик хола) и если она активна - то пишет +1 в счётчик, а через 25 сек помпы выкл и всё что насчитало за 25 сек выводит на дисплей
А зачем датчик Холла по времени? Если считать обороты, то наоборот надо ловить фронты датчика через прерывание и считать их в прерывании. Совсем не внутри цикла. Тогда можно по второй кнопке можно отключать помпу и выходить из цикла раньше в случае необходимости через return.
ну мне не важно сколько оно там насчитает. нужен сам факт подсчёта с выводом. я это всё в глаза вижу второй день. до этого дела со всем этим не знакомился, так что использовал тот код что вы (форумчане) мне и дали
while( millis() - TimeStartPomp <=25000);тот же delay(), тока вид сбокуНо мы в нутри этого делея и можем его в любой момент прервать.
Вот-вот. То что мне и нужно было!
внимательно посмотри на строчку, которую я написал. В каком мы нутре?
void delay(unsigned long ms) { uint32_t start = micros(); while (ms > 0) { yield(); while ( ms > 0 && (micros() - start) >= 1000) { ms--; start += 1000; } } }void yield(void) __attribute__ ((weak, alias("__empty")));Код выше скопирован из исходников - yield объявлена как weak ...
Переобъявляем yield и получаем активность внутри delay ..
https://wokwi.com/projects/343926146113471058
Главное не переусердствовать - delay вызывается не только в вашем коде, но и внутри Arduino Core и многих библиотек. Ваш код из yield будет срабатывать на все эти вызовы !!!
Помогать ТС'у прикрутить костыли к его изначально ошибочной конструкции , это такой тонкий троллинг ?
boolean testFlag = 0; void start_test_info() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Заполнение..."); delay(1000); lcd.setCursor(0, 1); lcd.print("Ожидайте..."); delay(500); start_filling(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Готово"); lcd.write(33); delay(1000); lcd.setCursor(0, 1); lcd.print("Начинаем тест..."); delay(2000); // start_test(); testFlag = 1; } void start_test() { digitalWrite(PIN_RELAY, HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Помпа ВКЛ."); digitalWrite(PIN_RELAY, HIGH); if (millis() - TimeStartPomp >= 25000) { lcd.setCursor(0, 0); lcd.print("Помпа ВЫКЛ"); digitalWrite(PIN_RELAY, LOW); testFlag = 0; } btn2.tick(); if (btn2.click()) { return_counter++; } oborotu(); } void loop() { if(/*условие на старт теста*/ && testFlag == 0) { start_test_info(); TimeStartPomp = millis(); } if(testFlag == 1) { start_test(); } }внимательно посмотри на строчку, которую я написал. В каком мы нутре?
Мы в внутри от do до while. И самое главное отличие нам не нужен йелд, что бы что то делать дополнительно, а следовательно мы можем прервать этот delay в любой момент, если потребуется.
АААААА, там do-while, это значит, что это я тупой спрасони. Прошу пардону.
А зачем на каждом прохождение лупа вызывать обороты?
А зачем на каждом прохождение лупа вызывать обороты?
Я так захотел , потому что.
Захоти не вызывать и не вызывай.
И ещё из yield нельзя прервать delay. А свой delay из do while можно. И внутри своего можно резвиться как угодно.
Аппаратный счетчик-самое простое решение как по мне
Собственно вопрос: как сделать несколько процессов одновременно?
https://arduino.ru/forum/programmirovanie/upravlenie-neskolkimi-protsess...
void yield() // (тут выпоняется другой код пока идут 25 сек) { if( ) // если кнопка нажата { Counter++; } }void yield() // (тут выпоняется другой код пока идут 25 сек) { if( ) // если кнопка нажата { Counter++; } }Так так у него был поставлен вопрос. Это самое простое и короткое решение для его кода. Меньше всего переделок.
На Амперке мы уже обсуждали как можно использовать делай с возможностью выхода из него по решению из yield()
Нашел примеры в которых в цикле мигают лампочкой. Но мне не нужен цикл. Эта часть кода - один из void`ов, которые запускаются при определённых условиях и должен выполниться лишь раз
Очень просто: после выполнения нужного Вам участка кода, поднимаете флаг. А в цикле loop() проверяете, поднят ли флаг. Если да - пропускаете, если нет - выполняете.
Вчера не ответил, спал уже почти...
Вот пример с одним флагом
#define Sens A0 unsigned long last_millis = 0; unsigned long last0_millis = 0; int timer = 0; bool Pomp_flg = false; void setup() { pinMode(Sens, INPUT_PULLUP); Serial.begin(9600); delay(300); } void loop() { if ((millis() - last_millis) >= 10) { last_millis = millis(); if ((!digitalRead(Sens)) && !Pomp_flg) { //если была Pomp_flg = true; //нажата кнопка Serial.println("ON");//включили помпу } if (Pomp_flg) timer++; if (timer == 2500) { timer = 0; Pomp_flg = false; Serial.println("OFF"); //выключили помпу } } //остальной код if ((millis() - last0_millis) >= 1000) { last0_millis = millis(); Serial.println("Rabotaet osnovnoi kod"); } }P.S Это как вставить код , что был вначале темы
#define Sens A0 unsigned long last_millis = 0; unsigned long last0_millis = 0; int timer = 0; bool Pomp_flg = false; void setup() { pinMode(Sens, INPUT_PULLUP); Serial.begin(9600); delay(300); } void loop() { if ((millis() - last_millis) >= 10) { last_millis = millis(); if ((!digitalRead(Sens)) && !Pomp_flg) { //если была Pomp_flg = true; //нажата кнопка Serial.println("ON");//включили помпу // здесь код до паузы // digitalWrite(PIN_RELAY, HIGH); // lcd.clear(); // lcd.setCursor(0, 0); // lcd.print("Помпа ВКЛ."); } if (Pomp_flg) timer++; if (timer == 2500) { timer = 0; Pomp_flg = false; Serial.println("OFF"); //выключили помпу // здесь код после паузы // digitalWrite(PIN_RELAY, LOW); // lcd.clear(); // lcd.setCursor(0, 1); // lcd.print("Помпа ВЫКЛ."); } } //остальной код if ((millis() - last0_millis) >= 1000) { last0_millis = millis(); Serial.println("Rabotaet osnovnoi kod"); } }С millis для систем которые не планируется выключать - т.е они работают месяцами будет баг если не учитывать что раз в несколько 10-ков часов в том же Nano (там по разному) будет wraping т.е. millis возвращает число миллисекунд со старта - и размерность переполнится. Читал, что в Nano что-то вроде от 54 часов до 7 дней вроде в разных версиях.
Поэтому если наступит переполнение - от новые данные millis после перехода из-за переполнения на 0 - будут всегда меньше старых если те взяты непосредственно перед переполнением. Система никогда не дождется той самой 1 секунды и залипнет в том состоянии которое было перед этой ситуацией. Стоит дописать проверку - что если после число меньше чем перед - то учесть число остатка или (если не важна точность) число миллисекунд перед обнулить.
Такой баг будет не всегда, отследить будет трудно, система будет зависать раз в случайное число дней (или недель).
опять великое переполнение миллис )))
опять великое переполнение миллис )))
В 32 битной системе максимум
4294967295/1000 = 4294967 секунд / 60 = 71582 минут /60 = 1193 часа / 24 = 49 суток.
Я полагаю, что конроль за такими вещами как температура в комнате с использованием котла на газе или палетах -будет работать на большей территории России в течении 4-6 месяцев в зависимости от региона. Вероятность что вы не отключите нагрев котла вас не пугает?
Ну, йоптЭ, приведи пример в коде, кто_ж мешает то, Апсудим, чО. Ни_ачкуешЪ???
Ну, йоптЭ, приведи пример в коде, кто_ж мешает то, Апсудим, чО. Ни_ачкуешЪ???
Хорошая попытка но нет. Сам все сам.
Это изначально было очевидно. ))))))))))))))))))))
Это изначально было очевидно. ))))))))))))))))))))
Да - ты победитель, теперь все?