CraftDuino v2.0
  • - это CraftDuino - наш вариант полностью Arduino-совместимой платы.
  • CraftDuino - настоящий конструктор, для очень быстрого прототипирования и реализации идей.
  • Любая возможность автоматизировать что-то с лёгкостью реализуется с CraftDuino!
Просто добавьте CraftDuino!

Программирование 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() для «одновременного» выполнения нескольких задач можно посмотреть на официальном сайте ардуино:
www.arduino.cc/playground/Code/Stopwatch

По теме:
Программирование Arduino — Работа со временем
Библиотека TimerOne
  • +2
  • 11 декабря 2010, 14:11
  • admin

Комментарии (5)

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

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

PutinW

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

unsigned long tm = millis();
unsigned long elapsed = (tm >= previousMillis) ? tm - previousMillis : 0xFFFFFFFF - previousMillis + tm + 1;
if( elapsed > interval ) {
  .......
}
avatar

avor

  • 13 декабря 2010, 11:54
+
0
if (value == LOW)
      value = HIGH;
    else
      value = LOW;


Думаю быстрее будет так:
value != value;


avatar

v1ctor

  • 12 марта 2011, 21:03
+
0
Имелось в виду наверное =! (присвоить инвертированное значение), а не != (логическое неравенство).

Собственно всю конструкцию:
if (value == LOW)
      value = HIGH;
    else
      value = LOW;

    digitalWrite(ledPin, value);

можно (и нужно) заменить на:
digitalWrite(ledPin, value=!value);

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

ЗЫ я не спец, дуину купил день назад, вот знакомлюсь :)
И кстати, просвятите, зачем объявлять
pinMode(ledPin, OUTPUT);
, если без таких объявлений код тоже всегда работает? Я правда не вижу подвоха, расскажите для общего развития.
avatar

DELme

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

nes

  • 8 октября 2014, 04:11

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.