Приклад настройки і роботи з таймером в avr, mainloop

У мікроконтролерах avr є такий периферійний модуль як таймер лічильник. Відповідно до своєї назви він вважає час. У таймер лічильника є регістр TCNT з якого можна прочитати скільки часу пройшло з моменту запуску таймера. Значення в цьому регістрі не в хвилинах або секундах, а в 'папуг' - 'тиках' таймера. Чому дорівнює один тик - залежить від тактової частоти, на якій працює мікроконтролер avr, і від налаштувань таймера.

Так само у таймера лічильника є настроюється дільник частоти, який визначає на скільки буде поділена тактова частота мікроконтролера перед тим як буде подана на таймер лічильник. Тривалість тика таймера є зворотною величиною від частоти, отриманої в результаті поділу.

наприклад:
Тактова частота = 11059200 Гц (11.0592 МГц)
Дільник = 1024
Частота таймера лічильника = Тактова частота / Дільник = 11059200/1024 = 10800 Гц
Тривалість періоду (тика) = 1/10800 = 92.593 * 10 ^ -6 секунди = 92.593 мкс

Для настройки дільника використовуються біти CS регістра TCCR.

Наприклад для таймера 1 в atmega8 використовуються регістр TCCR1B і біти CS10, CS11, CS12.

Залежність подільника від стану біт CS для таймера 1 в atmega8

TCCR1B = (1lt; lt; CS12) | (0lt; lt; CS11) | (1lt; lt; CS10); // xtall / тисячі двадцять чотири

У avr таймери можуть бути 8 або 16 розрядними. Розрядність визначає максимальну кількість тиків які може порахувати таймер. Для 8 розрядного це 256 тиків, для 16 це 65536.

У нашому випадку один тик дорівнює 92.593 мкс, відповідно максимальне значення, яке може виміряти 16 бітний таймер, це 65536 * 92.593 * 10 ^ -6 = 6.068 секунди, 8-ми бітний - 0.0237 секунди.

Після того як таймер дорахував до максимального значення, він переповнюється, тобто починає вважати з нуля. Цю ситуацію можна обробляти за допомогою переривань. Для цього треба дозволити переривання по переповнення таймера і виставити біт загального дозволу переривань.

Приклад коду для дозволу переривань таймера 1 avr atmega8:

TIMSK | = (1lt; lt; TOIE1); // дозволити переривання по переповнення таймера лічильника sei (); // виставити біт загального дозволу переривань

Так само треба визначити обробник даного переривання - функцію яка буде викликана при переповненні таймера.

Додамо в цю функцію код змінює стан ніжки PB0, до якої підключений світлодіод.

Приклад коду функції обробника переривання для таймера 1 avr atmega8:

ISR (TIMER1_OVF_vect)

Світлодіод буде змінювати свій стан через кожні 6 секунд.

Щоб світлодіод міняв свої статки з частотою 10Гц, треба щоб таймер відраховувати не 65536 тиків а менше. Розрахуємо необхідну кількість тиків:

Щоб таймер вважав не з нуля а з деякого значення, при ініціалізації і при кожному спрацьовуванні переривання в регістр TCNT1 будемо записувати число (65536 - 1080) = 64456.

Лістинг підсумкової програми для таймера 1 avr atmega8:

#include lt; avr / io.hgt; #include lt; avr / interrupt.hgt; ISR (TIMER1_OVF_vect)

Так само ви можете прочитати інші статті з рубрики «Мікроконтролери avr».

Архів з вихідними кодами під avr-gcc (WinAvr) можна завантажити тут.

Артем Колесников каже:

Артем Двинин каже:

Дякую за відгук. Так Ви праві, треба буде доповнити статтю, або може окрему замітку написати.

Дякуємо. Толково. Є питання. Таймер стартує при включенні МК. А як можна запускати і зупиняти його вручну (за допомогою кнопки наприклад).

Артем Двинин каже:

Будь ласка :)
Таймер стартує коли дільник частоти не дорівнює нулю, відповідно, що б зупинити таймер треба виставити дільник частоти рівним нулю, наприклад, для таймера 1 atmega8 треба обнулити біти CS12, CS11, CS10

Добрий день. як отримати сигнал від ІК приймача (38 КГц) його data підключений в PB0 у.
не знаю як налаштує таймери.
Допоможіть будь ласка.
за ранні спасибі.

Артем Двинин каже:

Доброго вам дня! А який у Вас мікроконтролер?

Допоможіть будь ласка. Зараз розбираюся з UART на avr studio4 (mega8)
Хочу зробити програму. в якій через термінал ми вводимо число. і світлодіод блимає. ну наприклад написав 10, значить блимати буде 10 раз в сек і тд.
Допоможіть порадою будь ласка
Заздалегідь вдячний
Ось мій код

Артем Двинин каже:

Може хто-небудь на асемблері викласти настройку таймера і мигалку на світлодіоді?

Добридень!
Потрібна ваша допомога! Я не програміст, починаю з простого - з Ардуіно (знаю, поганий початок, але так склалося). ось код

Ардуіно не вважає час менше 4 мкс, треба працювати з таймерами на пряму. Але я не знаю як і що. Допоможіть будь ласка!

Артем Двинин каже:

Назар, день добрий!
Вибачте, що не відразу відповідаю, літо, відпустка ... відпочиваю від комп'ютера :)
Ардуіно - нормальне початок, поки його можливостей вистачає, чомусь б і не використовувати, тим більше що це простіше ніж писати на голому Сі.
Можу підказати, як вирішити вашу задачу без бібліотек від arduino, використовуючи тільки ардуіновску плату.
Як компілятора буде avr-gcc або WinAvr.
Якщо Вам цікаво - пишіть, продовжимо спілкування :)

До речі, а що це за пристрій, який Ви розробляєте?

Привіт Артем! Спасибі за відповідь!
Я свою проблему вирішив, прилад - це вимірювач ємності від 1пФ + -0,25 пФ до 1,5 мкФ + -2,5нФ. Все працює, але цікаво було б зробити все не на Arduino IDE.
Ось мій код:

(1 lt; lt; TOIE0); // Disable Timer 0. TIMSK2 - =

Ще питання: як зробити що-б значення таймера при переповненні продовжувало збільшуватися, а не обнуляє і починалося спочатку? Тобто, я хочу зробити таймер 32-х бітовим. Це для того, що-б не робити окремі межі вимірювань, а просто збільшити час заряду конденсатора.
Заздалегідь дякую!

П.С. могу скинуть схемку, якщо цікаво.

Артем Двинин каже:

Доброго времени суток, Назар!
Таймер в avr 16 бітний, що б отримати 32 розряду можна налаштувати переривання по переповнення, і в цьому перериванні збільшувати програмний лічильник, назвемо його cnt.
Тоді виміряне значення буде (cnt <<16) + TCNT1;

А схема звичайно цікава, надішліть, будь ласка!

PS до речі, мені здається, в цьому рядку помилка:

while ((((ACSR - (1lt; lt; ACO)) == 0)) - (TCNT1 = 14001)

Справа може бути в тому, що у вас дільник = 1, тобто таймер працює з частотою 8МГц. З цієї ж частотою виконуються і команди мікроконтролера (1 - 3 такту на команду). Виходить, що якщо код обробника переривань виконується більш ніж за 256 тактів, то частота буде зменшуватися. Спробуйте дізасембліровать прошивку і подивитися який код генерується для обробника переривання.
Щоб отримати частоту більше ніж 8МГц / 256 можна спробувати переписати обробник на асемблері або використовувати таймер1 в режимі CTC (Clear Timer on Compare).

підкажіть а обов'язково значення в регістр OCR1A записувати в 16річном форматі? і обов'язково записувати значення спочатку в старший а потім молодший, тобто ось так:

TCCR0 = (1lt; lt; 0) | (1lt; lt; 1); // Налаштовуємо переддільник TIMSK | = (1lt; lt; TOIE0); // // ___________________________________________________ TIMER1 TCCR1B = (1lt; lt; CS12) | (0lt; lt; CS11) | (0lt; lt; CS10); // Налаштовуємо переддільник 256 TIMSK | = (1lt; lt; TOIE1); // TCNT1 = 0; // ___________________________________________________ TIMER2 // TCCR2 = (1lt; lt; CS12) | (0lt; lt; CS11) | (1lt; lt; CS10); // Налаштовуємо переддільник 1024 // TIMSK | = (1lt; lt; TOIE2); //

з таемером 2 все як то неработает

Артем Двинин каже:

Підкажіть будь ласка. У ATtiny2313a в налаштуваннях 16 бітного таймера в регістрі TCCR1A є такі біти: COMnA1: 0. COMnB1: 0, COMnC1: 0. З даташіта вичитав, що при збігу з регістром порівняння (відповідно до записаними значеннями в ці регістри) будуть змінюватися рівень напруги на протилежний, підтягуватися до + 5 або 0. Але от не можу зрозуміти, при активації даної функції можна міняти значення цих ніжок в програмі?

Артем Двинин каже:

Олександр, здрастуйте.
Виставляючи біти COMnA1: 0. COMnB1: 0, COMnC1: 0 Ви включаєте альтернативну функцію виведення, і забороняєте його роботу як звичайного порту введення-виведення (тобто виставити значення з програми не вийти). При цьому треба не забути налаштувати відповідний висновок на вихід.

Олександр М. каже:

Спробував прошити програму під AtMega 128 із зовнішнім кварцом на 16МГц, програма чомусь не запрацювала. Напевно треба виправити значення бітів?

Артем Двинин каже:

Доброго времени суток, Олександр.
Може спробувати спочатку просту програму?
Якщо буде блимати, то справа в налаштуваннях таймера, якщо немає, то не працює світлодіод.

#include #include int main (void)

Допоможіть початківцю!
Чи не запускається таймер на Attiny44

/////
#define F_CPU 8000000UL
#include

void init (void)
TCCR0B | = (1< TIMSK0 | = (1<>

ISR (TIM0_OVF_vect) // переривання

int main (void)
init (); // ініціалізація
sei (); // дозвіл всіх переривань
while (1)
asm ( "nop");
>
>

/////////////////////////
В даному випадку таймер навіть не починає рахувати!
Підкажіть в чому проблема ??
Заздалегідь вдячний.

1. З IDE завантажую скетч в Ардуіно Леонардо, де інформація по USB кожну секунду направляється на вихід. В консолі бачу щосекундне оновлення.
2. Підключаю замість консолі TeraTerm \ ttermpro.exe ». У вікні бачу щосекундне оновлення.
3. Всі закриваю, відключаю Ардуіно від USB.
4. Підключаю Ардуіно до USB. Підключаю TeraTerm \ ttermpro.exe ». У вікні бачу оновлення через 8 секуунд.

А чи не простіше в рахунковий регістр занести відразу нуль TCNT1 = 0;
А в регістр порівняння стільки тактів, скільки треба порахувати, наприклад 500 OCR1A = 500;
І налаштувати таймер на переривання за випадковим збігом. Ось весь код настройки:

TCCR1A | = (0 < TCCR1 | = (0 < TCCR1B | = (0 < TIMSK | = (1 < OCR1A = 461; // Число для порівняння (коли TCNT1 = OCR1A настане переривання за випадковим збігом)
TCNT1 = 0; // Обнуляємо значення рахункового регістра таймера / счётчіка1

Схожі статті