Arduino:Хакинг/Почему в работе с Arduino необязательно всегда использовать функцию delay()

Материал из Онлайн справочника
Перейти к навигации Перейти к поиску

Перевод: Максим Кузьмин (Cubewriter) Контакты:</br>* Skype: cubewriter</br>* E-mail: cubewriter@gmail.com</br>* Максим Кузьмин на freelance.ru
Проверка/Оформление/Редактирование: Мякишев Е.А.


Pixel Art Mini Meow Animated.gif Черновик


Почему в работе с Arduino необязательно всегда использовать функцию delay()[1]

Первый раз работая с Arduino, вы, возможно, сделали что-то вроде этого:

  • Подключили светодиод к Arduino
  • Загрузили скетч «Blink», каждую секунду включающий/выключающий этот светодиод

Этот пример – «Привет, мир!» из мира скетчей Arduino. Он показывает, как при помощи всего нескольких строчек кода создать нечто, способное выполнять задачи в реальном мире.

Blink-sketch.jpg

В этом примере используется функция delay(). С ее помощью задаются интервалы между включением/выключением светодиода.

Но дело вот в чем. Хотя delay() удобна и хорошо работает с простыми скетчами, при создании более-менее серьезных проектов от ее использования лучше воздержаться. И вот почему.

Как работает функция delay()

Функция delay() работает очень просто.

Ее единственным аргументом является целочисленное значение, и оно означает время (в миллисекундах), которое скетч должен подождать перед тем, как перейти к следующей строчке кода.

Таким образом, если вписать в скетч delay(1000), это остановит работу Arduino на 1 секунду.

Функция delay() – это блокирующая функция. Блокирующие функции не дают скетчу делать ничего, кроме одной единственной задачи, которая выполняется в данный момент.

То есть если вы хотите, чтобы ваш скетч выполнял одновременно несколько задач (к примеру, если он постоянно считывает и сохраняет данные, приходящие через входные контакты), от использования delay() нужно попросту отказаться. К счастью, ее есть чем заменить.

Функция millis() спешит на помощь

Будучи вызванной, функция millis() возвращает количество миллисекунд, прошедших с запуска скетча.

Окей. Но чем она полезна?

При помощи millis() и небольших расчетов вы можете определять временные интервалы, не блокируя остальные строчки кода.

Код ниже демонстрирует, как создать скетч-пример «Blink», но с millis() вместо delay(). Он включает светодиод, 1000 миллисекунд держит его во включенном состоянии, а потом выключает. Но другой код при этом не блокируется.

 1 /* 
 2 Пример «Blink» без функции delay()
 3 Отсюда: arduino.cc/en/Tutorial/BlinkWithoutDelay
 4 */
 5 
 6 // константы – это значения, которые не меняются;
 7 // задаем константу, чтобы задать номер контакта:
 8 const int ledPin =  13;  // номер контакта со светодиодом
 9 
10 // переменные – это значения, которые меняются: 
11 int ledState = LOW;      // для хранения статуса светодиода
12 
13 // как правило, для переменных, хранящих данные о времени, 
14 // тип данных «unsigned long» не используется;
15 // но в данном случае значение будет очень быстро увеличиваться
16 // и не поместится в типе данных «int»:
17 unsigned long previousMillis = 0;  // для хранения данных о том,
18                                    // когда светодиод был переключен
19                                    // в последний раз
20 
21 // значения в константах не меняются:
22 const long interval = 1000;           // интервал для мигания (мс) 
23 
24 void setup() {
25   // выставляем цифровой контакт в режим OUTPUT: 
26   pinMode(ledPin, OUTPUT);
27 }
28 
29 void loop() {
30   // здесь пишем код, выполнение которого будет постоянно повторяться;
31 
32   // проверяем, пришло ли время моргнуть светодиодом;
33   // оно пришло, если разница между текущим временем и временем,
34   // когда произошло последнее моргание, больше интервала,
35   // который вы задали в константе «interval»:
36   unsigned long currentMillis = millis();
37 
38   if (currentMillis - previousMillis >= interval) {
39     // сохраняем время, когда вы в последний раз мигнули светодиодом: 
40     previousMillis = currentMillis;
41 
42     // если светодиод выключен, включаем его, и наоборот: 
43     if (ledState == LOW) {
44       ledState = HIGH;
45     } else {
46       ledState = LOW;
47     }
48 
49     // задаем статусу светодиода значение из переменной «ledState»:
50     digitalWrite(ledPin, ledState);
51   }
52 }

Этот скетч можно найти по этой ссылке. В его основе лежат очень простые расчеты: вы просто вычитаете из текущего времени (currentMillis) время, когда светодиод был переключен в последний раз (previousMillis). Если остаток будет выше заданного интервала (в данном случае – 1000 миллисекунд), скетч обновит previousMillis на текущее время, а затем либо включит, либо выключит светодиод.

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

Таким образом, вы можете добавить в блок loop() какие-то другие задачи, и скетч будет по-прежнему мигать светодиодом раз в секунду.

Так какую функцию использовать?

Итак, мы научились двум разным способам того, как обращаться со временем в скетчах Arduino. Если delay() особо никаких усилий не требует, то millis() нужны дополнительные расчеты, но зато ваши скетчи будут многозадачными.


См.также

Внешние ссылки