Таймери ARDUINO UNO

Конструкції та програмування ARDUINO UNO
Відповісти
Аватар користувача
radioman
Site Admin
Повідомлень: 133
З нами з: 28 вересня 2020, 12:01
Звідки: Тернопіль
Дякував (ла): 8 разів
Подякували: 6 разів

Таймери ARDUINO UNO

Повідомлення radioman »

Виникла потреба у використанні ARDUINO UNO. Так як давно не писав для неї, зайнявся пошуками готових рішень.
Мені необхідно виконувати деякі дії з певною регулярністю, тому оптимальним рішенням є використання апаратних таймерів. Досить грунтовну інформацію знайшов у матеріалі Timer Interruptions. Використовуючи її, та деякі інші напрацювання, написав скетч "блимання" світлодіодом з використанням переривання таймеру:

Код: Виділити все

// https://radioman.com.ua/viewtopic.php?f=8&t=45

bool A_STATE = true;            // статус 13 виводу

void setup ( )
{
  pinMode ( 13, OUTPUT ) ;

  // ініціалізація Timer1
  cli ( ) ;                     // відключити глобальні переривання
  TCCR1A = 0 ;                  // встановити регістр 1A в 0
  TCCR1B = 0 ;                  // встановити регістр 1B в 0

  // Таймер переповнюється кожні 65535 відліків при дільнику 1024 або за 4,194с
  // Частота переривань = 16000000 / (1024 * (1 + 15624) = 1 s

  OCR1A = 15624 ;               // встановлення регістру збігу (1 секунда)
  TCCR1B |= ( 1  << WGM12 ) ;   // увімкнути CTC режим > скидання таймера за збігом
  TCCR1B |= ( 1  << CS10 ) ;    // встановити біт CS10 CS12 на дільник 1024
  TCCR1B |= ( 1  << CS12 ) ;
  TIMSK1 |= ( 1  << OCIE1A ) ;  // включити переривання зі збігом таймера
  sei ( ) ;                     // включити глобальні переривання
}

void loop ( )
{
  /* програма */
}

ISR ( TIMER1_COMPA_vect )       // Викликається ISR (TIMER1_OVF_vect), це відбувається завжди коли таймер переповнюється
{
  A_STATE = !A_STATE;           // Інвертуємо статус світлодіода
  digitalWrite(13, A_STATE);    // Виводимо нове значення на 13 контакт
}
PS. В даному прикладі по перериванню таймера відбувається зміна рівня на 13 виводі; але в обробнику переривань ми можемо виконувати будь-яке потрібне нам регулярне завдання.
Аватар користувача
radioman
Site Admin
Повідомлень: 133
З нами з: 28 вересня 2020, 12:01
Звідки: Тернопіль
Дякував (ла): 8 разів
Подякували: 6 разів

Re: Таймери ARDUINO UNO

Повідомлення radioman »

Більш детально про таймери Arduino UNO.
У мікроконтролері ATmega328 є три таймери: T0, T2 - по 8 біт та T1 - 16 біт. Вони мають деякі однакові режими роботи:

Нормальний режим роботи (по переповненню). Найпоширеніший режим, коли таймер просто рахує імпульси, що приходять, і при переповненні рахункового регістру встановлює прапор переривання по переповненню; рахунковий регістр скидається в 0 і підрахунок імпульсів починається спочатку.
Режим підрахунку імпульсів (Скидання по збігу, CTC). При збігу рахункового регістру з одним з регістрів порівняння виставляється прапор переривання за збігом, рахунковий регістр обнулюється і підрахунок починається спочатку.
Режим ШІМ. Змінюється ширина імпульсу залежно від значення, записаного в регістр збігу. Наприклад, для 8-бітного таймера (T0, T2), якщо записати в регістр збігу число 20, стан логічної одиниці на виході збігу буде 20 тактів з 256, а логічний 0 - 236 тактів з 256 (для неінверсного режиму). В інверсному режимі 20 тактів буде стан логічного 0 і 236 тактів логічної одиниці.
Режим корекції фази ШІМ. У звичайному режимі ШІМ фазу вихідного сигналу буде "плавати". Для того, щоб цього уникнути, у режимі корекції фази ШІМ при досягненні максимального значення, лічильний регістр таймера/лічильника починає зменшуватися. Це відбувається циклічно.

У 16-ти бітного таймера T1 є додаткові режими роботи:

Режим корекції фази та частоти ШІМ. Відрізняється від режиму корекції фази ШІМ лише моментом оновлення регістру порівняння - регістр порівняння оновлюється, коли значення рахункового регістру досягає мінімуму.
Режим захоплення. При надходженні сигналу від аналогового компаратора, а також на ICP1 (14 ніжка) значення рахункового регістру зберігається в регістрі захоплення, встановлюючи при цьому прапор переривання по захопленню.

Розберемо більш детально роботу таймера із скетчу в попередньому пості.
Для передділення частоти на 1024, необхідно біти CS10 та CS12 встановити у одиницю (15.11.2 TCCR1B – Timer/Counter1 Control Register B, ст.110 даташиту)
Встановлення переддільника частоти
Встановлення переддільника частоти

Код: Виділити все

TCCR1B |= ( 1  << CS10 ) ;   
TCCR1B |= ( 1  << CS12 ) ;
При дільнику 1024, 16-ти бітний таймер переповнюється кожні 65535 відліків , тобто при тактовій частоті 16 мГц за 4,1945с
Для отримання частоти переривань 1 Hz (Частота переривань = 16000000 / (1024 * (1 + 15624) = 1) нам необхідно записати в регістр OCR1A число 15624

Код: Виділити все

OCR1A = 15624 ;
Вмикаємо CTC режим (скидання таймера за збігом, mode 4), ст.100 (15.9.2 Clear Timer on Compare Match (CTC) Mode), ст.109 (Table 15-5. Waveform Generation Mode Bit Description) даташиту:

Код: Виділити все

TCCR1B |= ( 1  << WGM12 ) ;
і включаємо переривання за збігом таймера; 15.11.8 TIMSK1 – Timer/Counter1 Interrupt Mask Register, ст.112 даташиту:

Код: Виділити все

TIMSK1 |= ( 1  << OCIE1A ) ;
Відповісти