Нормальный режим
В нормальном режиме таймер на каждом такте увеличивает на единицу значение регистра TCNTn от 0 до переполнения, то есть до значения 256 для 8-битных таймеров или до 65536 для 16-битного.
При переполнении биты регистра TCNTn принимают значение 0, а также устанавливается флаг переполнения TOVn. То есть флаг TOVn в данном случае работает как 9-й или 17-й бит, но он может быть программно только установлен в единицу, но не обнулён. Если для таймера разрешено прерывание по переполнению, то микроконтроллер вызывает соответствующую функцию обработчик вектора TIMERn_OVF_vect.
В нормальном режиме нет ограничений на изменение значения регистра TCNTn, его можно изменять программно в любом месте программы.
Пример использования нормального режима
В данном примере я буду использовать таймер-счётчик 2 для того, чтобы мигать встроенным светодиодом.
Частоту мигания светодиода будет задавать значение потенциометра, подключенного к входу Analog 0.
Когда на входе Analog 0 будет низкий логический уровень, частота мигания будет равна 10 Герцам. При высоком логическом уровне - 1 Гц.
Для работы с таймером в скетче используется библиотека VEduino.
Код скетча (скачать код скетча):
#include <ve_avr.h> // Используется библиотека VEduino
volatile bool bOverflow = false; // Флаг прерывания (объявлен volatile, потому что изменяется в обработчике прерывания)
int counter = 0; // Счётчик прерываний
int frequency = 98; // Частота мигания светодиода (976 = 1Гц, 98 = 10 Гц)
void setup()
{
pinMode(LED_BUILTIN, OUTPUT); // Пин светодиода в режим вывода
DEV_TIMER2.setClockSelect(Prescaler2::Prescaler_64); // 16МГц / 64 = 250 кГц. Таймер-счётчик 2 будет
// увеличивать значение регистра TCNT2 на единицу
// каждые 4 микросекунды.
DEV_TIMER2.setWaveGenMode(Timer2::Normal); // Нормальный режим таймера-счётчика
DEV_TICTRL2.setOverflowIntEnable(true); // Разрешить прерывание по переполнению
interrupts(); // Разрешить прерывания
}
ISR(TIMER2_OVF_vect) // Обработчик прерывания TIMER2_OVF - переполнение таймера-счётчика 2
{
bOverflow = true; // Установить флаг прерывания
}
void loop()
{
while (bOverflow == false) ; // Ожидаем установки флага прерывания
bOverflow = false; // Сбрасываем флаг прерывания
++counter; // Увеличить счётчик на 1
if (counter == frequency / 2) // На половине значения частоты выключить светодиод
digitalWrite(LED_BUILTIN, LOW);
else if (counter == frequency) { // При достижении счётчиком значения частоты:
digitalWrite(LED_BUILTIN, HIGH); // Включить светодиод
counter = 0; // Обнулить счётчик прерываний
int potValue = analogRead(0); // Считать значение частоты, заданное потенциометром
frequency = map(potValue, 0, 1023, 98, 976);
}
}