Прямая работа с таймерами Arduino

ОБНОВЛЕНИЯ


  • v1.0

БИБЛИОТЕКА


directTimers v1.0

Библиотека для расширенного (ручного) управления таймерами ATmega328/168. Библиотека низкоуровневая и непростая в использовании, изучайте примеры!

  • Функции библиотеки позволяют получить доступ ко всем возможностям и режимам работы с таймерами/счётчиками + прерывания watchdog
  • Ничего не урезано и не упрощено, доступен весь описанный в даташите функционал
  • Разработчик – Egor ‘Nich1con’ Zaharov

Поддерживаемые платформы: платы на ATmega328/168 (Arduino Nano, UNO, Pro Mini)

УСТАНОВКА


  • Библиотеку можно найти и установить через менеджер библиотек по названию directTimers в:
    • Arduino IDE (Инструменты/Управлять библиотеками)
    • Arduino IDE v2 (вкладка «Library Manager»)
    • PlatformIO (PIO Home, вкладка «Libraries»)
  • Про ручную установку читай здесь

ДОКУМЕНТАЦИЯ


// n - номер таймера (0, 1 или 2)
void TIMERn_COMPA_attachInterrupt(void (*isr)());
void TIMERn_COMPB_attachInterrupt(void (*isr)());
void TIMERn_COMPA_detachInterrupt(void);
void TIMERn_COMPB_detachInterrupt(void);
void TIMERn_setClock(byte clk);
void TIMERn_setMode(byte mode);
void TIMERn_COMPA_mode(byte mode);
void TIMERn_COMPB_mode(byte mode);
byte TIMERn_getCounter(void);
void TIMERn_setCounter(byte value);
void TIMERn_COMPA_setValue(byte value);
void TIMERn_COMPB_setValue(byte value);

// прерывания watchdog
void WDT_attachInterrupt(void (*isr)(),int prescaler);
void WDT_detachInterrupt(void);

/* константы для TIMERn_clock() */
STOPPED             // тактирование будет остановлено , таймер "заморожен"
EXTERNAL_FALLING    // тактирование внешним клоком до 8 мгц по спаду
EXTERNAL_RISING     // тактирование внешним клоком до 8 мгц по фронту

// делители
PRESCALER_1
PRESCALER_8
PRESCALER_32
PRESCALER_64
PRESCALER_128
PRESCALER_256
PRESCALER_1024

/* константы для настройки режима работы таймеров */
STANDARD_MODE       // таймер считает до 255 и сбрасывается в 0, (может до 511/1023 для таймера 1)
CTC_MODE            // таймер считает от 0 до числа заданного функцией TIMERn_COMPA_setValue(), после чего сбрасывается (в этот момент может вызват прерывание)
FAST_PWM_8BIT       // аппаратный шим 8 бит
FAST_PWM_9BIT       // для таймера 1
FAST_PWM_10BIT 

// шим с коррекцией
PHASECORRECT_PWM_8BIT
PHASECORRECT_PWM_9BIT
PHASECORRECT_PWM_10BIT
FAST_PWM_CUSTOM             // шим с кастомной глубиной, глубина задается TIMER0/2_COMPA_setValue() и TIMER1_setTop();
PHASECORRECT_PWM_CUSTOM     // то же самое но с коррекцией

/* константы для управления аппаратными выходами с таймеров */
DISABLE_COMP     // выход отключен от ноги, ногой можно пользоваться
NORM_PWM         // выход генерирует шим >>> +5В при сбросе таймера, 0В при совпадении
INVERT_PWM       // выход генерирует инвертированный шим >>> 0В при сбросе таймера, +5В при совпадении
TOGGLE_PIN       // выход генерирует меандр >>> инверсия состояния пина при совпадении

ПРИМЕРЫ


Остальные примеры смотри в папке examples библиотеки, также примеры можно открыть из Arduino IDE/Файл/Примеры

#include 
/* пример генерации меандра на таймере 1*/
/* формула для расчета предела счета для генерации меандра приведена в шпаргалке README */
/* unsigned int top = (8000000/freqency)-1;  где top- предел счета, на который мы настроим таймер, freqency - желаемая частота меандра */
/* максимальная частота меандра - 8мгц */

// сгенерируем меандр с частотой 100кгц на двух каналах таймера 1 с возможностью смещения фазы 0...180 градусов относительно друг друга
// соотв для частоты 100 кгц >>> top = (8000000/100000)-1; >>> top = 79;

void setup() {
  TIMER1_setClock(PRESCALER_1); //установим максимальную частоту таймера
  TIMER1_setMode(CTC_MODE); // включим сброс по совпадению, происходит при совпадении счетного регистра со значением заданым TIMER1_COMPA_setValue();
  TIMER1_COMPA_mode(TOGGLE_PIN); // инвертирование состояние ноги при совпадении
  TIMER1_COMPB_mode(TOGGLE_PIN); // инвертирование состояние ноги при совпадении
  TIMER1_COMPA_setValue(79); //в режиме CTC_MODE задает предел счета и соотв частоту событий, на этом моменте уже начнется генерация меандра на канале А
}

void loop() {
  byte value = map(analogRead(A0), 0, 1023, 0, 79); // преобразуем значение с потенциометра в установленный нами диапазон 0...79
  /* 0...79 в данном случае эквивалентно сдвигу фазы на  0...180 градусов */
  TIMER1_COMPB_setValue(value);  // изменяя значение от 0 до 79 мы можем сдвигать меандр на канале В относительно первого на 0...180 градусов
}
#include 

/* пример генерации шим с выбранной частотой на таймере 1
  формула для рачета предела счета приведена в шпаргалке README */

/*
  Для режима FAST PWM >>> top = (Fтаймера/Fшим)-1;
  Для режима PHASECORRECT PWM >>> top = Fтаймера/(2*Fшим);
*/

// пусть частота ШИМ будет 25 кгц в режиме коррекции фазы >>> top = 8000000/25000 >>> top = 320;

void setup() {
  pinMode(9, 1); // настраиваем канал А как выход
  pinMode(10, 1); // настраиваем канал В как выход

  TIMER1_setClock(PRESCALER_1); // задаем таймеру максимальную частоту
  TIMER1_setMode(PHASECORRECT_PWM_CUSTOM); // включаем режим кастомного предела счета
  TIMER1_setTop(320); // устанавливаем предел счета 320, чтобы получить частоту 25 кгц с коррекцией фазы
  TIMER1_COMPA_mode(NORM_PWM); // настраиваем аппаратные выходы с таймера в режим ШИМ
  TIMER1_COMPB_mode(NORM_PWM);
}

void loop() {
  int dutyA = map(analogRead(A0), 0, 1023, 0, 320); // пересчитываем диапазон потенциометра в диапазон таймера 0...top >>> 0...320
  int dutyB = map(analogRead(A1), 0, 1023, 0, 320);

  TIMER1_COMPA_setValue(dutyA); // устанавливаем на выходе А заполнение потенциометром (pin 9)
  TIMER1_COMPB_setValue(dutyB); // (pin 10)
}
#include 
/* пример генерации стандартного шим 10 бит  */

void setup() {
  TIMER1_setClock(PRESCALER_1); // настройка делителя таймера
  TIMER1_setMode(FAST_PWM_10BIT); // настройка режима работы таймера
  TIMER1_COMPA_mode(NORM_PWM); // настроили аппаратные выходы с таймера в режим шим
  TIMER1_COMPB_mode(NORM_PWM);

  pinMode(9, OUTPUT); // аппаратный выход с таймера А
  pinMode(10, OUTPUT); // аппаратный выход с таймера B
}

void loop() {
  TIMER1_COMPA_setValue(analogRead(A0)); // заполнение шим канала А (pin 9) регулируется потенциометром
  TIMER1_COMPB_setValue(analogRead(A1)); // аналогично с каналом B (pin 10)
}
#include 
/* пример генерации нескольких прерываний по таймерам */

volatile int actualValue;

void setup() {
  Serial.begin(9600);

  TIMER1_setClock(PRESCALER_1024); // максимально замедляем таймер
  TIMER1_setMode(CTC_MODE); // включаем сброс таймера по совпадению
  TIMER1_COMPA_setValue(7811); // настроим таймер1 на прерывание 2 раза в секунду
  TIMER1_attach_COMPA(); // мигаем диодом
  pinMode(13, 1); // подключим светодиод на 13 ноге

  TIMER2_setClock(PRESCALER_1024); // максимально замедляем таймер
  TIMER2_setMode(CTC_MODE); // включаем сброс таймера по совпадению
  TIMER2_COMPA_setValue(24); // настраиваем прерывание на часототу 625 гц
  TIMER2_attach_COMPA(); // функция для получения актуального значения с ацп

  WDT_attachInterrupt(128); // настраиваем ватчдог на прерывание примерно раз в секунду >> доступны делители 16/32/64/128/256/512/1024 => ~0.125sec/0.25sec/0.5sec/1sec/2sec/4sec/8sec;
  while (millis() < 5000); // пока не пройдет 20 секунд сидим в setup и принимаем прерывания ватчдога
  WDT_detachInterrupt(); // отключаем прерывания ватчдога и продолжаем

}


void loop() {
  Serial.println(actualValue); // кидаем в порт актуальное значение с ацп
}

ISR_T2_COMPA {
  actualValue = analogRead(A0); // читаем ацп в прерывании
}

ISR_WDT {
  Serial.println("hello from watchdog"); // прерывание ватчдога
}

ISR_T1_COMPA { // прерывание мигания светодиодом
  digitalWrite(13, !digitalRead(13));
}

ПОДДЕРЖАТЬ


Вы можете поддержать меня за создание доступных проектов с открытым исходным кодом, полный список реквизитов есть вот здесь.

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

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