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

V predchádzajúcom článku som sa pokúsil vysvetliť a popísať čo je to časovač a čítač a takisto som som sa snažil na príklade ukázať naprogramovanie presného časového intervalu (záleží už len od presnosti frekvencie hodín).

V tomto článku len popíšem v čom sa odlišuje č/č1 od č/č0 a ukážem aj príklady na časovanie a využitie input capture. Na začiatok zistenie. Pokiaľ viem č/č1 sú dve verzie jedna staršia, ktorú som zaregistroval u rady Tiny a novšia v rade Mega. V tomto popise bude ako inak popisovaný č/č1 pre ATMega32.

Čítač/časovač1

Obsahuje (umožňuje):
-> 16bit čítač a časovač (č/č0 – 8bit);
-> 16bitové generovanie signálu PWM s možnosťou meniť periódu;
-> čítač vonkajších impulzov;
-> input capture unit – po privedení impulzu na ICP pin sa zachytí obsah registra TCNT1;
-> output capture unit – ako pri č/č0 s tým rozdielom že obsahuje dva 16bit porovnávacie registre; využíva sa pri PWM;
-> clear time on compare match;
-> generátor frekvencií;
-> štyri nezávislé zdroje prerušenia: od input capture, output capture A a B, pretečenie registra TCNT1;

obr1

Bloková schéma č/č1

Popis signálov na blokovej schéme:
-> BOTTOM – čítač dosiahne „bottom – spodok“ ak nadobudne hodnotu 0;
-> MAX – čítač dosiahne maximum ak nadobudne hodnotu 0xFFFF (65535);
-> TOP – čítač dosiahne „top – vrch“ ak nadobudne hodnotu rovnakú ako je nastavená pričom može byť: 0x00FF, 0x01FF alebo 0x03FF alebo hodnota ktorú obsahuje register ICR1, OCR1A/B;

Registre

16bit č/č1 využíva na svoju prácu tieto registre:

Konfiguračné registre:
TCCR1A – TCCR1B – 8bitové registre, ktorými sa nastavuje režim, delička hodín, PWM, porovnávanie a pod.;
TIMSK – 8bitový register na ovládanie prerušení od spomínaných štyroch zdrojov;
TIFR – 8bitový register, ktorý obsahuje „flag-y“ jednotlivých zdrojov prerušení;

Dátové registre:
ICR1 – 16bit register – sem sa uloží zachytená hodnota po privedení vopred definovaného impulzu na ICP pin;
OCR1A, OCR1B – 16bit registre, ktoré obsahujú porovnávané hodnoty;
TCNT1 – 16bit register – slúži na čítanie; obsahuje aktuálnu čítanú hodnotu;

16bit registre sa skladajú z dvoch 8bitových označených pridaním koncovky H (horný bajt) alebo L (dolný bajt) (napr. OCR1AL, OCR1AH). Prístup k takímto registrom – na konci článku.

Štruktúra jednotlivých registrov a popis ich bitov:

obr2

Obr.1 Register TCCR1A

Obsahuje bity pre nastavenie OutputCapture (COMxxx), vynutenie vystupov OC1xx (FOC1xx), nastavenie generovaného signálu PWM (WGM1x).

obr2a

Obr.2 Register TCCR1B

Umožňuje nastaviť potlačenie šumu na InputCapture (ICNC1 = log1), výber hrany pre InputCapture (ICES1) – nábežná -> log1, dobežná -> log0, nastavenie deličky bitmi CS1x.

obr3

Obr.3 Nastavenie bitov pre: Compare Output Mode – bez využitia PWM

obr7

Obr.4 Nastavenie preddeličky pre č/č1

obr8

Obr.5 Register TIMSK

Register pre nastavenie prerušení:
TICIE1 – prerušenie od InputCapture,
OCIE1A – prerušenie od OC, pri zrovnaní obsahu registrov TCNT1 a OCR1A,
OCIE1B – prerušenie od OC, pri zrovnaní obsahu registrov TCNT1 a OCR1B,
TOIE1 – prerušenie od pretečenia TCNT1 registra.

obr9

Obr.6 Register TIFR

Čítanie a časovanie

Čo sa týka časovania s č/č1 nijak sa neodlišuje od č/č0 až na 16bitový režim. No na ukážku som vytvoril primitívny program, ktorý v intervale 1s mení stav LED diódy pripojenej na PC0.

Program vyzerá takto:

/*
	xtal: 12MHz
*/

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

#define TC1 18661 //konstanta pre 12/256 MHz -> 1s

int main()
{
	//inicializacia led
	DDRC |= (1<<PC0);
	PORTC &= ~(1<<PC0);	//na zaciatku zhasnuta

	//nastavenie casovaca

	TCCR1A = 0;
	TCNT1 = TC1; 	//inicializacia citaca
	TIMSK = (1<<TOIE1); //nastavenie prerusenia od pretecenia TCNT1
	TCCR1B = (1<<CS12); //delicka 256 + spustenie casovania;

	sei();		//povolenie preruseni

	while(1)
	{
			// beh programu
	}

	return 0;
}

ISR(TIMER1_OVF_vect)  // obsluzna rutina prerusenia od pretecenia TCNT1
{
	TCNT1 = TC1;

	if (PINC & (1<<PC0)) //ak ledka svieti bude zhasnuta
	{
		PORTC &= ~(1<<PC0);
	}
	else if (!(PINC & (1<<PC0)))  //ak ledka nesvieti bude zasvietena
	{
		PORTC |= (1<<PC0);
	}
}

Na začiatku sa teda inicializuje pin, na ktorom je pripojená LED, ďalej časovač a prerušenie od pretečenia TCNT1. Čítač teda číta impulzy z oscilátora (12MHz) podelené deličkou 256. Keď pretečie (načíta do 2^16 = 65536 – 16bit čítač) vygeneruje sa prerušenie a v rutine prerušenia testujeme či ledka svieti alebo nie a zmení sa jej stav. Takto celý program beží dookola.

Input Capture Unit

Táto jednotka sa dá dobre využiť ak chcem zmeriať čas, v ktorom došlo k určitej vonkajšej udalosti. Jednoducho pracuje tak, že ak príde na pin ICP predtým definovaná úroveň signálu dôjde k zachyteniu obsahu registra TCNT1 do registra ICP1.

Ako príklad som vytvoril program, ktorý inkrementuje obsah TCNT1, vypisuje ho na displej a po stlačení tlačidla PD6 (ICP1) vypíše číslo na displej, ktoré bolo v okamžiku stlačenia tlačidla aktuálne v registri TCNT1.

A pripravil som ešte jeden zaujímavý program, ktorý zmeria čas medzi dvoma stlačeniami tlačidla PD6. Čas je však obmedzený na 5 sekúnd. Princíp je taky že pri prvom stlačení tlačidla sa uloží hodnota ICR1 do premennej time1 po ďalšom stlačení sa uloží ICR1 do time2. Zistí sa ich rozdiel a vynásobi sa časovou konštantou, ktorá je 1/(F_CPU/CS) čiže perioda frekvencie xtalu podelená 1024 (nastavenou deličkou). Ošetrený je aj prípad keď premenná time2 obsahuje menšiu hodnotu ako time1 teda TCNT1 medzi stlačeniami pretečie (ale iba raz :) ).
Skúste program upraviť tak, aby bolo možné meriať čas dlhší ako je 5 sekund. Tip: rátať do nejakej premennej počet pretečení TCNT1 a potom vyhodnotiť :)

PWM

Keďže táto časť je veľmi dlhá budem sa jej venovať v osobitnom článku.

Prístup k 16bitovým registrom

16bitové registre sú v týchto 8bit mikrokontroléroch realizované dvoma 8bitovými registrami, z ktorych jeden uchováva horny bajt (koncovka H napr. TCNT1H) a druhý dolný bajt (koncovka L napr. TCNT1L). Ak by sme chceli pristupovať k takémuto 16bit registru napr. v assembleri musíme pri zapisovaní najprv zapísať horný bajt do horného registra a až potom dolný bajt do dolného. Ak chceme čítať najprv sa číta spodný bajt. Príklad:

; zapis do registra TCNT1
LDI R17,0x01
LDI R16,0xFF
OUT TCNT1H,R17
OUT TCNT1L,R16
; citanie z registra TCNT1
IN R16,TCNT1L
IN R17,TCNT1H

Ak programujeme v c-čku nemusíme sa o nič starať je to jednoduche:

//zapis do registra TCNT1
uint16_t reg = 0x1FFF;
TCNT1 = reg;

//citanie z registra TCNT1
reg = TCNT1;

Záver

č/č má mnoho využití. Tie základne využitia som sa snažil popísať (ešte bude sľubované PWM). Viac vám už napovie datasheet :)

Príklady

11_casovac_1
12_input_capture1
13_input_capture2

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>