
Разглядывая примеры в 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”»
Пример хороший, взял на вооружение…
Но.
Что будет, если счетчик дойдет до 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;Думаю быстрее будет так:
Имелось в виду наверное =! (присвоить инвертированное значение), а не != (логическое неравенство).
Собственно всю конструкцию:
if (value == LOW) value = HIGH; else value = LOW; digitalWrite(ledPin, value);можно (и нужно) заменить на:
В результате получаем более краткий скетч, и при компиляции экономим с десяток байт в дуине. Да и очевидно операнд сравнения схавает несколько дополнительных тактов контроллера. В примере не критично, но в большом коде важная вещь.
ЗЫ я не спец, дуину купил день назад, вот знакомлюсь 🙂
И кстати, просвятите, зачем объявлять
, если без таких объявлений код тоже всегда работает? Я правда не вижу подвоха, расскажите для общего развития.
Функция pinMode(ledPin, OUTPUT) равносильна DDRx |= (1 << ledPin).
DDRx (Data Direction Register) — направление работы порта х. Вместо x подставляется название порта (А, B, C…). Если соответствующий пину бит в этом регистре равен 0 (а это значение по умолчанию), то пин работает как ввод, если 1 — как вывод. Когда выставляешь единицу, то к пину подключается драйвер, который позволяет пину отдавать ток до 20 мА.
Да, код работает и без этой функции, но вы можете заметить, что в этом случае светодиод светится крайне тускло, а некоторые отдельные могут вообще не светиться. Да, ток есть, но он очень маленький.