БИБЛИОТЕКА DIRECTTIMERS

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

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

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

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


// 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 0  			//- тактирование будет остановлено , таймер "заморожен"
EXTERNAL_FALLING 1	//-тактирование внешним клоком до 8 мгц по спаду
EXTERNAL_RISING 2 	//-тактирование внешним клоком до 8 мгц по фронту
PRESCALER_1 3		// делитель 1
PRESCALER_8 4		// делитель 8
PRESCALER_32 5		// и тд
PRESCALER_64 6
PRESCALER_128 7
PRESCALER_256 8
PRESCALER_1024 9
/* константы для настройки режима работы таймеров */
STANDARD_MODE 10 	// таймер считает до 255 и сбрасывается в 0, (может до 511/1023 для таймера 1)
CTC_MODE 11 		// таймер считает от 0 до числа заданного функцией TIMERn_COMPA_setValue(), после чего сбрасывается (в этот момент может вызват прерывание)
FAST_PWM_8BIT 12 	// аппаратный шим 8 бит
FAST_PWM_9BIT 13 	// для таймера 1
FAST_PWM_10BIT 14 
PHASECORRECT_PWM_8BIT 15	// шим с коррекцией
PHASECORRECT_PWM_9BIT 16
PHASECORRECT_PWM_10BIT 17
FAST_PWM_CUSTOM 18			// шим с кастомной глубиной, глубина задается TIMER0/2_COMPA_setValue() и TIMER1_setTop();
PHASECORRECT_PWM_CUSTOM 19	// то же самое но с коррекцией
/* константы для управления аппаратными выходами с таймеров */
DISABLE_COMP 20		// выход отключен от ноги, ногой можно пользоваться
NORM_PWM 21			// выход генерирует шим >>> +5В при сбросе таймера, 0В при совпадении
INVERT_PWM 22		// выход генерирует инвертированный шим >>> 0В при сбросе таймера, +5В при совпадении
TOGGLE_PIN 23		// выход генерирует меандр >>> инверсия состояния пина при совпадении

ПРИМЕРЫ


#include "directTimers.h"
/* пример генерации меандра на таймере 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); // инвертирование состояние ноги при совпадении
TIMER1_COMPB_mode(TOGGLE); // инвертирование состояние ноги при совпадении
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 "directTimers.h"
/* пример генерации шим с выбранной частотой на таймере 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(PWM); // настраиваем аппаратные выходы с таймера в режим ШИМ
TIMER1_COMPB_mode(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 "directTimers.h"
/* пример генерации быстрого шим 8 бит с частотой 31 кгц и коррекцией фазы */
void setup() {
TIMER2_setClock(PRESCALER_1); // настройка делителя таймера
TIMER2_setMode(PHASECORRECT_PWM_8BIT); // настройка режима работы таймера
TIMER2_COMPA_mode(PWM); // прямой шим канал А
TIMER2_COMPA_mode(INVERT_PWM); // инверсный шим канал B
pinMode(11, OUTPUT); // аппаратный выход с таймера А
pinMode(3, OUTPUT); // аппаратный выход с таймера B
}
void loop() {
int duty = analogRead(A0) / 4;
TIMER1_COMPA_setValue(duty); // заполнение шим канала А (pin 11) регулируется потенциометром
TIMER1_COMPB_setValue(duty); // заполнение равно каналу A и инвертировано. (pin 3)
}
#include "directTimers.h"
/* пример генерации стандартного шим 10 бит  */
void setup() {
TIMER1_setClock(PRESCALER_1); // настройка делителя таймера
TIMER1_setMode(FAST_PWM_10BIT); // настройка режима работы таймера
TIMER1_COMPA_mode(PWM); // настроили аппаратные выходы с таймера в режим шим
TIMER1_COMPB_mode(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 "directTimers.h"
/* пример генерации нескольких прерываний по таймерам */
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));
}

ОСТАЛЬНЫЕ БИБЛИОТЕКИ

У меня есть ещё очень много всего интересного! Смотрите полный список библиотек вот здесь.