Arduino таймеры: Arduino и прерывания таймера / Хабр

Содержание

Прерывания и многозадачность в Arduino

#include <Servo.h>

class Flasher

{

// Переменные-участники класса устанавливаются при запуске

int ledPin; // Номер контакта со светодиодом

long OnTime; // длительность ВКЛ в мс

long OffTime; // длительность ВЫКЛ в мс

 

// Контроль текущего состояния

int ledState; // устанавливает текущее состояние светодиода

unsigned long previousMillis; // время последнего обновления состояния светодиода

 

// Конструктор — создает объект Flasher, инициализирует переменные-участники и состояние

public:

Flasher(int pin, long on, long off)

{

  ledPin = pin;

  pinMode(ledPin, OUTPUT);

 

  OnTime = on;

  OffTime = off;

 

  ledState = LOW;

  previousMillis = 0;

}

 

void Update(unsigned long currentMillis)

{

  if((ledState == HIGH) && (currentMillis — previousMillis >= OnTime))

  {

   ledState = LOW; // ВЫКЛ

   previousMillis = currentMillis; // Запомнить время

   digitalWrite(ledPin, ledState); // Обновить состояние светодиода

  }

  else if ((ledState == LOW) && (currentMillis — previousMillis >= OffTime))

  {

   ledState = HIGH; // ВКЛ

   previousMillis = currentMillis; // Запомнить время

   digitalWrite(ledPin, ledState); // Обновить состояние светодиода

  }

}

};

 

class Sweeper

{

Servo servo; // объект servo

int pos; // текущее положение сервопривода

int increment; // определяем увеличение перемещения на каждом интервале

int updateInterval; // определяем время между обновлениями

unsigned long lastUpdate; // определяем последнее обновление положения

 

public:

Sweeper(int interval)

{

  updateInterval = interval;

  increment = 1;

}

void Attach(int pin)

{

  servo. attach(pin);

}

void Detach()

{

  servo.detach();

}

void reset()

{

  pos = 0;

  servo.write(pos);

  increment = abs(increment);

}

 

void Update(unsigned long currentMillis)

{

  if((currentMillis — lastUpdate) > updateInterval) //время обновиться

  {

   lastUpdate = millis();

   pos += increment;

   servo.write(pos);

   if ((pos >= 180) || (pos <= 0)) // инициализируем конец вращения

   {

    // инициализируем обратное направление

    increment = -increment;

   }

  }

}

};

 

Flasher led1(11, 123, 400);

Flasher led2(12, 350, 350);

Flasher led3(13, 200, 222);

 

Sweeper sweeper1(25);

Sweeper sweeper2(35);

 

void setup()

{

sweeper1.Attach(9);

sweeper2.Attach(10);

 

// Timer0 уже используется millis() — прерываемся примерно посередине и вызываем ниже функцию «Compare A»

OCR0A = 0xAF;

TIMSK0 |= _BV(OCIE0A);

 

pinMode(2, INPUT_PULLUP);

attachInterrupt(0, Reset, FALLING);

}

 

void Reset()

{

sweeper1. reset();

sweeper2.reset();

}

 

// Прерывание вызывается один раз в миллисекунду, ищет любые новые данные, и если нашло, сохраняет их

SIGNAL(TIMER0_COMPA_vect)

{

unsigned long currentMillis = millis();

sweeper1.Update(currentMillis);

 

// if(digitalRead(2) == HIGH)

{

  sweeper2.Update(currentMillis);

  led1.Update(currentMillis);

}

 

led2.Update(currentMillis);

led3.Update(currentMillis);

}

 

void loop()

{

}

timers — Таймеры Arduino. Как они работают

Сначала я займусь тем, что

TCCR0B=TCCR0B&0b11111000|0x01;

означает с чистой точки зрения программирования:

Давайте разложим его на части:

TCCR0B = TCCR0B & 0b11111000 | 0x01;

TCCR0B is a register. It could be any variable really — it’s just «a value» in this context. Just because it happens to control one of the timers is besides the point.

0b11111000 is a binary representation of a value. It’s the same as the hexadecimal number 0xF8. F is 15. 15 in binary is 1111. 8 is 8 in both hexadecimal and decimal. 8 in binary is 1000. Put the two together and you have 11111000. Incidentally, in decimal that is 248.

0x01 is hexadecimal for 1 in decimal — it’s also 1 in binary.

Between them are bitwise operators —

& is a bitwise AND operation, and | is a bitwise OR operation. AND calculates which bits in a pair of binary numbers are both on, and OR calculates which bits in a pair of binary numbers are on in either of the numbers.

Поэтому сначала возьмите первый. Скажем, что регистр TCCR0B содержит значение 0x6F , которое равно 157 в десятичной системе или 01101111 в двоичном формате. Первая операция — AND , которая с 11111000:

01101111
11111000 AND
--------
01101000

You can see that the last three bits of the value have been cleared because they aren’t 1 in both the left and right operands to the & operator.

Итак, следующая операция: OR с 0x01:

01101000
00000001 OR
--------
01101001

Эффективно оба операнда были наложены друг на друга, и любые биты, которые заданы в любом из операндов, будут отражены в результате.

Таким образом, наконец, значение сохраняется в TCCR0B .

Таким образом, конкретная операция очищает нижние три бита, а затем устанавливает младший бит TCCR0B.

Теперь то, что на самом деле означает, что делает регистр TCCR0B, можно почерпнуть из таблицы данных для чипа. Например, возьмите чип ATMega328P с платы Arduino UNO. Страница 109 из в техническом описании описывает этот регистр в деталях. Побитовый обзор выглядит следующим образом:

Эти биты соответствуют 1: 1 двоичным битам сверху в том же порядке. Таким образом, первый этап, очищающий самые младшие три бита, устанавливает CS02, CS01 и CS00 в 0. Второй этап, ORing 0x01, затем устанавливает CS00 в 1.

Далее приводится описание того, что они означают:

      
  • Биты 2: 0 — CS02: 0: Выбор часов
  •   
     

Три бита выбора тактового сигнала выбирают источник синхронизации, который будет использоваться таймером/счетчиком.

И таблицу, чтобы показать различные значения возможных значений:

Значение, которое было замаскировано и создано для этих трех бит, конечно, 001, которое в этой таблице является «CLK I/O/(No prescaling)», которое является таймером, работающим на частоте часов ввода-вывода. Если бы вы установили эти биты в 010, вы получите «CLK I/O/8 (From prescaler)». Таким образом, ваша маскировка изменится на:

TCCR0B = TCCR0B & 0b11111000 | 0x02;

Или более явно, чтобы вы могли видеть бит проще:

TCCR0B = TCCR0B & 0b11111000 | 0b010;

Что касается значений «A» и «B» (TCCR0A и TCCR0B), для управления таймером используются два регистра. Каждый из них служит другой цели. TCCR0A имеет биты, которые управляют PWM, а TCCR0B имеет биты, которые управляют самим таймером.

Не следует путать с OCCR0A и OCCR0B, которые представляют собой два отдельных числовых значения, которые сравниваются с значением счетчика таймера TCNT0, чтобы обеспечить два отдельных выхода ШИМ, синхронизированных с одной и той же временной базой.

Реле включения нагрузки по времени на arduino-совместимой плате – ARDUINO.MD

Итак, задача. Нужно включать-выключать некоторую нагрузку, скажем, насос для полива растений на улице, и делать это в автоматическом режиме с гибко настраиваемыми интервалами.

Для решения этой задачи нам понадобится

  • Uno – arduino-совместимая плата, которую мы программируем
  • Sensor shield (или плата прототипирования) – для облегчения соединения датчиков с платой
  • Провода мама-мама
  • Дисплей на 2 строки по 16 символов LCD1602
  • Реле переключения нагрузки
  • Датчик угла поворота с кнопкой
  • Блок питания 9V 1А (для тестирования можно питать устройство и по USB кабелю самой Arduino)

Принцип действия

К реле подключается полезная нагрузка, скажем, двигатель на 12 вольт или насос. Реле выступает в качестве включателя/выключателя, который управляется программно, т. е. мы в коде говорим, когда нам замкнуть контакты в реле (включить насос) или разомкнуть (выключить насос). Датчиком угла поворота мы настраиваем через какой промежуток времени (минут) нам нужно включить реле (ON) и через какой – выключить (OFF). Сколько осталось минут до окончания текущего режима, сколько минут продлится режим включения и выключения – все это мы видим на экране LCD.

Подключение

UNOLCD1602
РелеДатчик угла
 VCC 5V VCC + +
 GND GND – GND
 Analog 4 SDA
 Analog 5 SCL
 Digital 5 SW
 Digital 8 S
 Digital 11 CLK
 Digital 12 DT

Полный код программы: relay-timer-project. zip

Вот и видео того, что получилось.

Комментарий к видео.

На дисплее строка Active OFF 1 говорит, что активен режим OFF – реле выключено и это продлится еще 1 минуту. Строка ON: 4 OFF: 1 говорит что устройство настроено на периодическое включение реле на 4 минуты, затем выключение на 1 минуту. Крутим датчик угла поворота, регулируя сколько осталось до смены режима (ON/OFF). Нажав кнопку переходим в режим редактирования значения ON, далее по кнопке переходим в режим редактирования OFF, далее по кнопке возвращаемся в основной режим. Спустя минуту после щелчка загорается светодиод на реле (реле включено) и на дисплее видим смену режима на ON, который продлится 2 минуты. Отключаем питание устройства и включаем снова, видим, что настройки ON2 и OFF1 сохранились – при загрузке arduino прочла их из энергонезависимой памяти eeprom.

Также режим изменился на OFF.

Заключение

Если все-таки хочется сделать готовое устройство:

  • Плату arduino uno лучше заменить на arduino pro mini – она значительно меньше, дешевле и припаивать провода легче
  • Все соединительные провода между платой и остальными устройствами нужно припаять – ржавчина теперь не повлияет на долговечность соединительных контактов
  • Собрать все в корпус – на вид приличнее будет, да и защита от всяких воздействий (случайно задетого провода)
  • Добавить выключатель – при покидании жилища на длительное время (при том что в этом устройстве нет необходимости в отсутствии хозяев) лучше все-таки обесточивать девайс, и делать это выключателем удобнее, чем выдергивать блок питания из розетки

Удачных экспериментов!

Возможно, вам потребуются файлы:

Понравилось это:

Нравится Загрузка…

Похожее

Учебный курс AVR.

Таймер — счетчик Т0. Регистры. Ч1

   Таймер-счетчик является одним из самых ходовых ресурсов AVR микроконтроллера. Его основное назначение — отсчитывать заданные временные интервалы. Кроме того, таймеры-счетчики могут выполнять ряд дополнительных функций, как то — формирование ШИМ сигналов, подсчет длительности и количества входящих импульсов. Для этого существуют специальные режимы работы таймера-счетчика. 

   В зависимости от модели микроконтроллера количество таймеров и набор их функций может отличаться. Например, у микроконтроллера Atmega16 три таймера-счетчика — два 8-ми разрядных таймера-счетчика Т0 и Т2, и один 16-ти разрядный — Т1. В этой статье, на примере ATmega16, мы разберем как использовать таймер-счетчик Т0.

   Таймер-счетчик Т0 использует два вывода микроконтроллера ATmega16. Вывод T0 (PB0) — это вход внешнего тактового сигнала. Он может применяться, например, для подсчета импульсов. Вывод OC0 (PB3) — это выход схемы сравнения таймера-счетчика.

На этом выводе с помощью таймера может формировать меандр или ШИМ сигнал. Также он может просто менять свое состояние при срабатывании схемы сравнения, но об этом поговорим позже. 

   
   Выводы T0 и OC0 задействуются только при соответствующих настройках таймера, в обычном состоянии это выводы общего назначения. 

 

   Хоть это и скучно, но регистры — это то, без чего невозможно программировать микроконтроллеры, конечно, если вы не сидите плотно на Arduino. Так вот, таймер Т0 имеет в своем составе три регистра:


— счетный регистр TCNT0,
— регистр сравнения OCR0,
— конфигурационный регистр TCCR0.

Кроме того, есть еще три регистра, относящиеся ко всем трем таймерам ATmega16:

— конфигурационный регистр TIMSK,
— статусный регистр TIFR.
— регистр специальных функций SFIOR

Начнем с самого простого.

TCNT0

 

   Это 8-ми разрядный счетный регистр. Когда таймер работает, по каждому импульсу тактового сигнала значение TCNT0 изменяется на единицу. В зависимости от режима работы таймера, счетный регистр может или увеличиваться, или уменьшаться.
   Регистр TCNT0 можно как читать, так и записывать. Последнее используется когда требуется задать его начальное значение. Когда таймер работает, изменять его содержимое TCNT0 не рекомендуется, так как это блокирует схему сравнения на один такт.

OCR0  


   Это 8-ми разрядный регистр сравнения. Его значение постоянно сравнивается со счетным регистром TCNT0, и в случае совпадения таймер может выполнять какие-то действия — вызывать прерывание, менять состояние вывода OC0 и т.д. в зависимости от режима работы.

   Значение OCR0 можно как читать, так и записывать.

TCCR0 (Timer/Counter Control Register)



   Это конфигурационный регистр таймера-счетчика Т0, он определяет источник тактирования таймера, коэффициент предделителя, режим работы таймера-счетчика Т0 и поведение вывода OC0. По сути, самый важный регистр. 


   Биты CS02, CS01, CS00 (Clock Select) — определяют источник тактовой частоты для таймера Т0 и задают коэффициент предделителя. Все возможные состояния описаны в таблице ниже.

   
   Как видите, таймер-счетчик может быть остановлен, может тактироваться от внутренней частоты и также может тактироваться от сигнала на выводе Т0. 

   Биты WGM10, WGM00 (Wave Generator Mode) — определяют режим работы таймера-счетчика Т0. Всего их может быть четыре — нормальный режим (normal), сброс таймера при совпадении (CTC), и два режима широтно-импульсной модуляции (FastPWM и Phase Correct PWM). Все возможные значения описаны в таблице ниже.

Более подробно будем разбирать режимы в коде. Сейчас все нюансы все равно не запомнятся. 

   Биты COM01, COM00 (Compare Match Output Mode) — определяют поведение вывода OC0. Если хоть один из этих битов установлен в 1, то вывод OC0 перестает функционировать как обычный вывод общего назначения и подключается к схеме сравнения таймера счетчика Т0. Однако при этом он должен быть еще настроен как выход.
   Поведение вывода OC0 зависит от режима работы таймера-счетчика Т0. В режимах normal и СTC вывод OC0 ведет себя одинаково, а вот в режимах широтно-импульсной модуляции его поведение отличается. Не будем сейчас забивать себе голову всеми этими вариантами и разбирать таблицы для каждого режима, оставим это на практическую часть.

   И последний бит регистра TCCR0 — это бит FOC0 (Force Output Compare). Этот бит предназначен для принудительного изменения состояния вывода OC0. Он работает только для режимов Normal и CTC. При установки бита FOC0 в единицу состояние вывода меняется соответственно значениям битов COM01, COM00. FOC0 бит не вызывает прерывания и не сбрасывает таймер в CTC режиме.

TIMSK (Timer/Counter Interrupt Mask Register)


   Общий регистр для всех трех таймеров ATmega16, он содержит флаги разрешения прерываний. Таймер Т0 может вызывать прерывания при переполнении счетного регистра TCNT0 и при совпадении счетного регистра с регистром сравнения OCR0. Соответственно для таймера Т0 в регистре TIMSK зарезервированы два бита — это TOIE0 и OCIE0. Остальные биты относятся к другим таймерам.

TOIE0 — 0-е значение бита запрещает прерывание по событию переполнение, 1 — разрешает. 
OCIE0 — 0-е значение запрещает прерывания по событию совпадение, а 1 разрешает.

   Естественно прерывания будут вызываться, только если установлен бит глобального разрешения прерываний — бит I регистра SREG.

TIFR (Timer/Counter0 Interrupt Flag Register)


   Общий для всех трех таймеров-счетчиков регистр. Содержит статусные флаги, которые устанавливаются при возникновении событий. Для таймера Т0 — это переполнение счетного регистра TCNT0 и совпадение счетного регистра с регистром сравнения OCR0. 

Если в эти моменты в регистре TIMSK разрешены прерывания и установлен бит I, то микроконтроллер вызовет соответствующий обработчик.
   Флаги автоматически очищаются при запуске обработчика прерывания. Также это можно сделать программно, записав 1 в соответствующий флаг.

TOV0 — устанавливается в 1 при переполнении счетного регистра.
OCF0 — устанавливается в 1 при совпадении счетного регистра с регистром сравнения

SFIOR (Special Function IO Register)

   
    Начинающему про этот регистр в принципе можно и не знать, один из его разрядов сбросывает 10-ти разрядный двоичный счетчик, который делит входную частоту для таймера Т0 и таймера Т1. 

   Сброс осуществляется при установке бита PSR10 (Prescaler Reset Timer/Counter1 и Timer/Counter0) в единицу.

   Нудная часть закончена. Далее разберем как настроить таймер на определенную частоту, как таймер ведет себя в разных режимах, как генерировать ШИМ сигнал.

Собираем крафтовую розетку с таймером на базе Arduino

Розетка с таймером (ее же иногда называют «реле времени») — это устройство, функционал и назначение которого должно быть очевидно из названия. Вы подключаете какую-нибудь лампу в розетку через это устройство, в результате чего получаете возможность запрограммировать лампу. Например, лампа может автоматически включаться каждый день в 9 утра и выключаться в 10 вечера. Зачем это может быть нужно — уход за растениями, создание эффекта присутствия людей в доме с целью отпугивания воров, и так далее. Розетку с таймером в наше время легко купить готовую за небольшие деньги. Однако в этой заметке я расскажу, как сделать такое устройство своими руками.

Важно! Работа с переменным током высокого напряжения смертельно опасна. Если вы решите повторять действия, описанные далее, будьте предельно осторожны.

Примечание: Пользуясь случаем, я хотел бы поблагодарить пользователей форума EasyElectronics.ru с никами STT, BusMaster и Кот495 за то, что проконсультировали меня о некоторых нюансах работы с переменным током.

Спрашивается, зачем делать свое устройство, если можно просто купить готовое?

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

Свою розетку с таймером я собрал из следующих компонентов:

Вместо зарядного устройства для телефона можно было воспользоваться нормальным AC/DC преобразователем на 5 В, припаиваемым на плату. Но стоят AC/DC преобразователи сравнительно дорого, а лишних зарядных устройств у меня накопилось достаточно много. Так что я предпочел использовать валяющуюся без дела зарядку.

Повербанк тоже валялся без дела. Если лишнего повербанка у вас нет, вместо него можно воспользоваться Li-Ion аккумулятором форм-фактора 18650 в сочетании с платой на базе чипа TP4056 и каким-нибудь повышающим DC/DC преобразователем на ваш выбор. Как использовать эти компоненты ранее было подробно рассказано в заметке Паяем крафтовый повербанк с солнечной панелью. Вообще-то говоря, не всякий повербанк способен заряжаться от сети и одновременно заряжать подключенное к нему устройство. Поэтому в общем случае использовать аккумулятор, TP4056 и повышающий преобразователь DC/DC будет более правильно.

Отмечу также, что повербанк нужен исключительно для того, чтобы часы на устройстве не сбрасывались при отключении электричества в доме. Если для вас это не является проблемой (например, есть ИБП), то можно обойтись и без повербанка.

Названные компоненты были помещены в корпус и соединены таким образом:

Корпус я спроектировал во FreeCAD и распечатал на 3D-принтере RepRap Prusa i3 пластиком PLA. Высчитывать с точностью до миллиметра, где должны находится отверстия для крепления экранчика, мне было лень. Поэтому эти отверстия я просверлил дрелью уже после того, как корпус был напечатан. Разъемы XT60 были закреплены с помощью термоклея.

Заметьте, что реле впаяно в макетку. Так сделано по той причине, что ножки у реле очень хрупкие, и если припаяться к ним напрямую, они быстро отломаются (я проверял!). Если вы решите использовать другое реле, убедитесь, что оно рассчитано на достаточно большой ток, хотя бы 8 А. Проверьте также, что выбранное вами реле является моностабильным. То есть, при пропадании питания на катушке реле должно автоматически разрывать цепь.

Наконец, примите во внимание, что из соображений безопасности следует разрывать фазу и ноль одновременно, а не лишь один из контактов, как рисует в своих туториалах та же Амперка. Дело в том, что втыкаемая в розетку вилка не знает, где у нее ноль, а где фаза, и разрывая лишь один из контактов вы повышаете вероятность поражения пользователя электрическим током при случайном касании, казалось бы, отключенной нагрузки. Таким образом, следует использовать реле с двумя группами контактов.

Софтверная часть не представляет очень уж большого интереса, тем более, что я не сильно заморачивался с качеством кода. Использование экранчиков 1602 с I2C интерфейсом ранее подробно рассматривалось в заметке Об использовании экранчиков 1602 с I2C-адаптером. Что же касается части кода, отвечающей за время, она в существенной части была позаимствована из проекта часов на микроконтроллере ATmega328P. Действительно новым для нас здесь является разве что работа с роторным энкодером, поэтому ее и рассмотрим.

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

Как видите, сигнал достаточно просто декодировать. Если по фронту сигнала с контакта A на контакте B сигнал высокий или по спаду сигнала с контакта A на контакте B сигнал низкий, значит пользователь вращает ручку по часовой стрелке. Если же наоборот, по фронту сигнала с контакта A на контакте B сигнал низкий, а по спаду — высокий, значит ручка вращается против часовой стрелки.

Как это часто бывает в мире Arduino, декодирование сигнала от энкодера уже реализовано в библиотеке Rotary. Пример ее использования:

#include «Rotary.h»

Rotary rot(3, 2);

/* … */

void setup() {
    /* … */

    // rotory interrupt
    PCICR |= (1 << PCIE2);
    PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
    sei();
}

ISR(PCINT2_vect) {  
    unsigned char result = rot.process();
    if (result == DIR_NONE) {  
        // do nothing
    } else if (result == DIR_CW) {
        /* do something … */
    } else if(result == DIR_CCW) {
        /* do something else . ..*/
    }  
}

/* … */

В окончательном виде получившееся устройство выглядит так:

Конечно же, на ум приходит множество возможных улучшений. Например, можно добавить функцию управления по Bluetooth или же при помощи SMS. Не помешало бы также вывести на корпус индикацию процесса зарядки и текущего состояния аккумулятора. Где-нибудь сбоку стоило бы добавить кнопку полного отключения, например, на случай длительной транспортировки устройства. Возможность отключения подсветки экранчика была бы не лишней, так как подсветка довольно яркая и может, помимо прочего, мешать спать. Часы на кварцевом резонаторе не слишком точны, раз в пару месяцев их приходится подводить. В связи с этим стоит рассмотреть использование внешних часов реального времени. Ну и в целом получившаяся конструкция довольно громоздка, уродлива и сложна для повторения, не говоря уже о том, что микроконтроллер подошел бы и более простой, например, ATtiny2313. Так что, не лишено смысла сделать нормальную плату.

Как обычно, исходники прошивки и STL-файлы корпуса вы найдете на GitHub.

А что вы думаете об описанном проекте и какие идеи по его улучшению есть у вас?

Метки: AVR, Электроника.

Прерываний таймера Arduino: 6 шагов (с изображениями)

Uno имеет три таймера, которые называются timer0, timer1 и timer2. У каждого таймера есть счетчик, который увеличивается на каждый тик часов таймера. Прерывания таймера CTC запускаются, когда счетчик достигает заданного значения, сохраненного в регистре сравнения сравнения. Как только счетчик таймера достигает этого значения, он очищается (сбрасывается до нуля) на следующем такте часов таймера, затем он снова продолжает отсчет до значения сравнения.Выбирая значение сравнения для сравнения и устанавливая скорость, с которой таймер увеличивает счетчик, вы можете контролировать частоту прерываний таймера.

Первый параметр, который я буду обсуждать, — это скорость, с которой таймер увеличивает счетчик. Часы Arduino работают на частоте 16 МГц, это самая высокая скорость, с которой таймеры могут увеличивать свои счетчики. На частоте 16 МГц каждый тик счетчика представляет 1/16000000 секунды (~ 63 нс), поэтому счетчику потребуется 10/16000000 секунд, чтобы достичь значения 9 (счетчики имеют индекс 0), и 100/16000000 секунд, чтобы достичь значения. из 99.

Во многих ситуациях вы обнаружите, что установка скорости счетчика на 16 МГц является слишком быстрой. Timer0 и timer2 — это 8-битные таймеры, то есть они могут хранить максимальное значение счетчика 255. Timer1 — это 16-битный таймер, то есть он может хранить максимальное значение счетчика 65535. Как только счетчик достигнет своего максимума, он вернется к нулю. (это называется переполнением). Это означает, что на частоте 16 МГц, даже если мы установим регистр сравнения сравнения на максимальное значение счетчика, прерывания будут происходить каждые 256/16 000 000 секунд (~ 16 мкс) для 8-битных счетчиков и каждые 65 536/16 000 000 (~ 4 мс) секунд для 16-битный счетчик. Ясно, что это не очень полезно, если вы хотите прерывать только один раз в секунду.

Вместо этого вы можете контролировать скорость увеличения счетчика таймера с помощью так называемого предварительного делителя. Предварительный делитель определяет скорость вашего таймера в соответствии со следующим уравнением:

(скорость таймера (Гц)) = (тактовая частота Arduino (16 МГц)) / предварительный делитель

Таким образом, предварительный делитель 1 будет увеличивать счетчик на 16 МГц, а Предварительный делитель 8 будет увеличивать его до 2 МГц, предварительный делитель 64 = 250 кГц и так далее.Как указано в таблицах выше, предварительный делитель может быть равен 1, 8, 64, 256 и 1024. (Я объясню значение CS12, CS11 и CS10 на следующем шаге.)

Теперь вы можете рассчитать прерывание. частота с помощью следующего уравнения:

частота прерывания (Гц) = (тактовая частота Arduino 16000000 Гц) / (предварительный делитель * (регистр сопоставления + 1))
+1 присутствует, потому что регистр сопоставления сравнения имеет нулевой индекс

изменив приведенное выше уравнение, вы можете найти значение регистра сопоставления, которое даст желаемую частоту прерывания:

регистр сопоставления сопоставления = [16 000 000 Гц / (предварительный делитель * желаемая частота прерывания)] — 1
помните, что когда вы используете таймеры 0 и 2, это число должно быть меньше 256 и меньше 65536 для таймера 1

, поэтому, если вы хотите прерывание каждую секунду (частота 1 Гц):
регистр сравнения совпадений = [16,000,000 / (предварительный делитель * 1)] -1
с предварительным делителем 1024 вы получите:
compare match register = [16,000,000 / (1024 * 1)] -1
= 15,624
, так как 256 <15,624 <65 536, вы должны использовать timer1 для этого прерывания.

Роботы + большие данные: Документы по таймеру Arduino

Цикл реального времени Arduino перестает продвигаться, когда вы пишете delay () или используете прерывания в своем скетче. Вы можете поддерживать движение цикла в реальном времени, используя millis () для отслеживания времени и создания задержки, но это более сложно, и вскоре становится неудобно управлять.

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

Эта библиотека работает в мягком режиме реального времени, что означает, что она в основном будет работать вовремя, но может не работать, если производительность является проблемой. Это может выглядеть как потеря времени в микросекундах, когда таймер истекает, но до его перезапуска. Или это может выглядеть как загруженный цикл Arduino (), в котором разрешение таймера ухудшается и запускается только событие в течение 25 микросекунд после фактического события. (Микросекунда — это небольшая доля миллисекунды).

Существуют и другие решения проблем жесткого реального времени, которые требуют точного времени, которое не может соскользнуть ни по какой причине.Это соображения при использовании этого таймера в проекте, но по большей части; производительность потрясающая, и вы должны использовать эту библиотеку.

  1. Установите эту библиотеку и загрузите пример скетча в Arduino.
  2. Откройте последовательное соединение со скоростью 115200 бод.
  3. Наблюдайте за последовательной печатью таймера каждые три секунды.
Пример SketchArduinoC ++
RBD :: Timer constructor ([timeout_value])

Создайте новый таймер и передайте [необязательное] значение тайм-аута (в миллисекундах), которое аналогично предоставлению значения для setTimeout ().

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

ЭСКИЗ ПРИМЕРА

Задайте беззнаковое long больше нуля, чтобы изменить продолжительность работы таймера (в миллисекундах). Это можно сделать в конструкторе (), в setup () или внутри цикла (), чтобы изменить значение во время выполнения.Это переопределит любое значение, указанное для setHertz ().

ЭСКИЗ ПРИМЕРА

Введите целое число от 1 до 1000, чтобы приблизительно установить, сколько раз таймер будет перезапускаться за одну секунду. Это можно сделать внутри setup () или также внутри loop (), чтобы изменить значение во время выполнения. Это переопределит любое значение, указанное для setTimeout ().

ПРИМЕР ЭСКИЗ

При первом создании; таймер истечет. Перезапустите таймер, чтобы начать его использовать. Этот метод можно использовать с isExpired () для создания непрерывного цикла.

Проверьте onRestart (), чтобы выполнить код с определенным интервалом.

ЭСКИЗ ПРИМЕРА

Вызов stop () уничтожает все события и запрещает все, кроме isStopped (), возвращать истину. Вы должны вызвать restart (), чтобы снова активировать таймер.

ПРИМЕР ЭСКИЗА

Возвращает длинное беззнаковое значение, которое было предоставлено для setTimeout ().

ПРИМЕР ЭСКИЗ

Возвращает целочисленное значение, которое было предоставлено для setHertz ().

ЭСКИЗ ПРИМЕРА

Возвращает беззнаковое число, показывающее, сколько миллисекунд прошло с момента запуска таймера.

ПРИМЕР ЭСКИЗ

Возвращает целое число от 0 до 100, показывающее, сколько времени прошло в процентах от общего интервала. Если таймер проработал 500 мс за время ожидания 2000 мс: этот метод вернет 25.

ЭСКИЗ ПРИМЕРА

Возвращает длину без знака, показывающую, сколько миллисекунд осталось до конца таймера.

ПРИМЕР ЭСКИЗ

таймер

. getInversePercentValue ()

Возвращает целое число от 100 до 0, обратное тому, сколько времени прошло в процентах от общего интервала.Если таймер проработал 500 мс за время ожидания 2000 мс: этот метод вернет 75.

ПРИМЕР ЭСКИЗ

Возвращает истину, если время истекло. Этот метод можно использовать с restart () для создания непрерывного цикла.

Проверьте onRestart (), чтобы выполнить код с определенным интервалом.

ЭСКИЗ ПРИМЕРА

Этот метод запускает одно событие, когда таймер становится активным. Таймер должен истечь, а затем перезапуститься, чтобы это событие сработало снова.

ЭСКИЗ ПРИМЕРА

Этот метод запускает одно событие по истечении таймера.Таймер необходимо перезапустить, а затем дать ему время истечь, чтобы это событие сработало снова.

ПРИМЕР ЭСКИЗА

Это простой способ создания цикла вместо одновременного использования isExpired () и restart (). Используйте это для выполнения кода с определенным интервалом.

Этот метод определяет, когда таймер истекает, перезапускает таймер, а затем разрешает выполнение блока кода. Затем он ожидает, пока таймер истечет, чтобы снова выполнить эти действия.

ЭСКИЗ ПРИМЕР
Компоненты

Датчики

Дополнительные библиотеки

Тректор: управление таймерами сбора урожая в стиле Arduino

Здесь, в Viget, мы все используем Harvest, чтобы отслеживать, как мы проводим время.Это отличный инструмент, который позволяет легко отслеживать время, потраченное на различные клиентские и внутренние проекты … но я знал, что опыт может быть лучше.

Проблема

Хотя я нахожу интерфейс Harvest чистым и простым в использовании, часто бывает трудно отследить, где находится моя вкладка, особенно учитывая недавнюю популярность в Интернете комбинации значков оранжевый-фон-белая буква.

При загрузке новой вкладки (или использовании настольного приложения) поиск нужного таймера и его включение занимает всего полторы секунды, я знал, что есть возможности для улучшения. Эти секунды с половиной складываются.

Решение

Представляем Tracktor!

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

Подробности

Приложение Sinatra «Фермер» запускается локально, что позволяет мне хранить «Растения» (идентификаторы таймера урожая в паре с номерами кнопок) в базе данных и делать запросы «переключения» через Harvest API всякий раз, когда запрашивается / toggle? Button = [число] добавлено в приложение.

Что касается аппаратного обеспечения, я подключил 6 кнопок и 6 светодиодов к моему верному Arduino и решил использовать драгоценный камень Dino для управления компонентами Arduino с помощью Ruby. Скрипт под названием «Плуг» (это верно, метафоры фермы для всех) запускается и постоянно отслеживает нажатия кнопок. При каждом нажатии кнопки:

  1. число (от 1 до 6) добавляется в строку запроса моего HTTP-запроса к фермеру
  2. Фермер затем запускает запрос переключения Harvest API с соответствующим идентификатором таймера
  3. Фермер затем анализирует ответ и отправляет обратно информацию о состоянии (успешный запрос и состояние таймера включения / выключения), поскольку JSON
  4. Plow считывает ответ и дает указание соответствующему светодиоду отразить состояние таймера.

Конечный результат: если я догоняю электронные письма, и в Client Project X приходит запрос на экстренную помощь, я поднимаю руку, качаю ее вниз авторитетным и удовлетворительным «щелчком» по кнопке Client Project X и принимайтесь за работу. Спустя примерно 0,25–4 секунды я краем глаза наблюдаю, как два светодиода меняют свое состояние, и я знаю, что мое время отслеживается надлежащим образом.

The Future

Я прекрасно понимаю, что Tracktor можно улучшить. Планы на второй этап включают в себя любое из следующих действий:

  • физическое устройство меньшего размера
  • гораздо большее физическое устройство
  • ножное управление? («Я бы хотел, чтобы меня окружали кнопки и переключатели, чтобы я мог чувствовать себя пилотом.»-Сотрудник)
  • более шикарный и умный Фермер
  • Raspberry Pi, работающий с Фермером и Плугом, так что он может быть свободен от моего компьютера
  • Свисток и / или лук и стрелы активируют изменения таймера
  • Убери этот беспорядок

Если у вас есть какие-то интересные способы отслеживания своего времени, есть какие-то мысли о Tracktor, вы его полностью ненавидите или хотите сделать его самостоятельно, дайте мне знать в комментариях ниже!

И как всегда: код для всех, чтобы поделиться / критиковать: Tracktor

Таймер-0 / Счетчик-0 Концепция: Arduino / ATmega328p

Примечание

Эта статья является частью Руководства по программированию встроенного микропрограммного обеспечения C Arduino / ATmega328p . Попробуйте изучить домашнюю страницу курса, чтобы найти статьи на похожие темы.

Учебное пособие по Arduino Встроенный уровень регистра C Мастер-класс Arduino

Также посетите страницу выпуска для встроенной библиотеки аппаратных абстракций C на уровне регистров и код для AVR .

Введение

  • Характеристики
    • Два независимых блока сравнения выходов
    • Регистры сравнения выходов с двойной буферизацией
    • Сброс таймера при совпадении сравнения (автоматическая перезагрузка)
    • Без сбоев, фазово-корректирующий широтно-импульсный модулятор (ШИМ)
    • Переменный период ШИМ
    • Генератор частоты
    • Три независимых источника прерываний (TOV0, OCF0A и OCF0B)

Таймер-0 / счетчик-0 — это 8-битный модуль таймера / счетчика общего назначения с двумя независимыми модулями сравнения выходов и с поддержкой ШИМ.Это позволяет точно рассчитывать время выполнения программы (управление событиями) и генерировать волны.

Блок-схема AVR Atmega328p Timer-0 / Counter-0

Таймер-0 имеет два вывода ШИМ / переменной частоты, назначенных на порт ввода-вывода. OC0A отображается на PD6, который является цифровым выводом 6 на плате Arduino UNO. OC0B отображается на PD5, который является цифровым контактом 5 на плате Arduino UNO.

Схема контактов ввода-вывода Arduino UNO Назначение контактов Arduino UNO Atmega328p
Определения часто используемых терминов в таймере
BOTTOM Счетчик достигает BOTTOM, когда становится 0x00.
MAX Счетчик достигает своего MAXimum, когда становится 0xFF (десятичное 255).
TOP Счетчик достигает TOP, когда он становится равным наивысшему значению в последовательности счета. Значение TOP может быть фиксированным значением 0xFF (MAX) или значением, хранящимся в регистре OCR0A. Назначение зависит от режима работы.

Регистры и источник синхронизации

Многие регистры и битовые ссылки в этом разделе написаны в общем виде. Строчная буква «n» заменяет номер таймера / счетчика, в данном случае 0. Строчная буква «x» заменяет выходной модуль сравнения, в данном случае модуль сравнения A или модуль сравнения B. Однако при использовании регистра или бит определяет в программе, должна использоваться точная форма, т. е. TCNT0 для доступа к значению счетчика Timer / Counter0 и так далее.

Таймер / счетчик может синхронизироваться внутренне, через предварительный делитель или внешний источник синхронизации на выводе T0. Логический блок Clock Select управляет тем, какой источник тактовых импульсов и какой фронт использует таймер / счетчик для увеличения (или уменьшения) своего значения.Таймер / счетчик неактивен, если не выбран ни один источник синхронизации. Выходной сигнал логики выбора тактового сигнала называется тактовой частотой таймера (clkT0). Источник синхронизации выбирается логикой выбора часов, которая управляется битами выбора часов (CS02: 0), расположенными в регистре управления таймером / счетчиком (TCCR0B).

Регистры сравнения вывода с двойной буферизацией (OCR0A и OCR0B) постоянно сравниваются со значением таймера / счетчика. Результат сравнения может быть использован генератором сигналов для генерации выходного сигнала ШИМ или переменной частоты на выводах сравнения выходных сигналов (OC0A и OC0B).Событие сравнения сопоставления также установит флаг сравнения (OCF0A или OCF0B), который можно использовать для генерации запроса прерывания сравнения выходных данных.

Счетчик

Основной частью 8-битного таймера / счетчика является программируемый двунаправленный счетчик.

Блок-схема блока счетчика AVR
Описание сигнала:
№ Сообщает, что TCNT0 достиг максимального значения дно Сообщает, что TCNT0 достиг минимального значения

В зависимости от используемого режима работы счетчик очищается, увеличивается или уменьшается на каждом такте таймера (clkT0).clkT0 может генерироваться из внешнего или внутреннего источника тактовых импульсов, выбираемых битами выбора тактового сигнала (CS02: 0). Когда не выбран ни один источник синхронизации (CS02: 0 = 0), таймер останавливается. Однако ЦП может получить доступ к значению TCNT0 независимо от того, присутствует clkT0 или нет. Запись CPU отменяет (имеет приоритет) все операции очистки или подсчета счетчиков.

Последовательность подсчета определяется установкой битов WGM01 и WGM00, расположенных в регистре управления таймером / счетчиком (TCCR0A), и бита WGM02, расположенного в регистре управления таймером / счетчиком B (TCCR0B).Существует тесная связь между тем, как ведет себя (считает) счетчик, и тем, как формируются сигналы на выходах OC0A и OC0B сравнения выходов.

Флаг переполнения таймера / счетчика (TOV0) устанавливается в соответствии с режимом работы, выбранным битами WGM02: 0. TOV0 может использоваться для генерации прерывания ЦП.

Блок сравнения выходов

8-битный компаратор постоянно сравнивает TCNT0 с выходными регистрами сравнения (OCR0A и OCR0B). Когда TCNT0 равен OCR0A или OCR0B, компаратор сигнализирует о совпадении. При совпадении устанавливается флаг сравнения выходных данных (OCF0A или OCF0B) в следующем цикле тактовой частоты таймера. Если соответствующее прерывание разрешено, флаг сравнения выходов генерирует прерывание сравнения выходов. Флаг сравнения вывода автоматически сбрасывается при выполнении прерывания. В качестве альтернативы, флаг может быть сброшен программно, записав логическую единицу в его расположение бита ввода / вывода. Генератор формы сигналов использует сигнал совпадения для генерации выходного сигнала в соответствии с рабочим режимом, установленным битами WGM02: 0 и битами режима выхода сравнения (COM0x1: 0).Сигналы максимума и минимума используются генератором сигналов для обработки особых случаев экстремальных значений в некоторых режимах работы.

Блок-схема блока сравнения выходов AVR

Регистры OCR0x имеют двойную буферизацию при использовании любого из режимов широтно-импульсной модуляции (ШИМ). Для нормального режима работы и режима сброса таймера при сравнении (CTC) двойная буферизация отключена. Двойная буферизация синхронизирует обновление регистров сравнения OCR0x до начала или конца счетной последовательности.Синхронизация предотвращает возникновение несимметричных импульсов ШИМ нечетной длины, тем самым обеспечивая отсутствие сбоев на выходе.

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

В режимах генерации сигналов без ШИМ выходной сигнал совпадения компаратора может быть принудительно записан путем записи единицы в бит принудительного сравнения выходных данных (FOC0x).Принудительное сопоставление сравнения не установит флаг OCF0x или перезагрузит / очистит таймер, но вывод OC0x будет обновлен, как если бы произошло реальное сопоставление сравнения (настройки битов COM0x1: 0 определяют, установлен ли вывод OC0x, очищен или переключен) .

Запись TCNT0 в любом режиме работы будет блокировать все совпадения сравнения для одного тактового цикла таймера, существуют риски, связанные с изменением TCNT0 при использовании блока сравнения выходов, независимо от того, работает таймер / счетчик или нет. Если значение, записанное в TCNT0, равно значению OCR0x, сравнение будет пропущено, что приведет к формированию неправильной формы сигнала.Точно так же не записывайте значение TCNT0 равным BOTTOM, когда счетчик ведет обратный отсчет.

Настройка OC0x должна быть выполнена до настройки регистра направления данных для вывода порта. Самый простой способ установить значение OC0x — использовать стробирующие биты Force Output Compare (FOC0x) в нормальном режиме. Регистры OC0x сохраняют свои значения даже при переключении между режимами генерации сигналов.

Блок вывода сравнения совпадений

Биты режима вывода сравнения (COM0x1: 0) имеют две функции.Генератор сигналов использует биты COM0x1: 0 для определения состояния выходного сравнения (OC0x) при следующем сопоставлении. Кроме того, биты COM0x1: 0 управляют выходным источником вывода OC0x.

Регистры ввода-вывода, биты ввода-вывода и контакты ввода-вывода на рисунке выделены жирным шрифтом. Показаны только те части регистров общего управления портом ввода-вывода (DDR и PORT), на которые влияют биты COM0x1: 0. При обращении к состоянию OC0x ссылка относится к внутреннему регистру OC0x, а не к выводу OC0x. Если происходит сброс системы, регистр OC0x сбрасывается на «0».

Блок-схема блока вывода сравнения AVR

Общая функция порта ввода / вывода отменяется функцией сравнения выходов (OC0x) из генератора сигналов, если установлен один из битов COM0x1: 0. Однако направление вывода OC0x (вход или выход) по-прежнему контролируется регистром направления данных (DDR) для вывода порта. Бит регистра направления данных для вывода OC0x (DDR_OC0x) должен быть установлен как выходной, прежде чем значение OC0x станет видимым на выводе. Функция переопределения порта не зависит от режима генерации сигнала.Конструкция логики вывода сравнения выходов позволяет инициализировать состояние OC0x до включения выхода.

Генератор сигналов использует биты COM0x1: 0 по-разному в режимах Normal, CTC и PWM. Для всех режимов установка COM0x1: 0 = 0 сообщает генератору сигналов, что никакие действия с регистром OC0x не должны выполняться при следующем сопоставлении.

Режимы работы

Режим работы, то есть поведение выводов таймера / счетчика и вывода сравнения, определяется комбинацией битов режима генерации сигнала (WGM02: 0) и режима вывода сравнения (COM0x1: 0).Биты режима вывода сравнения не влияют на последовательность подсчета, в то время как биты режима генерации сигнала влияют. Биты COM0x1: 0 определяют, должен ли генерируемый выход ШИМ быть инвертированным или нет (инвертированный или неинвертированный ШИМ). Для режимов без ШИМ биты COM0x1: 0 определяют, должен ли выход быть установлен, очищен или переключен при совпадении сравнения.

Таймер нормальный режим

Самым простым режимом работы является нормальный режим (WGM02: 0 = 0). В этом режиме направление счета всегда вверх (увеличивается), и сброс счетчика не выполняется.Счетчик просто переполняется, когда он проходит свое максимальное 8-битное значение (TOP = 0xFF), а затем перезапускается снизу (0x00). При нормальной работе флаг переполнения таймера / счетчика (TOV0) будет установлен в том же тактовом цикле таймера, когда TCNT0 становится нулевым. Флаг TOV0 в этом случае ведет себя как девятый бит, за исключением того, что он только устанавливается, а не сбрасывается. Однако в сочетании с прерыванием переполнения таймера, которое автоматически очищает флаг TOV0, разрешение таймера может быть увеличено программно. В нормальном режиме нет особых случаев, которые следует учитывать, новое значение счетчика можно записать в любое время.Модуль сравнения выходных данных можно использовать для генерации прерываний в определенный момент времени. Использование функции сравнения выходных сигналов для генерации сигналов в нормальном режиме не рекомендуется, так как это будет занимать слишком много времени ЦП.

Временная диаграмма таймера / счетчика с предделителем (fclk_IO / 8)
Сброс таймера при совпадении по сравнению (CTC)

В режиме сброса таймера при сравнении или CTC (WGM02: 0 = 2) регистр OCR0A используется для управления разрешением счетчика. В режиме CTC счетчик обнуляется, когда значение счетчика (TCNT0) совпадает с OCR0A. OCR0A определяет верхнее значение счетчика, а значит, и его разрешение. Этот режим позволяет лучше контролировать выходную частоту сравнения. Это также упрощает операцию подсчета внешних событий.

Таймер AVR — временная диаграмма режима CTC

Прерывание может генерироваться каждый раз, когда значение счетчика достигает значения TOP, с помощью флага OCF0A. Если прерывание разрешено, процедура обработки прерывания может использоваться для обновления значения TOP. Однако изменение TOP на значение, близкое к BOTTOM, когда счетчик работает без значения или с низким значением предварительного делителя, должно выполняться с осторожностью, поскольку режим CTC не имеет функции двойной буферизации.Если новое значение, записанное в OCR0A, ниже, чем текущее значение TCNT0, счетчик пропустит сопоставление. Затем счетчик должен будет отсчитать свое максимальное значение (0xFF) и выполнить цикл, начиная с 0x00, прежде чем может произойти сравнение. Для генерации выходного сигнала в режиме CTC, выход OC0A может быть настроен на переключение своего логического уровня при каждом совпадении сравнения, установив биты режима выхода сравнения в режим переключения (COM0A1: 0 = 1). Значение OC0A не будет отображаться на выводе порта, если направление данных для вывода не установлено на вывод.Сгенерированный сигнал будет иметь максимальную частоту fOC0 = fclk_IO / 2, когда OCR0A установлен на ноль (0x00). Частота сигнала определяется следующим уравнением:

Расчет частоты режима CTC AVR

Переменная N представляет коэффициент предварительного масштабирования (1, 8, 64, 256 или 1024). Что касается нормального режима работы, флаг TOV0 устанавливается в том же тактовом цикле таймера, который счетчик считает от MAX до 0x00.

Режим быстрой ШИМ

Режим быстрой широтно-импульсной модуляции или быстрый режим ШИМ (WGM02: 0 = 3 или 7) обеспечивает возможность генерации высокочастотного сигнала ШИМ.Быстрый ШИМ отличается от других вариантов ШИМ однонаправленным режимом работы. Счетчик ведет счет от НИЖНЕГО к ВЕРХНЕМУ, затем перезапускается с НИЖНЕГО. ВЕРХ определяется как 0xFF, когда WGM2: 0 = 3, и OCR0A, когда WGM2: 0 = 7. В неинвертирующем режиме сравнения выходных данных выходное сравнение (OC0x) сбрасывается при совпадении сравнения между TCNT0 и OCR0x и устанавливается в НИЖНИЙ. . В режиме инвертирования выхода сравнения выход устанавливается на совпадение сравнения и очищается ВНИЗ. Из-за однонаправленного режима рабочая частота в быстром режиме ШИМ может быть вдвое выше, чем в режиме ШИМ с правильной фазой, в котором используется двухканальный режим.Эта высокая частота делает быстрый режим ШИМ хорошо подходящим для регулирования мощности, выпрямления и применения ЦАП. Высокая частота позволяет использовать внешние компоненты (катушки, конденсаторы) небольшого размера, что снижает общую стоимость системы.

Таймер AVR — режим быстрой ШИМ

В режиме быстрой ШИМ счетчик увеличивается до тех пор, пока значение счетчика не будет соответствовать значению TOP. Затем счетчик очищается в следующем тактовом цикле таймера. Значение TCNT0 на временной диаграмме показано в виде гистограммы для иллюстрации операции с однократным наклоном.Схема включает неинвертированный и инвертированный выходы ШИМ. Маленькие горизонтальные отметки на наклонах TCNT0 представляют собой сравнительные совпадения между OCR0x и TCNT0.

Флаг переполнения таймера / счетчика (TOV0) устанавливается каждый раз, когда счетчик достигает TOP. Если прерывание разрешено, процедура обработки прерывания может использоваться для обновления значения сравнения. В быстром режиме ШИМ блок сравнения позволяет генерировать сигналы ШИМ на выводах OC0x. Установка битов COM0x1: 0 на два приведет к неинвертированному ШИМ, а инвертированный выход ШИМ может быть сгенерирован путем установки COM0x1: 0 на три: Установка битов COM0A1: 0 в единицу позволяет контакту OC0A переключаться на Сравнить совпадения, если установлен бит WGM02.Эта опция недоступна для вывода OC0B. Фактическое значение OC0x будет видно на выводе порта только в том случае, если направление данных для вывода порта установлено как выходное. Форма сигнала ШИМ генерируется путем установки (или очистки) регистра OC0x при совпадении сравнения между OCR0x и TCNT0 и очистки (или установки) регистра OC0x в тактовом цикле таймера, счетчик очищается (изменяется с TOP на BOTTOM).

Частоту ШИМ для выхода можно рассчитать по следующей формуле:

Формула частоты AVR для быстрой ШИМ

Переменная N представляет коэффициент предварительного масштабирования (1, 8, 64, 256 или 1024).
Крайние значения для регистра OCR0A представляют особые случаи при генерации выходного сигнала ШИМ в быстром режиме ШИМ. Если OCR0A установлен равным BOTTOM, на выходе будет узкий всплеск для каждого тактового цикла таймера MAX + 1. Установка OCR0A равным MAX приведет к постоянно высокому или низкому выходному сигналу (в зависимости от полярности вывода, установленной битом COM0A1: 0). Может быть достигнута частотная (с коэффициентом заполнения 50%) выходная форма волны в режиме быстрой ШИМ. путем настройки OC0x для переключения логического уровня при каждом сопоставлении (COM0x1: 0 = 1).Сгенерированный сигнал будет иметь максимальную частоту fOC0 = fclk_I / O / 2, когда OCR0A установлен на ноль. Эта функция аналогична переключателю OC0A в режиме CTC, за исключением того, что функция двойного буфера блока сравнения выходов включена в режиме быстрой ШИМ.

Режим фазовой коррекции ШИМ

Режим ШИМ с коррекцией фазы (WGM02: 0 = 1 или 5) обеспечивает возможность генерации сигнала ШИМ с коррекцией фазы с высоким разрешением. Режим ШИМ с правильной фазой основан на работе с двойным наклоном. Счетчик ведет постоянный отсчет от НИЖНЕГО к ВЕРХНЕМУ, а затем от ВЕРХНЕГО к НИЖНЕМУ.TOP определяется как 0xFF, когда WGM2: 0 = 1, и OCR0A, когда WGM2: 0 = 5. В неинвертирующем режиме сравнения выходных данных результат сравнения выходных данных (OC0x) сбрасывается при совпадении сравнения между TCNT0 и OCR0x при обратном подсчете, и установите совпадение по сравнению с обратным отсчетом. В инвертирующем режиме сравнения выходов операция инвертируется. Работа с двойным уклоном имеет более низкую максимальную рабочую частоту, чем при одностороннем. Однако из-за симметричности режимов двойного наклона ШИМ эти режимы предпочтительны для приложений управления двигателем.

В режиме ШИМ с правильной фазой счетчик увеличивается до тех пор, пока значение счетчика не совпадет с TOP. Когда счетчик достигает TOP, он меняет направление счета. Значение TCNT0 будет равно TOP для одного такта таймера. Значение TCNT0 на временной диаграмме показано в виде гистограммы для иллюстрации работы с двойным наклоном. Схема включает неинвертированный и инвертированный выходы ШИМ. Маленькие горизонтальные отметки на наклонах TCNT0 представляют собой сравнительные совпадения между OCR0x и TCNT0.

AVR — Временная диаграмма PWM с коррекцией фазы

Флаг переполнения таймера / счетчика (TOV0) устанавливается каждый раз, когда счетчик достигает ВНИЗ. Флаг прерывания может использоваться для генерации прерывания каждый раз, когда счетчик достигает НИЖНЕГО значения. В режиме ШИМ с коррекцией фазы блок сравнения позволяет генерировать сигналы ШИМ на выводах OC0x. Установка битов COM0x1: 0 на два приведет к неинвертированному PWM. Инвертированный выход ШИМ может быть сгенерирован установкой COM0x1: 0 на три: Установка битов COM0A0 в единицу позволяет контакту OC0A переключаться на сравнение совпадений, если бит WGM02 установлен.Эта опция недоступна для вывода OC0B. Фактическое значение OC0x будет видно на выводе порта только в том случае, если направление данных для вывода порта установлено как выходное. Форма сигнала ШИМ генерируется очисткой (или установкой) регистра OC0x при совпадении сравнения между OCR0x и TCNT0 при увеличении счетчика и установкой (или очисткой) регистра OC0x при совпадении сравнения между OCR0x и TCNT0 при уменьшении счетчика. Частота ШИМ для выхода при использовании ШИМ с правильной фазой может быть рассчитана по следующему уравнению:

Формула частоты ШИМ коррекции фазы АРН

Переменная N представляет коэффициент предварительного масштабирования (1, 8, 64, 256 или 1024).Крайние значения для регистра OCR0A представляют особые случаи при генерации выходного сигнала ШИМ в режиме ШИМ с правильной фазой. Если OCR0A установлен равным BOTTOM, выход будет постоянно низким, а если установлен равным MAX, выход будет постоянно высоким для неинвертированного режима PWM. Для инвертированного ШИМ на выходе будут противоположные логические значения.

Таймер Arduino Pomodoro | Блог Джейкоба Эмерика

Крутое событие, которое происходит каждый квартал на Shutterstock, — это Coderage, 24-часовой период времени, когда все разработчики могут работать над тем, что им заблагорассудится.Проект не обязательно должен быть связан с работой, хотя мы часто используем инструменты, которые используем каждый день, для быстрой совместной работы. Некоторые из вещей, над которыми я работал в прошлом, включают плагин для Phergie, рефакторинг приложения для использования новой версии PHP и базовый анализ данных о клиентах. Во время Coderage на прошлой неделе я хотел развлечься с Arduino Uno, который последние несколько месяцев находится в моем офисе.

Чтобы быть более конкретным, я хотел создать таймер Pomodoro с помощью Arduino.Техника Pomodoro — это методология управления временем, которая сочетает в себе планирование, ориентированное на задачи, с периодами сосредоточенного времени, разбитыми на короткие периоды отдыха. Это традиционно 25-минутный интервал с пятиминутными периодами отдыха. Это привлекательный метод для тех, кто занимается технологиями, с четкими показателями, простыми процессами и оправданием для игнорирования электронной почты и других уведомлений. Создание таймера — это не только хороший проект, над которым можно работать вне ручного управления, это даст мне повод опробовать эту технику.

Я набросал некоторые идеи перед тем, как что-нибудь наладить. Я хотел создать своего рода рудиментарный таймер, чтобы отслеживать, как далеко продвинулись интервалы, не слишком усложняя их. Кроме того, я не хотел смотреть на мигающий светодиод, чтобы узнать, завершился ли интервал, поэтому я подумал, что какая-то мелодия будет хорошим предупреждением, чтобы узнать, когда закончился период Помидора или отдыха. Некоторые кнопки тоже были бы хороши, как для подтверждения (и перехода) к следующему шагу таймера, так и для сброса текущего интервала (в случае необходимого прерывания).

25-минутный интервал и 5-минутный перерыв сделали для приятной симметрии. Шесть светодиодов (5 синих и 1 зеленый) могли отслеживать местонахождение таймера. На 1-й минуте у меня будет мигать первый синий светодиод, на 7-й минуте первый синий будет непрерывным, а второй — мигающим, а когда 25-минутный Помидор будет завершен, все пять синих светодиодов будут гореть непрерывно. По завершении работы срабатывает предупреждение, а затем программа приостанавливается, пока не будет нажата кнопка, сигнализируя о том, что я готов перейти к перерыву, чтобы проверить свою электронную почту и подготовиться к следующему интервалу.Я решил не использовать кнопку сброса, потому что это так же просто, как отключить и снова подключить.

Код и проводка оказались проще, чем я думал. В руководстве достаточно примеров, чтобы показать, как установить резисторы для светодиодов и пьезозуммера. Единственная сложность заключалась в том, как «приостанавливать» действия при нажатии кнопки, что не является явной командой на Arduino и не объясняется подробно. В итоге я выполнил цикл while, который казался хакерским, но работал нормально.

 
  1. while (digitalRead (ackButton)! = LOW) {}

Ближе к концу проекта я решил немного поиграться с тонами.В конце концов, одна нота просто не годится. Я немного огляделся и с помощью моей склонной к музыке жены сопоставил несколько тонов из Super Mario с моим кодом. Это было незначительное дополнение, которое заставило нас немного посмеяться при завершении проекта.

Таймер Pomodoro на Arduino Uno

Хотя я не закончил презентацию своего проекта (попытка повернуть камеру ноутбука, чтобы продемонстрировать это, звучит сложно), работать над этим было весело. Я использовал его только один раз во время работы до сих пор с ограниченным успехом, так как я слишком много отвлекаюсь в течение дня для истинных непрерывных двадцати пяти минут концентрации.Я собираюсь подержать его еще несколько дней, прежде чем вытащить все провода и построить что-то новое… Хотя трудно сказать, что это будет.

Примечание: код и схема размещены на Github: jacobemerick / pomodoro-arduino.

Основы — прерывания по таймеру — игровая площадка 2014

Давайте поговорим о таймере и прерываниях по таймеру.
Таймер или, лучше сказать, счетчик — это часть оборудования, встроенная в нашу Arduino Uno.
Наша Arduino Uno имеет три встроенных таймера: timer0, timer1 и timer2.
Timer0 и timer2 имеют разрешение 8 бит, timer1 имеет разрешение 16 бит. Разница между 8 и 16 битами — это разрешение таймера. С 8-битным у нас 256 значений, с 16-битным — 65536 значений.

Прерывания по таймеру позволяют вам выполнять задачу через определенные интервалы времени, независимо от того, что еще происходит.

Timer0:
Мир Arduino использовал этот таймер для функции delay (). Не забывайте, если вы измените этот интервал таймера, вы измените функцию delay ()!

Timer1:
С помощью этого таймера можно создать тактовый интервал с интервалом в 1 секунду или больше.Позже подробнее…

Timer2:
Это также 8-битный таймер, такой как timer0. Этот таймер бесплатный.

Теперь немного подробнее. Для настройки таймера нам понадобится регистр таймера. Вот важный регистр:

TCNTx
Регистр таймера / счетчика.

OCRx
Регистр сравнения выходных данных.

TIMSKx
Регистр маски прерывания таймера / счетчика.

TCCRx
Регистр управления таймером / счетчиком.

Все таймеры используют этот регистр. Вы различаете регистр дополнительной цифрой. Timer0 имеет регистр TCNT0, таймер 1 использует TCNT1, а таймер 2 использует TCNT2.

Начнем с первого регистра.
В регистре TCNT хранится фактическое значение счетчика. Вы можете прочитать это значение или сохранить там свое собственное начальное значение.

Регистр OCR . Этим значением мы решаем, закончился ли цикл таймера. Мы должны рассчитать это значение. Помните, что наш таймер 8-битный или 16-битный.С 8bit у нас есть только 256 возможностей. Поэтому у нас есть возможность использовать предварительный делитель для большей гибкости.

Предварительное масштабирование : Это значение предварительного масштабирования может быть установлено на 1, 8, 64, 256 или 1024.

Хорошо, теперь посчитаем пример с timer0.
Нам нужно прерывание по таймеру с частотой 200 Гц. Частота Arduino Uno фиксированная, 16MHz .

OCR0 = 16.000.000 / (значение предварительной шкалы * нужная нам частота)

Начнем со значения предварительного масштабирования 64:
OCR0 = 16.000.000 / (64 * 200)
OCR0 = 1250
Внимание! Значение слишком велико, у нас только 8 бит, значение должно быть меньше 256! Нам нужно другое значение предварительного масштабирования.

Мы рассчитываем с предварительным масштабированием 256:
OCR0 = 16.000.000 / (256 * 200)
OCR0 = 312,5
Все еще слишком много!

Мы рассчитываем с предварительным масштабированием 1024:
OCR0 = 16,000,000 / (1024 * 200)
OCR0 = 78,125
OCR0 = 78

Ничего страшного.

TCCR. Наш контрольный регистр. Это 16 бит, поэтому у нас есть два регистра: TCCRxA и TCCRxB с 8 битами.

Нам нужны 3 бита в регистре TCCRxB, называемые CSx0, CSx1 и CSx2. CS — это сокращение от Clock Select. С помощью этих трех битов мы определяем значение предварительного масштабирования. В следующем порядке: CSx2 — CSx1 — CSx0:
0 0 1 значение предварительного масштабирования: 1
0 1 0 значение предварительного масштабирования: 8
0 1 1 значение предварительного масштабирования: 64
1 0 0 значение предварительного масштабирования: 256
1 0 1 значение предварительного масштабирования: 1024

1 1 0 не для предварительного масштабирования
1 1 1 не для предварительного масштабирования

Как мне установить CS12, CS11 и CS10 в моем коде ?:
Пример: timer0

TCCR0B = 0; // второй бит TCCR с начальным значением 0

TCCR0B | = (1 << CS02) // установить только бит CS02 -> значение предварительного масштабирования: 256
или
TCCR0B | = (1 << CS01) // установить только бит CS01 -> значение предварительного масштабирования: 8
или
TCCR0B | = (1 << CS02) | (1 << CS00) // установить бит CS02 и CS0 -> значение предварительного масштабирования: 1024

Следующие необходимые детали:
Мы можем управлять нашим Arduino разными способами.Есть:
а) нормальный режим
Самый простой режим. В этом режиме счетчик всегда ведет счет. Если максимальное значение достигнуто, оно снова начинается с 0.

b) Режим сброса таймера при сопоставлении (CTC)
В этом режиме мы можем управлять разрешением счетчика. Мы можем использовать значение предварительного масштабирования. Поэтому нам нужен этот мод!

c) Режим быстрой ШИМ
В режиме быстрой ШИМ счетчик увеличивается до тех пор, пока значение счетчика не будет соответствовать значению TOP. Затем счетчик очищается в следующем тактовом цикле таймера.

Чтобы решить, в каком режиме мы работаем с нашим Arduino, нам понадобится дополнительный регистр WGMx1 . WGM — это ярлык для режима генерации сигналов.

Для режима CTC нам понадобится следующий оператор кода (в примере: timer0)
TCCR0A | = (1 << WGM01)

Как включить прерывание по таймеру?
ТИМСК. Этот регистр необходим для включения / выключения таймера прерывания. После завершения настройки мы включаем таймер, используя этот регистр.
Нам нужен один бит из регистра TIMSKx , который называется OCIExA .

Установите этот бит в единицу, прерывание разрешено (в примере: timer0).
TIMSK0 | = (1 << OCIE0A)

Как это:

Нравится Загрузка …

Контроллер таймера воды Gardena с использованием Arduino Uno | Теодор Костачойу | Electronza

В этом сообщении в блоге я покажу, как управлять водяным клапаном от таймера / компьютера для воды Gardena с помощью Arduino Uno.

Контроллер, который я использовал в этом примере, — или, лучше сказать, был — модель T14E, но подойдет любой другой контроллер с таким же водяным клапаном.

Gardena Таймер для воды

Идея возникла, когда моя собака решила взять один из таймеров для воды в качестве своей игрушки и прогрызла его до неузнаваемости. Электроника и корпус были полностью повреждены, но мне удалось восстановить водяной клапан. Так почему бы не попробовать управлять им с помощью Arduino? Есть огромные возможности для изучения: использование часов реального времени для управления им, как работала оригинальная электроника, или управление им через Wi-Fi и т. Д.

Водяной клапан внутри контроллера Gardena

Как вы можете видеть на картинке выше, водяной клапан использует разъем RCA для управляющих сигналов. Я использовал оригинальную электронику от другого спринклера, чтобы определить, как он работает, и формы сигналов выглядят следующим образом без подключенного водяного клапана:

Сигнал для включения водяного клапана Сигнал для отключения водяного клапана

При подключении водяного клапана сигналы выглядят так:

Форма волны открытия клапана Gardena — снята с оригинального контроллера.Форма волны для закрытия клапана — с оригинальным контроллером Подробный вид формы волны закрытия клапана

Изначально я думал, что это просто: отрицательный импульс 9 В должен открыть клапан, а положительный импульс 9 В должен его закрыть. Я использовал щит Ардумото, чтобы воспроизвести это, но при проведении обширных тестов у меня возникли проблемы: некоторые старые клапаны открываются правильно, но не закрываются. Вернемся к измерениям, на этот раз с исходным контроллером и подключенным клапаном. Результаты показывают, что для открытия применяется отрицательный импульс 500 мс, а напряжение на клапане составляет около 7 В.Учитывая внутреннее сопротивление обмотки клапана, похоже, что для размыкания в цепи используется последовательный резистор 10 Ом, работающий как ограничитель тока. Для включения последовательного резистора 100 Ом.

После многих попыток я получил следующую схему:

Что касается гильзы RCA, то для включения воды применяется отрицательный импульс 9 В с длительностью 500 мс. Чтобы выключить воду, на центральный штифт подается положительный импульс длительностью 150 мс. Самый простой способ воспроизвести это — использовать H-мост, такой как экран Ардумото, но с поворотом: цепь, состоящая из двух резисторов и диода, вставлена ​​последовательно с вентилем.

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *