Разберем на практическом примере почему использование оператора delay() в своих программах ну.... такое себе удовольствие....
Возьмем любую Arduino-подобную платформу, кнопку и светодиод с токоограничивающим резистором.
Попробуем решить простую параллельную задачу:
- мигаем встроенным светодиодом 1 раз в секунду
- при нажатой кнопке BT1 светодиод L1 светится, при отпущенной гаснет
Для мигания встроенным светодиодом возьмем код из примера, с которого обычно начинается обучение Arduino и добавим строчку которая будет зажигать светодиод L1 при нажатии на кнопку.
Операторы в цикле loop () выполняются последовательно, а поскольку оператор delay() останавливает выполнение программы на заданное в параметре функции количество миллисекунд строка 23 в которой происходит копирование состояния кнопки фактически будет опрашиваться один раз в две секунды. (нажав/отпустив кнопку придется ждать до 2-х секунд прежде чем программа сможет зажечь/погасить светодиод). Даже при сборке простейших часов такой подход будет не приемлем - пока на дисплее мигают точки поуправлять таким с помощью кнопок (например чтобы установить время) будет проблематично.
Классический пример решения данной задачи предлагает ресурс с официальной документацией по Arduino в статье Blink Without Delay и его всегда можно использовать его в качестве шаблона.
Всю статью я сюда транслировать не буду, кому интересно можете ознакомиться с ней самостоятельно - там много англицких букаф, которые можно перевести гугл-переводчиком.
Мне столько кода для решения задачи моргания двоеточием в часах писать лень - попробуем воспользоваться фишками языка С и затолкнуть все в пару строк кода ;-)
Код который переключает светодиод 1 раз в секунду получился даже короче чем при использовании оператора delay() и не блокирует программу.
digitalWrite(ledBlinking, (millis() / 1000) % 2);
Как это работает?
Встроенная функция millis() возвращает значение равное количеству миллисекунд, прошедших с момента включения или перезагрузки Arduino.
Это число мы делим на 1000 (получается время в секундах)
Оператор % берёт остаток от деления на 2 этого промежуточного результата.
Четные числа на 2 делятся без остатка - то есть получается 0
Нечетные числа делятся на 2 с остатком 1
Таким образом, итоговое значение будет то 0, то 1, переключаясь каждую секунду. Это значение мы и записываем с помощью функции digitalWrite в цифровой выход 13 на котором находится встроенный светодиод.
Фактически мы пишем каждую итерацию цикла то 0 то 1. Эта метода не совсем подойдет если код необходимо выполнять каждую секунду, но только один раз. Поэтому добавим в нашу программу еще пару строчек:
Данный код переключает светодиод, и печатает в COM порт "1 SEС" каждую секунду при этом не блокируя опрос кнопки.
Вот такой вот он волшебный оператор % остаток от деления. Его можно использовать для многих практических решений.
Если хотите эффективно работать с машиной - приходится думать как машина, а если Вам интересно как можно использовать аппаратный таймер и при этом не развалить работу библиотек и не потерять в функциональности среды разработки Arduino IDE, читайте мою вторую статью где аналогичная задача решена с помощью прерывания на Timer 0.
Arduino - прерывайся по таймеру правильно
Всем удачи!