Dnes bude řeč o čítačích/časovačích AVR. Díl buze téměř celý teoretický. Na konci si ukážeme jak přesně časovat události, aniž bychom podstatně ovlivnili jiné důležité úkoly proceosru.
Úvodem
Procesory ATMEGA16 obsahuji celkem tři čítače/časovače. Dva osmibitové, jeden šestnáctibitový. Vstupní signály mohou být předděleny předřazenou předděličkou, a to v hodnotách 1;8;64;1024.
Především si ale musíme říci, na co nám čítače/časovače budou. Vzpomeňme si na náš program s blikající LEDkou. Procesor musel zpracovávat smyčky pro čekání a během tohoto procesu samozřejmě nemohl dělat nic jiného. Tento způsob je velmi neefektivní a využít jej můžeme pouze v malém množství případů. Lepším řešením by bylo, aby se časování odehrávalo na pozadí, toho právě můžeme dosáhnout pomocí čítačů/časovačů…
Teorie
Čítače časovače nastavujeme speciálními registry. Zde je jejich krátký výčet:
- TCNT(N) – obsahuje načítanou hodnotu
- OCR(N) – obshuje hodnotu, s níž se TCNT(N) porovnává
- TCCR(N) – řídí funkce čítače/časovače
- TIMSK – masky přerušení
Lépe než mnoho teoretických řádků poslouží jednoduchý příklad, který nám, jak jinak, zajistí blikání LED v pravidelných intervalech, během nichž však tentokrát můžeme vykonávat výpočty…
;********************************************************************************************
;* PROGRAM_BLIK03.ASM; *
;* Procesor ATMEGA16 - DIL *
;********************************************************************************************
;--------------------------------------------
; popis fce registru:
; -> R19 - pomocny registr (platny lokalne)
; -> R1 - slouzi pro pocitadlo preruseni
; -> R2 - slouzi pro pocitadlo preruseni
.NOLIST
.INCLUDE "m16def.inc"
.LIST
; PRIRAZENI JMEN PINUM, PORTUM A REGISTRUM
.CSEG
.ORG 0
RJMP RESET
.ORG OC0addr
RJMP PRERUSENI
.DEF TEMP = R19
.DEF INT_CNT = R2
.EQU BLIK_PORT_DRIVE = DDRC
.EQU BLIK_PORT_DATA = PORTC
.EQU BLIK_PIN = PORTC0
; NASTAVENI ZASOBNIKU
RESET: LDI R16,LOW(RAMEND)
OUT SPL,R16
LDI R16,HIGH(RAMEND)
OUT SPH,R16
; NASTAVENI CASOVACE_0 A JEHO PRERUSENI
LDI R19,12 ; nastavi zdroj signalu
OUT TCCR0,R19 ; casovace 0 na 31250Hz
LDI R19,250 ; nastavi porovnavanou
OUT OCR0,R19 ; hodnotu na 250 (preruseni 125/s)
LDI R19,02 ; povoli preruseni,
OUT TIMSK,R19 ; kdyz TCNT0=OCR0.
; NASTAVENI REGISTRU
CLR INT_CNT ; smaze pocitadlo preruseni
CLR INT_CNT ; smaze pocitadlo preruseni
LDI TEMP,255
OUT BLIK_PORT_DRIVE,TEMP
// ************************ HLAVNI PROGRAM ********************** //
ZACATEK_PROGRAMU:
SEI
// tady neco muzeme delat
RJMP ZACATEK_PROGRAMU ; skoci na zacatek (stale dokola)
// ************************ PODPOROGRAMY ************************ //
// ****************** OBSLUHY PRERUSENI *********************** //
PRERUSENI:
INC INT_CNT ; inkrementuje R2
LDI TEMP,125
CP R2,TEMP ; je-li R2 mensi
BRLO PRYC_LABEL ; nez TEMP jde pryc
CLR INT_CNT
SBIC BLIK_PORT_DATA,BLIK_PIN
RJMP CLEAR_PIN_LABEL
SBI BLIK_PORT_DATA,BLIK_PIN
RJMP PRYC_LABEL
CLEAR_PIN_LABEL:
CBI BLIK_PORT_DATA,BLIK_PIN
PRYC_LABEL:
NOP
RETI
Vysvětlení programu bude stručné. Nevíme sice zatím, co je to přerušení, ale můžeme si říci, že je to situace, kdy se stane určitá událost, běh programu se přeruší v místě právě zpracovávané instrukce a program skočí na vektor přerušení (řádek v programu). Z tohoto vektoru je zavolnána obslužná rutina, zde PRERUSENI. Po jejim konci se program vrátí na místo, odkud byl přerušen.
Náš program by měl zajistit blikání LED připojené na PC0, a to frekvencí závisející na frekvenci oscilátoru, který jsme si vybrali. Při oscilátoru 8 Mhz bude perioda 2 s. Ostatně, to si můžete sami ověřit v AVR studiu.
Podrobněji
; NASTAVENI CASOVACE_0 A JEHO PRERUSENI
LDI R19,12 ; nastavi zdroj signalu
OUT TCCR0,R19 ; casovace 0 na 31250Hz
LDI R19,250 ; nastavi porovnavanou
OUT OCR0,R19 ; hodnotu na 250 (preruseni 125/s)
LDI R19,02 ; povoli preruseni,
OUT TIMSK,R19 ; kdyz TCNT0=OCR
Tato část kódu nastaví časovač nula do režimu, kdy je porovnáván registr TCNT0 (čítač) a OCR0 (nastavená hodnota) – bity WGM01, WGM02. V tomto případě je čítač vynulován a je vyvoláno přerušení. Bity CS02, CS01, CS00 určují zdroj hodinového signálu. V tomto případě je to oscilátor předdělený 256. Tím dostaneme frekvenci přerušení (8 000 000 / 256) / (OCR0 + 1). Přerušení nám tedy vznikají 125× za sekundu.
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
FOC0 | WGM00 | COM01 | COM00 | WGM01 | CS02 | CS01 | CS00 |
Jakmile je vyvoláno přerušení, program odskočí na tento řádek:
RJMP PRERUSENI
Ten zajistí, že je vyvolána potředná obslužná rutina, která dovolí změnit stav LED pouze 125× za její vyvolání.
Pro dnešek je to vše. Do příště si vyzkoušejte uvedený program odsimulovat v AVR studiu. Sledujte zvláště registr TCNT0 a jeho změny. Významy jednotlivých bitů uvedených registrů si můžete nastudovat v katalogovém listu procesoru. Bude-li vám i tak něco nejasného, pište do komentářů pod článkem.