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

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

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* 
Пример «Blink» без функции delay()
Отсюда: arduino.cc/en/Tutorial/BlinkWithoutDelay
*/

// константы – это значения, которые не меняются;
// задаем константу, чтобы задать номер контакта:
const int ledPin =  13;  // номер контакта со светодиодом

// переменные – это значения, которые меняются: 
int ledState = LOW;      // для хранения статуса светодиода

// как правило, для переменных, хранящих данные о времени, 
// тип данных «unsigned long» не используется;
// но в данном случае значение будет очень быстро увеличиваться
// и не поместится в типе данных «int»:
unsigned long previousMillis = 0;  // для хранения данных о том,
                                   // когда светодиод был переключен
                                   // в последний раз

// значения в константах не меняются:
const long interval = 1000;           // интервал для мигания (мс) 

void setup() {
  // выставляем цифровой контакт в режим OUTPUT: 
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // здесь пишем код, выполнение которого будет постоянно повторяться;

  // проверяем, пришло ли время моргнуть светодиодом;
  // оно пришло, если разница между текущим временем и временем,
  // когда произошло последнее моргание, больше интервала,
  // который вы задали в константе «interval»:
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // сохраняем время, когда вы в последний раз мигнули светодиодом: 
    previousMillis = currentMillis;

    // если светодиод выключен, включаем его, и наоборот: 
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // задаем статусу светодиода значение из переменной «ledState»:
    digitalWrite(ledPin, ledState);
  }
}

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

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

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

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

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

См.также

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