Используем функции delay() и millis() в Arduino IDE правильно
Одна из основных ошибок новичков при написании скетчей для Arduino – чрезмерное использование функции delay().
Эта функция, (как указано в официальной документации) останавливает выполнение программы на указанное количество милисекунд. Давайте рассмотрим пример: вы подключили к Arduino кнопку и светодиод; когда вы нажимаете на кнопку, светодиод должен зажечься на 3 секунды.
Скетч может выглядеть примерно следующим образом (несолько модифицированная версия из оффициального туториала):
const int buttonPin = 2;
const int ledPin = 4;
if (digitalRead(buttonPin) == HIGH) <
Теперь добавим вторую кнопку и второй светодиод и попробуем обновить скетч, чтобы управлять двумя светодиодами, используя при этом функцию delay():
const int button1Pin = 2;
const int button2Pin = 3;
const int led1Pin = 4;
const int led2Pin = 5;
if (digitalRead(button1Pin) == HIGH) <
if (digitalRead(button2Pin) == HIGH) <
Схема подключения с использованием breadboard’a в данном случае выглядит так:

Вероятно, вы уже заметили проблему: когда один светодиод включен, вы не можете включить второй! Причина простая: когда первый светодиод включен, ваш скетч останавливает свою работу и, соответственно, не может проверить состояние второй кнопки.
Используем MILLIS
Для решения этой проблемы можно использовать функцию millis(): она возвращает количество милисекунд, которое прошло с момента запуска скетча.
Если вам надо узнать, когда прошло заданное время, вы можете:
сохранить в переменной начальное время, то есть момент времени, когда вы включили светодиод.
Периодически проверять (например, в теле цикла loop), разницу между начальным временем и фактическим на данный момент.
Ниже приведен новый скетч:
const int button1Pin = 2;
const int button2Pin = 3;
const int led1Pin = 4;
const int led2Pin = 5;
unsigned long led1OnTime;
unsigned long led2OnTime;
if (digitalRead(button1Pin) == HIGH) <
if (digitalRead(button2Pin) == HIGH) <
if(millis() — led1OnTime > 30000) <
if(millis() — led2OnTime > 30000) <
Введено две новые переменные: две (led1OnTime и led2OnTime), чтобы сохранить значения времени, когда светодиоды включаются и две (led1On и led2On), чтобы оценивать текущий статус светодиодов (вкл. или выкл. (on/off) или в булевом типе — true/false).
Когда кнопка нажата, скетч заставляет светодиод включится, сохраняет текущее время и меняет значение в переменной статуса.
Если светодиод горит (переменная состояния равна true), скетч периодечески проверяет длительность состояния вкл. (30 секунд, то есть 30000 милисекунд): если период превышает допустимый (30 секунд 30000 миллисекунд), то это значит, что светодиод выключен.
Оставляйте Ваши комментарии, вопросы и делитесь личным опытом ниже. В дискуссии часто рождаются новые идеи и проекты!
Arduino
Возвращает время в миллисекундах, прошедшее с начала выполнения программы на плате Arduino. Это число будет переполнено и сброситься до 0 примерно через 50 дней выполнения.
Синтаксис
Параметры
Возвращаемое значение
Количество миллисекунд, прошедших с момента запуска программы
Пример
Выводим значение, возвращаемое функцией millis() и ждем 1 секунду:
Функция micros()
Описание
Возвращает время в микросекундах, прошедшее с начала выполнения программы на плате Arduino. Это число будет переполнено и сброситься до 0 примерно через 70 минут выполнения.
Синтаксис
Параметры
Возвращаемое значение
Количество микросекунд, прошедших с момента запуска программы
Пример
Выводим значение, возвращаемое функцией micros() и ждем 1 секунду:
Примечания
На платах Arduino 16 МГц (например Uno и Nano) эта функция имеет разрешение в четыре микросекунды, поэтому значение всегда кратно четырем. На платах Arduino 8 МГц (например, LilyPad) эта функция имеет разрешение восемь микросекунд.
Функция delay()
Описание
Приостанавливает выполнение программы на заданноое время в миллисекундах.
Синтаксис
Параметры
ms — время в миллисекундах, на которое нужно приостановить программу
Возвращаемое значение
Пример
Мигаем встроенным светодиодом:
Примечания
Несмотря на то, что с помощью функции delay() легко создать мигающий светодиод и многие другие простые скетчи, использование функции имеет существенные недостатки. Во время приостановки программы невозможны любые манипуляции с пинами, например опрос датчиков. Также не будут работать многие математические функции. Поэтому рекомендуется в качестве альтернативы использовать функцию millis() .
Однако некоторые функции во вовремя выполнение delay() все же продолжают работать. Например, прерывания.
Функции времени

Простейшей с точки зрения использования функцией времени является задержка: программа “зависает” внутри функции задержки и ожидает указанное время. Задержка позволяет очень удобно и наглядно организовать работу простой “однозадачной” программы, у нас есть два варианта задержек:
- delay(time)
- Задержка на указанное количество миллисекунд (мс). 1 секунда = 1’000 мс.
- time принимает тип данных unsigned long и может приостановить выполнение на срок от 1 до 4 294 967 295 мс (
- Задержка на указанное количество микросекунд (мкс). 1 секунда = 1’000’000 мкс.
- time принимает тип данных unsigned int и может приостановить выполнение на срок от 4 до 16383 мкс (да, меньше чем максимум для этого типа данных) с разрешением 4 мкс.
- Работает не на таймере, а на пропуске тактов процессора, поэтому может работать в прерывании и при отключенных прерываниях.
- Иногда не совсем корректно работает с переменными, поэтому нужно стараться использовать константы ( const или просто число).
- Часто используется в библиотеках для эмуляции цифровых интерфейсов связи.
Задержки использовать очень просто:
Мышление “задержками” – главная проблема новичков. Организовать работу сложной программы при помощи задержки – невозможно, поэтому дальше рассмотрим более полезные инструменты.
Функция yield()
Разработчики Arduino позаботились о том, чтобы функция delay() не просто блокировала выполнение кода, но и позволяла выполнять другой код во время этой задержки. Данный “костыль” получил название yield() и работает следующим образом: если объявить функцию
то расположенный внутри неё код будет выполняться во время работы любой задержки delay() в программе! Это решение хоть и кажется нелепым, но в то же время позволяет быстро и без написания лишних костылей и таймеров реализовать пару параллельно выполняющихся задач. Это вполне соответствует идеологии Arduino – максимально простая и быстрая разработка прототипа. Рассмотрим простой пример: стандартный мигающий светодиод, но с опросом кнопки:
Функции счёта времени
Данные функции возвращают время, прошедшее с момента запуска программы, так называемый аптайм (англ. uptime). Таких функций у нас две:
-
millis() – миллисекунды, тип unsigned long , от 1 до 4 294 967 295 мс (
Эти функции позволяют организовать программу практически любой сложности с любым количеством параллельно выполняющихся по таймеру задач. Подробнее об этом поговорим в уроке про многозадачность.
millis() в часы и секунды
Миллисекунды – не самый удобный способ оценить время работы программы. Можно перевести его в более человеческие часы, минуты и секунды при помощи нехитрых математических операций:
delay()
С помощью функции delay() заставить мигать светодиод достаточно просто. Помимо этого, во многих программах функция задержки используется для таких задач, как обработка дребезга контактов и пр. Несмотря на это, использование функции delay() в коде программы имеет существенные недостатки. В процессе действия delay() такие операции, как считывание данных с датчиков, математические вычисления или операции с выводами не могут выполняться. Фактически, функция delay() приводит к остановке практически всех операций. Альтернативный способ контролировать время — использование функции millis() (смотрите пример кода, приведенный ниже). Опытные программисты обычно избегают использования delay() для установки временных интервалов больше нескольких десятков миллисекунд (за исключением очень простых программ Arduino).
Тем не менее, некоторые события и участки кода могут работать и в процессе выполнения микроконтроллером функции delay(), т.к. эта функция не влияет на работу прерываний. Так, по прежнему будут срабатывать прерывания, записываться данные, поступающие на вывод RX по последовательному интерфейсу, а также будет поддерживаться ШИМ-сигнал, формируемый функцией analogWrite().
Смотрите также
Железо

Это расширенный стартовый набор. В комплект входит Arduino Mega R3, макетные платы, множество датчиков, управляемые механизмы и необходимые радиоэлектронные компоненты. Полный список.

Arduino Uno — плата на базе микроконтроллера ATmega328P с частотой 16 МГц. На плате есть все необходимое для удобной и быстрой работы.