Міністерство освіти і науки України
Національний університет “Львівська політехніка”
Кафедра КСА
Звіт до лабораторної роботи №2
на тему «Реалізація програмних затримок за допомогою таймерів»
з предмету «Програмування мікроконтролерів систем автоматики»
Варіант № 3
Львів 2015
Мета роботи: ознайомитися зі структурою периферійних модулів таймерів мікроконтролерів AVR. Навчитися писати програми з відліком часових інтервалів за допомогою таймерів/лічильників мікроконтролера.
Короткі теоретичні відомості
МК AVR мають на борту різні реалізації таймерів. Перш за все це 8-ми та 16-ти розрядні таймери/лічильники. Останні, відповідно, можуть відраховувати точніші та довші інтервали часу. Також присутні в моделях AVR і сторожові таймери (Watchdog Timer), що призначені для контролю за несанкціонованим зациклюванням програми.
8-розрядні таймери/лічильники. У МК AVR реалізовано три виконання 8-розрядних таймерів/лічильників, що відрізняються набором виконуваних функцій. Перше виконання має реалізовані лише восьмирозрядний лічильник та лічильник зовнішніх подій. Друге виконання має додатково 8-розрядний ШІМ (широтно-імпульсний генератор) та формувач сигналів. Третє виконання ще додає керування таймером/лічильником в асинхронному режимі (годинник реального часу). У моделях AVR можуть бути присутні 2 восьмирозрядні таймери, які позначаються відповідно T0 та T2. Кількість таймерів та їхнє виконання залежать від конкретної моделі. Також від виконання залежить і кількість переривань, що можуть бути згенеровані таймером.
Як 8- так і 16-розрядні таймери AVR використовують у своїй роботі 10-розрядний попередній подільник частоти. Він використовується для всіх наявних таймерів в моделі МК, окрім таймера з керуванням в асинхронному режимі, який має свій окремий попередній подільник.
Рис. 1. Блок попереднього дільника таймера
На виході мультиплексора дільника частоти вхідна тактова частота, від якої тактується МК, розбита на ряд підчастот, які зменшені у вказане число раз. Наприклад, clk/64 означає, що відраховується 64 тактів МК, після чого посилається імпульс для таймера. Таким чином, ми можемо сповільнити роботу нашого таймера.
Варто мати на увазі, що попередній подільник працює незалежно від таймера. У результаті чого виникає невизначений проміжок часу (від 1 до значення дільника) між дозволом таймера та його першим відліком при сумісній роботі з дільником частоти. Для цього передбачена можливість скиду значень попереднього дільника частоти шляхом запису лог. 1 у відповідний біт регістра SFIOR.
Таймери, що не мають асинхронного режиму роботи, можуть тактуватися також від зовнішнього сигналу Тзовн. При цьому можна налаштувати відлік або по наростанню фронту сигналу, або по його спаду. Частота зовнішнього сигналу повинна бути у 2,5 рази меншою за частоту тактового генератора МК.
Попередній подільник частоти для асинхронного таймера може тактуватися як від основного генератора тактової частоти МК, так і від автономного генератора із своїм зовнішнім кварцем. Цей автономний генератор оптимізований під годинниковий кварц 32 768 Гц. Асинхронний подільник має додаткові коефіцієнти поділу 32 та 128, однак відсутній підрахунок від зовнішніх імпульсів.
Вибір режиму тактування таймера здійснюється за допомогою трьох бітів CSn, що розміщені у регістрі TCCRn (табл. 1).
Таблиця 1. Вибір тактового сигналу для таймерів виконання 1, 2
CSn2
CSn1
CSn0
Джерело тактового сигналу
0
0
0
Таймер зупинений
0
0
1
clkI/O
0
1
0
clkI/O/8
0
1
1
clkI/O/64
1
0
0
clkI/O/256
1
0
1
clkI/O/1024
1
1
0
Рахунок імпульсів на виводі Tn
за спадаючим фронтом
1
1
1
Рахунок імпульсів на виводі Tnза наростаючим фронтом
Таймери/лічильники можуть працювати у 4-х режимах:
Нормальний режим. 8-розрядний лічильний регістр нараховує 256 тактів таймера, виникає переповнення, і рахунок продовжується зі значення 0. При виникненні переповнення виставляється у регістрі TIFR прапор переповнення TOV та генерується переривання (якщо це переривання дозволене у регістрі TIMSK прапорцем TOIE, а також виставлений загальний дозвіл у регістрі стану SREG).
Скид при співпадінні. У цьому режимі наш лічильний регістр здійснює рахунок тактів таймера до вказаного 8-розрядного значення у регістрі порівняння OCR, після чого скидається у значення 0. Під час обнулення лічильного регістра виставляється прапор співпадіння OCF та генерується переривання, якщо звісно є загальний дозвіл на переривання у SREG та виставлений прапор дозволу OCIE у регістрі TIMSK.
Швидкий ШІМ.
ШІМ з точною фазою.
Таблиця 2. Режими роботи 8-розрядних таймерів
WGMn1
WGMn0
Режими роботи таймера
0
0
Нормальний (по переповненню)
0
1
ШІМ з точною фазою
1
0
Скид при співпадінні
1
1
Швидкий ШІМ
Для нормального режиму та скиду при співпадінні можемо налаштувати поведінку виводу таймера OCn (табл. 3).
Таблиця 3. Керування виводом OC у норм. реж. та скиду при співп.
COMn1
COMn0
Поведінка
0
0
Таймер відключений від виводу OC
0
1
Стан виводу змінюється на протилежний
1
0
Вивід скидується в «0»
1
1
Вивід скидується в «1»
При необхідності стан виводу OCn може бути змінений примусово, шляхом запису лог. 1 у розряд FOCn регістра TCCRn. Переривання при цьому не генерується.
Завдання до лабораторної роботи
Зібрати у пакеті симуляції Proteus схему на основі МК ATmega32A та написати програму мовою асемблер для реалізації такого алгоритму:
Лінійка з 8-ми одноколірних світлодіодів. При натисканні кнопки світлодіоди починають почергово блимати по одному з обох боків рухаючись назустріч.
P7→P0→P6→P1→ P5→P2→P4→P3
1. Часові інтервали вимірюються за допомогою таймерів, при цьому паралельно виконується робота в основній програмі.
2. При використанні таймера 2 в асинхронному режимі передбачається, що він тактується від годинникового кварца 32768 Гц.
3. При переключенні світлодіодів звукова піщалка має видавати звук тривалістю 0,1 сек.(для непарних варіантів) та 0,2 сек. (для парних варіантів).
Рис. 2. Принципова схема пристрою, що зібрана у пакеті Proteus
Код програми пристрою мовою асемблер
.include "m32Adef.inc"
.def _flag = r0 ; 0біт - пауза =0 (пораховано), =1(ще рахує)
; 2біт - тривалість паузи =0(1сек), =1(0.5сек)
.def _count = r21
.def _count2= r22
.def _countA= r23
.def _countBuz = r24
.CSEG
.org $000
jmp RESET ; Reset Handler
.org $014
jmp TIM0_COMP ; Timer0 Compare Handler
.org $028
reti ;Store Program Memory Ready Handler
;підпрограма переривання по співпадінню Таймера 0 ----------------
TIM0_COMP: sbrs _flag, 0 ; якщо відлік дозволений
rjmp Task0end
inc _count ; _count++
cpi _count, 100 ; порівнюємо з числом 20
brne Task0end ; на кінець, якщо не рівне
rjmp ready
ready: clt ; Т=0
bld _flag, 0 ; 0біт=1 (пауза порахована)
clr _count ; _count=0
Task0end:
;----------------------Task3 (звук)--------------------------
sbrs _flag, 4
rjmp Task3end
inc _countBuz
cpi _countBuz, 6
brne Task3end
clt
bld _flag, 4 ;(пораховано)
clr _countBuz ;(обнулення)
cbi PORTD, 2 ;викл. звук
Task3end:
T0end: reti
;------------------------------------------------------------------------------------------
RESET: ldi r16, Low(RAMEND)
out SPL, r16
ldi r16, High(RAMEND)
out SPH, r16
ldi r16, 0x00
ldi r17, 0xFF
out DDRC, r16 ; порт C на вхід
out PORTC, r17
out DDRD, r17 ; порт D на вихід
out PORTD, r16
out DDRA, r17
out PORTA, r16
clr _countA
clr _countBuz
; таймер_0 скид по співпадінню, 25msec, Prescaler=1024, OCR=0xC2
ldi r16, (1<<WGM01)|(1<<CS02)|(1<<CS00)
out TCCR0, r16 ; OCR=0xC2
ldi r16, 0x59
out OCR0, r16 ; OCR=0xC2
ldi r16, (1<<OCIE0)
out TIMSK, r16 ; дозвіл на перер. по співпадінню
; обнулюємо регістри
clr _count
clr _flag
sei ; заг. дозвід на переривання
;---------- Основна програма -------------------------------------------------------
main:
sbic PINC, 5
rjmp end ; а якщо ні -- робимо щось інше
ldi _count2, 0
PUSH _count2
ldi _count2, 8
PUSH _count2
ldi _count2, 16
PUSH _count2
ldi _count2, 4
PUSH _count2
ldi _count2, 32
PUSH _count2
ldi _count2, 2
PUSH _count2
ldi _count2, 64
PUSH _count2
ldi _count2, 1
PUSH _count2
ldi _count2, 128
PUSH _count2
foo:
sbrc _flag, 0 ; якщо пауза відрахована, тоді інверсія робимо роботу
rjmp PC5end ; а якщо ні -- робимо щось інше
set
bld _flag, 0
bld _flag, 4
POP _count2
CPI _count2, 0
breq end
out PORTA, _count2
sbi PORTD, 2
PC5end:
rjmp foo
end:
rjmp main
Висновки: виконавши дану лабораторну роботу, я отримав практичні навики програмування мовою асемблер мікроконтролерів AVR з використанням таймерів та звукових сигналів.