Функции времени

Задержки


Простейшей с точки зрения использования функцией времени является задержка: программа “зависает” внутри функции задержки и ожидает указанное время. Задержка позволяет очень удобно и наглядно организовать работу простой “однозадачной” программы, у нас есть два варианта задержек:

  • delay(time)
    • Задержка на указанное количество миллисекунд (мс). 1 секунда = 1’000 мс.
    • time принимает тип данных unsigned long и может приостановить выполнение на срок от 1 до 4 294 967 295 мс (~50 суток) с разрешением 1 мс.
    • Работает на системном таймере, поэтому не работает внутри прерывания и при отключенных прерываниях.
  • delayMicroseconds(time)
    • Задержка на указанное количество микросекунд (мкс). 1 секунда = 1’000’000 мкс.
    • time принимает тип данных unsigned int и может приостановить выполнение на срок от 4 до 16383 мкс (да, меньше чем максимум для этого типа данных) с разрешением 4 мкс.
    • Работает не на таймере, а на пропуске тактов процессора, поэтому может работать в прерывании и при отключенных прерываниях.
    • Иногда не совсем корректно работает с переменными, поэтому нужно стараться использовать константы (const или просто число).
    • Часто используется в библиотеках для эмуляции цифровых интерфейсов связи.

Задержки использовать очень просто:

void setup() {}

void loop() {
  // что-то выполнить
  delay(500); // подождать полсекунды
}

Мышление “задержками” – главная проблема новичков. Организовать работу сложной программы при помощи задержки – невозможно, поэтому дальше рассмотрим более полезные инструменты.

Функция yield()


Разработчики Arduino позаботились о том, чтобы функция delay() не просто блокировала выполнение кода, но и позволяла выполнять другой код во время этой задержки. Данный “костыль” получил название yield() и работает следующим образом: если объявить функцию

void yield() {
  // ваш код
}

то расположенный внутри неё код будет выполняться во время работы любой задержки delay() в программе! Это решение хоть и кажется нелепым, но в то же время позволяет быстро и без написания лишних костылей и таймеров реализовать пару параллельно выполняющихся задач. Это вполне соответствует идеологии Arduino – максимально простая и быстрая разработка прототипа. Рассмотрим простой пример: стандартный мигающий светодиод, но с опросом кнопки:

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  digitalWrite(13, 1);
  delay(1000);
  digitalWrite(13, 0);
  delay(1000);
}

void yield() {
  // а тут можно опрашивать кнопку
  // и не пропустить нажатия из за delay!
}
Данный трюк работает на AVR Arduino, на esp8266 его нет

Функции счёта времени


Данные функции возвращают время, прошедшее с момента запуска программы, так называемый аптайм (англ. uptime). Таких функций у нас две:

  • millis()миллисекунды, тип unsigned long, от 1 до 4 294 967 295 мс (~50 суток), разрешение 1 мс. После “переполнения” отсчёт начинается с нуля.
  • micros()микросекунды, тип unsigned long, от 4 до 4 294 967 295 мкс (~70 минут), разрешение 4 мкс. После “переполнения” отсчёт начинается с нуля.

Обе эти функции:

  • Работают в “фоне” на прерываниях таймера
  • Продолжают работать внутри задержек delay() и delayMicroseconds(), т.е. ход времени не сбивается
  • Прекращают считать время, пока отключены прерывания (через noInterrupts() или cli())
  • Не меняют своего значения внутри обработчика прерывания (внешнего, таймера), потому что прерывания сами отключаются на время обработки
  • Можно вызывать внутри обработчика прерывания

Эти функции позволяют организовать программу практически любой сложности с любым количеством параллельно выполняющихся по таймеру задач. Подробнее об этом поговорим в уроке про многозадачность.

Раньше здесь было рассказано про таймер на millis(). Информация переехала в урок про многозадачность.

millis() в часы и секунды


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

  uint32_t sec = millis() / 1000ul;      // полное количество секунд
  int timeHours = (sec / 3600ul);        // часы
  int timeMins = (sec % 3600ul) / 60ul;  // минуты
  int timeSecs = (sec % 3600ul) % 60ul;  // секунды

Видео


Полезные страницы


4.7/5 - (23 голоса)
Подписаться
Уведомить о
guest

57 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии