Отказ от delay()
- Войдите на сайт для отправки комментариев
Пт, 16/11/2012 - 22:11
Все мы знаем чудесный пример "моргаем светодиодом без delay()" - приведу его еще разок:
const int ledPin = 13; // the number of the LED pin // Variables will change: int ledState = LOW; // ledState used to set the LED long previousMillis = 0; // will store last time LED was updated long interval = 1000; // interval at which to blink (milliseconds) void setup() { // set the digital pin as output: pinMode(ledPin, OUTPUT); } void loop() { unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { // save the last time you blinked the LED previousMillis = currentMillis; // if the LED is off turn it on and vice-versa: if (ledState == LOW) ledState = HIGH; else ledState = LOW; // set the LED with the ledState of the variable: digitalWrite(ledPin, ledState); } }
Естественно, тут все чудесно работает.
А вот как быть, когда delay() требуется внутри функции?
Пример:
void setup() { ... } void loop() { ... func(...); ... } float func(...) { ... delay(...); ... }
Когда у нас требуется задержка в loop - тут все понятно, а как в этом случае поступать? В функцию передали активность, но вот функция должна подождать (например, как это происходит в случае работы с датчиком DS18B20).
Как организовать задержку в этом случае?
Да точно также.
да, так понятно, но при этом пока "не вернемся" из функции Blink - ничего не происходит.
реальный пример:
есть микроконтроллер, к которому подключен ИК-приемник (обрабатываем ИК-команды), датчик DS18B20 (меряем температуру), RF-трансивер (беспроводное управление и "съем данных" с "датчиков", ну и пара управляемых цепей.
И вот с задержкой при чтении датчика температуры - засада. Пока мы находимся внутри функции чтения его значения (собственно, там просто ждем около 0.75с) - ничего не работает (беспроводной запрос к модулю не отрабатывается и т.п.).
Как обойти?
да, так понятно, но при этом пока "не вернемся" из функции Blink - ничего не происходит.
Это почему? Все происходит, мы "пролитаем" функцию Blink насвозь без задержек.
Как обойти?
Да, очень просто, когда заходите в функцию измерения температуры проверяете флаг, если не взведен, то отправляете команду конвертации температуры, взводите флаг и так же как в Blinkе ждете, сбрасываете этот флаг после того как истекло время.
Покажите свою функцию измерения температуры.
Ничего экзотического:
Объявляете глобально переменные
и делаете так
И естественно первые 800 мс функция будет возвращать 0.
да, так будет работать, если в loop просто будем дергать эту функцию и ждать, когда она отдаст ответ.
но в реальной жизни, так не получится (в моем случае) - эта функция вызывается, когда от "главного" модуля через RF-трансивер пришел соотвествтвующий запрос. Соответственно, первый вызов этой функции ничего не даст - придется продолжать опрашивать ее до появления ответа (правда, тут параллельно можно успевать и все прочие дела делать).
Пока для себя придумалось другое решение - завести глобальную переменную с текущим значением температуры и периодически ее просто обновлять (например, раз в минуту). Тогда при появлении запроса от "главного" модуля просто отдавать ее значение, не заморачиваясь в данном случае на процесс получения его значения.
Что скажете про такой подход?
Можно и так, можно как угодно, решений миллион. Температура параметр инерционный, поэтому можно и раз в минуту обновлять. Вы можете объявить глобально
int
Temp
, функцию сделатьvoid
и увеличить в 07 строке время new_time = millis() + 60000; и будет вам обновление раз в минуту.В чем необходимость отказываться от delay? Это не может быть самоцелью. В примере с blink просто продемонстрировано как работать с прерываниями, не более. Чтобы моргать светодиодом и ничего более при этом не делать прерывания не нужны.
1. Прочитайте внимально сообщение #2 и поймете зачем ustas хочет избавиться от delay.
2. Причем здесь прерывания?
1. Прочитайте внимально сообщение #2 и поймете зачем ustas хочет избавиться от delay.
2. Причем здесь прерывания?
вы правы - не внимательно прочитал. Когда разбирался с таймерами там тоже был пример blink без delay
В данном случае скорее всего прерывание по таймеру не прокатит, так как OneWire использует задержки, а как известно задержки в прерывании ведут себя некорректно. Если только в прерывании взводить флаг, который будет проверяться в основном цикле.
Коллеги!
Чтобы навсегда забыть о millis(), lastMillis, previousMillis и расстановке флагов
посмотрите простенькую бибпиотеку:
http://arduino.cc/playground/Code/SimpleTimer
Сказка!
В лупе только timer.run();
Сама с миллисами работает,
можно выполнять единожды, можно энное количество раз, можно периодически...
Таймеры можно разрешать, запрещать, удалять, рестартовать как угодно(но обычно это не надо)
Очень удобно работает setTimeout - вставляется вместо delay()
Подскажите и мне пожалуйста как мне избавиться от delay! Уже всю голову себе сломал. Идея в том чтобы включать фотоаппарат, делать фото и выключать фотик. В данный момент все работает нормально, но delay не позволяет нормально вывыдить информацию на LCD экран во время выполнения функции фотографирования.
Под спойлером моя (неработающая) версия без delay.
Буду Вам очень признателен, если подскажете как решить мою проблему.
Переменные nmrDST и fotoTime должны быть глобальные. fotoTime присваивайте время не при входе в функцию а при исполнении очередного действия, после присвоения nmrDST=.. (обычно переменную такого типа как nmrDST называют "состояние", а сам подход - машина состояний)
А вобще, Вы движитесь верным путем. Так тогда уж идите до конца: обявляете const массив ArrTime для хранения временных интервалов, причем в данном случае в сотнях мимлсекунд, т.е. вместо 14000 храним 140, для экономии. В начале функции проверяем типа if(millis()-fotoTime < ArrTime[nmrDST]*100) return; Соответственно в проверках времени в остальных местах нет нужды и вместо кучи if пишем один switch. Для полного отпада - значения nmrDST обявляем в enum в виде констант с осмымленными названиями. И на последок - оптимизируем switch как получатся будет по ситуации.
Ого! Оперативно ответили :)
maksim, опробовал Ваш вариант. Не работает :(. При вызове функции без интервалов отрабатывают первые три case, При следующем запуске отрабатывают остальные 4-7 case. Последующие вызовы функции вообще тишина. :(
Logik, Ваше предложение не проверял, т.к. пока продумываю код для написания, согласно Ваших рекомендаций.
Замените && на ||
не, все равно получается что при первом вызове отрабатывается case 1 и case 2 с задержкой похожей на секунду. А вот дальше каждый case срабатывает только при очередном вызове функции. :(
Естественно, все от того, что вы не понимаете, что такое неблокирующая функция и как ей пользоваться. С чего вы взяли, что нужно вызывать функцию foto()? Где должна быть функция и как ею пользоваться показано в моем примере, если не понятно, то обьясняю: функция foto() должна находиться (вызываться) в функции loop() и нигде больше, что бы запустить последовательность фотографирования необходимо выполнить: state = 1;, в моем примере это делается в функции setup().
Может так будет понятнее:
В этом случае fotorun() вызывается в loop(), а foto() вызывайте там где вызываете.
maksim, не ругайтесь. Вы все правильно сказали - не понимаю я что такое неблокирующая функция. Честно говоря, я до этого и вообще не знал про такие :). Сделал все как Вы порекомендовали... все чётко работает. Спасибо!
Здравствуйте!Писал в соседней ветке...В ардуино новичок,поэтому делаю много ошибок...Стоит задача работа светофора,запускаемая удержанием кнопки 5сек.,с начала работы программы 2сек.Уважаемый maksim направил на эту ветку форума,за что ему отдельная благодарность...Код я написал,но почему-то не работает.Буду рад любой помощи и соответственно любым комментариям.Заранее спасибо
Пельмень
У Вас вот эта проверка if (state == HIGH && (millis() - changeTime) > 2000) никогда не будет истиной
потому что перед этим в коде if (state == state2) - changeTime = millis(); разница в 2 сек. наступить не может
Зачем Вы добавляете еще 2000 если перед этим делали задержку 5000
Вот такого кода мне кажется будет достаточно, проверил работает
Благдарю за участие!!!
ТЗ изменилось маленько,пока Вы мне открывали глаза,но в любом случае спасибо
Добрый день! Пытался несколько раз скопировать эту библиотеку - не получается, Скетч её не видит. Адрес папки:
Program Files(x86)\Arduino\libraries\SimpleTimer\SimpleTimer.h\SimpleTimer.h
Выдаёт ошибку:
Arduino: 1.6.7 (Windows 10), Плата:"Arduino/Genuino Uno"
Добрый день! Пытался несколько раз скопировать эту библиотеку - не получается, Скетч её не видит. Адрес папки:
Program Files(x86)\Arduino\libraries\SimpleTimer\SimpleTimer.h\SimpleTimer.h
Выдаёт ошибку:
Arduino: 1.6.7 (Windows 10), Плата:"Arduino/Genuino Uno"
он же просит положить библиотеку сюда
C:\Users\Asus\Documents\Arduino\libraries
Сделал. Не помогло. У меня две папки Arduino:
C:\Users\Asus\Documents\Arduino\libraries
C:\Program Files(x86)\Arduino\libraries
Может, удалить вторую? Скетч, похоже, к ней обращается.
Спасибо
В програм файлес лежит комплект поставки ИДЕ.
Пусть лежит. Не трогайте там ничего.
Все ваши "любимые" библиотеки держите под юзером.
А удалить там можете хоть и все.
Если они вам совсем не нужны.
Тогда блинк точно будет работать!
Понял. Спасибо. Юмор заценил. Буду тренироваться дальше
"SimpleTimer.h" достаньте из папки с аналогичным именем и переложите в папку "SimpleTimer"
Спасибо. Проблема была в неправильном расширении. По ссылке сказано скачать и положить в папку. Но нужно ещё и отредактировать в специальном редакторе, чтобы у файла появилось расширение .hи .cpp. Вот на этом и забуксовал. Поэтому нашёл в инете архивированную библиотеку и вставил без проблем в Ардуино. Всё заработало. Всем спасибо.
Тест удачности отписки об уведомлениях......
Тест удачности отписки об уведомлениях......
Контрольный выстрел))))
Фигвам ! ( индейское жилище)
Мимо!
Отписка работает!
Тема 2012 года была в засушенном состоянии,
я тогда ещё совсем молодой был, тогда и подписался, а тут вдруг пошли сообщения.
Привет всем знатокам, прошу не пинать, только начинаю.
Помогите с задачкой пожалуйста, условия таковы:
Нажимаю на кнопку включается на 1сек один светодиод, отпускаю кнопку включается на 1сек другой светодиод.
Код ниже, только переключает светодиоды, а нужно вкл. на 1сек.
http://arduino.ru/tutorials/BlinkWithoutDelay
http://robocraft.ru/blog/arduino/385.html
Ссылок и я накидать могу. Только вот видел я уже это. Не пойму где ставить условие на срабатывание. До цикла - все диоды обновятся одновременно. После - будут обновляться не последовательно, а группами по 2 по три и т.д. Объясните пжлст как тут поступить.
millis(). А еще проще создаешь класс с setup() и loop() методами .
Не могли бы вы напримере кода который я привел показать как это сделать?
Доброго времени суток!
Так уж случилось, что я технарь, но не программист. Прошу сразу не пинать и не отправлять по ссылкам. Неделю уже бьюсь над проблемой, пересмотрел кучу страниц текста, кода, объяснений...
Есть скетч управления WS2812 по принципу, что все модули ленты горят своим цветом исходя из места в массиве, но если Цвет задан КРАСНЫЙ, то данные светодиоды должны еще и моргать одновременно... Так вот при реализации с delay они моргают по очереди (циклично). Без delay (с применение millis) никак не получается их заставить моргать даже по очереди, а надо чтоб без delay и моргали все красные одновременно.
Направьте, плиз, в нужном направлении. :)
То есть, остальные диоды как зажглись один раз своим цветом, так и горят, а которые должны быть красными весело мигают?
Так а в чём отличие от примера Blink without delay? Берёте прямо его. Только там где по прошествии нужного времени состояние одного диода меняется, Вам в цикле по всем пробежаться нужно будет. Я с этой библиотекой не знаком, но скорее всего FastLED.show() можно один раз после установки состояния всех красных сд вызывать.
Пока именно так.. Позже на разные данные буду навешивать разные типы индикации, и прочее - прочее...
Подобие из Blink without delay не получается, тк (как я понимаю) в ленту надо запустить последовательность битов, а лента чувствительна к временным интервалам и не получается точно выставить таймауты горения и выключения... Может это и не так, но у меня пока ничего не получилось... Пробую-пробую, но пока безрезультатно(
В ардафруит библиотеке тоже ничего не выходит...
Направьте, плиз, в нужном направлении.
Вы, код-то напишите, сюда его выложите. И опишите поведение Ваших светодиодов с этим кодом, что получилось и что не устраивает. Без этого сложно что-то советовать, не видя результат.