Sunteți pe pagina 1din 19

CAPITOLUL 1

CONSIDERAŢII GENERALE PRIVIND


STRUCTURA ŞI FUNCŢIONAREA UNUI SISTEM
DE PRELUCRARE NUMERICĂ CU PROCESOR

În acest capitol sunt prezentate principii generale privind structura şi


funcţionarea unui sistem de prelucrare numerică cu procesor (SPN).
Structura generală a unui SPN este prezentată în figura 1.1. Unitatea centrală de
prelucrare (UCP), este cea mai importantă componentă a unui astfel de sistem.
Principala funcţie a UCP este de a executa un program reprezentat printr-o secvenţă de
instrucţiuni. Programul este încărcat în prealabil în memorie, mai concret în memoria
program. Execuţia programului implică existenţa unor date care urmează să fie
prelucrate. Acestea se găsesc fie în memoria de date, fie sunt preluate de la periferice.
Execuţia programului se concretizează prin generarea unor date care pot fi stocate în
memoria de date sau pot comanda perifericele. Perifericele asigură schimbul de
informaţii cu exteriorul. În cea mai simplă formă perifericele sunt reprezentate de
porturile de intrare-ieşire (intrări-ieşiri numerice). Alte exemple de periferice sunt:
convertoarele analog-numerice (intrări analogice), convertoarele numeric-analogice
(ieşiri analogice), interfeţele (porturile) seriale, temporizatoarele.
Un procesor (microprocesor), care este specific calculatoarelor personale,
conţine doar UCP, relativ la figura 1.1. Acesta are o mare putere de calcul deoarece
trebuie să execute mai multe aplicaţii în acelaşi timp. De aceea, memoria şi perifericele
sunt externe, fiind poziţionate în interiorul carcasei calculatorului. Un microcontroler, la
fel ca un procesor de semnal, conţine toate cele 3 elemente componente din figura 1.1
integrate în aceeaşi capsulă. Aceste două dispozitive sunt folosite pentru aplicaţii
dedicate. Diferenţa între cele două este că procesorul de semnal este optimizat din punct
de vedere al instrucţiunilor pentru a face prelucrări de semnal (filtrări numerice sau
transformări Fourier rapide) în timp ce un microcontroler are integrate o gamă mai largă
de periferice, în special intrări-ieşiri numerice.

UCP MEMORIE PERIFERICE

Fig. 1.1 Structura generală a unui SPN.


12 Consideraţii generale - 1

1.1. Consideraţii generale privind unitatea centrală de prelucrare (UCP)

Aşa cum s-a precizat, UCP a unui SPN execută un program reprezentat printr-o
secvenţă de instrucţiuni. Aceste instrucţiuni pot fi, în cazul cel mai general, de forma:
adună două numere, transferă un număr în memorie, la o adresă dată, deplasează un
număr cu o unitate spre dreapta, etc. Fiecare instrucţiune este reprezentată printr-un
număr de octeţi (în general, între 1 şi 8) care reprezintă codul maşină al instrucţiunii.
Secvenţa de instrucţiuni obţinută în acest fel este memorată în memoria program.
Execuţia unei instrucţiuni înseamnă extragerea codului maşină din memorie,
decodificarea, iar apoi execuţia propriu zisă.
Codul maşină al unei instrucţiuni trebuie să furnizeze următoarele informaţii:
-operaţia care trebuie executată; această informaţie este precizată de primul
octet sau cuvânt de 16 biţi din codul maşină, numit şi cod operaţie; uneori acest octet
(cuvânt) poate specifica şi operandul destinaţie;
-operandul sau operanzii sursă, care pot fi conţinuţi în clar în codul maşină, sau
trebuie extraşi din memorie (caz în care trebuie cunoscută adresa) sau din registre;
-operandul destinaţie.
Codul maşină este înţeles de sistemul de prelucrare numerică, dar mult mai
dificil de utilizat în această formă de operatorul uman. De aceea, acesta scrie programul
(instrucţiunile) într-un limbaj mai accesibil, numit limbaj de asamblare, în care
instrucţiunile sunt reprezentate prin aşa numitele mnemonici urmate de operanzi. O
mnemonică este o scriere prescurtată a funcţiei implementată de instrucţiune. În practică
există programe speciale numite compilatoare sau asambloare, care transformă limbajul
de asamblare în cod maşină.
Exemplu:
Instrucţiune în limbaj de asamblare: LDAA #3Ah. Mnemonica este LDAA
(prescurtarea de la Load Accumulator A) iar câmpul #3Ah reprezintă operandul.
Codul maşină al instrucţiunii: 86h 3Ah
Efectul instrucţiunii: încarcă acumulatorul A (operand destinaţie) cu numărul
3Ah (operand sursă).
Primul octet al codului maşină, 86h, reprezintă codul operaţiei şi după
decodificare are efectul: încarcă acumulatorul A cu numărul care urmează în codul
maşină al instrucţiunii. Operandul sursă (3Ah), apare atât în formatul instrucţiunii în
limbaj de asamblare, cât şi în codul maşină.
Limbajul de asamblare este specific fiecărui dispozitiv (procesor,
microcontroler, sau procesor de semnal), chiar dacă în general există elemente comune,
cum ar fi mnemonici ca MOV, JUMP, ADD, etc. De aceea, trecerea la un alt dispozitiv
poate ridica probleme, datorită diferenţelor între limbajele de asamblare. O variantă mai
simplă de a scrie programe pentru astfel de dispozitive este folosirea unui limbaj de
nivel înalt, cum ar fi C, care este acelaşi, indiferent de tipul dispozitivului. Şi în acest
caz există compilatoare care transformă liniile de program C în cod maşină specific
fiecărui dispozitiv. Totuşi, aceste compilatoare nu generează acelaşi cod maşină ca şi în
1 - Consideraţii generale 13
cazul în care funcţia implementată de secvenţa de program C ar fi fost scrisă în limbaj
de asamblare.
Orice UCP are un circuit de iniţializare sau Reset. Efectul acestui circuit este de
a permite începerea execuţiei programului de la început (de la o adresă prestabilită).
Funcţia unui astfel de circuit devine efectivă la conectarea tensiunii de alimentare sau la
aplicarea unui semnal (activ pe nivel coborât de obicei) la un pin dedicat al UCP, numit
chiar Reset.
De asemenea, UCP conţine un număr de registre de uz general. Acestea sunt
folosite ca sursă şi destinaţie pentru operanzi sau pot fi încărcate cu numere care
reprezintă adrese de operanzi. În plus, mai există 3 registre cu funcţii standard care se
găsesc în aceeaşi formă în fiecare variantă de UCP. Acestea sunt: registrul PC (Program
Counter, numărător de adrese sau de program), registrul SP (Stack Pointer, indicator al
vârfului stivei) şi registrul SR (Status Register, registru de stare sau al indicatorilor de
condiţii, acesta neavând o denumire standard, valabilă pentru toate dispozitivele).
Registrul PC indică adresa din memorie a instrucţiunii care urmează să fie
executată (adresa primului octet al instrucţiunii). Rezultă că după fiecare instrucţiune
registrul PC îşi măreşte conţinutul cu numărul de octeţi ai codului maşină ai instrucţiunii
respective. Acest lucru este valabil când execuţia programului este liniară, adică nu
există ramificaţii în program. O ramificaţie înseamnă că următoarea instrucţiune
executată nu este cea de la adresa care urmează după ultimul octet al instrucţiunii
curente, ci una situată la o adresă mai mare sau mai mică. Există trei posibilităţi de
ramificaţii: instrucţinui de salt, apeluri de subrutine sau răspunsuri la cereri de
întrerupere. În aceste situaţii, registrul PC va fi încărcat cu adresa instrucţiunii unde se
va face saltul. Această adresă este cu un număr de unităţi mai mare sau mai mică decât
conţinutul registrului PC înainte de salt.
Exemplu:
În figura 1.2 se prezintă o secvenţă de program în limbaj de asamblare. În
prima coloană sunt adresele, în a doua codurile maşină, iar în a treia instrucţiunile în
limbaj de asamblare. Astfel, începând cu prima instrucţiune, IDIV, şi până la
instrucţiunea BRA *–6, execuţia programului este liniară, încât registrul PC are
succesiv, valorile: 4023h, 4025h, 402Ah, 402Fh, 4031h, 4034h, 4037h. Instrucţiunea
BRA *–6 este o instrucţiune de salt (necondiţionat), execuţia ei înseamnă un salt la o
adresă situată cu 6 locaţii mai sus. Ca urmare, registrul PC va fi încărcat cu valoarea
4031h şi nu cu 4039h, care este adresa instrucţiunii care urmează după BRA *–6.

Fig 1.2 Secvenţă de program în limbaj de asamblare


împreună cu codurile maşină corespunzătoare.
14 Consideraţii generale - 1
Funcţia registrului SP este în strânsă legătură cu registrul PC, aşa cum se va
vedea în continuare. Apelul unei subrutine sau răspunsul la o cerere de întrerupere
înseamnă un salt la o adresă unde este plasată subrutina (subrutina de întrerupere).
Astfel, în figura 1.3 instrucţiunea CALL S_1, aflată la adresa ADR1 apelează
subrutina S_1, aflată la adresa AS_1. La încheierea subrutinei (instrucţiunea RET)
programul trebuie să se reîntoarcă la instrucţiunea care urmează după cea care a făcut
apelul, adică instrucţiunea Instr. 1, aflată la adresa ADR1+n (n reprezintă numărul de
octeţi ai instrucţiunii Instr.1). Pentru a fi posibil acest lucru, registrul PC trebuie încărcat
cu adresa ADR1+n. Această adresă a fost disponibilă în registrul PC după extragerea
codului maşină al instrucţiunii CALL S_1, înainte de decodificarea şi execuţia acestei
instrucţiuni. De aceea, execuţia instrucţiunii CALL S_1 înseamnă mai întâi salvarea
registrului PC şi abia apoi încărcarea lui cu adresa de salt (AS_1, în acest caz). Zona de
memorie unde se realizează salvarea se numeşte stivă.
Uneori este însă posibil ca din subrutina S_1 să fie apelată o altă subrutină, de
exemplu subrutina S_2 aflată la adresa AS_2. Apelul se face prin instrucţiunea CALL
S_2, aflată la adresa ADR2. Înseamnă că adresa ADR2+n trebuie de asemenea salvată în
stivă. De obicei salvarea în stivă se face la adrese descrescătoare. În acest sens, registrul
SP (Stack Pointer, indicator al vârfului stivei) este decrementat cu 1 pentru fiecare octet
salvat în stivă. Conţinutul acestui registru indică adresa ultimului octet salvat.
Presupunând că înainte de execuţia instrucţiunii CALL S_1 conţinutul
registrului SP era 4000h, în tabelul 1.1 se prezintă conţinutul memoriei stivă după
execuţia instrucţiunii CALL S_2. Deoarece fiecare adresă salvată în stivă conţine 2
octeţi (octetul mai semnificativ, notat H şi cel mai puţin semnificativ, notat L), înseamnă
că registrul SP a fost decrementat de 4 ori, adică conţine valoarea 3FFCh. La execuţia
instrucţiunii RET din subrutina S_2, registrul PC se încarcă cu conţinutul stivei de la
adresele SP şi SP+1 (adică 3FFCh şi 3FFDh), iar registrul SP se incrementează cu 2
unităţi. La execuţia instrucţiunii RET din subrutina S_1 registrul PC se încarcă de
asemenea cu conţinutul stivei de la adresele SP şi SP+1 (3FFEh şi 3FFFh în acest caz),
după care registrul SP se incrementează din nou cu 2 unităţi. Rezultă că numerele
existente în stivă se citesc în ordinea inversă celei în care au fost salvate, de unde
denumirea de stivă sau memorie LIFO (Last In First Out).

MEMORIE PROGRAM
PROGRAM APELANT SUBRUTINA S_1 SUBRUTINA S_2
ADRESE INSTRUCŢIUNI ADRESE INSTRUCŢIUNI ADRESE INSTRUCŢIUNI

….. AS_1 …… AS_2 ……


ADR1 CALL S_1 ……. ……
ADR1+n Instr. 1 ADR2 CALL S_2
…… ADR2+n Instr.2
….. RET

RET

Fig. 1.3 Apelul unei subrutine.


1 - Consideraţii generale 15

Tabelul 1.1 Conţinutul memoriei stivă


Adresă Conţinut
3FFFh (ADR1+n)H
3FFEh (ADR1+n)L
3FFDh (ADR2+n)H
3FFCh (ADR2+n)L

În practică există posibilitatea ca în stivă să se salveze şi alte numere în afară de


adresele de revenire, prin intermediul instrucţiunilor de tip PUSH, în timp ce citirea din
stivă se face cu instrucţiuni de tip POP sau PUL. În acest caz programatorul trebuie să
gestioneze accesarea corectă a stivei, ţinând cont de posibilitatea apelării unei subrutine
care prin instrucţiunile CALL şi RET afectează stiva.
Registrul SR (Status Register) conţine la majoritatea dispozitivelor biţii
indicatori care sunt modificaţi în urma execuţiei unei instrucţiuni aritmetice sau logice:
C (Carry), V (Overflow), N (Negative), Z (Zero). Funcţiile acestor biţi vor fi prezentate
în cap.2.
De asemenea, registrul SR conţine şi bitul care permite validarea întreruperilor
mascabile, notat de obicei GIE (General Interrupt Enable). În afară de aceşti biţi,
registrul SR mai poate conţine şi alţi biţi.
Instrucţiunile unui SPN se execută sincronizat, în funcţie de un semnal de tact.
Durata de execuţie a unei instrucţiuni este egală cu un număr de perioade ale semnalului
de tact, numite ciclii maşină. Pentru fiecare instrucţiune producătorii precizează numărul
de ciclii maşină. Astfel, dacă se cunoaşte durata de execuţie a fiecărei instrucţiuni, se
poate determina durata execuţiei unei secvenţe de instrucţiuni. Pe acest principiu se
bazează realizarea aşa numitelor bucle de temporizare, adică secvenţe de instrucţiuni a
căror durată de execuţie este cunoscută foarte precis, fiind direct proporţională cu un
parametru (numărul de execuţii repetitive ale buclei).
Aşa cum s-a spus anterior, compilarea unui program scris în C va genera mai
multe instrucţiuni în cod maşină decât dacă funcţia ar fi fost scrisă în limbaj de
asamblare. Rezultă că, pe de o parte, secvenţa va ocupa o memorie mai mare, iar pe de
altă parte, durata de execuţie va fi mai mare. Înseamnă că scrierea în limbajul C este
avantajoasă când memoria şi timpul de execuţie nu sunt critice.
Exemplu:
Se doreşte scrierea numerelor de la 1 la 10 într-o zonă a memoriei. Această
operaţie se va face atât în limbaj de asamblare, cât şi în limbaj C. În figura 1.4 a),
respectiv, 1.5 a) se prezintă codurile sursă ale celor două variante de program (doar
partea de buclă). În figura 1.4b), respectiv 1.5b) se prezintă variantele obţinute după
compilare (codurile maşină, dar şi varianta dezasanblată), în cele două cazuri. Se
observă că în cazul în care programul a fost scris în limbaj de asamblare, codul conţine
3 instrucţiuni care ocupă 6 octeţi, iar în cazul în care programul a fost scris în C, codul
conţine 7 instrucţiuni care ocupă 12 octeţi. Explicaţia:
În varianta în limbaj de asamblare, programatorul a ales 2 instrucţiuni
eficiente:
16 Consideraţii generale - 1
STAA 1,X+, salvează în memorie şi incrementează adresa în vederea realizării
următorului transfer;
DBNE B,e, decrementează un contor şi face saltul dacă contorul nu este 0.
În varianta în C, compilatorul a găsit câte 2-3 instrucţiuni pentru fiecare din
acţiunile care în asamblare au fost realizate prin câte o instrucţiune.

a) b)
Fig. 1.4 Program în limbaj de asamblare

a) b)
Fig. 1.5 Program în limbaj C.

1.2. Consideraţii generale privind perifericele unui microcontroler

Având în vedere că subiectul acestei cărţi este legat de microcontrolere, mai


concret cele din seria MSP430 de la Texas Instruments, în acest paragraf se vor descrie
probleme generale referitoare la perifericele unui microcontroler.

1.2.1. Periferice de tip „Digital I/O”

Perifericele de tip „Digital I/O” (intrări-ieşiri digitale (numerice) sau porturi de


intrare-ieşire) reprezintă cea mai simplă posibilitate de interfaţare a unui microcontroler
cu exteriorul. În general, aproape fiecare din pinii unui microcontroler posedă o funcţie
de intrare-ieşire numerică. În afară de aceasta, pinii mai pot realiza o interfaţă cu alte
periferice mai avansate existente în interiorul microcontrolerului.
În figura 1.6 se prezintă principial funcţiile de ieşire şi de intrare ale unui pin.
Astfel, pentru un pin având funcţia de ieşire, informaţia binară (un bit cu
valoarea 0 sau 1 logic) este transmisă din microcontroler la pin, regăsindu-se sub forma
unei tensiuni (0 logic-0V, 1 logic-tensiunea de alimentare pozitivă +Vcc). Tensiunea
respectivă poate fi măsurată cu un voltmetru.
Pentru un pin având funcţia de intrare, informaţia binară aplicată la pin sub
forma unei tensiuni de la o sursă (0 logic-0V sau masă, 1 logic-tensiunea de alimentare
pozitivă +Vcc) este transmisă în microcontroler, regăsindu-se în valoarea unui bit (0 sau
1 logic).
Rezumând, cele două operaţii pot fi prezentate sintetic astfel:
1 - Consideraţii generale 17
Ieşire: bit (scris prin program)→tensiune la pin (măsurată cu un voltmetru).
Intrare: tensiune la pin (aplicată de la o sursă)→bit (citit prin program).

Microcontroler Microcontroler +VCC

pin pin
bit 0/1 bit 0/1

ieşire intrare
Fig. 1.6 Funcţiile de ieşire şi, respectiv, de intrare ale unui pin.

Pinii unui microcontroler sunt grupaţi în porturi de 8 sau 16 biţi. Fiecare pin
poate fi programat individual ca intrare sau ieşire, folosind biţii din registrele de direcţie.
O facilitate importantă pe care o au perifericele Digital I/O este posibilitatea ca
la fiecare pin al unui port să se conecteze un rezistor intern. Celălalt terminal al
rezistorului poate fi conectat fie la borna pozitivă a tensiunii de alimentare (1 logic) fie
la borna de masă (0 logic), figura 1.7. În primul caz, rezistorul se numeşte de tip „pull-
up”, iar în al doilea caz de tip „pull-down”. Starea unui pin conectat la un rezistor pull-
up, obţinută printr-o operaţie de citire de către microcontroler, este 1 logic, chiar dacă
pinul este neconectat în exterior. Dacă ulterior pinul este conectat în exterior la masă,
atunci prin citire se obţine 0 logic. În acest fel se pot detecta tranziţii de pe 1 logic pe 0
logic ale pinului, fără a fi necesar ca rezistorul să fie conectat în exterior, ceea ce
înseamnă că se face economie de componente şi, mai ales, de spaţiu pe cablajul
imprimat. Similar, un pin conectat la un rezistor pull-down este „văzut” la nivel 0 logic
de microcontroler, iar conctarea lui în exterior la tensiunea de alimentare pozitivă
permite citirea nivelului 1 logic sau detecţia unei tranziţii de pe 0 logic pe 1 logic a
pinului respectiv.

Microcontroler Microcontroler
+Vcc pin

pin

rezistor „pull-up” rezistor „pull-down”


Fig. 1.7 Conectarea unui rezistor pull-up, respectiv, pull-down la un pin.
18 Consideraţii generale - 1

1.2.2. Periferice de tip „Timer”

Un periferic de tip „Timer” sau temporizator generează evenimente periodice.


Perioada evenimentelor sau temporizarea se stabileşte prin numărarea unui număr
prestabilit de impulsuri cu o anumită perioadă. Astfel, temporizatorul conţine un
numărător şi un generator de semnal de tact. Numărătorul se încarcă cu o constantă iar
apoi se decrementează cu 1 la fiecare impuls primit [1]. Temporizarea corespunde
anulării conţinutului numărătorului. Primul impuls primit după anulare reîncarcă
constanta şi apoi procesul se continuă în acest fel. Există şi varianta în care numărătorul
începe numărarea de la 0 şi îşi incrementează conţinutul la fiecare impuls primit. În
acest caz temporizarea corespunde momentului când conţinutul numărătorului egalează
o constantă prestabilită, iar la următorul impuls primit numărarea reîncepe de la 0. De
fiecare dată când temporizarea se încheie (conţinutul numărătorului se anulează sau
egalează constanta predefinită) un bit indicator (flag) este trecut pe 1 logic.
Expresia temporizării este
Cst
T= = Cst ⋅ T0 , (1.1)
f0
unde Cst este constanta de temporizare, iar f0=1/T0 reprezintă frecvenţa impulsurilor de
numărat.
Pe baza relaţiei (1.1) rezultă cele două posibilităţi de modificare a perioadei de
temporizare: modificarea constantei Cst sau modificarea frecvenţei f0. A doua variantă
se realizează de obicei prin divizarea semnalului furnizat de generatorul de tact.
Există temporizatoare de 8 biţi, 16 biţi, 24 de biţi, etc. În funcţie de numărul de
biţi al temporizatorului rezultă valoarea maximă a constantei Cst.
În practică, utilizarea unui temporizator implică să se facă o acţiune de fiecare
dată când perioada de temporizare s-a încheiat (modificarea stării unui led, citirea stării
unui pin programat ca intrare, declanşarea unei conversii analog-numerice, etc.). Pentru
aceasta este necesară testarea continuă a bitului indicator (flag) şi executarea acţiunii
respective în momentul când bitul devine 1. Bitul respectiv trebuie imediat şters (trecut
pe 0) pentru ca ulterior să se poată detecta noua trecere pe 1.
Pe lângă funcţia de bază de temporizare, aceste periferice mai au două funcţii
auxiliare: funcţia de captură şi funcţia de comparare.
Funcţia de captură presupune existenţa unui semnal exterior microcontrolerului
(aplicat la un pin) pe lângă structura de bază care conţine numărătorul şi generatorul de
semnal de tact. În acest caz numărătorul numără crescător.
Principiul funcţiei de captură este prezentat în figura 1.8 unde N reprezintă
numărul de la ieşirea numărătorului iar s reprezintă semnalul exterior. Operaţia de
captură implică captarea (reţinerea) conţinutului numărătorului în momentele de timp
corespunzătoare fronturilor semnalului s. Astfel, la momentele t1, t2, t3, t4 sunt captate în
ordine numerele N1, N2, N3, N4. Se observă că valorile N3 şi N4 sunt obţinute după ce
numărătorul depăşeşte, adică ajunge la valorea maximă 2n după care reia numărarea de
la 0 (n reprezintă numărul de biţi al numărătorului). Dacă se cunoaşte perioada
1 - Consideraţii generale 19
impulsurilor de numărat T0, pe baza valorilor captate se pot determina parametrii de
timp ai semnalului s astfel:
-durata impulsului ti (teoretic, este egală cu t2–t1 sau t4–t3); se calculează prin
relaţia ti=(N2–N1) × T0 sau ti=(N4–N3) × T0
-perioada semnalului T (este egală cu t3–t1 sau t4–t2); se calculează prin relaţia
T=(N3+2n–N1) × T0 sau T=(N4+2n–N2) × T0
-durata pauzei, tp (este egală cu t3–t2); se calculează prin tp=(N3+2n–N2) × T0.
În cazul calculului perioadei sau pauzei s-a ţinut cont de faptul că a avut loc o
depăşire a numărătorului şi ca urmare la numerele captate după depăşire a fost adunată
capacitatea numărătorului, 2n. Pentru a evita depăşirile, în practică, perioada cu care apar
acestea trebuie aleasă mult mai mare decât valoarea estimată a intervalelor de timp care
urmează să fie măsurate.
La un temporizator uzual, capturile se pot face pe front crescător (t1 sau t3 în
figura 1.8), pe front descrescător (t2 sau t4) sau pe ambele fronturi (t1, t2, t3, t4).
De regulă, valorile captate sunt salvate în registre speciale. De fiecare dată când
are loc o captură, un bit indicator (flag) este trecut pe 1 logic. De aceea, acest bit trebuie
testat, iar când devine 1, valoarea aferentă din registrul respectiv trebuie citită, după care
bitul indicator trebuie şters.

Fig. 1.8 Principiul funcţiei de captură.


20 Consideraţii generale - 1
Dacă funcţia de captură presupune aplicarea unui semnal extern, funcţia de
comparare generează un semnal extern (la un pin). Pentru aceasta, pe lângă structura
clasică care conţine numărătorul şi generatorul de semnal de tact, mai există un
comparator. Acesta compară conţinutul numărătorului N cu un număr fix, N1. În
momentul în care conţinutul numărătorului devine egal cu numărul N1, ieşirea unui
circuit comută de pe nivel coborât pe nivel ridicat (figura 1.9). A doua comutare are loc
la depăşirea capacităţii de numărare a numărătorului. În acest mod se formează semnalul
s care reprezintă semnalul generat de temporizator în funcţia de comparare.

Fig. 1.9 Principiul funcţiei de comparare.

Perioada semnalului obţinut este


T = 2n T0 , (1.2)
iar durata impulsului este
ti = (2n − N1 )T0 . (1.3)
Cei doi parametri se pot modifica în funcţie de T0 (perioada), respectiv în
funcţie de T0 şi N1 (durata impulsului). Există situaţii în practică când a doua comutare
are loc când conţinutul numărătorului devine egal cu un număr N2<2n–1. În acest fel,
există o a doua posibilitate de a modifica perioada, în funcţie de N2. De asemenea, forma
semnalului obţinut poate fi complementară celei din figura 1.9.
Generarea unui semnal de forma semnalului s din figura 1.9 se face deosebit de
simplu din punct de vedere al programului, implicând doar câteva înscrieri de registre.
1 - Consideraţii generale 21
Totuşi, există un bit indicator (flag) care devine 1 în momentul egalităţii la comparare.
Generarea semnalului s nu este condiţionată de testarea acestui bit şi de executarea
vreunei acţiuni în momentul trecerii pe 1 a bitului. Această facilitate a temporizatorului
poate fi folosită pentru a executa (sincroniza) alte acţiuni în momentul egalităţii la
comparare.
Unele microcontrolere conţin un modul dedicat pentru generarea semnalelor
dreptunghiulare cu perioadă şi durată variabile numit PWM (Pulse Width Modulator).
Acesta utilizează funcţia de comparare, dar nu are implementată funcţia de temporizare.
Un microcontroler mai conţine un alt timer mai special, diferit de cel prezentat
anterior. Acest timer este numit “watchdog timer” şi funcţionează în principiu ca un
timer de uz general, cu o excepţie: în momentul în care s-a încheiat perioada de
temporizare, acesta face o iniţializare a sistemului, încât execuţia programului va fi
reluată de la început. Pentru ca acest lucru să nu se întâmple în mod nedorit, programul
în rulare trebuie ca periodic să-i reîncarce constanta de temporizare. Dacă reîncărcarea
nu se întâmplă înseamnă că programul funcţionează necorespunzător (de exemplu a
intrat într-o buclă infinită), ceea ce înseamnă că iniţializarea dată de watchdog timer este
binevenită.

1.2.3. Periferice de tip “ADC”

Un periferic de tip “ADC” (Analog to Digital Converter, convertor analog-


digital sau analog-numeric) primeşte la intrare o tensiune, care poate lua orice valoare
într-un interval dat, pe care o converteşte într-un număr reprezentat prin n biţi. Expresia
numărului furnizat de ADC, notat NADC, numit şi rezultatul conversiei este
U
N ADC = 2n in , (1.4)
U ref
unde Uin reprezintă tensiunea de intrare iar Uref reprezintă o tensiune de referinţă, care
impune şi intervalul în care Uin poate lua valori, adică [0, Uref). Numărul de biţi n are
valori de tipul 8, 10, 12 sau chiar 16 şi se mai numeşte rezoluţie.
Cuanta convertorului (numită şi 1 LSB) este reprezentată prin expresia
U ref
q= n . (1.5)
2
Folosind cuanta se poate determina tensiunea de intrare în funcţie de rezultatul
conversiei, Uin=qNADC. Aceasta reprezintă însă o aproximare a Uin deoarece
determinarea rezultatului prin relaţia (1.4) implică o aproximare în sensul că NADC
reprezintă de fapt cel mai apropiat întreg de numărul raţional 2nUin/Uref.
Rezultatul conversiei poate fi reprezentat în formatul fără semn sau în formatul
cu semn. Formatul fără semn (codul binar natural) înseamnă: rezultatul numai zerouri (0
0...0) pentru Uin=0 [V],..., rezultatul 011...11 pentru Uin=Uref/2 [V],..., şi numai 1
(11,...11) pentru Uin=Uref –q [V].
Formatul cu semn (codul complementul lui 2) este utilizat când se doreşte
convertirea unei tensiuni bipolare U in ∈ [−U ref / 2,U ref / 2) . Aceasta este transformată
într-o tensiune unipolară înainte de conversie,
22 Consideraţii generale - 1
U in' = U in + U ref / 2 , (1.6)
'
astfel încât U ∈ [0,U ref ) . Dacă s-ar folosi formatul fără semn, determinarea Uin implică
in

operaţia
U in = qN ADC − U ref / 2 . (1.7)
unde NADC este rezultatul conversiei, iar qNADC reprezintă aproximarea U in' .
Dacă se foloseşte formatul cu semn, nu mai este necesară scăderea dată prin
relaţia (1.7) pentru obţinerea Uin. Rezultatele obţinute sunt prezentate în tabelul 1.2.
Astfel, prin înmulţirea cuantei cu rezultatele obţinute, rezultă valori conforme cu Uin (se
ştie că 100…00= –2n–1 în codul complementul lui 2).

Tabelul 1.2 Rezultate pentru formatul cu semn


Uin Uin’ Rezultat (cod)
-Uref/2 0 100….00
....
0 Uref/2 000…00
….
Uref/2–q Uref–q 011…11

În practică, pentru a se obţine rezultatul unei conversii analog-numerice trebuie


mai întâi să se dea startul acesteia. Execuţia conversiei analog-numerice durează un
anumit interval de timp. La încheierea acestui interval, rezultatul conversiei, NADC, este
încărcat într-un registru special iar un bit indicator (flag) este trecut pe 1. Aşadar,
execuţia unei astfel de conversii implică generarea startului, urmată de testarea continuă
a bitului indicator şi citirea rezultatului conversiei după ce acest bit trece pe 1. Apoi,
bitul indicator trebuie şters.
Startul conversiei înseamnă prelevarea unui eşantion (valoarea momentană) din
tensiunea de intrare şi menţinerea valorii respective constante pe durata conversiei.
Frecvenţa cu care se prelevează eşantioanele reprezintă frecvenţa (rata) de eşantionare.
Echivalent, distanţa în timp între două eşantioane successive reprezintă perioada (pasul)
de eşantioanare.
Există mai multe modalităţi de a declanşa startul conversiei şi implicit de a
stabili frecvenţa de eşantionare. Una dintre acestea este aşa numitul start prin program,
care se pretează în special când se fac conversii singulare. Uneori există posibilitatea să
se facă conversii successive la viteza maximă posibilă, adică după ce o conversie a fost
încheiată să se treacă automat la următoarea. Cea mai des folosită modalitate de a face
conversii successive este utilizarea unui temporizator pentru a realiza declanşarea
conversiilor. În acest sens, convertorul poate fi programat pentru a prelua semnalul
furnizat de temporizator (obţinut de exemplu, folosind funcţia de comparare a acestuia)
şi a-l folosi pentru a da startul conversiei.
1 - Consideraţii generale 23
1.2.4. Periferice de tip “DAC”

Un periferic de tip “DAC” (Digital to Analog Converter, convertor digital-


analogic sau numeric-analogic) realizează operaţia inversă unui ADC: primeşte la
intrare un număr notat NDAC, reprezentat prin n biţi şi generează la ieşire o tensiune, care
ia valori într-un interval dat. Expresia tensiunii de ieşire Uout este
N
U out = U ref DAC , (1.8)
2n
unde Uref reprezintă o tensiune de referinţă, care impune şi intervalul în care Uout poate
lua valori, adică [0, Uref). Numărul de biţi n are valori de tipul 8, 10, 12 sau chiar 16 şi se
mai numeşte şi rezoluţie.
Cuanta convertorului (numită şi 1 LSB) este reprezentată prin expresia
U ref
q= n . (1.9)
2
În practică, scrierea numărului de n biţi într-un registru de date care deserveşte
perifericul DAC are ca efect generarea tensiunii de ieşire. Aceasta devine stabilă după
un anumit timp în raport cu momentul înscrierii registrului de date, numit „settling
time”. În general, acest timp este mult mai scurt decât cel în care se face o conversie
analog-numerică. Pentru modificarea periodică a numărului NADC care se înscrie în
registrul de date se recomandă folosirea unui temporizator. Astfel, la încheierea fiecărei
perioade de temporizare noul număr poate fi înscris în registrul de date.

1.2.5. Periferice de tip „Interfaţă serială”

Un periferic de tip „Interfaţă serială” face conexiunea între două dispozitive,


(între care cel puţin unul poate fi un microcontroler) şi foloseşte la un moment dat o
singură linie pentru a transmite informaţia într-un sens, bit cu bit. Există variante care
transmit pe aceeaşi linie informaţia şi în celălalt sens (evident nu în acealaşi timp) sau
care folosesc o a doua linie pentru transmisia în celălalt sens.
În cadrul unei comunicaţii seriale, dispozitivul care transmite (emiţător)
modifică periodic nivelurile logice (biţii) pe linia de transmisie. Aceasta este conectată
la dispozitivul care recepţionează (receptor). Pentru o comunicaţie corectă, receptorul
trebuie să testeze (eşantioneze) propria linie de recepţie la momente de timp identice cu
cele la care emiţătorul modifică biţii (cu aceeaşi perioadă sau frecvenţă şi cu o fază ceva
mai mare). Pentru aceasta este nevoie de un semnal de tact.
Principalele tipuri de interfeţe seriale cu care sunt dotate microcontrolerele
uzuale sunt:
-interfaţa serială asincronă de tip UART (Universal Asyncronous Receiver
Transmit) numită şi RS-232; în acest caz există o linie pe care se face transmisia într-un
sens şi o altă linie pentru transmisia în celălat sens, şi evident o linie de masă.
Termenul de asincron se referă la faptul că fiecare dispozitiv are propriul semnal
de tact. Frecvenţa cu care se transmit sau recepţionează biţii (frecvenţa de comunicaţie)
se numeşte Baud Rate (BR).
24 Consideraţii generale - 1
Semnalele de tact ale fiecărui dispozitiv trebuie programate pe aceeaşi
frecvenţă. Sincronizarea de fază între cele două generatoare este produsă de bitul de start
(tranziţia din 1 în 0) generat de dispozitivul care începe transmisia.
Formatul datelor pentru o astfel de transmisie este prezentat în figura 1.10.
Durata unui bit este 1/fC, unde fC reprezintă frecvenţa de comunicaţie. După bitul de
start, reprezentat de tranziţia de pe nivel ridicat pe nivel coborât, urmează 7 sau 8 biţi de
date, care se pot transmite începând cu LSB sau cu MSB, iar la sfârşit 1 sau 2 biţi de
stop, pe nivel ridicat. Biţii de start şi de stop permit realizarea sincronizării transferului
de date între receptor şi emiţător. De asemenea, se mai poate introduce opţional un bit
de paritate, folosit pentru detecţia erorilor de transmisie.

Fig. 1.10 Formatul datelor pentru transmisia serială asincronă.

-interfaţa serială sincronă de tip SPI (Serial Peripheral Interface); termenul de


sincron se referă la faptul că există o linie comună de semnal de tact comandată de unul
dintre dispozitive, cel care are funcţia de master. Şi în acest caz există câte o linie pentru
transmisia în fiecare sens şi una de masă.
Comunicaţia serială sincronă între o componentă cu funcţie master şi o
componentă cu funcţie slave este prezentată în figura 1.11.

Fig. 1.11 Comunicaţia serială sincronă.


1 - Consideraţii generale 25
Comanda interfeţei SPI pentru funcţia master/slave se realizează prin linia de
selecţie /SS (Slave Select). Interfaţa SPI a componentei master conţine circuite (baud
rate generator) pentru generarea semnalului de tact (Serial Clock) SCK. Cele două
dispozitive SPI conţin câte un registru de deplasare (shift register) de n biţi (valori
uzuale pentru n: 8, 16) care sunt interconectate într-o configuraţie de registru distribuit
de 2n biţi [1] prin liniile de date MOSI (Master Out/Slave In) şi MISO (Master In/Slave
Out), figura 1.11. Transferul de date se realizează prin deplasarea cu n biţi a conţinutului
registrului distribuit, sincronizată cu semnalul de tact SCK, şi are ca rezultat schimbul
de octeţi între cele două componente master/slave.
Alte interfeţe seriale folosite în comunicaţia între două dispozitive
(microcontrolere) sunt:
-interfaţa serială I2C (Inter-Integrated Circuit);
-interfaţa serială CAN (Control Area Network).

1.3. Întreruperi

Sistemul de întreruperi al unui SPN este o caracteristică a unităţii centrale de


prelucrare. Sursele de întreruperi provin în marea lor majoritate de la periferice. Având
în vedere importanţa conceptului de întreruperi pentru un SPN, acesta este prezentat
într-un paragraf special.
Algoritmul implementat de un SPN trebuie să ţină cont de apariţia unor
evenimente externe unităţii centrale, care apar la momente de timp necunoscute cu
precizie. O parte dintre acestea apar datorită programării prealabile a unor periferice,
cum ar fi:
-încheierea perioadei de temporizare pentru un temporizator;
-recepţia unui caracter printr-o interfaţă serială;
-disponibilitatea rezultatului unei conversii analog-numerice.
Altele apar în mod total neprevăzut, cum ar fi modificarea nivelului logic aplicat
unui pin ca urmare a acţionării unui buton.
În toate aceste situaţii evenimentul respectiv este evidenţiat prin activarea
(trecerea pe 1 logic) unui bit indicator (flag). Momentul când acest bit trece pe 1 trebuie
cunoscut cu precizie de către unitatea centrală pentru a se face anumite acţiuni
(modificarea stării unui led, citirea caracterului recepţionat printr-o interfaţă serială sau
citirea rezultatului conversiei analog numerice, etc.). De aceea, programul rulat de
unitatea centrală trebuie să conţină o buclă în care se testează continuu starea bitului de
tip flag, aşteptând trecrea sa pe 1. Această metodă de lucru se numeşte tehnica testării
sau polling. Utilizarea acestei tehnici este potrivită în cazul unor aplicaţii simple în care
se aşteaptă doar un singur eveniment exterior. În astfel de cazuri programul va intra în
bucla de aşteptare nemaiputând să mai facă alte acţiuni.
În situaţiile în care sunt aşteptate mai multe evenimente externe şi în plus
programul trebuie să execute acţiuni curente, se pretează utilizarea tehnicii
întreruperilor. În acest caz, programul nu trebuie să testeze fiecare bit de tip flag,
deoarece de câte ori un astfel de bit trece pe 1 logic, execuţia programului curent se va
26 Consideraţii generale - 1
întrerupe, se va face un salt pentru a se executa o acţiune în strânsă legătură cu
evenimentul care a activat flag-ul (subrutină de deservire a înreruperii, interrupt service
routine sau simplu, subrutină de întrerupere), după care execuţia programului curent va
fi continuată din punctul din care a fost întrerupt.
Pentru ca funcţionarea SPN să decurgă conform celor de mai sus, fiecare
periferic are un bit pereche cu bitul flag, numit bit de validare a întreruperii (interrupt
enable). Pentru ca perifericul să poată face aşa numita cerere de întrerupere (interrupt
request) în momentul trecerii pe 1 logic a bitului flag, bitul de validare a întreruperii
trebuie pus pe 1 logic în prealabil. În plus, pentru ca cererea de întrerupere să fie
acceptată de unitatea centrală, un alt bit, numit bit general de validare a întreruperilor
(general interrupt enable-GIE, face parte din registrul SR) trebuie să fie şi el pus pe 1
logic în prealabil. În figura 1.12 este prezentată structura care permite generarea
cererilor de întrerupere într-un dispozitiv (microcontroler) în care sunt mai multe
periferice care pot activa biţi de tip flag, sau, sunt mai multe surse de întrerupere. Prin
IF1, IE1, IF2, IE2,... au fost notaţi biţii de tip flag (Interrupt Flag), respectiv cei de
validare a întreruperilor (Interrupt Enable), pentru perifericele (sursele) 1,2,... În
literatură se foloseşte termenul Interrupt Flag pentru bitul care semnifică apariţia unui
eveniment, chiar dacă utilizarea lui nu implică neapărat generarea de întreruperi.
Odată ce un bit de tip flag a trecut pe 1 logic, iar acest fapt a generat o cerere de
întrerupere (sau a fost detectată trecerea pe 1 logic prin program), flag-ul respectiv
trebuie şters. Altfel, s-ar genera întreruperi repetate, sau, respectiv, nu s-ar putea detecta
trecerea sa pe 1 logic şi data următoare. Modalitatea de ştergere depinde de la caz la caz,
se poate face implicit (de exemplu prin citirea caracterului recepţionat prin interfaţa
serială), sau trebuie scris un 0 logic pe poziţia bitului respectiv (în unele situaţii, un 1
logic scris peste acel bit are ca efect ştergerea sa!)

IF1
IE1

IF2 Cerere de
.. întrerupere
IE2
..
..
..
GIE
Fig. 1.12 Generarea cererilor de întrerupere.

În cadrul unui SPN, sursele de întrerupere au anumite niveluri de prioritate.


Astfel, dacă în timpul deservirii unei cereri de întrerupere (prin execuţia subrutinei de
întrerupere) o altă sursă mai prioritară face o cerere de întrerupere, execuţia subrutinei
corespunzătoare sursei mai puţin prioritară este oprită şi programul continuă cu
deservirea întreruperii mai prioritare, după care se reia execuţia subrutinei întrerupte. De
asemenea, dacă două surse generează cereri de întrerupere în timpul execuţiei unei
1 - Consideraţii generale 27
instrucţiuni, va fi deservită mai întâi cea cu prioritate mai mare iar apoi cea cu prioritate
mai redusă.
Activarea bitului GIE în scopul generării cererii de întrerupere înseamnă de fapt
validarea întreruperilor mascabile, deoarece dacă acest bit este 0, nu se va genera
cererea de întrerupere respectivă, adică întreruperile sunt mascate. În afara întreruperilor
mascabile, microcontrolerele suportă şi întreruperi nemascabile, adică întreruperi care
nu pot fi invalidate prin program, deoarece soluţionarea lor este esenţială pentru
funcţionarea corectă a programului. În această categorie intră:
-întreruperile de sistem, sau Reset, care au ca efect reluarea execuţiei
programului de la început;
-întreruperi provocate de un defect al oscilatorului de tact;
-întreruperi provocate de încercări de scriere în zone interzise ale memoriei;
-înreruperi externe (de la un pin);
-întreruperi datorită împărţirii la 0.
În principiu, funcţionarea unui microntroler la acceptarea unei cereri de
întrerupere se face conform figurii 1.13. Instrucţiunea în curs de execuţie în momentul
primirii cererii de întrerupere se află în PROGRAMUL PRINCIPAL la adresa ADR1. Ea
este executată complet, după care se face automat saltul pentru execuţia SUBRUTINEI
DE ÎNTRERUPERE. După încheierea subrutinei de întrerupere, execuţia programului
continuă de la adresa ADR1+n (n reprezintă numărul de octeţi ai instrucţiunii de la
adresa ADR1). Pentru a fi posibil acest lucru, adresa ADR1+n, care este conţinută în
registrul PC după extragerea instrucţiunii de la adresa ADR1, este automat salvată în
stivă. Apoi, registrul PC este încărcat (tot automat!) cu adresa subrutinei de întrerupere
(numită şi vector de întrerupere, interrupt vector) corespunzătoare sursei i. Efect: începe
execuţia subrutinei de întrerupere. De remarcat că înaintea execuţiei subrutinei de
întrerupere, o parte dintre registrele microcontrolerului, printre care registrul SR, sunt
salvate în stivă. Execuţia subrutinei de întrerupere se încheie cu o instrucţiune de tip
RETI (return from interrupt) care implică refacerea registrelor salvate în stivă, inclusiv
a registrului Program Counter, având ca efect continuarea execuţiei de la adresa
ADR1+n.

MEMORIE PROGRAM

PROGRAM PRINCIPAL SUBRUTINĂ DE ÎNTRERUPERE


ADRESE INSTRUCŢIUNI ADRESE INSTRUCŢIUNI

.........
Întrerup. sursă i
ADR1 Adr. subr. sursă i ........
ADR1+n ......... .........

RETI

Fig. 1.13. Funcţionarea unui microntroler la acceptarea unei cereri de întrerupere.


28 Consideraţii generale - 1
Fiecărei surse de întrerupere trebuie să îi corespundă propria subrutină de
întrerupere. Pentru aceasta, proiectanţii microcontrolerelor implementează o tabelă în
memorie în care alocă un spaţiu de doi octeţi pentru fiecare sursă de întrerupere, unde
utilizatorul trebuie să înscrie adresa subrutinei de întrerupere (vectorul de întrerupere).
Evident, tot utilizatorul trebuie apoi să plaseze subrutinele corespunzătoare fiecărei
surse la adresele pe care le-a completat în tabel. Adresa din tabelă la care sunt situaţi cei
2 octeţi pentru fiecare sursă se numeşte adresa vectorului de întrerupere. În momentul
acceptării cererii de întrerupere, unitatea centrală comandă încărcarea registrului PC cu
vectorul de întrerupere corespunzător sursei care a făcut cererea de întrerupere.
De regulă, adresa FFFEh este dedicată întreuperii de sistem (Reset) care are
prioritatea cea mai mare (tabelul 1.3). În continuare, adresele descrescătoare sunt
dedicate celorlalte surse, în ordinea descrescătoare a priorităţilor: mai întâi celorlalte
întreruperi nemascabile, iar apoi surselor de întrerupere mascabile. În tabelul 1.3 s-a
considerat 3100h vectorul de întrerupere pentru sursa Reset, în presupunerea că 3100h
este adresa de început a programului principal.

Tabelul 1.3 Surse, adrese de vectori de întrerupere şi vectori de întrerupere


Sursa Adresa vectorului Vectorul de întrerupere
de întrerupere
Reset FFFEh 3100h
1 FFFCh
2 FFFAh
3 FFF8h
. . .
. . .
. . .

În figura 1.14 se prezintă conţinutul minimal al unui program care realizează o


configurare pentru două surse de întrerupere. În acest exemplu, ştergerea biţilor de tip
flag se face explicit la intrarea în subrutina de întrerupere. Există însă situaţii când acest
lucru se face implicit la intrarea în subrutina de întrerupere.
Dacă programul este realizat în limbaj de asamblare, vectorii de întrerupere
(adresele subrutinelor de întrerupere) sunt aleşi de utilizator în continuarea programului
principal. Înscrierea acestor vectori la adresele lor, aşa cum sunt specificate de către
producători (tabelul 1.3), respectiv, plasarea (încărcarea) subrutinelor de întrerupere la
adresele alese anterior trebuie făcută “manual” folosind directive ale asamblorului sau
chiar instrucţiuni (2 octeţi, care reprezintă un vector de întrerupere se înscriu la 2 adrese
succesive).
Dacă programul este realizat în limbajul C, acest proces se face mai automatizat.
Astfel, în funcţie de mediul de programare utilizat, numele funcţiei care reprezintă
subrutina de întrerupere trebuie să conţină cuvântul cheie interrupt precum şi un număr
calculat în funcţie de adresa vectorului de întrerupere. O altă variantă implică declararea
1 - Consideraţii generale 29
unei constante a cărei valoare este chiar adresa vectorului de întrerupere (constanta este
definită într-o listă standard - fişier cu extensia .h).

Program Principal ADRESE INSTRUCŢIUNI


Iniţializare
-Înscriere Vector întrerupere
pentru sursa 1, în memorie, la Subrutină întrerupere sursa 1
adresa vectorului de Vector -Ştergere bit IF1
întrerupere al sursei 1 întrerupere
...
-Înscriere Vector întrerupere sursa 1
pentru sursa 2, în memorie, la ...
adresa vectorului de Cerere ...
întrerupere al sursei 2 întrerupere RETI
-Iniţializare stivă (RAM) de la sursa 1
-Programare periferice care
generează întreruperi
(sursa 1, sursa 2)
-Validare întrerup. mascabile

Buclă infinită (funcţii program)


Subrutină întrerupere sursa 2
Vector -Ştergere bit IF2
întrerupere ...
sursa 2 ...
...
RETI
Fig. 1.14 Structura minimală a unui program configurat pentru două surse de întrerupere.

După cum se cunoaşte, stiva este folosită pentru salvarea adresei de revenire din
întrerupere. De aceea, registrul care indică vârful stivei trebuie iniţializat la limita
superioară a memoriei RAM (deoarece în majoritatea cazurilor, la accesarea acesteia
pentru salvare, vârful se modifică descrescător). Această iniţializare este realizată
automat la scrierea programelor în limbajul C, iar în majoritatea cazurilor şi pentru
limbajul de asamblare (proiectul iniţial conţine o instrucţiune corespunzătoare).

S-ar putea să vă placă și