Прежде, чем программировать таймеры, поскольку мне удобно использовать библиотечные функции Arduino, то мне хотелось бы иметь возможность узнать, в каком режиме работает таймер-счётчик 0.
Поэтому прежде всего я решил написать скетч, который общался бы с Arduino IDE через последовательный порт и выполнял бы функции терминала, для того, чтобы я мог в Arduino IDE открыть окно монитора, ввести команду и получить в ответ дамп регистров. В результате получилась библиотека под названием Simple Dumping Monitor, используя которую я получил следующую о состоянии таймера-счётчика 0 микроконтроллера ATmega328p Arduino:
>t0Timer 0Clock source /64 prescalerWGM mode 3 - Fast PWMTOP FFUpdate of OCR0x at BOTTOMTOV0 flag set on MAXOC0A Output mode 0-disconnectedOC0B Output mode 0-disconnectedTOV interrupt enabledCOMPA interrupt disabledCOMPB interrupt disabledTCNT0 55OCR0A 00OCR0B 00Synchronization mode inactiveИтак, как следует из вышеприведённого дампа, таймер-счётчик 0 тактируется через предделитель /64, то есть с частотой 250 кГц, в режиме быстрого ШИМ с переполнением каждые 256 тактов (976.5625 Гц), выводы ШИМ не задействованы, прерывания по совпадению не используются ни A, ни B, но вызывается прерывание по переполнению. То есть с частотой 976 Гц вызывается прерывание системного таймера Arduino.
Некоторое время у меня заняло написание библиотеки классов VE_AVR, с помощью которой в варианте VEduino программирование таймеров-счётчиков микроконтроллеров ATmega осуществляется столь же просто и непринуждённо, как добавление нескольких строчек кода в скетч.
Вот исходный код примера VEduino_Timer:
#include <ve_avr.h> // Скетч использует библиотеку VEduino. #define LED_PIN 13 // Предполагается мигание светодиодом. /** * Эти переменные объявлены volatile, поскольку их значение меняется * в обработчике прерывания. */ volatile bool bLedOn = false; volatile uint16_t potValue; /** * Функция предварительной настройки после сброса. */ void setup() { pinMode(LED_PIN, OUTPUT); // Настройка вывода Digital 13. potValue = analogRead(0) << 6; // Напряжение на потенциометре, подключенному к входу Analog In 0, // умножается на 2 шесть раз. DEV_TIMER1.setClockSelect(TimerW::Prescaler_64); // 16МГц / 64 = 250 кГц. Таймер-счётчик 1 будет // увеличивать значение регистра TCNT1 на единицу // каждые 4 микросекунды. DEV_TIMER1.setWaveGenMode(TimerW::FastPWM_OCRA); // Таймер-счётчик 1 будет сравнивать значение регистров // TCNT1 и OCR1A и всякий раз, когда они будут равны, DEV_TICTRL1.outCompIntEnableA();// будет вызываться функция-обработчик прерывания TIMER1_COMPA_vect. interrupts(); // Включить прерывания. } /** * Функция итерации основного цикла программы. */ void loop() { potValue = analogRead(0) << 6; // Считать значение потенциометра. if (bLedOn) // Если светодиод должен светиться, digitalWrite(LED_PIN, HIGH); // то включить светодиод. else digitalWrite(LED_PIN, LOW); // Либо наоборот - выключить. }/** * Обработчик прерывания сравнения вывода A таймера-счётчика 1 */ ISR(TIMER1_COMPA_vect) { // Установить значение следующего прерывания согласно напряжению от потенциометра. DEV_TIMER1.setOutputCompareA(potValue); bLedOn = ! bLedOn; // Сменить состояние светодиода в основном цикле программы. } Потенциометр в данном примере подключается к входу Analog In 0:
По пока невыясненным причинам в даташите микроконтроллера ATmega16U4/32U4 отсутствует таймер-счётчик 2. Тем не менее, таймер работает, так что в библиотеку VEduino Library for Arduino добавлена поддержка данного периферийного устройства.
В папке examples можно найти скетч-пример VEduino_LEDfade, который демонстрирует использование таймера-счётчика 2 микроконтроллера Leonardo для управления яркостью свечения светодиодов, подключенных к выводам Digital 8 (OC2A) и Digital 2 (OC2B), с помощью потенциометра, подключенного к выводу A0.
Cхема подключения:
Исходный код скетча VEduino_LEDfade:
#include <ve_avr.h> // This sketch uses VEduino Library. #define LED1 DEV_TIMER2_OCA // Set up your own values here: PORT, PIN #define LED2 DEV_TIMER2_OCB // Set up your own values here: PORT, PIN uint8_t potValue; void setup() { DEV_TIMER2.setClockSelect(Prescaler2::Prescaler_64); DEV_TIMER2.setWaveGenMode(Timer2::FastPWM); DEV_TIMER2.setCompOutModeA(Timer2::Clear); DEV_TIMER2.setCompOutModeB(Timer2::Clear); setModeOutput(LED1); setModeOutput(LED2); } void loop() { potValue = analogRead(A0) >> 2; DEV_TIMER2.setOutputCompareA(potValue); DEV_TIMER2.setOutputCompareB(potValue); }Скачать библиотеку VEduino можно со страницы Библиотека VE_AVR.
Подробнее почитать о таймерах-счётчиках Arduino, а также рассмотреть и скачать примеры использования счётчиков в разных режимах, можно в разделе Таймеры-счётчики Arduino.
Автор: Андрей Шаройко <vanyamboe@gmail.com>