You are on page 1of 87

Arhitecturi de sisteme incorporate

Microcontrolere si sisteme
integrate

Controlul dimensiunii timp in aplicațiile de tip


sistem incorporat: temporizatoare si numărătoare
Microchip AVR 8 biți:
• Sistemul de temporizare/numărare
• Întreruperi (partea 2a):
• Întreruperile externe
• Utilizarea întreruperilor cu compilatorul WinAVR

1
Temporizatoare si numărătoare -1

• Un temporizator/numărător (timer/counter), de fapt un sistem de


temporizare/numărare, reprezintă una din resursele esențiale ale
oricărui microcontroler sau mai degrabă ale oricărui sistem incorporat
– Funcționalitatea lui este asemănătoare cu a unui astfel de sistem (temporizator/
numărător) de sine stătător, cum exista multe utilizate in industrie si nu numai
– Cele două denumiri pot fi si sunt folosite interșanjabil in cele ce urmeaza
• Referința de timp este data de un semnal de ceas/ de tact (clock)
• Diferența intre cele două denumiri este data de sursa semnalului de
ceas
• Ele reprezintă o resursă hardware care permite fie “măsurarea” unui
interval de timp pe baza numărării perioadelor ceasului sistem (sau a
unuia derivat din acesta), fie numărarea de evenimente (contorizarea
lor), evenimente in mod tipic externe sistemului
– Hardware un temporizator/numărător este un numărător (o mașină secvențială
sincrona formata dintr-un set de circuite bistabile) de cele mai multe fiind utilizat ca un
numărător binar
– In continuare vom folosi de multe ori termenul generic de timer
– Vom mai presupune, cum ar fi normal după atâta școală, că știți ce este
acela un numărător, dacă nu, vezi Wikipedia,
http://en.wikipedia.org/wiki/Counter
2
Temporizatoare si numărătoare -2
• In figură este prezentat un timer simplu care constă dintr-un numărător (registru de
numărare) de 8 biţi pre-încărcabil, cu un semnal de ceas si un semnal de ieșire
• Programul (aplicația software) poate încărca (load) registrul de numărare cu o valoare
inițială, intre 0x00 si 0xFF; cu alte cuvinte se poate si scrie in registrul de numărare
• Fiecare tranziție a semnalului de ceas va incrementa (de exemplu) această valoare
• Când valoarea numărătorului de 8 biți ajunge la maximum, la următoarea tranziție de ceas
semnalul de ieșire își modifică starea, indicând o depășire superioară (overflow), in acest
caz
• Semnalul de ieșire poate fi utilizat pentru a genera o întrerupere sau a seta un bit, pe care
unitatea centrala îl poate citi
• Pentru a reporni un ciclu de numărare cu aceiași lungime, programul re-încărcă (re-load)
registrul de numărare cu aceiași valoare sau cu o valoare diferită
• Dacă numărătorul este unul care numără in sens crescător (up counter) el numără de la
aceasta valoare către valoarea maximă, 0xFF in acest exemplu.
• Dacă numărătorul este unul care numără in sens descrescător (down counter) el va
număra către valoarea minimă, 0x00, indicând, la depășirea inferioară (underflow) a acestei
valori de fapt o cerere de împrumut (borrow)

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

• Depășirile superioare sau inferioare in cazul unui


temporizator/ numărător (si nu numai ele) sunt asociate
unor evenimente
• Aceste eveniment pot fi memorate cu ajutorul unor circuite
bistabile suplimentare (unor biți suplimentari)
• Prin raportare la evoluția programului (a unității centrale)
aceste eveniment sunt asincrone in cazul utilizării ca
numărător (ceas extern) si sincrone in cazul utilizării ca
temporizator (ceas intern)
• Unitatea centrală poate “afla” despre aceste evenimente
prin două modalități:
– Una neeficientă, prin interogarea bitului asociat
evenimentului într-o buclă de așteptare (polling)
– Una eficientă, cu utilizarea sistemului de întreruperi, in
care situație, evenimentul declanșează o cerere de
întrerupere (interrupt request)

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)

Semnalizare depasire sau cererea


de întrerupere depăşire TOV

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

In foile de catalog ale variantelor


modernizate apare o noua schema
bloc care ilustrează si
funcționalitățile disponibile- practic
aceleași ca la variantele clasice:
aici facilitatea de comparare si
generare forme de unda

17
TCB – seriile Tiny si Mega modernizate

In foile de catalog ale variantelor


modernizate apare o noua schema
bloc care ilustrează si
funcționalitățile disponibile- practic
aceleași ca la variantele clasice:
aici facilitatea de captare, de
comparare si generare forme de
unda

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

ICP (Input CaPture) - Intrare capturare Timer1


20
Funcția de capturare (captare, memorare)
a intrării (Input Capture Unit)
• Trebuie reamintit că de fapt sub controlul unei intrări se
“capturează”/memorează valoarea numărătorului in momentul
apariției evenimentului si nu a intrării!
• Timer/Counter 1 incorporează un sub-sistem care ii permite să
“captureze” evenimente externe si să le asocieze o “ștampilă de
timp”” (time-stamp) generata de evoluția numărătorului si care să
permită determinarea momentului in care au apărut
• Semnalul extern care indică apariția unui eveniment este aplicat pe
pinul ICP1 (o funcție alternativă a unui pin) sau prin intermediul
comparatorului analogic
• Ștampilele de timp, memorate in registrul de 16 biţi ICR1, pot fi
apoi utilizate pentru a calcula perioada, frecvența, durata unui
impuls, factorul de umplere sau alte caracteristici ale semnalului
aplicat, pe baza cunoașterii perioadei semnalului de ceas
• Aceleași ștampile de timp mai pot fi utilizate, de exemplu, si pentru
a realiza un jurnal (log), in care să fie înregistrate evenimente, in
ordinea apariției lor temporale
• OBSERVATIE Alternativ, registrul ICR1 poate fi utilizat si pentru a
memora/defini valoarea TOP utilizată de numărător

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

FOC0 WGMO0 COM01 COM00 WGM01 CS02 CS01 CS00

• WGM0 1:0 Modurile • COM0 1:0 Modul


generare formă de undă egalitate comparare la
– 00 Normal ieșire (mod Normal)
– 01 PWM fază corectă
– 00 Pinul nu face nimic,
– 10 CTC este deconectat
– 11 PWM rapid
– 01 Comută (toggle -
• CS0 2:0 Selecţie ceas schimbă starea)
– Codifică 8 variante de – 10 Şterge (clear)
ceas (vezi slide biţi CS),
inclusiv oprirea lui – 11 Setează (set)
• Comportarea / descrierea
este puţin diferită in fiecare 23
WGM- Waveform Generation Mode
mod WGM
Modul Normal (Timer 0): principiul de funcţionare
• Modul Normal este selectat cu Setare TOV0 -
ajutorul câmpului de biti
WGM0 1:0 = 00 (din registrul Întrerupere
TCCRO) depăşire Timer 0
• Numărătorul poate fi încărcat td
cu o valoare iniţială intre 0x00
si 0xFF (0..255), care va defini
lungimea ciclului de TOP=255
numărare:
– Ca timp td= tOV0 Evoluţie
– Ca număr de valori nd
• Când atinge valoarea 0xFFH
crescătoare nd
are loc depăşirea, la următorul numărător
ceas va trece in 0x00H si reia
ciclul de numărare
• La atingerea valorii 0x00H TOP - nd
este setat si indicatorul TOV0
• Tipic, in rutina de tratare a
întreruperii, este re-încărcat, Încărcare iniţială Re-încărcare
cu aceiaşi valoare iniţială,
pentru a avea aceiaşi lungime (prima iniţializare)
a următorului ciclu de
numărare
BOTTOM=0
tTOV0

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

AVR 8 biți are si posibilitatea


realizării unui PWM hardware, cu
ajutorul unor funcționalități ale
sistemului de temporizare
numărare.
26
Modul PWM rapid ( Fast, High-Speed
PWM)
• Este modul care permite obținerea celei mai mari frecvențe de
ieșire, ușurând eventual filtrarea trece – jos a semnalului, dacă
se dorește extragerea componentei de cc (cazul implementării
unei tehnici de conversie numeric-analogica) – frecvența
maximă fiind dublă fata de modul cu fază corectă
– Are dezavantajul unei asimetrii a semnalului datorita evoluției doar
crescătoare a valorii
• Modul PWM rapid este selectat cu ajutorul câmpului de biți
WGM0 1:0 = 11 (din registrul TCCRO) si poate furniza un tren
de impulsuri PWM cu o frecvență relativ ridicată (comparativ
cu celelalte moduri PWM)
• In acest mod numărătorul are o evoluție doar crescătoare
• Numărătorul va număra de la BOTTOM la MAX si apoi
repornește de la BOTTOM
• In modul Comparare ieşire fără inversare ( non-inverting
Compare Output mode), pinul OC0 (Output Compare 0) este
șters la egalitatea dintre TCNT0 si OCR0, si este setat atunci
când numărătorul ajunge la BOTTOM.
• In modul Comparare ieșire cu inversare (inverting Compare
Output mode), pinul OC0 este setat la egalitate si șters la 27
BOTTOM.
Modul PWM rapid
• In acest mod numărătorul va fi incrementat pană se ajunge la
valoarea MAX
• După aceasta numărătorul este șters la următorul ceas de
numărare
• O diagramă temporală (din foia de catalog AVR) este prezentată in
slide-ul următor
• Este reprezentată ca histogramă evoluția crescătoare a valorilor
lui TCNT0
• Ieșirile PWM (OC0) pot fi utilizate in două moduri: cu inversare
(/OC) si fără inversare (OC)
– Valoarea lui OCR0 este actualizată (update) de program, de mai multe
ori, pentru a controla dinamic factorul de umplere
– Liniile scurte orizontale marchează punctul in care apare egalitatea
dintre OCR0 si TCNT0.
• Tipic, modul PWM rapid se utilizează acolo unde se poate valorifica
frecvența potențial mai ridicată a formei de undă,
– De exemplu, la implementarea unei tehnici de conversie numeric-
analogice (cu modulație PWM urmată de o filtrare trece-jos)

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:

• rFPWM = log (TOP +1) / log (2)

• In acest mod numărătorul va fi incrementat până când


ajunge la:
– una din valorile fixe 0x00FF (8 biti), 0x01FF (9 biti), sau 0x03FF
(10 biti), pentru WGM1 3:0 = 5, 6, sau 7,
– la valoarea din ICR1 (pentru WGM1 3:0 =14), sau
– la valoarea din OCR1A (pentru WGM1 3:0 = 15). 30
Modul PWM cu fază corectă (PWM Phase
Correct Mode)
• Acest mod, selectat prin intermediul câmpului de biti WGM0 1:0 = 01
(din registrul TCCRO), face posibilă generarea unor forme de undă
PWM într-o relație de fază corectă pentru mai mult ieșiri PWM (de
exemplu OC1 ci OC3) datorita simetriei semnalului (valoarea creste si
descreste)
• Rezoluția (dimensiunea numărătorului) in acest mod este fixată la 8
biţi
• OBS. Timerul 1 mai are si un mod PWM cu fază si frecvență corectă
• Acest mod este bazat pe evoluția crescătoare si descrescătoare a
numărătorului (numără in sus si apoi in jos)
• Numărătorul TCNT0 numără, repetat, crescător de la BOTTOM(0x00)
la MAX (0xFF) si apoi descrescător de la MAX (0xFF) la BOTTOM
(0x00)
• In acest mod frecvența maximă a formei de undă va fi la jumătate
față de modul rapid
• In modul Comparare ieșire fără inversare (non-inverting Compare
Output mode), pinul OC0 (Output Compare 0) este şters la egalitatea
dintre TCNT0 si OCR0, si este setat atunci când numărătorul ajunge
la BOTTOM.
• In modul Comparare ieşire cu inversare (inverting Compare Output
mode), pinul OC0 este setat la egalitate si şters la BOTTOM.
31
Modul PWM cu fază corectă
• Valoarea factorului de umplere este fixată/programată prin intermediul lui
OCR0
• Datorită naturii simetrice a acestui mod el este preferat in aplicații de
natura controlului motoarelor electrice (control PWM)
• Numărătorul este incrementat până când ajunge la valoarea MAX (adică
0xFF).
• Când ajunge la valoarea MAX, își va schimba direcția de numărare si va fi
decrementat
• Valoarea lui TCNT0 va rămâne egală cu MAX pentru o perioadă a
semnalului de ceas, începând apoi să scadă pană la BOTTOM (adică la
0x00); apoi procesul este reluat
• O diagramă temporală (din foia de catalog AVR) este prezentată in slide-ul
următor
• Este reprezentată evoluția crescătoare/descrescătoare a lui TCNT0 (ca
histogramă)
• Precum si evoluția ieșirilor PWM (OC0) in cele două moduri: cu inversare
(/OC) si fără inversare (OC)
– In exemplu valoarea lui OCR0 este actualizată (update) de mai multe ori pentru
a controla dinamic factorul de umplere
– Liniile scurte orizontale marchează punctul in care apare egalitatea dintre
OCR0 si TCNT0.

• Datorita simetriei semnalului acest mod este preferat pentru comanda


PWM a (micro)motoarelor de cc
32
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 OCn, in acest mod, va fi:
fOCnPCPWM = fclock / (N*512); 33
Determinarea stării sistemului de
temporizare/numărare prin interogare

• Starea unui temporizator/ numărător (din punct de


vedere al evenimentelor asociate) poate fi
determinată si prin interogarea într-o buclă (“polling”)
a indicatorilor de stare asociați (care sunt aceiași cu
cei utilizați si de sistemul de întreruperi)
– In mod tipic, se citește registrul TIFR - Timer Interrupt Flag
Register si unde se verifică care din biți sunt setați
– Evenimentele de tip depășire, egalitate comparare,
capturare intrare, setează biții corespunzători din TIFR
• TOVn si OCFn (n=0, 1 sau 2)
– Timerul 1 are de fapt două registre de comparare, câte unul
pentru fiecare din cele canale A si B: OCR1A si OCR1B
• ICF1
• Biții pot fi șterși si “manual”, de utilizator/aplicație, scriind
un “1” in poziția corespunzătoare
34
Registrul TIFR: indicatorii de cerere de întrerupere
pentru sistemul de temporizare/numărare

• Registrul TIFR - Timer/counter Interrupt Flags

7 6 5 4 3 2 1 0

OCF2 TOV2 ICF1 OCF1A OCF1B TOV1 OCF0 TOV0

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

ATENTIE: Acești indicatori vor fi șterși in mod automat atunci când se


utilizează sistemul de întreruperi (nu se folosește polling-ul) si se 35
intra in rutina de tratare a întreruperii respective.
Determinarea stării sistemului de
temporizare/numărare utilizând sistemul de
întreruperi
• Este vorba de identificarea evenimentelor asociate stării
unui temporizator/ numărător cu ajutorul sistemului de
întreruperi
• Pentru aceasta in primul rând trebuie activate
întreruperile corespunzătoare in registrul TIMSK-
Timer Interrupt MaSK (presupunând ca întreruperile sunt
activate global)
• Fiecare eveniment legat de sistemul de
temporizare/numărare are un bit de activare pentru
întreruperea corespunzătoare in registrul TIMSK:
– TOIEn si OCIEn (n = 0, 1, 2)
• Timerul 1 are doi biţi de tip OCIE1, OCIE1A si OCIE1B, câte unul pentru
fiecare canal A si B
– TICIE1 (capturare intrare, doar pentru Timerul 1)
– Vectorii de întrerupere din tabela sunt OVFn.., OCn… si IC1
36
Registrul TIMSK de activare/dezactivare a
întreruperilor asociate sistemului de
temporizare/numărare

• TIMSK - Timer/Counter Interrupt Mask

7 6 5 4 3 2 1 0

OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0

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

COM1A1 COM1A0 COM1B1 COM1B0 FOC1A FOC1B WGM11 WGM10

Biţii din câmpurile numite WGM1: WGM13, WGM12, WGM11 si WGM10


codifică pentru Timerul 1:
- 1 Normal15 moduri de funcţionare
- 2 de tip CTC
- 12 de tip PWM
Consultați foaia de catalog pentru a afla semnificaţia exactă!
Biţii din câmpurile numite COM1.. codifică cele 4 moduri de control pentru
ieşirile / pinii OC1 ale celor 2 canale A si B ale Timerului 1 (similar Timer 0)
•Registrul TCCR1B
TCCR1B Timer/Counter 1 Control Register B
7 6 5 4 3 2 1 0

ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10 42


Valoarea registrului de numărare TCNT
• Valoarea curentă a registrului de numărare TCNTi; i=0, 1, 2,..
poate fi citită sau scrisă in orice moment
• Un exemplu in C de citire si scriere pentru valoarea respectiva
in cazul Timer0 (TCNT0, 8 biti) este:
unsigned char numarator;
…..
numarator=TCNT0;
…..
TCNT0=0x55;
….
ATENTIE
• Funcția de comparare a ieșirii este dezactivată pentru un ciclu
de numărare după o operație de scriere in numărător
• Modificarea valorii registrului de numărare, atunci când el
numără, poate duce la pierderea unui eveniment de tip
comparare ieșire

De cele mai multe ori procedura corectă de citire sau scriere a


registrului (registrelor) de numărare este:
 Se oprește numărătorul
 Se citește sau se scrie registrul (registrele)
 Se repornește numărătorul 43
Valoarea registrului de numărare pentru
Timer/Counter 1: accesul pe 16 biţi
• Este vorba de un temporizator/numărător de 16 biţi!
– Registrul de numărare are un octet superior TCNTH si unul
inferior TCNTL
– Accesul la acesta pereche de registre (TCNTH:TCNTL) si
construirea unei valori pe 16 biți (într-o variabilă
corespunzătoare) presupune o tehnică specială: contează
ordinea in care se citesc cele doua jumătăți!
• Întotdeauna se citește primul octetul inferior TCNTL
– Aceasta realizează si memorarea internă a octetului superior
ce va fi citit la următoarea citire
• Întotdeauna se scrie primul octetul superior TCNTH
– Scrierea următoare, cea pentru octetul inferior, va duce la
memorarea in registrul intern si a octetului superior

Este o consecință a faptului ca intern există doar un singur buffer (registru


tampon) TEMP de 1 octet care este folosit “in comun” de toate registrele de
16 biţi aferente Timerului 1.

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

• ATENTIE: Denumirile registrelor (si mnemonicile utilizate de compilator)


si gruparea biților pentru același timere (0, 1, ..) pot fi diferite, funcție de
varianta de AVR, consultați foaia de catalog; de exemplu pentru Timer 0 la
ATiny avem 2 registre TCCR0A si TCCR0B, pe când la ATMEGA avem un
singur TCCR0, etc.
• Configurarea se face prin intermediul unor biți dedicați de control in registrele
de control si stare deja menționate, si ea presupune:
– Programarea modului de lucru: normal, CTC, PWM, etc.
– Programarea valorilor inițiale ale registrelor de numărare (dacă este cazul)
– Configurarea întreruperilor aferente lor (dacă este cazul)
– Alegerea/programarea sursei de ceas si eventual a valorii frecventei semnalului
de ceas (a factorului de divizare dorit pentru ceas); odată ce a fost
aleasă/programată sursa de ceas numărătorul începe să funcționeze / să numere
(cu excepția cazului in care aici este selectată combinația “ceas oprit”), poate
genera întreruperi
– Dacă aplicația utilizează întreruperile, atâta timp cât se face aceasta configurare,
este bine ca întreruperile să fie dezactivate global (cu instrucțiunea cli), ele
activându-se (cu instrucțiunea sei) eventual după terminarea acestei configurări
46
Un exemplu de utilizare/configurare Timer 0, modul
normal (ATMega16), pentru generarea unei întârzieri

#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*/

/*O functie de initializare a lui Timer 0 si a canalelor de


iesire OC0A si OC0B in modul dorit*/
void InitPWM()
{
/*Mod PWM rapid, ceas fara divizare (:1), control al lui OC0
pe ambele canale A si B*/
TCCR0A|=(1<<WGM00)|(1<<WGM01)|(1<<COM0A1)|(1<<COM0B1);
TCCR0B |= (1<<CS00);
/* OC0A = pin PB2 configurat ca iesire
OC0B = pin PD5 configurat ca iesire */
DDRB|=(1<<PB2);
DDRD|=(1<<PD5);
}
49
Explicarea programării registrelor de
control din funcţia InitPWM()
TCCR0A - Timer Counter Control Register (TIMER0)
TCCR0B - Timer Counter Control Register (TIMER0)

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)

Determinarea frecventei PWM


Dacă avem un ceas sistem de fclock=4 MHz (perioada de 0.25 usec) vom avea
o durată a ciclului de numărare de 28 * 0.25usec = 256 * 0.25usec = 64
usec, deci f PWM = cca. 15.6 KHz
Sau folosind formula deja data f PWM= fclock / (1*256) = 4000 000/256 =
15625Hz = 15.625 kHz 50
Exemplu pentru Timer 0, PWM rapid
/*Factorul de umplere: dat printr-o valoare pe 8 biti fara
semn, ca o valoare intre 0 – 255
0 -> FU% = 0% si 255-> FU% = 100% */

/*actualizeaza factorul de umplere , pe 8 biti pe cele 2


canale A si B, cu valori complementare */
void SetPWMOutput(unsigned char factor_umplere)
{
OCR0A = factor_umplere;
OCR0B = 255-factor_umplere; /*complement fata de 255*/
}

/*O functie simpla care realizeaza o intarziere software*/


void Asteapta()
{/*functia se afla in biblioteca descrisa de delay.h */
_delay_loop_2(10000);
/*realizeaza o intarziere de 4*argument cicluri masina,
adica de 4*10000*0.25usec = 10000 usec = 10msec */
} 51
Exemplu pentru Timer 0, mod PWM rapid-2
int main() /*Programul principal*/
{
unsigned char val_PWM =0;
InitPWM(); /*Initializeaza Timer 0, PWM rapid 8 biti */
while(1) /* bucla fara sfarsit /*
{

/*o prima bucla in care crestem factorul de umplere de la 0 la 100% */


for(val_PWM =0; val_PWM; val_PWM ++)
{ /* Actualizam factorul de umplere PWM */
SetPWMOutput(val_PWM);
Asteapta(); /*O mica intarziere*/
} /*in timp real bucla ar trebui sa dureze cam 2.5 sec*/

/*a 2a bucla in care descrestem factorul de umplere de la 100% la 0 */


for(val_PWM =255; val_PWM >0; val_PWM --)
{ /* Actualizam factorul de umplere PWM */
SetPWMOutput(val_PWM);
Asteapta(); /*O mica intarziere*/
}
}/*end while*/
}
52
AVR 8 biti, din nou despre sistemul de
întreruperi si sursele de întreruperi
• Întreruperile, la modul general (nu neapărat in contextul AVR 8
biti), pot fi clasificate ca:
– interne sau externe
– software sau hardware
• O întrerupere externă este declanșată de un dispozitiv extern
microcontrolerului (aflat in exteriorul lui)
• O întrerupere internă este declanșată de un dispozitiv integrat
microcontrolerului (aflat pe același cip), tipic un periferic
• Putem avea o întrerupere hardware care apare datorită
modificării stării unei componente hardware a unui sistem
de calcul, in particular a unui MCU
• Putem avea si o întrerupere software care este
declanșată de execuția unei instrucțiuni specifice de către
unitatea centrala (CPU)
– AVR 8 biți nu are instrucțiuni specifice de intrerupere software
– care sa genereze o intrerupere - in setul de instrucțiuni, dar
problema poate fi eventual conturnată, astfel încât să avem o
întrerupere generată de execuția unei instrucțiuni

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

Un compilator C rezolvă el această problema de salvare a


contextului, deoarece generează automat codul pentru 62
salvarea si restaurarea intregului context, context care include
si SREG.
Întreruperile AVR 8 biți: evenimente
si condiții
• Toate întreruperile/cererile de întrerupere AVR se
încadrează in două mari clase/categorii:
– Întreruperi bazate pe un eveniment
• Sunt declanșate de un eveniment si sunt memorate in mod automat;
cererea de întrerupere este ștearsă automat la intrarea in rutina de
tratare sau trebuie ștearsă prin program (de utilizator, “manual”).
• O puteți imagina ca ieșirea unui bistabil care este setat de acel
eveniment, memorand faptul ca evenimentul a avut loc
• Daca ea trebuia ștearsă de utilizator si nu a fost ștearsă de el in rutina
de tratare a întreruperii, după întoarcerea din aceasta, va fi tratata din
nou, deși acum nu mai are legătură cu evenimentul!
– Întreruperi bazate pe o condiție
• Provocate dacă o anumită condiție este îndeplinită (este adevărată);
cererea de întrerupere este ștearsă/dispare atunci când condiția nu
mai este îndeplinită (devine falsă), si nu sunt memorate
• O puteți imagina ca ieșirea unei porți care este setată de o anumita
combinație a intrărilor, fara capacitate de memorare

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

• Bazate pe • Bazate pe condiție:


evenimente:
– Întreruperi externe
– Întreruperi externe declanșate pe nivel
declanșate pe front
(tranziție de semnal) – Recepție caracter
– Depășirile pentru USART (port serial):
temporizatoare Data Ready, Receive
/numărătoare si Complete
eveniment – EEPROM disponibil
comparare ieșire pentru operare
(match)

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

• Pentru ATTiny 2313 (DIP20)


avem 3 întreruperi externe –
care corespund unor semnale
aplicate pe anumiţi pini: int0
– RESET (pin 1 – PA2)
– INT0 (pin 6 – PD2)
– INT1 (pin 7 – PD3)

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

• Registrul MCUCR - MCU Control Register


7 6 5 4 3 2 1 0

ISC11 ISC10 ISC01 ISC00

• Bitii ISC – Interrupt Sense Control bits


– 00 – nivel “0” INT0
– 01 – modificare nivel INT1
– 10 – front negativ
– 11 – front pozitiv
70
Cum sunt identificate evenimentele de tip
întreruperi externe: dimensiunea timp

• Unitatea centrală (CPU) testează starea logică a


pinilor corespunzători lui INT0, INT1, .. la fiecare
ciclu (perioadă) a ceasului sistem (clkCPU)
• Pentru a detecta / identifica o tranziție sau
modificare de nivel, intr-un ciclu trebuie să avem
detectat un “0” si in următorul un “1” sau invers
– Impulsurile foarte scurte (cu durata mai mică de un ciclu)
pot să nu fie detectate (nu este văzută de CPU nici o
modificare sau tranziţie)
• O întrerupere pe nivel “0” va fi luată in considerare
doar dacă, la sfârșitul execuției instrucțiunii curente,
starea pinului aferent este “0”

71
Registrul MCUCSR- registrul de control si
stare pentru cazul in care există INT2
• Registrul MCUCSR - MCU Control and Status Register

MCUCSR – MCU Control and Status Register


7 6 5 4 3 2 1 0

ISC2

• Bitul ISC – Interrupt Sense Control bit INT2


– 0 – front negativ
– 1 – front pozitiv
• Spre deosebire de INT0 si INT1, doar aceste configurări există
pentru INT2 (la ATMEGA16 sau similar)!

72
Registrul GICR- activarea individuala a
întreruperilor externe

• GICR General Interrupt Control Register


GICR – General Interrupt Control Register
7 6 5 4 3 2 1 0

INT1 INT0 INT2

• Aici întreruperile externe pot fi activate/dezactivate individual


(mascate)

//exemplu activare int1 si dezactivare int0

GICR |= (1<<INT1);
GICR &= ~(1<<INT0);

73
Registrul GIFR- aici se gasesc indicatorii
corespunzători cererilor de întrerupere externe

• GIFR- General Interrupt Flag Register

7 6 5 4 3 2 1 0

INTF1 INTF0 INTF2

• Un indicator setat (in ‘1’) arată că o întrerupere


externa se află in aşteptare pentru a fi tratată
• Indicatoarele pot fi oricând citite
– Aceste indicatoare sunt utilizate doar dacă configurarea
este pentru tranziţii (modificare nivel)
• Pentru configurarea pe nivel indicatorul este întotdeauna
“0”
– Evenimentul specificat va seta flagul; el va fi şters prin
tratarea întreruperii sau eventual poate fi sters si
“manual”
74
AVR 8 biti- cum se pot realiza si
întreruperi software
• In setul de instrucțiuni AVR 8 biti, spre deosebire de
alte unitati centrale, nu există o instrucțiune care să
producă o întrerupere software (gen trap), dar este
posibilă o soluție de conturnare a acestei lipse
• Dacă pinii corespunzători întreruperilor externe sunt
disponibili si sunt configurați si utilizați ca ieșiri de
aplicație, programul poate controla el starea
indicatorilor respectivi (de ex. INT0 sau INT1),
aducându-i in “1” sau “0”
– Aceasta acțiune poate declanșa o întrerupere conform
configurării întreruperilor externe
• Deoarece o instrucțiune a programului este cea care
a generat astfel întreruperea, ea poate fi numită
întrerupere software
75
Întreruperile AVR 8 biti si compilatorul WinAVR
• Nu există un consens general in ce privește proiectarea
compilatoarelor C legat de cum anume pot fi manipulate
mai bine de programator întreruperile, făcând ca detaliile
care sunt dependente de mașină (CPU) să fie cat mai
bine „ascunse” utilizatorului.
• Pentru un microcontroler AVR 8 biți (si nu numai)
compilatorul C va crea o tabelă corespunzătoare de
vectori, prin compilarea codului sursă.
• Compilatoarele C existente pentru AVR 8 biti sunt
proiectate cu metode specifice pentru a realiza
completarea acestei tabele de întreruperi, cum este
cazul si compilatorului WinAVR pe care il vom discuta in
continuare.
• Fiecare întrerupere va fi identificată printr-un nume
predefinit, care este prezent intr-un fișier header
specific fiecărei variante de microcontroler AVR.

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

/* Intrerupere depasire Timer/Counter1 */


#define TIMER1_OVF_vect _VECTOR(5)
/*vectorul corespunzator intreruperii data de depasirea
Timer-ului 1 este al 5-lea din tabela*/

Pentru ca compilatorul să înţeleagă aceste macroinstrucţiuni (si altele),


mai trebuie inclus si un alt fişier header specific interrupt.h.

#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
}

In afara de întreruperile „dorite” pentru evitarea unor întreruperi parazite (care


de fapt nu ar trebui sa apară) se poate folosi tot macroinstrucţiunea ISR() cu un
argument specific:

ISR(_vector_default)
{
//codul care trateaza intreruperile parazite
}

Este o măsura de siguranţa care imbunătăteste fiabilitatea aplicaţiei.

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)

• Ea nu face altceva decât să pună codul instrucțiunii RETI (întoarcere


din întrerupere) in poziția corespunzătoare vectorului specificat in
tabela de întreruperi.

• Alte macroinstrucţiuni importante (fără nici un argument) definite in


același fișier header sunt:

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

• Versiunile mai vechi ale compilatorului WinAVR foloseau o


macroinstrucţiune similară lui ISR numita SIGNAL() care nu mai este
utilizată la versiunile curente (este deprecated, obsolete).

• O altă macroinstrucţiune legată de manipularea întreruperilor este


ISR_ALIAS(vector_actual, vector_tinta) care este utilă pentru a face ca
un vector să indice de fapt un alt vector.
– In felul acesta se pot trata întreruperi diferite cu aceiaşi rutina de tratare a
întreruperilor.
• Dacă de exemplu am dori ca cele două întreruperi externe INT0 si INT1 să
fie tratate cu o rutină unică de tratare, am avea:

ISR (INT0_vect) //rutina de tratare a intreruperii INT0


{ PORTB = 0x42;
}
……..
ISR_ALIAS(INT1_vect, INT0_vect);

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

unsigned char led;

/* rutina de tratare a intreruperii externe int0 */


ISR(INT0_vect) { led = 0x01;
}
/* rutina de tratare a intreruperii externe int1 */
ISR(INT1_vect) { led = 0x00;
81
}
Întreruperi si compilatorul WinAVR: întreruperile
externe
Programul principal:

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 */

/*reinitializam numaratorul pentru urmatorul ciclu de


numarare */
TCNT1H=(-500000/16) >> 8;
TCNT1L=(unsigned char)(-500000/16) ;

/*… aici vom pune prelucrarile din subrutina de tratare a


intreruperii */
}
85
Un exemplu de utilizare/configurare Timer 0, modul normal
(ATMega16) si sistemul de întreruperi - 1
#include <avr/io.h>
#include <avr/interrupt.h>
/* variabila globala pentru contorizarea numarului de depasiri 8 biti, valoare maxima este
256 */
uint8_t total_depasiri;
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
COM01=COM00=0, mod normal, OC0 deconectat de pin */
/* dorim o intarziere de baza sa-i zicem de 200msec=0.2 sec
aceasta corespunde la 0.200/0.001024 = 195 (195.31 trunchiat)
de incrementi pt acest interval de timp, deci
registrul va numara incepand de la 256-195 pana la valoarea maxima 256 (255+1)
moment in care va avea loc depasirea */
/* initializam registrul de numarare timer */
TCNT0 = 256-195;
/* initializam variabila de contorizare */
total_depasiri = 0;
/* activam intreruperea corespunzatoare lui Timer 0*/
TIMSK |= (1 << TOIE0);
} 86
Un exemplu de utilizare/configurare Timer 0, modul normal
(ATMega16) si sistemul de întreruperi -2
/* functia/subrutina de tratare a depasirii pentru Timer 0 TCNT0 apelata de fiecare data cand are loc o
depasire */
ISR(TIMER0_OVF_vect)
{
/* reincarcam pentru ca urmatorul ciclu sa aiba aceiasi lungime */
TCNT0 = 256-195;
/* incrementam contorul, el va numara modulo 256! */
total_depasiri++;
}

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
}
}

You might also like