Professional Documents
Culture Documents
Asi Msi 7
Asi Msi 7
Microcontrolere si sisteme
integrate
1
Temporizatoare si numărătoare -1
Registru de numărare
Magistrală de date
Ieşire depăşire/
(internă)
împrumut
Semnal intern scriere-
(re)încărcare 3
Ceas numărare
Temporizatoare si numărătoare - 3
• Însă un registru de numărare poate fi si citit (tipic prin intermediul unui alt registru
intermediar)
• O facilitate des întâlnită la un sistem de temporizare/numărare este aşa zisa funcție de
captură/captare/memorare a intrării la un moment definit de timp(input capture)
– Un astfel de timer similar celui prezentat in figură, are un registru de tip D Latch (transparent) conectat la
ieșirea registrului de numărare
• Timer-ul are un semnal de ceas stabil, cu frecventa constantă (tipic provenind din ceasul
sistem) astfel că el incrementează sau decrementează in mod constant, liber (free
running timer)
• Un semnal extern poate înscrie si memora valoarea curentă a registrului de numărare in
registrul latch, de unde aceasta, garantat stabilă, poate fi citită de unitatea centrală
– Acest semnal de ceas definește si momentul din care conținutul registrului poate fi citit
• Tipic acest eveniment generează si el un semnal de ieșire – un eveniment (care nu a
mai fost ilustrat in figură), putând genera de exemplu o întrerupere
• O funcție ceva mai complicată (neilustrată aici), este cea de comparare a ieșirii (output
compare); ieșirea numărătorului este comparată cu ieșirea unui registru (cu aceiași
dimensiune, programabil de utilizator) cu ajutorul unui comparator numeric; la egalitate se
generează un eveniment (schimbare stare pin sau întrerupere)
Registru de numărare Registru latch (memorare iesiri)
Magistrală de date
(internă)
Ceas
numărare
Semnal extern de scriere, 4
captura intrare
Temporizatoare si numărătoare - 4
5
AVR 8 biți: temporizatoare si numărătoare
(Timer / Counters)
• Microcontrolerele din familia AVR 8 biti au un sistem de
temporizare/numărare care cuprinde un anumit număr de
temporizatoare/ numărătoare, funcție de variantă, numerotate cu 0, 1,
2, etc., având registre de numărare de 8 sau 16 biți
• Trebuie consultată foaia de catalog a variantei respective de AVR,
pentru a vedea cate temporizatoare sunt disponibile pentru o anumita
variantă si ce caracteristici au ele; de exemplu:
– ATTiny 2313 are 2 temporizatoare/numărătoare: Timer 0 de 8 biți, Timer 1
de 16 biți
– ATMega16 are 3 temporizatoare numărătoare: Timer 0 de 8 biți, Timer 1
de 16 biti si Timer 2 de 8 biți
– ATMega64 are 4 temporizatoare/numărătoare: Timer 0 de 8 biți, Timer 1
de 16 biti si Timer 2 de 8 biți si Timer 3 de 16 biti
– ATMega 1280 sau 2560 au 6 temporizatoare/numărătoare: Timer 0 de 8
biti, Timer 1 de 16 biți si Timer 2 de 8 biți, Timer 3 de 16 biți, Timer 4 de 16
biti, Timer 5 de 16 biți
• Timerele 3, 4, 5 sunt similare Timer-ului 1
– ATTiny 13 are doar un singur temporizator/ numărător Timer 0 de 8 biți
• Prezentarea care urmează este una introductivă, fără pretenții de
exhaustivitate 6
AVR 8 biți, sistemul de temporizare
numărare la variantele modernizate
(Microchip)
• Variantele modernizate de Tiny si MEGA (seriile 0
si 1) au un sistem de temporizare / numărare
reorganizat, cu denumiri actualizate si oarecum
diferite pentru registrele si câmpurile de biți
aferente
• Exista acum:
– un Timer A (TCA) de 16 biți
– de la unul la patru Timere B (TCB), de 16 biți, cu intrări
de captare
• Există in continuare toate facilitățile existente la
vechile Timer 0 si Timer 1
• Pe lângă unele modificări de funcționalitate trebuie
ținut cont ca schimbarea numelor afectează si
mnemonicile utilizate de compilator așa ca
obligatoriu trebuie consultate foile de catalog
7
AVR 8 biti: temporizatoare (Timers)
• Fiecare temporizator/numărător este compus dintr-un
registru de numărare (numărătorul propriu-zis), care este
de fapt si un registru de date (el poate fi citit si/sau scris)
• Semnalul de ceas poate incrementa acest registru:
numărătoarele AVR 8 biti numără tipic in sus (sunt up
counters)
– Exista si situații speciale când pot număra in jos
• Numărătoarele AVR sunt numărătoare binare
• Numărătoarele AVR sunt numărătoare programabile,
adică in ele se poate (pre) înscrie o valoare de la care să
înceapă să numere- astfel lungimea ciclului de numărare
este programabila
• Dacă semnalul de ceas pentru acest numărător provine,
eventual printr-o divizare suplimentară (realizată cu un mic
numărător, programabil, numit prescaler), din ceasul
sistem, avem o funcționare ca temporizator (timer)
– In modul Timer evoluția lui este una sincronă cu cea a unității
centrale si a perifericelor AVR, având același semnal de ceas intern
8
Rezoluția si durata maximă de numărare /
temporizare
• Rezoluția (resolution) unui numărător poate fi exprimată absolut
prin numărul de biți N utilizați efectiv de registrul de numărare
binar: putem o avea o rezoluție de 8, 10, 12, 16 biţi sau exprimată
ca valoare relativă de 1/28, 1/210, 1/212, 1/216, etc.
• In aplicații interesează însă ca rezoluția (in modul temporizator) sa
fie exprimata absolut ca valoare de timp.
• Rezoluția va fi dată de perioada TClock a semnalului de ceas sau
frecvența FClock a acestuia: TClock = 1/ FClock , ea fiind si
ponderea celui mai puțin semnificativ bit (a unui increment) a
numărătorului exprimata in unități de timp;
• Funcţie de perioada semnalului de ceas TClock = 1/ FClock si
dimensiunea registrului ca număr de biţi N, rezultă o
durată/lungime maximă (a unui ciclu complet) de
numărare/temporizare de la 0 la o valoare maximă: 2N * TClock
• Dacă dorim să obținem o durată mai mică, in registrul respectiv de
numărare(care este un registru in care se poate si scrie) se poate
scrie o valoare mai mică decât valoarea maximă, scurtând
corespunzător durata ciclului de numărare (el va număra de acea
valoare la valoarea maximă)
9
AVR 8biti - numărătoare (Counters)
• Dacă semnalul de ceas provine din exteriorul
microcontrolerului, prin intermediul unor pini dedicați,
avem o funcționare in modul numărător (counter),
deoarece el practic numără evenimentele externe
– In acest mod evoluția lui este, tipic, asincronă cu cea a
unității centrale si a perifericelor AVR, cele care folosesc
ceasul sistem
• Din punct de vedere funcțional nu sunt diferențe intre
modul temporizator si cel numărător, utilizându-se
practic si același hardware (cu excepția circuitului
care furnizează semnalul de ceas)
– Din acest motiv, in continuare, pentru a fi si mai conciși
(limba română nu excelează prin aşa ceva) de multe ori le
vom numi pe scurt si Timer sau Timere înțelegând că este
vorba de fapt, din punct de vedere funcțional, de un
numărător (ca mașină secvențială) cu anumite caracteristici
specifice
• Evenimentele asociate acestor temporizatoare /
numărătoare pot declanșa întreruperi care sunt
integrate in sistemul de întreruperi AVR 8 biți 10
Evenimentele asociate sistemului de
temporizare/numărare
• Principalele eveniment sunt descrise mai jos.
• Depășirea (Timer OVerflow)
– In funcționarea normală (când se numără in sus) depășirea apare atunci când
valoarea registrului de numărare TCNT (Timer CouNTer) trece de la 0xFF la
0x00 (pe 8 biti) sau de la 0xFFFF la 0x0000 (pe 16 biți): adică la 0xFF+1 sau
0xFFFF +1
– Ca efect al depasirii este setat (=‘1’) indicatorul/bitul TOVi din registrul TIFR;
unde i =0, 1, 2… identifică numărătorul in cauză
• Egalitatea la (egalitate) comparare (Output Compare match)
– Utilizează ca hardware suplimentar un registru cu un număr de biți egal cu al
numărătorului- registru de comparare- in care utilizatorul poate scrie o valoare
– Si un comparator numeric pe mai mulți biți care compara ieșirea registrului cu
cea a numărătorului
– Utilizatorul este informat despre egalitatea atunci când valoarea registrului de
numărare TCNT devine egală cu cea a registrului de comparare pentru ieșire -
registrul OCR (Output Compare Register)
– Ca efect, este setat (=‘1’) indicatorul/bitul OCFi din registrul TIFR; unde i =0, 1,
2… identifică numărătorul in cauză
• Captare/memorare conținut (Input Capture)
– Timerul 1 mai are si un eveniment care înseamnă, “capturarea” / memorarea
(capture) valorii curente a numărătorului, la un moment de timp dat de un semnal
extern (aplicat pe pinul ICP - Input CaPture)
– Ca efect, pe lângă memorarea valorii numărătorului in acel moment, mai este
setat (=‘1’) indicatorul/bitul ICF1 din registrul TIFR, astfel încât utilizatorul sa știe
ca avut loc un astfel de eveniment ;
11
Modurile de operare / funcționare pentru
sistemul de temporizare/numărare
• Descrierea care urmează este una sumară si orientată pe familia
ATMega (exemplu ATMega 32)
• Modurile de operare sunt stabilite/configurate, in principal, prin
intermediul câmpurilor de biţi de control WGM si COM, aflate in
registrele TCCR0, TCCR1A, TCCR1B (si TCCR2 dacă Timer 2 există)
– Funcție de varianta de AVR, numele registrelor pot fi puțin diferite, așa ca este
esențial sa fie consultata foaia de catalog
• Modul Normal
– Numărătorul numără in sus, TOV este setat atunci când atinge valoarea 0
(valoarea maximă +1)
• Modul ștergere numărător la (egalitate) comparare: CTC - Clear
Timer on Compare Mode
– Numărătorul numără in sus până când ajunge la o valoare egală cu cea
aflată in registrul de comparare ieșire OCR (Output Compare Register): la
următorul ceas de numărare el va fi resetat la 0 si bitul OCFx (Output
Compare Flag) va fi setat
• Modurile PWM (Pulse Width Modulation), permit generarea, pe
anumiți pini de ieșire, a unor trenuri de impulsuri modulate in durată
(in factor de umplere), sunt mai multe, vom reveni asupra
subiectului …
12
Valorile BOTTOM, MAX, TOP: cazul lui
Timer 0
• In diagramele din foile de catalog AVR, care descriu
funcționarea sistemului de temporizare/numărare se face
mereu referință la un set de 3 valori, numite generic:
BOTTOM, MAX si TOP; ele sunt explicate in continuare
pentru Timer 0 si respectiv Timer 1
• De subliniat ca Timer 0 este unul de 8 biți, așa ca valorile
respective sunt pentru acesta valori exprimate pe 8 biți
– BOTTOM: Numărătorul ajunge la valoarea BOTTOM atunci când
devine 0x00.
– MAX: Numărătorul ajunge la valoarea lui MAX-imă atunci când
devine 0xFF ( 255 in zecimal).
– TOP: Numărătorul ajunge la valoarea TOP atunci când devine
egal cu cea mai mare valoare din secvenţa de numărare.
• Valoarea TOP poate fi asignată valorii fixate 0xFF (MAX) sau este valoarea
memorată in registrul OCR0
• Aceasta asignare depinde de modul de operare ales.
13
Valorile BOTTOM, MAX, TOP: cazul lui
Timer 1
• Timer 1 este unul de 16 biți, așa ca valorile respective sunt
pentru acesta valori exprimate maxim pe 16 biți
– BOTTOM: Numărătorul ajunge la valoarea BOTTOM atunci când
devine 0x0000.
– MAX: Numărătorul ajunge la valoarea lui MAX-imă atunci când
devine 0xFFFF (65535 in zecimal).
– TOP: Numărătorul ajunge la valoarea TOP atunci când devine egal
cu cea mai mare valoare din secvența de numărare:
• Valoarea TOP poate fi asignată uneia din următoarele valori fixate:
– 0x00FF ( valoarea maximă pe 8 biți),
– 0x01FF ( valoarea maximă pe 9 biți),
– 0x03FF ( valoarea maximă pe 10 biti) sau
– o valoare pe 16 biti memorată in registrul OCR1A sau o valoare pe
16 biti memorată in registrul ICR1.
• Aceasta asignare depinde de modul de operare ales.
14
Schema bloc a unui temporizator / numărător:
Timer 0 (8 biţi)
Pin Semnal
extern de
Timer 0: registrul de numărare TCNT0 are 8 biţi ceas
Observație
Timer 1, Timer 2: registrele de numărare TCNT1 sau TCNT2 au 16 biţi, respectiv 8 biţi,
15
dar schema principială este practic similară
Unitatea de comparare a ieșirilor (Timer 0):
registrul OCR si comparatorul
Cererea de întrerupere
egalitate comparare
Pin ieşire
externa
Are la bază un comparator numeric (de 8 biţi pentru Timer 0), ale cărui intrări provin de
la ieşirile registrului de comparare OCR si cele ale registrului de numărare TCNT
Pentru Timer 1 unitatea de comparare este similară, dar este una de 16 biţi
(comparator, OCR si TCNT). 16
TCA – seriile Tiny si Mega modernizate
17
TCB – seriile Tiny si Mega modernizate
18
Acțiuni automate ale sistemului de
temporizare/numărare
• Timerele 1 si 2 (când acestea există) pot fi configurate să
realizeze in mod automat ștergerea (reset), setarea (set) sau
comutarea stării (toggle) unor biţi, având asociați si anumiți pini
de ieșire, atunci când apare o egalitate de comparare
• Este o caracteristică hardware si nu presupune intervenţia
CPU sau a programului utilizator
• Pinii asociați sunt numiți OCnx (Output Comparenx - funcție
alternativă a unor biţi din porturile respective)- si ei trebuie să
fie configurați ca ieșiri (prin intermediul registrului DDR al
portului respectiv)
• Atunci când sunt utilizați in acest mod ei, nu mai pot fi folosiți
ca intrări ieșiri de uz general, ei fiind sub controlul hardware al
sistemului de temporizare numărare, nu sub cel al programului!
• Trebuie consultată foaia de catalog pentru identificarea lor:
– De exemplu la ATtiny 2313 avem (2 timere, 4 canale):
• OC0A PB2; OC0B PD5 ; OC1A PB3 ; OC1B PB4
– la ATMega 16 avem (2 timere, 3 canale):
• OC0 PB3 ; OC1A PD5 ; OC1B PD4
19
Pinii OCnx, ICP, T0 si T1
ATMega 16
T0, T1 – Intrări ceas extern pentru Timer 0 si Timer1
ATtiny 2313
21
ICRn are 16 biti si cele două registre de de
capturare de 8 biţi ICRnH si ICRnL ICR se citesc
la fel ca cele două registre de numărare TCNTnH
si TCNTnL, prin intermediul lui
TEMP un registru buffer (temporar) de 8 biţi
22
Registrul de control pentru Timer0, moduri de
operare
Registrul TCCRO Timer/Counter 0 Control Register
7 6 5 4 3 2 1 0
24
Trece prin 0x00
La egalitatea TCNT=OCR0:
- Iniţializare numărător
Modul CTC (Timer 0) - Setare OCF0 si cerere
de întrerupere
• Modul CTC este - Eventual schimbare de
selectat cu ajutorul stare pentru pinul OC0
câmpului de biti
WGM0 1:0 = 10 (din MAX=255
registrul TCCRO)
• Valoarea scrisă in Evoluţie numărător
registrul OCR0 este
folosită pentru a td Aici TOP =
“programa” lungimea valoare OCR0
ciclului de numărare (nd,
td, tOC0) Ştergere iniţiala
• Pinul OC0 poate (prima iniţializare)
eventual să-si schimbe nd
starea la egalitate
(comutare, ştergere sau
setare)
BOTTOM=0
tOC0
25
Re-iniţializare
PWM - Pulse Width Modulation (modulația in
durată sau in factor de umplere)
O modulație PWM înseamnă modificarea dinamică, sub controlul
programului in acest caz (cu sau fără contribuția unui hardware dedicat) a
factorului de umplere pentru o formă de undă numerică :
FU% = (TH / T)*100 Perioada T (si deci si
frecvența f) rămâne
T constantă, se modifică
TH doar TH (cat este in “1”)
Având la dispoziție numai o ieșire
numerica se poate implementa un
PWM software
28
Dacă fclock este frecvenţa oscilatorului sistem, iar
N = {1, 8, 64, 256, 1024} este factorul de (pre)divizare ales
Atunci frecvenţa de comutare a lui OC0 (TOP=256 ) va fi:
fOCnPWM = fclock / (N*256);
29
Rezoluția in modul PWM rapid (cazul
Timer1)
• Rezoluția (dimensiunea numărătorului) in modul PWM
rapid poate fi fixă, de 8, 9 sau 10 biţi, sau definită de
valorile din ICR1 sau OCR1A.
• Valoarea minimă permisă este de 2 biți (ICR1 sau
OCR1A conțin 0x0003), si rezoluția maximă este de 16
biți (ICR1 sau OCR1A conțin pe MAX).
• Rezoluția, exprimata ca număr de biți, poate fi calculată
cu o relație de forma:
7 6 5 4 3 2 1 0
Timer 0
Timer 1
- Indicator (cerere întrerupere) comparare ieşire OCF
- Indicator (cerere întrerupere) depăşire Timer TOV Timer 2
- Indicator (cerere întrerupere) capturare (capture) intrare ICF
7 6 5 4 3 2 1 0
Timer 0
Timer 1
– Activare întrerupere comparare ieşire OCIEi (2 canale A si B)
– Activare întrerupere depăşire Timer TOIEi Timer 2
– Activare întrerupere capturare (capture) intrare TICIE1
37
Sursele de ceas utilizabile pentru sistemul de
temporizare/numărare
• Sistemul de temporizare/numărare poate folosi drept ceas de numărare:
– Un ceas provenit, eventual prin (pre)divizare (prescaling), din ceasul sistem (intern):
funcționare in mod temporizator sau
– Un semnal extern de ceas: funcționare in mod numărător
• Funcție de dimensiunea numărătorului (de numărul sau de biţi, 8 sau 16) si de
perioada ceasului de numărare vom putea determina:
– Durata maximă a intervalului de temporizare
– Rezoluția cu care putem controla această durată: cât înseamnă ca timp un increment
al numărătorului
• Ceasul sistem poate fi (pre)divizat, înainte de a deveni ceas pentru Timer,
pentru a putea genera intervale de temporizare mai mari:
– Este disponibilă o (pre)divizare cu factorii ficși de: 8, 64, 256 si 1024
– Tot prin intermediul acestui sistem de predivizare ceasul de numărare poate fi
oprit (ceasul oprit este starea implicită după un Reset!)
– Timerul 2 (atunci când el există) are mai multe opțiuni, permițând si (pre)divizarea
semnalului de ceas extern, nu numai a celui intern, mai mulţi factori de divizare, etc.
38
Exemplu de determinare a duratei maxime de
temporizare si a rezoluției de numărare
• Să presupunem că:
– Avem frecvența ceasului sistem este de 8 MHz (cu perioada
de 125nsec sau 0.125usec)
– Utilizăm un timer de 16 biți (valoarea lui maximă va fi 0xFFFF)
– Dorim să obținem cel mai mare interval de temporizare
posibil, si vom folosi cel mai mare factor de divizare, adică
1024
• Avem (0xFFFF + 1) * 1024 * perioada ceasului sistem =
65536*1024*125 nsec = 67 108 864 * 125 nsec = 8.388608
secunde=cca 8.3 sec ca durată maximă a unui ciclu de
numărare.
• Deoarece numărătorul incrementează la fiecare 1024
perioade ale ceasului sistem, vom avea o rezoluție (ca timp)
de: 1024* 125nsec = 0.000128 secunde (cca 0.12msec sau
128usec)
• Fără a folosi nici o (pre)divizare rezoluția ar fi fost de
125nsec (0.125µs), iar valoarea maximă a duratei doar de
0.008192 secunde (cca. 8msec)
39
Unitatea de (pre)divizare (prescaler) a ceasului
pentru ATMega16 ( pentru Timer 0 si Timer 1)
Semnale
externe
de
ceas 40
Selecţia sursei semnalului de ceas
TCCR0 and TCCR1B – Timer/Counter Control TCCR2 – Timer/Counter Control
Register (Timerul 0 si Timerul 1) Register (Timerul 2)
CSn2, CSn1, CSn0 (Biţii 2:0) sunt biţii de CS22, CS21, CS20 (Biti 2:0) sunt biţii
selectare a semnalului de ceas (n = 0 sau de selectare a semnalului de ceas
1) 000 = Ceasul este oprit; timerul nu mai
numără (implicit după reset!)
• 000 = Ceasul este oprit; timerul nu mai 001 = ClkT2S:1
numără (implicit după reset!) 010 = ClkT2S :8
• 001 = fără divizare a lui ceasul Clk I/O :1 011 = ClkT2S :32
• 010 = divizare a lui Clk I/O :8 100 = ClkT2S :64
• 011 = divizare :64 101 = ClkT2S :128
• 100 = divizare :256 110 = ClkT2S :256
• 101 = divizare :1024 111 = ClkT2S :1024
• 110 = Ceas extern, pe pinul Tn, numărare Unde, implicit, după reset:
pe front căzător ClkT2S= Clk I/O
• 111 = Ceas extern, pe pinul Tn, numărare Prin setarea bitului ASR2 din registrul
pe front ridicător ASSR , ClkT2S va proveni de pe pinul
TOSC1 (aplicație de tip ceas de
timp real – RTC , cu o frecventa de
31.768kHz )
ATENTIE: Ceasul sistem este de fapt clk I/O (vezi sistemul de generare al ceasului pentru
AVR) care poate fi oprit si prin intrarea in unele moduri de tip “sleep”
Daca se utilizează oscilatorul intern RC, frecventa oscilatorului fosc = Clk I/O=Clk CPU doar
daca fuzibilul CKDIV8 (daca el exista) este neprogramat 41
Daca fuzibilul CKDIV8 este programat atunci Clk I/O=Clk CPU = fosc :8 !
Registrele de control pentru Timerul 1
•Registrul TCCR1A
TCCR1A Timer/Counter 1 Control Register A
7 6 5 4 3 2 1 0
44
Alte registre de date pentru Timer 1
• Pentru Timer 1 in afară de registrele de numărare, la
categoria registre de date mai există si alte registre
de 16 biți, si toate se citesc / scriu la fel ca registrele
de numărare!
• Unele din ele au o utilizare duală, vezi registrul ICR1
• Toate registrele asociate Timer 1 au 16 biţi, având un
octet superior (H) si unul inferior (L)
– TCNT1H:TCNT1L (16 biţi)
• Registrul de numărare pentru Timer 1
– OCR1AH:OCR1AL (16 biţi)
• Valoare comparare ieşire Timer 1– canalul A
– OCR1BH:OCR1BL (16 biţi)
• Valoare comparare ieşire Timer 1– canalul B
– ICR1H:ICR1L (16 biţi)
• Valoare capturare intrare Timer 1 (Input Capture)
45
Configurarea generală a sistemului de
temporizare numărare AVR 8 biți
• Înainte de a fi utilizat, orice numărător – temporizator trebuie
configurat/inițializat corespunzător
#include <avr/io.h>
void Timer0_init()
{
/* frecventa oscilatorului fosc= 1MHz (RC intern)
factorul de divizare = 1024
Fclock= 1000 000 /1024 = 975.56Hz
Tclock= 1/ 975.56 = 0.001024 sec
adica CS02= 1, CS01=0, CS00=1 */
TCCR0 |= (1 << CS02)|(1 << CS00);
/*toti ceilalti biti din registrul TCCR0 au valoarea implicita dupa reset,
adica 0:
FOC=0 fara fortare iesire la out. compare
WGM00=WGM01=0, mod normal, Top= 0xFF ATENTIE care va fi valoarea maxima a
intarzierii!!
COM01=COM00=0, mod normal, OC0 deconectat de pin
*/
/* initializam la 0 registrul de numarare timer */
TCNT0 = 0;
} 47
Un exemplu de utilizare/configurare Timer 0
(ATMega16), in modul normal, pentru generarea unei
întârzieri -cont
/*====================================================*/
int main(void)
{
/* sa zicem ca avem un LED conectat pe pinul PC7, deci este iesire */
DDRC |= (1 << PC7);
/* initializam timerul */
Timer0_init();
/* o bucla fara sfarsit */
while(1)
{
/* dorim o intarziere sa-i zicem de 200msec = 0.2 sec
daca timerul pleaca de la 0, vom avea 0.200/0.001024 = 195 (195.31
trunchiat)
de incrementi pt acest interval de timp, deci verificam daca timerul
a ajuns la 195 */
if (TCNT0 >= 195)
{
PORTC ^= (1 << PC7); /* comutam starea pinului/LED-ului, la
fiecare 200msec */
TCNT0 = 0; /* si aducem la 0 registrul de numarare*/
} //end if
} //end while
} 48
Un exemplu de utilizare/configurare Timer 0,
modul PWM rapid (ATTiny 2313)
/* Exemplu PWM hardware folosind Timerul 0 de 8 biti*/
/* Se pot utiliza doar iesirile OC0A = pin PB2 si OC0B = pin
PD5*/
#include <avr/io.h>
#include <util/delay.h>
#define F_CPU 4000000UL /*utilizata de biblioteca delay*/
Mod de lucru
Câmpul WGM0 2:0 = 011 Mod PWM rapid
Modul de control al pinilor OC0
Câmpul COM0A 1:0 = 10 In modul PWM rapid şterge pe OC0 la
egalitate cu OCR0 si-l setează la BOTTOM (mod
fără inversare)
Câmpul COM0B 1:0 = 10 Idem pentru canalul B
Ceasul pentru Timer 0
Câmpul CS0 2:0 = 001 Ceasul sistem, fără divizare (:1)
53
Rutinele de tratare a întreruperii
• O rutină de tratare a întreruperii este de fapt
subrutina care are ca particularitate (in limbaj e
asamblare) că se termină cu o instrucțiune
(asamblare) specială AVR numită RETI (Return
from INTerrupt): întoarcere din întrerupere
• Rutinele de tratare a întreruperilor nu sunt apelate
explicit, ci in mod implicit/automat, de un
mecanism hardware
• Adresa lor de început este “plasată” automat in
numărătorul program al CPU, de un hardware
dedicat
– Cele de mai sus se refera si interesează in primul rând la
programarea in limbaj de asamblare; in limbaj evoluat
(de exemplu C) funcțiile aferente sunt practic identice cu
o funcție normala, diferă doar modalitatea de apelare,
care este controlata de compilator
54
Sistemul de întreruperi al AVR 8 biti
• Microcontrolerele din familia AVR 8 biti pot gestiona,
funcție de variantă, un număr diferit de surse de
întrerupere, de la câteva pana la câteva zeci
• ATMega16 are 21 de surse, ATTiny2313 are 19,
ATMega 128 are 35, s.a.m.d
• Numărul de întreruperi pentru o anumita varianta
depinde de natura perifericelor (un periferic poate avea
asociate una sau mai multe întreruperi), precum si de
cât de multe periferice sunt implementate
• Sursele de întreruperi sunt numerotate de la 1 la n,
prioritatea lor fiind in aceasta ordine, cu numărul 1
(Reset) cel mai prioritar si n cel mai puțin prioritar
• Fiecare întrerupere provoacă apelarea automată a unei
rutine de tratare specifică, de la o anumită adresă din
memoria de program
– Reset-ul este văzut ca un tip particular de întrerupere, “rutina de
tratare” a Reset-ului fiind plasată la adresa 0x0000, adică locul
de unde se va executa prima instrucțiune a programului AVR
55
Vectorii de întrerupere AVR 8 biti
• O rutina in limbaj de asamblare de tratare a întreruperii k trebuie
plasată in memoria de program la adresa de forma 2*(k-1)
– La adresa 0x0000 este rutina pentru “reset”
– La adresa 0x0002 este rutina pentru întreruperea externă 0
– La adresa 0x0004 este rutina pentru întreruperea externă 1
– Dar in continuare lucrurile pot diferi funcție de variantă!
• ATENTIE: funcție de varianta de microcontroler AVR, același tip
periferic poate avea vectori (adrese) diferite de tratare
– De exemplu pentru ATTiny2313 comparatorul analogic are vectorul 11
(0x000A), iar pentru ATMega același periferic are vectorul 19 (0x0024),
s.a.m.d
– Trebuie verificată neapărat tabela de vectori dată in foaia de catalog a
microcontrolerului in cauză!
• Pentru că “in vectorul de întrerupere” este rezervat un “loc” doar de 32
de biţi (2 cuvinte program) per întrerupere, loc suficient numai pentru
una sau doua instrucțiuni, de fapt fiecare rutina de tratare începe cu
o instrucțiune de salt la o altă locație din memoria program de
unde începe de fapt codul rutinei de tratare propriu-zise
• Completarea tabelei este realizată de compilatorul C, prin mijloace
specifice puse la dispoziția programatorului C sau in mod explicit
de programatorul in limbaj de asamblare
– La adresă se va afla in mod tipic o instrucțiune de tip jmp rutina, care este
o instrucțiune de 32-biti (2 cuvinte in memoria de program), care încape 56 in
spațiul rezervat pentru fiecare intrare in tabela de vectori
Tabela de vectori pentru ATtiny 2313
57
Tabela de vectori pentru ATMega32
58
AVR 8 biti: activarea individuală si
globală a întreruperilor
• Fiecare sursă potențială de întreruperi poate fi activată
sau dezactivată individual
• Dezactivare întrerupere = mascare întrerupere
– “Întreruperea” corespunzătoare Reset-ului este singura
excepție: ea este nemascabilă, nu poate fi dezactivată
• Indicatorul global de întreruperi I, din registrul de stare
SREG trebuie să fie setat (=1) pentru ca orice
întrerupere să aibă loc si să poată fi tratată: el este un
bit de activare globală a întreruperilor AVR 8 biti (desi
se află in registrul de stare…)
– Din nou “întreruperea” corespunzătoare reset-ului este o
excepție; ea nu poate fi dezactivată nici global
59
AVR 8 biti: acțiunile asociate utilizării
unei întreruperi
• DACA
– Întreruperile sunt activate global
– SI o întrerupere specifică este activată
– SI condiția / evenimentul de întrerupere este prezent(ă)
• ATUNCI se va genera o cerere de întrerupere si va avea loc
tratarea ei
• Ce se întâmplă atunci din punct de vedere al unității
centrale?
– După terminarea execuției instrucțiunii curente:
• Valoarea curentă a lui PC (a numărătorului program) este salvată in
stivă (este singura componentă a contextului astfel salvată!)
• Întreruperile sunt dezactivate global (I=0)
• Vectorul corespunzător de întrerupere (o adresă fixă) este adus in PC
(PC=vector)
• Se execută instrucțiunea de la acea adresă
60
Utilizarea stivei in cazul
întreruperilor
• Pentru ca execuția unei rutine de tratare a întreruperii este similara
unui apel de subrutina, stiva are un rol esențial pentru salvarea
contextului (adică cel puțin a adresei de întoarcere)
• Deoarece întreruperile au nevoie să utilizeze stiva, este esențial ca,
in faza de inițializare a unei aplicații care folosește întreruperile, să fie
inițializată corect si stiva (prin intermediul indicatorului de stivă SP)
– Cu alte cuvinte trebuie sa ne asiguram ca este suficient “loc” in stiva si ca in
urma salvării contextului sau a mai multor contexte, stiva nu se “ciocnește” cu
alte zone utile de memorare (variabile, etc.) ducând la distrugerea datelor
• Un compilator rezolvă automat această problemă (prin intermediul
unor mijloace specifice), alteori ea trebuie realizată explicit de
programator (obligatoriu la limbajul de asamblare!)
• In cazul unui compilator rutinele de tratare a întreruperilor vor/pot
utiliza stiva si pentru a salva contextul in momentul apariției
întreruperii, nu numai adresa de întoarcere, aceasta acțiune fiind
aproape transparenta pentru utilizator
61
Registrul de stare AVR 8 biti:
SREG
• Rutinele de tratare a întreruperilor nu trebuie să modifice
registrul de stare SREG (el trebuie să fie neschimbat), el
făcând parte din context
• Registrul SREG nu este salvat automat in stiva!
• In limbaj de asamblare, un exemplu de salvare si
restaurare a lui SREG:
rutina_tratare_intrerupere:
push r0 ;salvez pe r0 in stiva
in r0, SREG ;salvez in r0 pe SREG
… ;aici nu folosesc la altceva pe r0
out SREG, r0 ;restaurez pe SREG din r0
pop r0 ;restaurez pe r0 din stiva
reti
63
Întreruperi AVR 8 biti bazate pe
evenimente
• Chiar dacă întreruperile sunt dezactivate (individual
si/sau global), indicatorul aferent cererii de
întrerupere poate fi setat de evenimentul asociat, in
mod independent
– Aceasta se întâmplă deoarece ele trebuie sa poată fi
testate si prin polling
• Odată setat, indicatorul poate rămâne setat
(memorează evenimentul) si poate declanșa o
întrerupere, odată ce întreruperile vor fi din nou
activate
– Acest gen de indicator de cerere de întrerupere este
șters:
• Automat când are loc tratarea a întreruperii (când se intră in
rutina de tratare a întreruperii) sau
• “Manual”, prin program, scriind un “1” in el (in bitul respectiv)
• Trebuie însă citită cu atenție foaia de catalog si văzut care sunt
șterse in mod automat si care trebuie șterse de utilizator!
64
Întreruperi AVR 8 biti bazate pe
condiţii
• Chiar dacă întreruperile sunt dezactivate, global
si individual, indicatorul aferent acestui tip de
cerere va fi setat când condiția asociată devine
adevărată
– Similar precedentei categorii, aceasta se întâmplă
deoarece ele trebuie sa poată fi testate si prin polling
• Dacă însă condiția devine falsă înainte ca
întreruperile să fie (re)activate, indicatorul este
șters si cererea de întrerupere va fi “pierdută”
– Aceste indicatoare sunt șterse imediat ce condiția
devine falsă
– Mai pot fi necesare si alte acțiuni “manuale” ale
utilizatorului pentru a gestiona corect aceasta
ștergere
65
Exemple de întreruperi AVR
66
AVR 8 biti - Întreruperile externe
ATMega16
• Luând ca exemplu un
ATMega16 (in capsula DIP40)
avem 4 întreruperi externe –
care corespund unor semnale int2
aplicate pe anumiţi pini:
– RESET (pin 9)
– INT0 (pin 16 – PD2) reset
– INT1 (pin 17 – PD3)
– INT2 (pin 3 – PB3)
int0
67
AVR 8 biti - Întreruperile externe
ATTiny 2313
68
AVR 8 biti: configurarea întreruperilor externe
• In primul rând trebuie stabilit cum/ când semnalul
extern declanșează o cerere de întrerupere:
• Pe baza îndeplinirii unei condiții:
– Când nivelul logic pe pin este “0”
• Sau declanșate de un eveniment:
– Când nivelul pe pin s-a modificat (a comutat din “0” in
“1” sau din “1” in “0”)
– Front căzător - negativ (tranziție nivel pin din “1” in “0”)
– Front ridicător - pozitiv (tranziție nivel pin din “0” in “1”)
69
Registrul MCUCR - registrul de control (si)
pentru întreruperile externe
71
Registrul MCUCSR- registrul de control si
stare pentru cazul in care există INT2
• Registrul MCUCSR - MCU Control and Status Register
ISC2
72
Registrul GICR- activarea individuala a
întreruperilor externe
GICR |= (1<<INT1);
GICR &= ~(1<<INT0);
73
Registrul GIFR- aici se gasesc indicatorii
corespunzători cererilor de întrerupere externe
7 6 5 4 3 2 1 0
76
Întreruperi si compilatorul WinAVR -1
De exemplu in cazul ATTiny2313 acesta se numeşte iotn2313.h. Aici
găsim, de exemplu:
/* Intreruperea Externa 0 */
#define INT0_vect _VECTOR(1)
/*vectorul corespunzator intreruperii externe 0 este
primul din tabela*/
Sau
#include <avr/interrupt.h>
77
Întreruperi si compilatorul WinAVR - 2
Toate întreruperile pot fi descrise folosind macroinstrucţiunea ISR(vector),
de exemplu o subrutina care tratează depăşirea Timer-ului 1 este declarata
ca mai jos:
ISR(TIMER1_OVF_vect)
{
//codul care trateaza intreruperea
}
ISR(_vector_default)
{
//codul care trateaza intreruperile parazite
}
78
Întreruperi si compilatorul WinAVR - 3
• Dacă dorim ca pentru o întrerupere particulară, rutina de tratare să
nu facă practic nimic, cu excepţia întoarcerii din subrutină, se utilizează
macroinstrucţiunea EMPTY_INTERRUPT (vector) astfel :
EMPTY_INTERRUPT(ADC_vect)
cli() care şterge bitul I (=0) din SREG dezactivând global sistemul de
întreruperi
sei() care setează bitul I (=1) din SREG activând global sistemul de
întreruperi
79
Întreruperi si compilatorul WinAVR - 4
80
Întreruperi si compilatorul WinAVR, exemplu de utilizare a
întreruperilor externe
• Un mic exemplu de program care utilizează întreruperile externe 0 si 1 pentru a
aprinde/stinge un LED conectat pe pinul PB0 al portului B.
• Întreruperile sunt generate cu ajutorul unor comutatoare puse pe pinii PD2 (INT0) si PD3
(INT1).
• Acționarea comutatorului aduce intrarea respectivă in „0”, generând cererea de întrerupere
externă corespunzătoare.
– Se presupune că am “deparazitat” corespunzător contactele!
#include <avr\io.h>
#include <avr\iotn2313.h>
#include <avr\interrupt.h>
/*doua exemple de macroinstructiuni folosite pt a citi scrie in
porturi*/
#define outp(a, b) b = a
#define inp(a) a
int main(void) {
/* doar PB0 din PortB va fi iesire pt LED */
outp(0x01, DDRB);
/* tot Portul D ca intrari, PB2 si PB3 */
outp(0x00, DDRD);
/* activam individual pe int0, int1 /*
outp((1<<INT0)|(1<<INT1), GIMSK);
/* activarea globala a intreruperilor */
sei();
led = 0x01;
/*aici se termina partea de initializare */
for (;;) {/* o bucla fara sfarsit */
/*in care doar actualizam portul B din variabila led */
outp(led, PORTB);
}
}
82
Întreruperi si compilatorul WinAVR: un exemplu de
utilizare a lui Timer1 - 1
/* Definire vector intrerupere depasire:
Timer/Counter1 Overflow */
#define TIMER1_OVF_vect _VECTOR(5)
int main(void)
{
//initializam timerul 1
Init_Timer1 ();
/*Activam global sistemul de intreruperi, pana aici
intreruperile au fost dezactivate! */
sei();
//o bucla fara sfarsit
while(1)
{ //..programul “principal” va fi intrerupt
// periodic, executandu-se rutina de tratare
// a intreruperii ISR(TIMER1_OVF_vect)
}
}
83
Întreruperi si compilatorul WinAVR: exemplu utilizare
Timer1 - 2
O funcție de inițializare a lui Timer 1 :
Init_Timer1 (){
/** Configuram Timer1- de 16 biti,
folosind ceasul sistem ca sursa de ceas
cu o divizare suplimentara de :64 **/
TCCR1B |= (1 << CS10 | 1 << CS11 );
/** Ceasul pt Timer 1 = system clock/64
Ceasul sistem este de 4MHz (perioada 0.25usec)
Perioada semnal ceas = 16 usec (.25usec x 64 )
Dorim o perioada de numarare de cca. 0.5sec
adica 500 000 de usec / 16 usec
Initializam Timer1, pe 2 octeti: ca valoare pe 16 biti **/
TCNT1H=(-500000/16) >> 8; // intai octetul H !
TCNT1L=(unsigned char)(-500000/16); // apoi octetul L !
/* Activam intreruperea lui Timer1 */
TIMSK |= 1 << TOIE1;
}
84
Întreruperi si compilatorul WinAVR: exemplu de
utilizare Timer1 - 3
/*============================================
Rutina de tratare a intreruperii Timer1 - la depasire
=============================================*/
ISR(TIMER1_OVF_vect)
{
TIFR |= 1<<TOV1; /*stergem flagul de cerere de
intrerupere */
int main(void)
{
/* sa zicem ca avem un LED conectat pe pinul PC7, care trebuie sa fie iesire */
DDRC |= (1 << PC7);
/* initializam timerul */
Timer0_init();
/* activam global intreruperile*/
sei();
/* o bucla fara sfarsit */
while(1)
{
/* verificam doar daca numarul de depasiri a ajuns = 10 */
if (total_depasiri >= 10) /* ATENTIE '>=' ! */
{
PORTC ^= (1 << PC7); /* comutam starea pinului/LED-ului */
total_depasiri = 0; /* aducem la 0 contorul de depasiri */
}
/*intarzierea totala va fi deci de 10*0.2 sec = 2 sec
atat sta LEDul aprins, respectiv stins*/
87
}
}