Timer-ele sunt sisteme integrate în microcontroler care au ca scop măsurarea unor intervale fixe de timp şi de a genera întreruperi la expirarea intervalului măsurat.Tot cu ajutorul timer-elor se pot genera trenuri de impulsuri de o anumită frecvenţă sau compararea a 2 intervale de timp.Timer-ele funcţionează independent de unitatea centrală a micrcontrolerului astfel eliminându-se momentele de timp în care microcontrolerul este blocat într-o buclă de aşteptare.
Timer-ele conţin un numărător liber central(NLC) care are rolul de a număra fiecare impuls de tact.Acest NLC este de fapt un registru de 8 sau 16 biţi care la fiecare impuls este incrementat cu o unitate.Numărătorului i se poate da o valoare de start cuprinsă între 00h/0000h şi FFh/FFFFh.Dacă NLC-ul are valoarea FFh/FFFFh şi primeşte un impuls el se resetează,noua valoare fiind 00h/0000h.Tot în momentul resetării numărătorul trimite un semnal către sistemul de întreruperi.
Microcontrolerul ATMega8 oferă 3 timere:Timer 0,Timer 1 şi Timer 2 însă momentan ne vom concentra asupra Timer-ului 0.
Timer/Counter 0
Timer-ul 0 este un timer de uz general pe 8 biţi care are următoarea schemă bloc:
În cazul de faţă NLC-ul este reprezentat de registrul TCNT0 la care avem acces de citire şi scriere.Observăm din schemă că o dată ce s-a atins valoarea 0xFF se trimite un semnal către logica de control care poate genera o cerere de întrerupere.Sursa semnalului care incrementază NLC-ul poate fi externă(T0) sau internă(semnalul de tact al microcontrolerului) care poate fi prescalată.La fiecare tact clkT0 numărătorul TCNT0 este incrementat:
Registrul TCCR0 are rolul de a selecta şi prescala susra semnalului de tact, el având forma:
Din acest registru vom folosi numai ultimii 3 biţi (CS02, CS01, CS00) pentru setare.Valorile pe care le poate lua şi seminificaţiile lor sunt următoarele:
000– nu se selectează nici o sursă de tact;
001– foloseşte ceasul intern fără prescalare;
010– foloseşte ceasul intern cu prescalarea 8 (clkT0/8);
011– foloseşte ceasul intern cu prescalarea 64 (clkT0/64);
100– foloseşte ceasul intern cu prescalarea 256 (clkT0/256);
101– foloseşte ceasul intern cu prescalarea 1024 (clkT0/1024);
110– foloseşte o sursă externă de tact la pinul T0.Se ia în considerare frontul descrescător;
111– foloseşte o sursă externă de tact la pinul T0.Se ia în considerare frontul crescător;
Pentru a se putea genera o cerere de întrerupere a timer-ului 0 trebuie ca cel mai semnificativ bit al registrului SREG(bitul I) să fie 1 şi cel mai nesemnificativ bit al registrului TIMSK, bitul TOIE0 să fie tot 1.
Cererea de întrerupere este semnalizată în registrul TIFR în cel mai nesemnificativ bit,TOV0.Dacă registrul TCNT0 a fost umplut,TOV0 devine 0 şi atunci sistemul va genera o întrerupere executându-se codul de la adresa 0x009.
În majoritatea aplicaţiilor cu timere se foloseşte prescalarea sursei de tact.Calcului prescalării se face în felul următor:
Mai întâi calculăm frecvenţa la care dorim să se genereze o întrerupere.Frecvenţa va fi raportul dintre o secundă şi intervalul la care dorim să primim semnalul de la timer.
În funcţie de această frecvenţă vom alege frecvenţa externă sau vom prescala ceasul intern.Prescalarea ceasului intern se face în aşa fel încât frecvenţa rezultantă să fie egală sau mai mică cu frecvenţa dorită.
Dacă prescalând timerul nu obţinem o frecvenţă egală cu cea dorită şi obţinem o frecvenţă mai mică, atunci se calculează valoarea de start a NLC-ului.Această valoare va fi raportul dintre frecvenţa internă şi prescalarea aleasă la pasul anterior înmulţită cu frecvenţa dorită:
Pentru a înţelege mai bine cum se calculează frecvenţa vom calcula prescalarea şi n-ul pentru timpul de 0,2 secunde.Ceasul folosit va fi cel intern.Datele de pornire sunt: tdorit = 0.2s,fint =1MHz.
Observăm ca această frecvenţă este mai mică decât frecvenţa pe care dorim să o scoată timerul(5Hz), în consecinţă vom calcula valoarea de pormire a lui TCNT0.
Din păcate în numărător nu se pot reţine date în virgulă mobilă aşa că lui TCNT0 i se va atribui valoarea 195.Acest lucru va duce însă la o mică eroare de măsurare a timpului care totuşi este insesizabilă la o funcţionare pe termen scurt.
Pentru acest exempu configurarea regiştrilor va fi următoarea:
TCNT0=195;
TCCR0=0x05;
TIMSK=0x01;
Vom considera că la generarea unei întreruperi se va schimba starea unui pin la care avem legat un LED.Pinul de care vom lega LED-ul este PB0.
Programul îl puteţi downloada de la secţiunea Download-Timer0-Aplicaţie 1.
Schema electrică este una simplistă:
Când creaţi proiectul în CodeVision AVR,la secţiunea de setare a caracteristicilor, veţi seta pinul PB0 ca pin de ieşire iar pentru setarea parametrilor timer-ului veţi merge la Timers-Timer 0 şi veţi alege la Clock Source: System Clock, la Clock Value:0.977Hz,selectaţi Owerflow Interrupt şi la Time value treceţi C3h(195 în decimal).Observăm că frecvenţa aleasă nu este cea calculată de noi însă aceată alegere va seta TCCR0=0x05, adică prescalarea cu 1024.
Observăm că la generare avem următoarele setări:
TCCR0=0x05;
TCNT0=0xC3;
TIMSK=0x01;
În concsecinţă setările sunt bine făcute.Ce a mai apărut nou în program este funcţia de tratarea a întreruperilor generate de timer,funcţie în care vom iniţializa de fiecare dată TCNT0 şi în care vom schimba valoarea PORTB-ului:
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitializam valoarea timerului
TCNT0=0xC3;
// Schimbam starea PORTB-ului
PORTB =~PORTB;
}
Bun, probabil aţi observat că acest program se putea face şi fără timere de aceea următorul exemplu va fi unul mai complex şi anume un ceas digital reglabil.Aplicaţia va avea un LCD pe care vom putea citi ceasul şi 2 butoane prin care se va regla minutul şi ora,butoane care vor fi legate la pinii INT0 şi INT1.Aplicaţia o puteţi downloada de la secţiunea Download- Timer 0- Aplicaţie 2.
Schema electrică este următoarea:
Următorul lucru pe care trebuie să îl facem este să calculăm frecvenţa timerului astfel încât să avem o întrerupre la o secundă.Pentru aceasta frecvenţa dorită este 1 MHz.Dacă folosim ceasul intern şi prescalăm cu maximul adică cu 1024 observăm că noua frecvenţă obţinută este de 3.81Hz, frecvenţă care este mai mare decât frecvenţa pe care dorim să o folosim.Pentru a elimina acest neajuns vom folosi o variabilă suplimentară în program care se incrementează la fiecare 0,1 secunde,adică la 10Hz.Când se ajunge la valoarea 10, variabila care reţine secundele se incrementează iar valoarea variabilei suplimentare va deveni 0.Momentan vom calcula valorile regiştrilor pentru frecvenţa dorită de 10Hz.În consecinţă vom folosi iar prescalarea cu 1024 însă vom calcula n-ul pentru 10Hz:
Pentru a mai diminua din erori vom rotunji n-ul la 98 şi nu 97.Configurarea pentru generarea programului în CodeVision AVR se face la fel ca mai înainte însă la Timer Value treceţi 62(98 în decimal).De asemenea nu uitaţi să configuraţi LCD-ul pe portul B şi să activaţi întreruperile externe.
Programul va avea 3 funcţi de tratare a cererilor de întrerupere,două pentru tratarea butoanelor care modifică ora şi minutul şi una pentru tratarea întreruperii generate de timerul 0.Funcţia care tratează întreruperea externă INT0 are rolul de a incrementa minutul iar funcţia care tratează întreruperea externă INT1 are rolul de a incrementa ora.Dacă minutul a ajuns la valoarea 60 sau ora la valoarea 24 , ele trebuiesc resetate.Funcţia care tratează timerul 0 are rolul de a incrementa o variabilă suplimentară până la valoarea 10 , adică echivalentul unei secunde,la această valoare ea resetându-se şi incrementând variabila secundă(sec) cu o unitate.În aceste funcţii sunt verificate variabilele de ceas dacă au ajuns la valoarea maximă şi dacă da ele sunt resetate şi totodată sunt incrementate variabilele care le urmează.
În cele trei funcţii se are grijă ca după fiecare modificare a variabilelor să se scrie noua stare a ceasului pe LCD.Acest lucru se face prin modificarea sirului de caractere linie1.
Din păcate ceasul nostru nu este unul exact, existând erori de măsurare a timpului, erori care pot fi înlăturate folosind un oscilator extern special pentru ceas.
Aplicaţia realizată fizic o puteţi vedea aici:
1 comentarii:
Dar codul In Assembler puteti sa-l puneti sau nu?
Trimiteți un comentariu