Mikrokontroléry rady AVR – čítač/časovač 0

V predchádzajúcom dieli tohto seriálu som uviedol (upravil) príklad kitt na ledkách s použitím čítača/časovača a prerušenia. Dnes túto veľmi užitočnú jednotku popíšem, ukážem prečo je tak dôležitá v mnohých programoch.

Čítač/časovač (ďalej č/č) – Timer/Counter0 – neumožňuje len presne časovať beh určitej časti programu, ale takisto dokáže (ako to už z názvu vyplýva) aj čítať vnútorné alebo aj vonkajšie impulzy (v čom sa skrýva princíp samotného časovania), generovať signál PWM, generovať signál určitej frekvencie, môže slúžiť ako delička impulzov a pod.

Mikrokontroléry rady AVR obsahujú niekoľko jednotiek č/č a označujú sa číslom (0, 1, ..). Konkrétne ATMega32 obsahuje tri takéto jednotky a to č/č0, č/č1 a č/č2. Každá z nich dokáže vykonávať základné činnosti (čítať, časovať) ale obsahujú aj navyše nejaké funkcie. V tomto článku sa budem zaoberať čítačom/časovačom 0 pre ATMega32.

Čítač/časovač 0

– 8-bitový modul čítača – časovača

Jednoduchá bloková schéma tejto jednotky je na nasledujúcom obrázku. Na púzdre má vyvedené dva piny, z ktorých je jeden vstupný T0 (PB0) a slúži na pripojenie vonkajšieho generátora pulzov, ktoré sa majú čítať alebo sa nimi má inak riadiť chod programu. Druhým z pinov je výstupný OC0 (PB3). Väčšinou sa využíva ako výstup signálu PWM.

obr1

Obr.1 Bloková schéma zapojenia č/č0

Vstupno výstupnými registrami, ktoré sa využívajú na riadenie sú:

a) TCNT0 (TimerCounterRegister) – 8-bit register, ktorý slúži na čítanie impulzov – obsahuje aktuálny stav čítania

b) OCR0 (OutputCompareRegister) – 8-bit register, ktorý obsahuje hodnotu, s ktorou sa má porovnávať obsah registra TCNT0

c) TIFR (TimerInterruptFlagRegister) – 8-bit register, ktorý slúži na „sledovanie“ žiadostí na prerušenia od tejto jednotky (a ostatných jednotiek č/č)

d) TIMSK (TimerInterruptMaskRegister) – 8-bit register, slúži na maskovanie (nastavovanie) prerušení od tejto jednotky (a ostatných jednotiek č/č)

e) TCCR0 (TimerCounterControlRegister) – slúži na riadenie čítača časovača

Hodiny a deličky č/č0

Č/č môže byť riadený vnútornými hodinami priamo alebo predelenými deličkou, ktorá sa dá nastaviť registrom TCCR0 ale takisto ho môžeme riadiť aj externými impulzmi privedenými na už spomínaný pin T0. Pozri blok Clock Select na obr1. Ak nie je vybraný zdroj hodín č/č je v neaktívnom stave.

obr2

Obr.2 Bloková schéma deličky č/č0 (č/č1)

Výber požadovanej deličky sa nastavuje bitmi CS02:00 v registry TCCR0. Poskytované sú: delička 8, 64, 256 a 1024. Delička sa dá takisto aj vypnúť. Nasledujúca tabuľka ukazuje ich nastavovanie.

obr3

Obr.3 Nastavenie deličky v TCCR0

Čítač a časovanie

Čítač je hlavnou časťou tejto jednotky. Čítač číta vstupné impulzy do registra TCNT0, ktoré sa môžu neskôr v programe vyhodnotiť napr. ako počet nábežných (dobežných) hrán nejakého signálu alebo sa presne prepočítať na určitý čas. Jeho bloková schéma je na nasledujúcom obrázku.

obr4

Obr. 4 Bloková schéma čítača

Popis signálov:

count – inkrementuje alebo dekrementuje register TCNT0 o 1
direction – vyberá medzi ikrementáciou alebo dekrementáciou
clear – vyresetuje – nastaví na 0 register TCNT0
clk – zdroj hodín
TOP – signalizuje že TCNT0 dosiahol maximálnu hodnotu – 255 (0xFF 8-bitový)
BOTTOM – signalizuje, že TCNT0 dosiahol minimálnu hodnotu – teda 0

To do akej hodnoty môže čítač čítať impulzy je riadené bitmi WGM01 a WGM00 registra TCNT0. Ak sú bity nastavené na nulu pracujeme v normálnom režime. Viac o tomto nastavení v časti o generovaní signálu PWM.

Príklad:
Upraviť program kitt s predchádzajúceho seriálu (v jazyku C) tak, aby rozsvietenie LED8 oproti LED1 bolo v čase 1 sekundy, t.j. zmena stavu medzi jednotlivými LED-kami je 1/8 sekundy teda 125 ms.
Využiť pritom vnútorný kalibrovaný oscilátor 1MHz a prerušenie od pretečenia TCNT0

Riešenie:
Predtým ako začnem rozoberať riešenie príkladu by som chcel vysvetliť ešte jeden veľmi dôležitý pojem, pre tých fakt začínajúcich a to je pretečenie časovača. Pretečenie je stav keď čítač po načítaní (do príslušného registra) na hodnotu maximalného rozsahu (u č/č0 – 8bit – 255) prejde cez tento rozsah (na 256) a znuluje sa. Teda prečíta nad hodnotu max. rozsahu 255. V takomto prípade sa po nastavení generuje prerušenie.

Daný príklad musíme riešiť tak, aby bol čas 1s meraný čo najpresnejšie t.j. treba zvoliť takú deličku, aby sme čo najlepšie využili rozsah čítacieho registra TCNT0 – ide o rozlíšenie.
Prečo musíme využiť deličku?
Potrebujeme aby medzi jednotlivými stavmi LED bola medzera 125 ms. Za ten čas musíme čítačom čítať prichádzajúce impulzy a presne v čase 125 ms musí čítač pretiecť t.j. TCNT0 = 256 a v rutine prerušenia zmeníme stav LEDiek.
1 perióda pri 1MHz trvá: T = 1/f = 1 us. Ak by sa mal register TCNT0 inkrementovať každý impulz priamo z oscilátora pretiekol by za čas t = 1e-6 * 2^8 = 256 us, čo je príliš rýchlo. Deličkou musíme túto hodnotu upraviť.

Skúsme podeliť našu frekvenciu napr. deličkou 256. Dostávame periódu: T = 1/(f/256) = 256 us a teda TCNT0 (pri počiatočnej hodnote 0) pretečie za čas 65,536 ms. Tento čas je ešte stále krátky keďže potrebujeme merať až 125 ms. Inú možnosť ako použiť deličku 1024 už nemáme iba ak zvoliť deličku menším číslom a pomôcť si nejakou premennou alebo prejsť na č/č1, ktorý je 16-bitový. Ale načo zbytočne zapratávať pamäť? A čo ak chceme č/č1 využiť na niečo iné?

Výpočet časovej konštanty pre deličku 1024:
Perióda pri deličke 1024 je T = 1/(f/1024) = 1,024 ms. TCNT0 (pri počiatočnej hodnote 0) pretečie za čas 262,144 ms. Keďže tento čas je príliš veľký upravíme počiatočnú hodnotu TCNT0 na konštantu ktorú vypočítame takto (teda čítač nebude čítať od nuly ale od určitej hodnoty, ktorú vypočítame):

dt = perioda prerusenia (pri TCNT0=0) – merany cas = 262,144 – 125 = 137,144 ms
t1 = perioda frekvencie casovaca0 = 1,024 ms
TC0 = dt / t1 = 137,144 / 1,024 = 133,9 = 134

Skúška: 256 – 134 = 122; 122*1,024ms = 124,928 ms ; teda rozsah čítača – naša konštanta nám dá číslo, ktoré musí časovač načítať (počet pulzov) a toto číslo ak vynásobíme periódou frekvencie časovača dostaneme náš meraný rozsah. Jednoduchšie to už nejde :)
Takže na začiatok programu nastavíme do registra hodnotu 134 a pri každom pretečení ju musíme znova nastaviť na túto hodnotu.

#include <avr/io.h>
#include <avr/interrupt.h>

#define TC0 134  //casova konstanta

unsigned char ii = 0;  //premenna pre cyklus - pocitanie prepnuti
unsigned char smer = 0;  //premenna pre urcenie smeru chodu 0-vpred 1-vzad
unsigned char led = 1;  //stav led

int main()
{
	OSCCAL = 0xA4; //kalibrovanie oscilatora

	DDRC = 0xFF;  //PORTC vystupny
	PORTC = 1; //na zaciatku prva led svieti

	//inicializacia casovaca
	TCNT0 = TC0;
	TIMSK = (1<<TOIE0);  //nastavenie prerusenia od pretecenia TCNT0
	TCCR0 = (1<<CS02)|(1<<CS00);  //nastavenie preddelicky a spustenie casovaca

	sei();  //povolenie preruseni

	while(1)  //program
	{
		//tu mozeme nieco robit
	}

	return 0;
}

ISR (TIMER0_OVF_vect)  //rutina prerusenia od pretecenia TCNT0
{
	TCNT0 = TC0;  //nastavenie casovej konstanty

	if (smer == 0)  //smer vpred
	{
		if (ii<7)
		{
			led <<= 1;  //rotacia do lava o jeden bit
			PORTC = led;
			ii++;
		}
		else if (ii == 7)
		{
			smer = 1;
		}
	}
	else if (smer == 1)  //smer vzad
	{
		if (ii>0)
		{
			led >>= 1;  //rotacia do prava o jeden bit
			PORTC = led;
			ii--;
		}
		else if (ii == 0)
		{
			smer = 0;
		}
	}
}

Output Compare

Táto časť jednotky č/č0 neustále (po nastavení) porovnáva hodnotu TCNT0 a OCR0 a ak zistí ich rovnosť nastaví príslušný bit v registri TIFR prípadne vyvolá prerušenie tohto typu. Takéto porovnávanie registrov sa dá využiť aj v predchádzajúcom príklade a to tak že TCNT0 necháme na 0 a OCR0 nastavíme na konštantu 122. Pri ich rovnosti dôjde k prerušeniu. Najčastejšie sa však využíva pri generovaní PWM signálu na výstupnom pine OCR0. Čo opíšem v nasledujúcej časti.

obr5

Obr. 5 Bloková schéma OutputCompare Unit

Režimy práce tejto časti jednotky sa dajú nastavovať bitmi COM00:1 v registry TCCR0 viď. nasledujúca tabuľka a závisia aj od súčasne nastaveného PWM režimu bitmi WGM00:1

obr6

Obr.6 Nastavenie režimov OutputComapre Unit bitmi COM00:1 pri rôznych PWM režimoch

Generovanie signálu PWM

Existujú tri režimy (spôsoby) generovania PWM signálu:
a) CTC Mode – Clear Timer on Compare Match
b) Fast PWM Mode
c) Phase Correct PWM Mode (resp. Center Aligned PWM)
Nastavujú sa bitmi WGM00:1 v registri TCCR0 podľa tabuľky:

obr7

Obr.7 Nastavenie bitov WGM00:1

Čo sa týka riešenia programu pre generovanie signálu PWM tak v tejto časti seriálu nebude. Budem sa tejto problematike podrobnejšie venovať pri č/č1.
Hore uvedené režimy sú pekné popísané aj s časovými diagramami v datasheete str. 74.

Štruktúra vstupno-výstupných registrov č/č0

obr8

Obr.8 Register TCCR0

obr9

Obr.9 Register TIMSK

obr10

Obr.10 Register TIFR

Záver

Jednotka č/č0 má mnoho využití a programy ktoré som tu riešil sa dajú riešiť aj inak. Treba si nájsť ten svoj spôsob, samozrejme by mal byť čo najefektívnejší. Veď aj o to v programovaní ide. Snažil som sa popísať tie najčastejšie využívané funkcie č/č0 a o ostatných sa pre zaujímavosť môžete dočítať v datasheete (ide o CompareMatch Output Unit, Fast PWM, Phase Correct PWM a iné režimy).

Príklad

Download 05_kitt_casovac

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *

Môžete použiť tieto HTML značky a atribúty: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>