Программирование таймеров-счётчиков Arduino

Программирование таймеров-счётчиков Arduino.

Прежде, чем программировать таймеры, поскольку мне удобно использовать библиотечные функции Arduino, то мне хотелось бы иметь возможность узнать, в каком режиме работает таймер-счётчик 0.

Поэтому прежде всего я решил написать скетч, который общался бы с Arduino IDE через последовательный порт и выполнял бы функции терминала, для того, чтобы я мог в Arduino IDE открыть окно монитора, ввести команду и получить в ответ дамп регистров. В результате получилась библиотека под названием Simple Dumping Monitor, используя которую я получил следующую о состоянии таймера-счётчика 0 микроконтроллера ATmega328p Arduino:

>t0
Timer         0
Clock source /64 prescaler
WGM mode 3 - Fast PWM
TOP         FF
Update of OCR0x at BOTTOM
TOV0 flag set on MAX
OC0A Output mode 0-disconnected
OC0B Output mode 0-disconnected
TOV interrupt         enabled
COMPA interrupt         disabled
COMPB interrupt         disabled
TCNT0         55
OCR0A         00
OCR0B         00
Synchronization mode inactive

Итак, как следует из вышеприведённого дампа, таймер-счётчик 0 тактируется через предделитель /64, то есть с частотой 250 кГц, в режиме быстрого ШИМ с переполнением каждые 256 тактов (976.5625 Гц), выводы ШИМ не задействованы, прерывания по совпадению не используются ни A, ни B, но вызывается прерывание по переполнению. То есть с частотой 976 Гц вызывается прерывание системного таймера Arduino.

VEduino Library как решение

Некоторое время у меня заняло написание библиотеки классов 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:

Таймер-счётчик 2 платы Arduino Leonardo

По пока невыясненным причинам в даташите микроконтроллера ATmega16U4/32U4 отсутствует таймер-счётчик 2. Тем не менее, таймер работает, так что в библиотеку VEduino Library for Arduino добавлена поддержка данного периферийного устройства.

В папке examples можно найти скетч-пример VEduino_LEDfade, который демонстрирует использование таймера-счётчика 2 микроконтроллера Leonardo для управления яркостью свечения светодиодов, подключенных к выводам Digital 8 (OC2A) и Digital 2 (OC2B), с помощью потенциометра, подключенного к выводу A0.

Cхема подключения:

Схема подключения потенциометра и светодиодов для скета VEduino_LEDfade.

Исходный код скетча 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

Скачать библиотеку VEduino можно со страницы Библиотека VE_AVR.

Подробнее почитать о таймерах-счётчиках Arduino, а также рассмотреть и скачать примеры использования счётчиков в разных режимах, можно в разделе Таймеры-счётчики Arduino.

Автор: Андрей Шаройко <vanyamboe@gmail.com>