Программирование Arduino/CraftDuino — Blink без delay



Разглядывая примеры в Arduino IDE, Вы, возможно, обратили внимание на скетч
BlinkWithoutDelay (Examples – Digital — BlinkWithoutDelay)

Этот скетч интересен тем, что он выполняет задачу включения/выключения светодиода без функции delay(). Это означает, что мы можем «одновременно» с миганием светодиода выполнять ещё какую-нибудь интересную задачу 🙂

Как же это реализовано? Как обычно – всё достаточно просто 🙂
Вместо обычного delay() используется millis(), которая, как мы помним, возвращает нам число миллисекунд, с момента исполнения Arduino/Freeduino текущей программы.

Итак, сам скетч:

/* Blink without Delay – мигаем без задержки :)
 *
 * Включение/выключение светодиода, подключённого к  
 * цифровому порту, без использования функции delay().  
 * Это означает, что «одновременно» можно выполнять другой код, 
 * без прерывания на мигание светодиодом :)
 *
 * http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 */

int ledPin = 13;           // наш светодиод на 13 порту
int value = LOW;           // предыдущее состояние светодиода
long previousMillis = 0;   // здесь будет храниться время последнего изменения состояния светодиода 
long interval = 1000;      // интервал мигания в миллисекундах

void setup()
{
  pinMode(ledPin, OUTPUT); // устанавливаем порт, как выход
}

void loop()
{
  // здесь можно поместить свой код для постоянного выполнения

  // проверяем – настало ли время изменить состояние светодиода
  // для этого берём разность между текущим временем и 
  // временем последнего изменения состояния светодиода,   
  // а затем сверяем полученный интервал с нужным интервалом 
  // мигания – если больше – значит пора мигать ;)
  if (millis() - previousMillis > interval) {
    previousMillis = millis();   // запоминаем текущее время
    // если светодиод был выключен – включаем и наоборот :)
    if (value == LOW)
      value = HIGH;
    else
      value = LOW;

    digitalWrite(ledPin, value);
  }
}

Вот собственно и всё 🙂

Чуть более усложнённый пример использования millis() для «одновременного» выполнения нескольких задач можно посмотреть на официальном сайте ардуино:
http://www.arduino.cc/playground/Code/Stopwatch

По теме
Программирование Arduino — Работа со временем
Библиотека TimerOne


5 комментариев на «“Программирование Arduino/CraftDuino — Blink без delay”»

  1. Пример хороший, взял на вооружение…
    Но.
    Что будет, если счетчик дойдет до 4294967295 и обнулится, а значение previousMillis будет равняться к примеру 4294967000?
    Или данное выражение:
    (millis() — previousMillis > interval)
    не является как (1223 — 4294967000 = -4294965777 > 1000)
    ?

    Извините, если глупый вопрос, я тут новичек.

    • Вопрос не глупый. Так и будет: переворот счетчика через 0 с последующей некорректной работой.
      Только произойдет это через ~50 дней. (На самом деле в приведенном выше коде некорректность — необходимо использовать беззнаковые переменные, чтобы достичь этого максимального периода).
      Если ваш скетч должен функционировать более продолжительное время, то надо вставить проверку на переворот. Например так:

      unsigned long tm = millis();
      unsigned long elapsed = (tm >= previousMillis) ? tm - previousMillis : 0xFFFFFFFF - previousMillis + tm + 1;
      if( elapsed > interval ) {
        .......
      }
      
    • Имелось в виду наверное =! (присвоить инвертированное значение), а не != (логическое неравенство).

      Собственно всю конструкцию:

      if (value == LOW)
            value = HIGH;
          else
            value = LOW;
      
          digitalWrite(ledPin, value);

      можно (и нужно) заменить на:

      digitalWrite(ledPin, value=!value);

      В результате получаем более краткий скетч, и при компиляции экономим с десяток байт в дуине. Да и очевидно операнд сравнения схавает несколько дополнительных тактов контроллера. В примере не критично, но в большом коде важная вещь.

      ЗЫ я не спец, дуину купил день назад, вот знакомлюсь 🙂
      И кстати, просвятите, зачем объявлять

      pinMode(ledPin, OUTPUT);

      , если без таких объявлений код тоже всегда работает? Я правда не вижу подвоха, расскажите для общего развития.

    • Функция pinMode(ledPin, OUTPUT) равносильна DDRx |= (1 << ledPin).
      DDRx (Data Direction Register) — направление работы порта х. Вместо x подставляется название порта (А, B, C…). Если соответствующий пину бит в этом регистре равен 0 (а это значение по умолчанию), то пин работает как ввод, если 1 — как вывод. Когда выставляешь единицу, то к пину подключается драйвер, который позволяет пину отдавать ток до 20 мА.
      Да, код работает и без этой функции, но вы можете заметить, что в этом случае светодиод светится крайне тускло, а некоторые отдельные могут вообще не светиться. Да, ток есть, но он очень маленький.

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Arduino Bluetooth CraftDuino DIY Google IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение