Arduino.ru
Останавливает выполнение программы на заданное в параметре количество миллисекунд (1000 миллисекунд в 1 секунде).
Синтаксис
delay(ms)
Параметры
ms: количество миллисекунд, на которое приостанавливается выполнение программы. (unsigned long)
Возвращаемое значение
Пример
int ledPin = 13; // светодиод подключен на порт 13 void setup() < pinMode(ledPin, OUTPUT); // устанавливается режим порта - выход >void loop() < digitalWrite(ledPin, HIGH); // включаем светодиод delay(1000); // ожидаем секунду digitalWrite(ledPin, LOW); // выключаем светодиод delay(1000); // ожидаем секунду >
Замечания по использования функции
Не рекомендуется использовать эту функцию для событий длиннее 10 миллисекунд, т.к. во время останова, не могут быть произведены манипуляции с портам, не могут быть считаны сенсоры или произведены математические операции. В качестве альтернативного подхода возможно контролирование времени выполнения тех или иных функций с помощью millis().
Большинство активности платы останавливается функцией delay(). Тем не менее работа прерываний не останавливается, продолжается запись последовательно (serial) передаваемых данных на RX порту, ШИМ сигнал (analogWrite) продолжает генерироваться на портах.
Смотрите также
Авторизация
Примеры
Изменяем яркость светодиода — плавное изменение яркости светодиода функцией analogWrite().
Мигаем светодиодом — пример подключения светодиода к Arduino и работы с ним
Тактовая кнопка — считывание состояния кнопки
Мигаем светодиодом без delay() — еще один, более практичный способ мигать светодиодом
Замена delay() для неблокирующих задержек в Arduino IDE
Первое, с чем сталкивается осваивающий Arduino новичок, это неприятное свойство функции delay() — блокирование выполнения программы. Множество примеров в интернете используют эту функцию, но практическое применение как-то намекает, что лучше без неё обойтись.
Как и положено начинающему, я изобрёл велосипед сделал свою реализацию неблокирующей задержки. Задача стояла так:
- Обеспечить псевдомногозадачность, чтобы разные события происходили в своё время, со своими интервалами и не блокировали друг-друга.
- Было удобно этим пользоваться.
- Можно было оформить как библиотеку и легко включать в другие проекты без копипастов.
В результате получилось вот такое.
#include SmartDelay foo(1000000UL); // в микросекундах void loop () < if (foo.Now()) < // Код здесь выполняется каждый интервал в микросекундах, указанный в конструкторе выше. >//Прочий код >
Метод Now() возвращает true, если интервал прошёл. В этом случае отсчёт начинается снова на тот же интервал. То есть, Now() каждый раз «перезаряжается» автоматически.
Классическое мигание светодиодом можно сразу усложнить до мигания двумя. Например, лампочки подключены к ножкам 12 и 11, должны мигать с интервалом в 1с и 777мс соответственно.
#include SmartDelay led12(1000000UL); SmartDelay led11(777000UL); setup () < pinMode(12,OUTPUT); pinMode(11,OUTPUT); >byte led12state=0; byte led11state=0; void loop () < if (led12.Now()) < digitalWrite(12,led12state); led12state=!led12state; >if (led11.Now()) < digitalWrite(11,led11state); led11state=!led11state; >>
В цикле можно выполнять ещё что-то, мигание светодиодов не будет блокировать выполнение этого кода.
Понятно, что это не полная замена delay(), который останавливает поток на заданное время, надо писать программу всегда как МКА (механизм конечных автоматов). То есть, хранить состояние и в зависимости от него переходить к нужному месту кода.
. action1(); delay(1000); action2(); delay(500); action3(); .
byte state=0; SmartDelay d(); . switch (state) < case 0: action1(); d.Set(1000000UL); state=1; break; case 1: if (d.Now()) < action2(); d.Set(500000UL); state=2; >break; case 2: if (d.Now()) < action3(); d.Stop(); state=0; >break; > .
Метод Set(интервал) устанавливает новый интервал и возвращает старый. Просто посмотреть на интервал можно методом Get();
Stop() останавливает обработку и Now() всегда возвращает false.
Start() возобновляет работу и Now() начинает работать как обычно.
Если надо притормозить подсчёт времени, но не останавливать совсем, то есть метод Wait(). Например, если мигает светодиод 12, а при нажатии кнопки не мигает, достаточно добавить вот такой код в loop() в примере с двумя диодами выше:
. if (digitalRead(9)) led12.Wait(); .
Так, при высоком уровне сигнала на 9 ноге диод на 12 мигать не будет и продолжит, когда там появится 0.
Когда по такому «таймеру» отрисовывается экран, например, и параллельно обрабатываются кнопки, то бывает нужно перерисовать экран или часть сразу после нажатия на кнопку, а не ждать окончания интервала. Для этого служит метод Reset(), после которого следующий вызов Now() вернёт true. Например:
SmartDelay display(1000000UL); void loop() < if (btClick()) display.Reset(); // ткнул в кнопку, надо отрисовать экранчик. if (display.Now()) screenRedraw(); // отрисовка экранчика. >
Из багов я вижу только, что не учитывается переполнение счётчика микросекунд, а в остальном да, надо почистить код. Мне не нравится, как сделан Reset(), пока думаю.
Объектный подход мне понравился, позволяет спрятать весь код в библиотеку, в которую можно потом уже никогда не заглядывать. Теперь эта маленькая библиотечка живёт во всем моих проектах 🙂
Работаем с задержками без delay() на arduino.
В прошлом уроке мы поняли принцип считывания значения с матричной клавиатуры и написали простой код, который реализует данное действие. Прежде чем переходить к более сложной задаче — сохранению введённого значения с клавиатуры, попробуем реализовать функцию работы с замком разного типа, и открытию его по кнопке с обратной стороны двери, а также сделаем звуковую и световую индикацию при открытии.

Мы рисовали общую схему нашего устройства, но сейчас посмотрим на элементы, с которыми мы будем работать в данном уроке. Собственно — их 5. — это зуммер, реле с 2 типами контактов, светодиод, показывающий состояние прохода и кнопка мгновенного действия. Подготовим для всех них понятные имена
#define ledAccess 8 // Светодиод - разрешающий #define ledDenied 9 // Светодиод - запрещающий #define buttonOpen 10 // Кнопка разблокировки #define lock 11 // Контакт замка #define buzzer 12 // Контакт динамика
Также нам понадобится новая переменная — флаг, который будет указывать тип замка. Замок у нас может быть электромагнитный или электромеханический — отличаются по принципу действия. Если на магните нужно снимать напряжение в момент открытия, то на механике, наоборот подавать напряжение на соленойд для открытия.
bool lockType = 1; // Тип замка - электромеханический = 1. Электромагнитный = 0
Теперь зададим режим работы пинов нашей периферии. Как не сложно догадаться на вход у нас будет настроен только контакт кнопки, все остальные устройства являются исполнительными и будут настроены на выход. Чтобы не вешать внешнее сопротивление, настроим внутреннюю резистивную подтяжку на входе кнопки.
pinMode(buttonOpen, INPUT); // контакт кнопки на вход с подтяжкой digitalWrite(buttonOpen, HIGH); pinMode(lock, OUTPUT); // контакт замка на выход pinMode(ledAccess, OUTPUT); // разрешающий светодиод pinMode(ledDenied, OUTPUT); // запрещающий светодиод pinMode(buzzer, OUTPUT); // зуммер
Первым делом попытаемся избавиться от задержки delay() в ардуино, чтобы во время ожидания, наш контроллер мог решать другие задачи. Нам это нужно будет, для управлением временем открытия замка, зажиганию диодов, подачи звука, и чтобы в это время мы могли решать другие задачи, такие как, опрос клавиатуры, кнопки выхода и считывателя.
Смотрите также: Матричная клавиатура на arduino. Опрос кнопок
К счастью, в ардуино уже есть для этого инструменты. Попытаюсь дать короткое объяснение, почему delay это плохо. Для этого отвлечёмся и представим абстрактную задачу, где один светодиод у нас моргает каждую 1 секунду, а другой, каждые 0,2 секунды. Возьмём обычный пример мигания через delay
void setup() < pinMode(8, OUTPUT); // Пины 8 и 9 конфигурируем на выход pinMode(9, OUTPUT); >void loop() < digitalWrite(8, HIGH); // В этом блоке подаём 5в на pin8, ждём 1 секунду, снимаем напряжение, опять ждём 1 секунду delay(1000); digitalWrite(8, LOW); delay(1000); digitalWrite(9, HIGH); // В этом блоке подаём 5в на pin9, ждём 200мс, снимаем напряжение, опять ждём 200мс delay(200); digitalWrite(9, LOW); delay(200); >
Естественно, в данном примере, они мигают по очереди, потому-что пока выполняется delay, контроллер делает бесполезные операции в цикле. Можно конечно сделать мигание второго диода в прерывании, но опять же, использовать там delay не получится, чтобы выдержать 200мс.

Можно извратиться, и рассчитать задержки свечения светодиода, который мигает чаще, так, чтобы создать второму диоду нужные 1 секунду простоя и свечения.
void setup() < pinMode(8, OUTPUT); //Пины 8 и 9 конфигурируем на выход pinMode(9, OUTPUT); >void loop() < digitalWrite(8, HIGH); digitalWrite(9, HIGH); // набираем задержку 1000мс блоками из 200мс delay(200); // первые 200мс digitalWrite(9, LOW); delay(200); // уже 400мс digitalWrite(9, HIGH); delay(200); // 600мс digitalWrite(9, LOW); delay(200); // теперь 800мс digitalWrite(9, HIGH); delay(200); // набрали 1000мс, можно погасить led8 digitalWrite(8, LOW); digitalWrite(9, LOW); //опять набираем задержку 1000мс блоками из 200мс delay(200); digitalWrite(9, HIGH); delay(200); digitalWrite(9, LOW); delay(200); digitalWrite(9, HIGH); delay(200); digitalWrite(9, LOW); delay(200); >
Всё работает как надо, но согласитесь, это конкретное извращение. Также, в такой код будет невероятно трудно вставить другие задачи, требующие многозадачности.
Смотрите также: Отладка программы

Как ещё можно реализовать задержку, чтобы в это время, можно было делать другой код? Самое лучшее решение — запустить условие проверки с некой переменной, которая постоянно увеличивает значение. В ардуино уже реализована такая переменная millis() , которая увеличивается каждую миллисекунду на 1. Её максимальное значение равно 4294967295мс, что приблизительно составляет почти 50 суток. Пока не будем думать, о том, что она может переполнится (в этом ничего страшного нет), и посмотрим, как мы можем использовать эту переменную
unsigned long currentTime; // Переменная текущего времени if (millis() - currentTime > 1000) // Если время контроллера millis, больше переменной на 1000, то запускаем условие if < currentTime = millis(); // Приравниваем переменную текущего времени к времени контроллера, чтобы через 1000мс опять сработал наш цикл. //здесь любое действие. >
Всё просто! Мы используем вспомогательную переменную текущего времени currentTime, На старте её значение равно = 0, как и millis() = 0. Но millis() у нас постоянно увеличивается, а currentTime — нет. Поэтому через 1000мс, сработает условие if (millis() — currentTime > 1000), т.е. мы создали задержку в 1с, но код при этом выполнялся циклично в loop, и мы могли успеть обработать много периферии. Потом мы просто обновляем нашу переменную currentTime, и она снова ждёт сравнения с millis(), когда она вырастет на 1000мс. Попробуем сделать вышестоящую задачу, мигание двумя светодиодами с разной задержкой. но при этом вставим в loop какой нибудь код, пусть будет отправка в терминал, и проверим, как это работает. Я сделал для наглядности вторую переменную currentTime2, для второго светодиода.
unsigned long currentTime; // Переменная времени диода 8 unsigned long currentTime2; // Переменная времени диода 9 bool ledState=0; // Переменная состояния диода 8 bool ledState2=0; // Переменная состояния диода 9 unsigned long a; // Переменная для проверки работоспособности кода в условиях задержки void setup() < Serial.begin(9600); // Конфигурируем серийный порт pinMode(8, OUTPUT); //Пины 8 и 9 конфигурируем на выход pinMode(9, OUTPUT); >void loop() < if (millis() - currentTime >1000) // Проверяем время для первого диода (1000мс) < currentTime = millis(); ledState=!ledState; // Меняем состояние первого диода на противоположное digitalWrite(8, ledState); >if (millis() - currentTime2 > 200) // Проверяем время для второго диода (200мс) < currentTime2 = millis(); ledState2=!ledState2; // Меняем состояние второго диода на противоположное digitalWrite(9, ledState2); >a++; Serial.println (a); >
Для состояний светодиодов, возьмём переменную bool ledState и ledState2. Мы задали её тип как boolean, а это значит что она может принимать два значения — true и false, что в принципе равно 0 и 1. Чтобы не писать по несколько раз HIGH, LOW, мы подставляем туда состояние светодиода ledState. А меняем его каждый раз логическим отрицанием (!) на противоположное значение.
ledState=!ledState;
В конце цикла loop, впишем команду инкрементирования переменной a++, и отправки значения в серийный порт, чтобы отследить, будет ли выполняться этот код в момент ожидания задержек.
a++; Serial.println (a);
Смотрим, что получилось
Смотрите также: самодельный Термовакуумный аппарат

Видно, что теперь у нас и светодиоды моргают с заданными задержками (1000мс и 200мс) и в серийный порт с постоянством отправляется новая переменная. Отлично — теперь мы можем получить какие-то задатки многозадачности, и продолжить писать код для нашего устройства в следующей статье.
Задержка delay Ардуино и millis без delay

Функции delay(), millis() и delayMicroseconds() Arduino играют важную роль и написание большинства скетчей без этих команд практически невозможно. На нашем сайте вы найдете множество уроков и проектов с millis(), где необходим отсчет времени или с delay(), например, чтобы избежать дребезга контактов у тактовой кнопки. Рассмотрим назначение и применение команд задержки времени в Ардуино программировании.
Ардуино delay: задержка включения / выключения
Для занятия нам потребуется:
- Arduino Uno / Arduino Nano / Arduino Mega.
В этой записи мы рассмотрим только основные характеристики функций задержки, а примеры использования представим в виде небольших скетчей. Для работы вам потребуется только сама плата Ардуино. Начнем обзор с delayMicroseconds Arduino, т.к. данную функцию не часто можно встретить в программах, а также рассмотрим, как заменить задержку delay на millis в программировании Arduino IDE.
Arduino delayMicroseconds()
Команда delayMicroseconds останавливает выполнение программы на заданное количество микросекунд (в 1 секунде 1 000 000 микросекунд). При необходимости задержки в программе более чем на несколько тысяч микросекунд рекомендуется использовать delay(). Продемонстрируем на простом примере использование функции в скетче для мигания встроенным светодиодом на плате Arduino.
// пример использования delayMicroseconds() для мигания светодиодом void setup() < pinMode(13, OUTPUT); > void loop() < digitalWrite(13, HIGH); // подаем сигнал HIGH на выход delayMicroseconds(100); // задержка 100 микросекунд digitalWrite(13, LOW); // подаем сигнал LOW на выход delayMicroseconds(100); // задержка 100 микросекунд >
Arduino delay()
Команда delay останавливает выполнение программы на заданное количество миллисекунд (в 1 секунде 1 000 миллисекунд). Во время задержки программы с помощью функции delay(), не могут быть считаны подключенные к плате датчики или произведены другие операции, например, запись в еепром Ардуино данных. В качестве альтернативы следует использовать функцию millis(). Смотри пример далее.
// пример использования delay() для мигания светодиодом void setup() < pinMode(13, OUTPUT); > void loop() < digitalWrite(13, HIGH); // подаем сигнал HIGH на выход delay(100); // задержка 100 миллисекунд digitalWrite(13, LOW); // подаем сигнал LOW на выход delay(100); // задержка 100 миллисекунд >
Arduino millis()
Команда millis возвращает количество прошедших миллисекунд с момента начала выполнения программы. Счетчик времени сбрасывается на ноль при переполнении значения unsigned long (приблизительно через 50 дней). Функция millis позволяет сделать многозадачность Ардуино, так как выполнение программы не останавливается и можно выполнять параллельно другие операции в скетче.
// пример использования millis() при мигании светодиодом unsigned long timer; void setup() < pinMode(13, OUTPUT); Serial.begin(9600); // запускаем монитор порта > void loop() < timer = millis(); // запускаем отсчет времени digitalWrite(13, HIGH); // подаем сигнал HIGH на выход delay(1000); // задержка 1 секунда digitalWrite(13, LOW); // подаем сигнал LOW на выход delay(1000); // задержка 1 секунда // выводим количество миллисекунд прошедших с момента начала программы Serial.print("Time: "); Serial.println(timer); >

Используем в Ардуино millis вместо delay
В последнем примере вывод счетчика на мониторе порта прерывается на время задержки в программе delay(1000); — в этом заключается главное отличие этих функций. При подключении датчиков к плате необходимо получать данные от них постоянно, поэтому команду delay заменяют на millis. Как это сделать в скетче для Arduino IDE с мигающим светодиодом — продемонстрируем в следующем примере.
// пример замены delay на millis в программе unsigned long timer; // переменная времени boolean ledState = 0; // переменная состояния светодиода void setup() < pinMode(13, OUTPUT); Serial.begin(9600); // запускаем монитор порта timer = millis(); // запускаем отсчет времени > void loop() < if (millis() - timer > 1000) // проверяем сколько прошло миллисекунд < ledState=!ledState; // меняем состояние светодиода на противоположное digitalWrite(13, ledState); timer = millis(); > // выводим количество миллисекунд прошедших с момента начала программы Serial.print("Time: "); Serial.println(timer); >
Заключение. Команда millis Arduino не останавливает выполнения программы, а начинает отсчет времени с начала запуска счетчика в миллисекундах. В отличии от этого, delay и delayMicroseconds останавливают выполнение программы на заданное количество миллисекунд или микросекунд соответственно. Применение определенной задержки в скетче Ардуино микроконтроллеров зависит от поставленной задачи.
