Программирование таймеров-счётчиков 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:
#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>