Как узнать время выполнения скетча ардуино. Arduino — функции — время. Пример delay с миганием светодиодом

Windows

Здравствуйте, Андрей. Весьма интересен ваш подход к передаче багажа знаний и опыта, вами накопленного. Очень помогает в начинаниях. Ну и я, начиная осваивать arduino имею желание прогрессировать. Тем более, что с посторонней помощью у меня это получается быстрее. Итак: сперва моя задача была сделать робота, едущего по линии. Сделал — все отлично. Но дальше, снабжая его дополнительными опциями, не понимал — почему он перестал корректно реагировать на линию. Набрел на эту статью и понял причину.

Теперь у меня к вам вопрос: в ниже указанном и готовом скетче, учитывая проблемы с delay, нужно ли мне везде, где присутствует эта функция перейти на millis? Если так, то я понимаю, что скетч придется переделывать почти весь? И не совсем понятно, как использовать millis в замере расстояния? Спасибо.

//Робот с функцией следования по белой полосе

// **********************Установка выводов моторов ************************

int MotorLeftSpeed = 5; // Левый (А) мотор СКОРОСТЬ - ENA

int MotorLeftForward = 4; // Левый (А) мотор ВПЕРЕД - IN1

int MotorLeftBack = 3; // Левый (А) мотор НАЗАД - IN2

int MotorRightForward = 8; // Правый (В) мотор ВПЕРЕД - IN3

int MotorRightBack = 7; // Правый (В) мотор НАЗАД - IN4

int MotorRightSpeed = 9; // Правый (В) мотор СКОРОСТЬ - ENB

// **********************Установка выводов УЗ датчиков***********************

int trigPinL = 14; // задание номера вывода левого trig УЗ датчика

int echoPinL = 15; // задание номера вывода левого echo УЗ датчика

int trigPinC = 10; // задание номера вывода центрального trig УЗ датчика

int echoPinC = 11; // задание номера вывода центрального echo УЗ датчика

int trigPinR = 12; // задание номера вывода правого trig УЗ датчика

int echoPinR = 13; // задание номера вывода правого echo УЗ датчика

// ********************* Установка выводов датчиков линии *******************

const int LineSensorLeft = 19; // вход левого датчика линии

const int LineSensorRight = 18; // вход правого датчика линии

int SL; // статус левого сенсора

int SR; // статус правого сенсора

// *********************Установка вывода световой и звуковой сигнализации**************

int Light = 2; // задание номера вывода световой сигнализации

int Zumm = 6; // задание номера вывода зуммера

int ledState = LOW; // этой переменной устанавливаем состояние светодиода

long previousMillis = 0; // храним время последнего переключения светодиода

long interval = 300; // интервал между включение/выключением светодиода (0,3 секунды)

// *********************Переменная измерение дистанции датчиками*************

unsigned int impulseTimeL=0;

unsigned int impulseTimeC=0;

unsigned int impulseTimeR=0;

long distL=0; // дистанция, измеренная левым УЗ датчиком

long distC=0; // дистанция, измеренная центральным УЗ датчиком

long distR=0; // дистанция, измеренная правым Уз датчиком

// *********************************** SETUP ********************************

Serial.begin (9600); // запускаем серийный порт (скорость 9600)

//*************** Задаем контакты моторов****************

pinMode (MotorRightBack, OUTPUT); // Правый (В) мотор НАЗАД

pinMode (MotorRightForward, OUTPUT); // Правый (В) мотор ВПЕРЕД

pinMode (MotorLeftBack, OUTPUT); // Левый (А) мотор НАЗАД

pinMode (MotorLeftForward, OUTPUT); // Левый (А) мотор ВПЕРЕД

delay (duration);

//*************** Задаем контакты датчиков полосы**************

pinMode (LineSensorLeft, INPUT); // определением pin левого датчика линии

pinMode (LineSensorRight, INPUT); // определением pin правого датчика линии

// ***************Задание режимов выводов УЗ датчиков**********************

pinMode (trigPinL, OUTPUT); // задание режима работы вывода левого trig УЗ датчика

pinMode (echoPinL, INPUT); // задание режима работы вывода левого echo УЗ датчика

pinMode (trigPinC, OUTPUT); // задание режима работы вывода центрального trig УЗ датчика

pinMode (echoPinC, INPUT); // задание режима работы вывода центрального echo УЗ датчика

pinMode (trigPinR, OUTPUT); // задание режима работы вывода правого trig УЗ датчика

pinMode (echoPinR, INPUT); // задание режима работы вывода правого echo УЗ датчика

// ***************Задаем контакты световой и звуковой сигнализации********************************

pinMode (Zumm,OUTPUT); // задание режима работы вывода зуммера

pinMode (Light,OUTPUT); // задание режима работы вывода световой сигнализации

// ****************** Основные команды движения ******************

void forward (int a, int sa) // ВПЕРЕД

analogWrite (MotorRightSpeed, sa);

analogWrite (MotorLeftSpeed, sa);

void right (int b, int sb) // ПОВОРОТ ВПРАВО (одна сторона)

digitalWrite (MotorRightBack, LOW);

digitalWrite (MotorLeftBack, LOW);

digitalWrite (MotorLeftForward, HIGH);

analogWrite (MotorLeftSpeed, sb);

void left (int k, int sk) // ПОВОРОТ ВЛЕВО (одна сторона)

digitalWrite (MotorRightBack, LOW);

digitalWrite (MotorRightForward, HIGH);

analogWrite (MotorRightSpeed, sk);

digitalWrite (MotorLeftBack, LOW);

void stopp (int f) // СТОП

digitalWrite (MotorRightBack, LOW);

digitalWrite (MotorRightForward, LOW);

digitalWrite (MotorLeftBack, LOW);

digitalWrite (MotorLeftForward, LOW);

// **************************Измерение дистанции*********************

void izmdistL () // измерение дистанции левым УЗ датчиком

digitalWrite (trigPinL, HIGH);

digitalWrite (trigPinL, LOW); // импульс 10мС на вывод trig УЗ датчика для измерения расстояния

impulseTimeL = pulseIn (echoPinL, HIGH); // считывание расстояния с УЗ датчика

distL=impulseTimeL/58; // Пересчитываем в сантиметры

void izmdistC () // измерение дистанции центральным УЗ датчиком

digitalWrite (trigPinC, HIGH);

digitalWrite (trigPinC, LOW); // импульс 10мС на вывод trig УЗ датчика для измерения расстояния

impulseTimeC = pulseIn (echoPinC, HIGH); // считывание расстояния с УЗ датчика

distC=impulseTimeC/58; // Пересчитываем в сантиметры

void izmdistR () // измерение дистанции центральным УЗ датчиком

digitalWrite (trigPinR, HIGH);

digitalWrite (trigPinR, LOW); // импульс 10мС на вывод trig УЗ датчика для измерения расстояния

impulseTimeR = pulseIn (echoPinR, HIGH); // считывание расстояния с УЗ датчика

distR=impulseTimeR/58; // Пересчитываем в сантиметры

// *********************************** LOOP *********************************

// ********************** Режим следования по ЛИНИИ *************************

// *********************световая и звуковая сигнализация**************

tone (Zumm,900); // включаем звук на 900 Гц

tone (Zumm,900); // включаем звук на 800 Гц

unsigned long currentMillis = millis ();

if (currentMillis — previousMillis > interval) //проверяем не прошел ли нужный интервал, если прошел то

previousMillis = currentMillis; // сохраняем время последнего переключения

if (ledState == LOW) // если светодиод не горит, то зажигаем, и наоборот

ledState = HIGH;

digitalWrite (Light, ledState); // устанавливаем состояния выхода, чтобы включить или выключить светодиод

// ************************ Измерение дистанции************************

Serial.println (distL);

Serial.println (distC);

Serial.println (distR);

if (distL>50 && distC>50 && distR>50) // если измеренная дистанция больше 50 сантиметров — едем

SL = digitalRead (LineSensorLeft); // считываем сигнал с левого датчика полосы

SR = digitalRead (LineSensorRight); // считываем сигнал с правого датчика полосы

// ************************* Следование по черной линии ***********************

// РОБОТ на полосе - едем прямо

if (SL == LOW & SR == LOW) // БЕЛЫЙ - БЕЛЫЙ - едем ПРЯМО

forward (10, 100);// ПРЯМО (время, скорость)

// РОБОТ начинает смещаться с полосы - подруливаем

else if (SL == LOW & SR == HIGH) // ЧЕРНЫЙ — БЕЛЫЙ - поворот ВЛЕВО

left (10, 100);// поворот ВЛЕВО (время, скорость)

else if (SL == HIGH & SR == LOW) // БЕЛЫЙ — ЧЕРНЫЙ - поворот ВПРАВО

right (10, 100);// поворот ВПРАВО (время, скорость)

// ФИНИШ — РОБОТ видит обоими датчиками полосу

else if (SL == HIGH & SR == HIGH) // ЧЕРНЫЙ — ЧЕРНЫЙ — СТОП

stopp (50);// СТОП

else // если измеренная дистанция меньше или равна минимальной — стоим

Первое, с чем сталкивается осваивающий Arduino новичок, это неприятное свойство функции delay() - блокирование выполнения программы. Множество примеров в интернете используют эту функцию, но практическое применение как-то намекает, что лучше без неё обойтись.

Как и положено начинающему, я изобрёл велосипед сделал свою реализацию неблокирующей задержки. Задача стояла так:

  • Обеспечить псевдомногозадачность, чтобы разные события происходили в своё время, со своими интервалами и не блокировали друг-друга.
  • Было удобно этим пользоваться.
  • Можно было оформить как библиотеку и легко включать в другие проекты без копипастов.
Подсмотрев, что большинство ардуинских библиотек сделаны с применением ООП, я тоже решил не выделываться и написал класс SmartDelay , который можно получить с гитхаба как zip для добавления в Arduino IDE или сделать git clone в ~/Arduino/libraries/

В результате получилось вот такое.

#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. Для этого нужно всего лишь научиться использовать функцию millis.


Следует понимать, что функция delay приостанавливает выполнение вашей программы Arduino, делая ее неспособной делать что-либо еще в этот период времени. Вместо того, чтобы приостанавливать всю нашу программу в течение определенного времени, мы научимся подсчитывать, сколько времени прошло до завершения действия. Это, конечно же, осуществляется с помощью функции millis() и нескольких переменных друзьями для хранения наших данных. Чтобы все было легко в понимании, мы начнем с первого обучающего скетча под названием «Blink», но в данном случае будем мигать светодиодом без задержки.


Начало этой программы такое же как и у любой другой стандартной программы для Arduino. Сначала идет объявление всех нужных переменных и линий ввода/вывода (например, линии 13 для светодиода). Здесь нам также потребуется переменная типа integer для хранения текущего состояния светодиода. Она будет установлена в LOW, поскольку начальное состояние светодиода – выключено. Затем объявим переменную «previousMillis» типа «unsigned long». В отличие от «int» длинные переменные без знака представляют собой 32 бита, это нужно для переменных, значение которых может стать очень большим – как потенциальное время, которое мы можем ожидать, до тех пор, пока не будет предпринято действие. Переменная previousMillis будет использоваться для хранения времени, когда последний раз мигал светодиод. Есть также тип «const long», он тоже 32-разрядный, но он не меняет значение, то есть это для констант (в данном случае для константы interval). Мы установим его на 1000 и используем в качестве времени паузы, измеряемого в миллисекундах.


const int ledPin = 13; // определяем вывод светодиода // Variables will change: int ledState = LOW; // ledState используется для определения состояния светодиода unsigned long previousMillis = 0; // сохранит время, когда последний раз обновлялся светодиод // constants won"t change: const long interval = 1000; // интервал мигания в мимлисекундах void setup() { // настройка линии 13 выхода pinMode(ledPin, OUTPUT); }

Затем мы переходим в бесконечный цикл. Помните, что вместо задержки мы хотим подсчитать, сколько времени прошло с момента нашего последнего мигания, в нашем случае 1000 мс. Если указанное время прошло, пришло время изменить состояние нашего светодиода.


Во-первых, мы установим беззнаковый длинный (unsigned long) «currentMillis» равный «millis ()», что определяет текущее время в миллисекундах. Это поможет нам выяснить, превысила ли разница между текущим временем и предыдущим временем 1000 мс. Для этого мы говорим: «Если текущее время минус предыдущее время, когда наш светодиод мигал, больше или равно нашему назначенному значению 1000 мс, сохраните время последнего мигания как предыдущее». Это поможет нам вспомнить, сколько времени прошло с момента последнего мигания в следующем обходе цикла. Затем, если состояние светодиода LOW, сделайте его HIGH, иначе сделайте его LOW. Затем с помощью команды digitalWrite выведите текущее состояние на светодиод.


void loop() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { // сохраняем время последнего изменения состояния светодиода previousMillis = currentMillis; // если светодиод выключен, то включим его, и наоборот if (ledState == LOW) { ledState = HIGH; } else { ledState = LOW; } // выход на светодиод digitalWrite(ledPin, ledState); } }

Функция millis() позволяет считать время, прошедшее с момента запуска текущей программы. Функция возвращает значение в формате «unsigned long» и позволяет считать значения до 50 дней с момента запуска программы. По прошествии этого времени отсчет начнется заново. Ниже приведен пример использования функции millis():

Unsigned long time; void setup(){ Serial.begin(9600); } void loop(){ Serial.print(«Время включения: «); time = millis(); // запомнить значение времени Serial.println(time); // отправка информации через последовательный порт delay(1000); }

В приведенном выше примере, каждую секунду в монитор порта будет отправляться информация о времени, которое прошло с момента запуска программы. Поскольку время измеряется в миллисекундах, то каждое последующие значение будет отличаться на 1000. Точность считывания зависит от стабильности кварцевого резонатора Arduino.

Функция micros()

Функция micros() является аналогом функции millis(), разница заключается в точности измерения. С помощью функции micros() мы получим время, прошедшее от запуска текущей программы в микросекундах. Счетчик подсчитанных микросекунд будет сброшен по истечении 70 минут. Ниже приведен пример использования функции micros():

Unsigned long time; void setup(){ Serial.begin(9600); } void loop(){ Serial.print(«Время с момента запуска: «); time = micros(); Serial.print(time); Serial.println(» мкс «); delay(1000); }

Так же, как и в примере с функцией millis(), здесь каждую секунду в монитор порта будет отправляться информация об измеренном времени, разница состоит только в том, что в данном случае время измеряется в микросекундах.

Функция delay()

Функция delay() позволяет приостановить выполнение текущей программы на указанное в параметре время. Синтаксис команды выглядит следующим образом:

//команды delay(500); //задержка на 0,5 сек //команды delay(1000); //задержка на 1с

Время указывается в миллисекундах (1 сек = 1000 мс). Данный параметр может иметь тип «unsigned long», который находится в диапазоне от 0 до 4294967295. Ниже пример использования команды delay():

#define ledPin 13 void setup() { pinMode(ledPin,13); } void loop() { digitalWrite(ledPin,HIGH); //включить LED delay(500); //подождать 500ms (0,5 сек) digitalWrite(ledPin,LOW); //выключить LED delay(1000); //подождать 1000 мс (1 сек) }

В приведенном выше примере, светодиод загорается на 0,5 секунды, затем гаснет на 1 секунду и так далее, пока питание Arduino не будет отключено.

Функция delayMicroseconds()

Функция delayMicroseconds() является разновидностью функции delay(). Разница заключается в количестве и точности отсчета времени. Функция delay() позволяет отсчитывать время с точностью до 1 миллисекунды, в то время как delayMicroseconds() с точностью до 1 микросекунды.

Значение, которое можно указать в параметре, находиться в диапазоне от 0 до 16383. Для более длинных временных интервалов следует использовать функцию delay() или несколько раз использовать delayMicroseconds().

#define outPin 8 void setup() { pinMode(outPin, OUTPUT); // контакт 8 как выход } void loop() { digitalWrite(outPin, HIGH); // контакт 8 высокое состояние delayMicroseconds(50); // пауза 50 микросекунд digitalWrite(outPin, LOW); // контакт 8 низкое состояние delayMicroseconds(50); // пауза 50 микросекунд }

Этот пример генерирует меандр с периодом 100 микросекунд и заполнением 50%.

Задержки в Ардуино играют очень большую роль. Без них не сможет работать даже самый простой пример Blink, который моргает светодиодом через заданный промежуток времени. Но большинство начинающих программистов мало знают о временных задержках и используют только Arduino delay, не зная побочных эффектов этой команды. В этой статье я подробно расскажу о временных функциях и особенностях их использования в среде разработки Arduino IDE.

В Arduino cуществует несколько различных команд, которые отвечают за работу со временем и паузы:

  • delay()
  • delayMicroseconds()
  • millis()
  • micros()

Они отличаются по точности и имеют свои особенности, которые стоит учитывать при написании кода.

Использование функции arduino delay

Синтаксис

Ардуино delay является самой простой командой и её чаще всего используют новички. По сути она является задержкой, которая приостанавливает работу программы, на указанное в скобках число миллисекунд. (В одной секунде 1000 миллисекунд.) Максимальное значение может быть 4294967295 мс, что примерно ровняется 50 суткам. Давайте рассмотрим простой пример, наглядно показывающий работу этой команды.

Void setup() { pinMode(13, OUTPUT); } void loop() { digitalWrite(13, HIGH); // подаем высокий сигнал на 13 пин delay(10000); // пауза 10000мс или 10 секунд digitalWrite13, LOW); // подаем низкий сигнал на 13 пин delay(10000); // пауза 10000мс или 10 секунд }

В методе setup прописываем, что пин 13 будет использоваться, как выход. В основной части программы сначала на пин подается высокий сигнал, затем делаем задержку в 10 секунд. На это время программа как бы приостанавливается. Дальше подается низкий сигнал и опять задержка и все начинается сначала. В итоге мы получаем, что на пин поочередно подается, то 5 В, то 0.

Нужно отчетливо понимать, что на время паузы с помощью delay работа программы приостанавливается, приложение не будет получать никаких данных с датчиков. Это является самым большим недостатком использования функции delay в Arduino. Обойти это ограничения можно с помощью прерываний, но об этом мы поговорим в отельной статье.

Пример delay с миганием светодиодом

Пример схемы для иллюстрации работы функции delay.
Можно построить схему со светодиодом и резистором. Тогда у нас получится стандартный пример – мигание светодиодом. Для этого на пин, который мы обозначили как выходной, необходимо подключить светодиод плюсовым контактом. Свободную ногу светодиода через резистор приблизительно на 220 Ом (можно немного больше) подключаем на землю. Определить полярность можно, если посмотреть на его внутренности. Большая чашечка внутри соединена с минусом, а маленькая ножка с плюсом. Если ваш светодиод новый, то определить полярность можно по длине выводов: длинная ножка – плюс, короткая – минус.

Функция delayMicroseconds

Данная функция является полным аналогом delay за исключением того, что единицы измерения у нее не миллисекунды, а микросекунды (в 1 секунде – 1000000 микросекунд). Максимальное значение будет 16383, что равно 16 миллисекундам. Разрешение равно 4, то есть число будет всегда кратно четырем. Кусочек примера будет выглядеть следующим образом:

DigitalWrite(2, HIGH); // подаем высокий сигнал на 2 пин delayMicroseconds(16383); // пауза 16383мкс digitalWrite(2, LOW); // подаем низкий сигнал на 2 пин delayMicroseconds(16383); // пауза 16383мкс

Проблема с delayMicroseconds точно такая же, как у delay – эти функции полностью «вешают» программу и она на некоторое время буквально замирает. В это время невозможна работа с портами, считывание информации с датчиков и произведение математических операций. Для мигалок данный вариант подходит, но опытные пользователи не используют её для больших проектов, так как там не нужны такие сбои. Поэтому, гораздо лучше использовать функции, описанные ниже.

Функция millis вместо delay

Функция millis() позволит выполнить задержку без delay на ардуино, тем самым обойти недостатки предыдущих способов. Максимальное значение параметра millis такое же, как и у функции delay (4294967295мс или 50 суток).

С помощью millis мы не останавливаем выполнение всего скетча, а просто указываем, сколько времени ардуино должна просто “обходить” именно тот блок кода, который мы хотим приостановить. В отличие от delay millis сама по себе ничего не останавливает. Данная команда просто возвращает нам от встроенного таймера микроконтроллера количество миллисекунд, прошедших с момента запуска. При каждом вызове loop Мы сами измеряем время, прошедшее с последнего вызова нашего кода и если разница времени меньше желаемой паузы, то игнорируем код. Как только разница станет больше нужной паузы, мы выполняем код, получаем текущее время с помощью той же millis и запоминаем его – это время будет новой точкой отсчета. В следующем цикле отсчет уже будет от новой точки и мы опять будем игнорировать код, пока новая разница millis и нашего сохраненного прежде значения не достигнет вновь желаемой паузы.

Задержка без delay с помощью millis требует большего кода, но с ее помощью можно моргать светодиодом и ставить на паузу скетч, не останавливая при этом систему.

Вот пример, наглядно иллюстрирующий работу команды:

Unsigned long timing; // Переменная для хранения точки отсчета void setup() { Serial.begin(9600); } void loop() { /* В этом месте начинается выполнение аналога delay() Вычисляем разницу между текущим моментом и ранее сохраненной точкой отсчета. Если разница больше нужного значения, то выполняем код. Если нет - ничего не делаем */ if (millis() - timing > 10000){ // Вместо 10000 подставьте нужное вам значение паузы timing = millis(); Serial.println ("10 seconds"); } }

Сначала мы вводим переменную timing, в ней будет храниться количество миллисекунд. По умолчанию значение переменной равно 0. В основной части программы проверяем условие: если количество миллисекунд с запуска микроконтроллера минус число, записанное в переменную timing больше, чем 10000, то выполняется действие по выводу сообщения в монитор порта и в переменную записывается текущее значение времени. В результате работы программы каждые 10 секунд в монитор порта будет выводиться надпись 10 seconds. Данный способ позволяет моргать светодиодом без delay.

Функция micros вместо delay

Данная функция так же может выполнить задержку, не используя команду delay. Она работает точно так же, как и millis, но считает не миллисекунды, а микросекунды с разрешением в 4мкс. Её максимальное значение 4294967295 микросекунд или 70 минут. При переполнении значение просто сбрасывается в 0, не забывайте об этом.

Резюме

Платформа Arduino предоставляет нам несколько способов выполнения задержки в своем проекте. С помощью delay вы можете быстро поставить на паузу выполнение скетча, но при этом заблокируете работу микроконтроллера. Использование команды millis позволяет обойтись в ардуино без delay, но для этого потребуется чуть больше программировать. Выбирайте лучший способ в зависимости от сложности вашего проекта. Как правило, в простых скетчах и при задержке меньше 10 секунд используют delay. Если логика работы сложнее и требуется большая задержка, то вместо delay лучше использовать millis.