Библиотека TimerOne


Когда программируешь для Arduino, иногда бывает нужно периодически выполнять какие-либо действия через определённые интервалы времени — скажем, 100 раз в секунду; или хочется иметь ШИМ с большим разрешением или другой частотой, чем позволяет стандартная функция analogWrite(), или вдруг хочется выполнять какую-то работу параллельно, а вездесущий delay() всё портит. Вот тут-то может пригодиться библиотека TimerOne, которую я вам в двух словах опишу.

Эта библиотека позволяет использовать в своих целях один из таймеров в МК AVR, установленных на платах Arduino. Аппаратных таймеров в ATmega168 и ATmega328 имеется 3 штуки (в ATmega1280 и ATmega2560 их 6), и называются они Timer0, Timer1 и Timer2. Все они используются для ШИМ в функции analogWrite(), но разрядность такой ШИМ ограничена наименьшей разрядностью таймеров, а Timer0 и Timer2 — 8-разрядные, поэтому максимальное значение, которое воспринимает analogWrite() — 255. Но Timer1-то 16-разрядный! Чтобы задействовать мощь этого таймера, один добрый человек и написал библиотеку TimerOne. Скачаем библиотеку отсюда, установим и посмотрим, какие методы доступны в библиотеке:

void initialize(long period = 1000000)

Этот метод нужно вызвать для инициализации таймера, прежде чем вызывать какие-либо другие. По умолчанию задаётся интервал срабатывания в 1 секунду, но можно указать свой в микросекундах. Минимальный доступный интервал — 1 микросекунда.
После инициализации пины 9 и 10 на Arduino (11 и 12 на Arduino Mega) смогут использоваться библиотекой для ШИМ, но остановится analogWrite()’овская ШИМ на этих пинах, если таковая была задействована до вызова initialize(). Пока работаете с библиотекой TimerOne, для перечисленных выше пинов analogWrite() не вызывайте, и наоборот.

void setPeriod(long period)

Устанавливает интервал срабатывания таймера в микросекундах. Минимальный интервал равен 1 мкс (соответственно, максимальная частота — 1 МГц), максимальный — 8388480 мкс (около 8.4 с).

void pwm(char pin, int duty, long period = -1)

Включает ШИМ на указанном пине. Параметр duty указывает заполнение ШИМ, которое может меняться от 0 до 1023. Да-да, не вся «16-битность» таймера задействована, увы. Параметр period позволяет задать интервал срабатывания, но учтите, что период задаётся не для отдельного пина, а вообще для таймера. То есть, если вы укажете период для 9го пина, то повлияет и на 10й. Неочевидно, да.
Ещё один момент — можно указывать в качестве номера пина 1 и 2 вместо 9 и 10, но здесь тоже нужно быть внимательным: если указать 1 или 2, то это сработает и на Arduino Mega (пины 11 и 12), и на простой Arduino (пины 9 и 10), но если указать 9 или 10, то сработает только на Arduino… Брр, и что только автор библиотеки курил?

void setPwmDuty(char pin, int duty)

Устанавливает заполнение ШИМ для указанного пина, если ШИМ на нём уже включена.

void disablePwm(char pin)

Выключает ШИМ на выбранном пине.

void attachInterrupt(void (*isr)(), long period = -1)

Устанавливает функцию (обработчик прерывания), которая будет вызываться по завершении установленного интервала таймера. Такая функция должна иметь вид:

void xxxxx()
{
 ...
}

Параметр period, как обычно, задаёт интервал срабатывания (и, как всегда, для всего таймера). Нужно быть осторожным, и не выполнять слишком много кода в обработчике, иначе главный цикл (loop) может вообще никогда не получить управления. Если задать период в 1 мкс, то такой исход практически гарантирован, т.к. за это время AVR с кварцем в 16 МГц (как на Arduino) успеет выполнить инструкций где-то на десяток тактов — то есть, сложить пару-тройку чисел, и даже на один digitalWrite() этого времени не хватит. В общем, не советую устанавливать обработчик для периодов меньше 100 мкс (0.1 мс), если вы не рассчитали по тактам время выполнения обработчика и не уверены на 100%, что времени хватит (:

void detachInterrupt()

Отключает обработчик прерывания.

void start()

Запускает таймер, если он был остановлен.

void stop()

Останавливает таймер.

Применение всему этому придумать несложно: первое, что пришло в голову — мигалка двумя светодиодами не то что без delay(), а вообще без нашего участия. Светодиоды будут на пинах 9 и 10:

#include <TimerOne.h>

void setup()
{
  Timer1.initialize(); // 1 секунда по умолчанию - то, что надо
  Timer1.pwm(9, 512); // полсекунды светимся (512 / 1024), на полсекунды гасим

  pinMode(10, OUTPUT);
  Timer1.attachInterrupt(Timer1_action);
}

void Timer1_action()
{
  // LED секунду горит, секунду - нет
  digitalWrite(10, !digitalRead(10));
}

void loop()
{
  // пока мы тут что-нибудь делаем, светодиоды мигают сами по себе
}

Ну, а что ещё можно сделать, используя TimerOne, зависит уже от вашей фантазии.

Ссылки
http://www.arduino.cc/playground/Code/Timer1
Timer One Library for Arduino

По теме
Программирование Arduino — аналоговый ввод/вывод
ШИМ — Широтно-Импульсная Модуляция
Программирование Arduino — прерывания
Программирование Arduino/CraftDuino — Blink без delay


6 комментариев на «“Библиотека TimerOne”»

    • Это не таймер, а фигня. Эта библиотека __совсем__ не использует аппаратные таймеры.

      The algorithm looks like this:

      lastMillis = 0
      forever do:
          if (millis() - lastMillis > n)
              call the particular piece of code
              lastMillis = millis()
          end
      end

  1. Минимальный интервал равен 1 мкс (соответственно, максимальная частота — 1 МГц), максимальный — 8388480 мкс (около 8.4 с).

    У меня stop() работает странно… если в лупе просто поставить стоп, то светодиод всёравно
    будет моргать, только время увеличивается в несколько раз +- (>10)
    т.е. если период 0,1с, то со стоп получится 1,28с
    если период 1с, то со стоп получится 14,2с
    если период 5с, то со стоп получится 78,4c
    если период 10с, то со стоп получится 132с
    Примерно так… почему не знаю…

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

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
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение