ARCAdaptor

Всё в твоих руках

Блеск И Нищета delay()

Ни для кого не секрет, что Arduino и подобные платы – отличный старт, для желающих поближе познакомиться с микроконтроллерами, программированием и разработкой устройств.

Среда Arduino предоставляет действтительно интуитивно понятные средства для того, чтобы сосредоточиться на главном.

Где же уловка ? Она есть и не одна.

Сегодня мы попробуем развенчать функцию “delay”, столь любимую новичками.

Рассмотрим простой код, прямо из примера, поставляемого со средой Arduino.

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

Что с ним не так ?

Вроде всё хорошо.

  • Зажигаем лампочку
  • Ждем
  • Гасим
  • Ждем

Намылить-смыть-повторить...

А теперь представьте, что микроконтроллер не просто “подмигивает”, но ещё и выполняет какую-то полезную нагрузку – например, общается с внешним миром – ждет ввода данных или замыкания контакта.

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

И что же делать ?

Избавляться от delay. Для этого в Arduino-мире есть довольно простой и достаточно элегантный ход.

Существует оператор millis(), который возвращает количество миллисекунд, прошедших после старта программы. Возвращаемый тип – unsigned long. То есть переполнение случится где-то дней через 50 после старта микропрограммы.

Теперь рассмотрим немного измененный код. К счастью, он тоже включен в примеры и называется “BlinkWithoutDelay”

int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);      
}

void loop()
{
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

Что происходит здесь ?

  • Делаем “зарубку”
  • Проверяем, не прошла ли одна секунда от зарубки
  • Если да, меняем состояние светодиода и делаем новую зарубку
  • Намылить-смыть-повторить

Несмотря на то, что код изрядно “поправился” работает он более корректно.

К сожалению, мир не идеален и масса готовых компонент всё также использует этот самый delay. Но, теперь мы предупреждены и знаем, что можно посмотреть на предмет внезапно появившихся “глюков”.

Кстати, данный текст навеян историей из реальной жизни – при разработке front-end для управления интернет радио “весь цинизм” при чтении данных из UART и случился – и потеря названия трека было наименьшей из проблем.

И вот ведь как получается – даже в таких далеких от микроконтроллеров вещей, как JavaScript. Там тоже всё исполняется в один поток, но есть приёмы, как это обойти – например, механизм callback'ов.

Итак, delay – обращаться с большой осторожностью и не злоупотреблять без обоснованной необходимости. Удачных проектов!

comments powered by Disqus