VLSI SI MICROPROCESOARE – CURS 0 PROIECTAREA CU MICROPROCESOARE – CURS 0 Scurt istoric al calculatoarelor – Preistoria Conceptul de calculator cu… [625797]

1

VLSI SI MICROPROCESOARE – CURS 0
PROIECTAREA CU MICROPROCESOARE – CURS 0

Scurt istoric al calculatoarelor – Preistoria
Conceptul de calculator cu program memorat a ap ărut în mintea unui matematician englez pe nume
Charles Babbage, în secolul XIX. In 1834 Babbage a început proiectarea unei ma șini puse în mi șcare
de for ța aburului, pe care a numit-o “Analytical Engine”. Nemul țumit de gre șelile pe care le g ăsise în
tabelele matematice ale vremii , Babbage a vrut s ă construiasc ă o ma șin ă care s ă rezolve ecuații
matematice. Pe hârtie, ma șina sa analitic ă consta în mii de ro ți din țate puse în mi șcare de for ța
aburului, și un centru logic pe care Babbage l-a numit “moara” . Conform proiectului ma șina ar fi avut
mărimea unui stadion de fotbal. Un proiect de asemene a m ărime necesita sume de bani pe m ăsur ă.
Babbage a fost ajutat financiar de Augusta Ada, Con tes ă de Lovelace, fiica poetului Lord Byron.
Frumoasa contes ă era de asemenea o bun ă matematician ă și este considerat ă ast ăzi primul
programator. Contesa voia s ă foloseasc ă cartele perforate pentru a indica ma șinii analitice ce anume s ă
fac ă. Aceast ă idee a fost împrumutat ă de la cartelele folosite la r ăzboaiele de țesut Jacquard, ce
stabileau modelul unei țes ături. “Ma șina analitic ă combin ă modelele (formulele) algebrice a șa cum
războiul de țesut Jacquard combin ă florile și frunzele”, scria aceasta.
In cinstea Adei, contes ă de Lovelace, ast ăzi, un limbaj de programare paralel ă se nume ște
ADA.
Cu toate c ă Babbage a dedicat aproape 40 de ani din via ța sa acestui proiect, ma șina sa analitic ă
nu a fost gata niciodat ă. Pur și simplu tehnologia acelor vremuri era prea înapoia t ă.
Oricum, spre sfâr șitul secolului, cartele perforate au fost folosite experimental pentru a tabela
informa țiile recens ământului din 1890 . Ma șinile electrice de tabelat folosite în acest experi ment au fost
proiectate de un tân ăr inginer, pe nume Herman Hollerith. In curând, car telele perforate au devenit
foarte r ăspândite, fiind folosite pentru o mul țime de activit ăți de birou. Compania lui Hollerith a fost
absorbit ă de o alt ă companie, ce va fi considerat ă mai târziu cel mai mare nume în industria
calculatoarelor, International Tabulating Machines. Aceasta și-a schimbat ulterior mumele în
International Busniness Machines – IBM.
In 1930 IBM a finan țat un proiect ce avea ca scop construirea unei ma șini de calculat puternice.
Compania i-a dat lui Howard Aiken, profesor la univ ersitatea Harvard , 500.000$ pentru construc ția
calculatorului Mark 1. La finalizarea proiectului, în 1944 , Mark 1 putea înmul ți dou ă numere de 23 de
cifre în aproximativ 5 secunde. Mark 1 era o ma șina electromecanic ă, ceea ce însemna mii de relee
zgomotoase, ce se închideau și deschideau pe m ăsur ă ce se efectuau calculele.
Tuburile cu vid (l ămpile) au înlocuit destul de repede releele electro mecanice, dând na ștere lui
ENIAC, primului calculator numeric electronic const ruit în SUA. A fost prezentat în 1946 la
Universitatea din Pennsylvania. Construit pentru a calcula tabelele de tragere ale artileriei, ENIAC
(Electronic Numerical Intergrator and Calculator) cânt ărea 30 de tone, con ținea 18.000 de tuburi,
70.000 de rezisten țe, 10.000 de condensatoare și ocupa cam 100 mp. Costul proiectului ENIAC a fost
de aproximativ jum ătate de milion de dolari și putea executa 5.000 de adun ări și sc ăderi pe secund ă.
Ast ăzi, un calculator de buzunar programabil dep ăș ește performan țele lui ENIAC. De asemenea,
ma șina nu era prea fiabil ă. L ămpile se stricau, în medie, una la 7 minute.

2
Tranzistorul
Marea “str ăpungere” în tehnologia de calcul a fost f ăcut ă cu dou ă zile înaintea cr ăciunului în
1947 , când trei oameni de știin ță ce lucrau la Bell Labs au testat un dispozitiv din cristal cunoscut sub
numele de tranzistor, prescurtarea pentru “transfer ul rezisten ței”. (Ace știa au câ știgat premiul Nobel
pentru aceast ă inven ție.) Aceste mici cristale, sau semiconductoare a șa cum au devenit cunoscute,
ac ționau ca și comutatoare, controlând scurgerea curentului în c ircuite. Semiconductoarele au înlocuit
tuburile cu vid. Ele erau mult mai mici și mai fiabile. Nu degajau atâta c ăldur ă ca tuburile, deci puteau
sta mult mai aproape unele de altele. Nu aveau p ărți în mi șcare, deci erau mult mai fiabile. Si, poate
lucru cel mai important, semiconductoarele erau ief tin de fabricat.
Wiliam Shockley, unul din inventatorii tranzistorul ui, a p ărăsit Bell Labs pentru a se întoarce la
Palo Alto în Santa Clara Valley, California pentru a forma propria sa companie, în inima a ceea ce va
fi cunoscut sub numele de Valea Siliciului (Silicon Valley).

Silicon Valley – Circuitul integrat
Denumirea de Silicon Valley a ap ărut de abia în 1971 și a f ăcut repede înconjurul lumii, întrucât avea
o semnifica ție real ă, siliciul fiind materia prim ă esen țial ă pentru semiconductori. In bun ă m ăsur ă,
istoria modern ă a electronicii se confund ă cu dezvoltarea acestui complex de cercetare și produc ție.
Adev ăratele puncte nodale în evolu ția microelectronicii și informaticii sunt reprezentate de
descoperirile f ăcute aici.
Jum ătate în glum ă se spune c ă cea mai mare “firm ă” din Silicon Valley este Universitatea din
Stanford, situat ă chiar la intrarea în Vale, lâng ă Palo Alto. Ca orice vorb ă de spirit, aprecierea exprim ă
un mare adev ăr. Începuturile și evolu ția atât de spectaculoas ă a ținutului sunt intim legate de aceast ă
unitate de înv ăță mânt și cercetare, care a acordat asisten ța știin țific ă, a furnizat idei și proiecte, a
confirmat stadiul promi ță tor al unor investiga ții.
Istoria Silicon Valley-ului este o întâlnire ferici t ă de factori favorizan ți și șanse abil valorificate
de un om plin de ini țiativ ă – Fred Terman. Era cadru universitar la celebrul M assachusetts Institute of
Technology, unde avea în fa ța o carier ă str ălucit ă. S-a îmboln ăvit îns ă de pl ămâni și a fost nevoit s ă se
întoarc ă pe ță rmul însorit al Californiei. Aproape tot anul 1925 l-a petrecut în pat, punându- și pe piept
pungi cu nisip. Dup ă ce s-a îns ănăto șit nu a mai plecat, r ămânând s ă lucreze la Universitatea din
Stanford, unde tat ăl s ău fusese un foarte apreciat profesor de psihologie.
Principala preocupare a conducerii acestei unit ăți de înv ăță mânt era modul în care s-ar putea
transforma în bani p ământul pe care îl primise în dotare: circa 4000 ha. De vândut nu putea fi vorba
pentru c ă actul de dona ție (întocmit de familia Stanford în amintirea fiulu i cere se stinsese din via ță cu
pu țin timp înainte de a intra la facultate) interzicea posibilitatea înstr ăin ării. Terman, care ajunsese
între timp prorector al Universit ății, a avut ideea transform ării acestui p ământ într-un parc industrial de
tehnologie înalt ă, creat în 1951. Arendarea p ământului a avut deci drept scop câ știgarea unor bani
pentru Universitate. Abia mai târziu el a facilitat transferul tehnologiei din laboratoarele de cercet are
către firmele instalate aici, devenind arma secret ă a Stanfordului. Prima firm ă, instalat ă în acela și an
închiriat pogonul de p ământ cu 4000$ pe un interval de 99 de ani. Cum nici o clauz ă a contractului nu
se refer ă la efectele infla ției, ast ăzi acest p ământ este, de departe cel mai ieftin din toat ă zona.
Wiliam Hewlett și David Packard au fost doi studen ți str ăluci ți ai lui Terman, pe care acesta i-a
îndrumat într-o serie de cercet ări în domeniul electronicii. Mai târziu au fondat o firm ă – Hewlett &
Packard -, care la început mergea destul de anevoio s. In 1954 au închiriat o suprafa ță destul de mare în
parcul universit ății, folosind prilejul pentru a continua cercet ările cu cadrele de aici. A fost primul
nucleu de cercetare și produc ție constituit în zon ă. De altfel, din acel moment, firma a început s ă

3evolueze rapid, ajungând în 1996 la un volum de vân z ări de 472,5 miliarde dolari și un profit de 38,4
miliarde dolari. Când conduc ătorii de firme veneau s ă se intereseze despre condi țiile închirierii și
avantajele instal ării în acest perimetru, Terman îi ruga “s ă vorbeasc ă despre avantajele apropierii de
universitate cu Packard și Hewlett”. In 1955 șapte companii erau instalate în parc, în 1962- 32, în
1970- 70. Ast ăzi circa 90 de firme, ce utilizeaz ă 25.000 de muncitori, ocup ă fiecare palm ă de p ământ
din cele alocate în acest scop.
Ca urmare a încas ărilor de pe urma arend ării p ământului, dar și folosind cu pricepere sprijinul
financiar al firmelor în dezvoltarea propriilor lab oratoare, Universitatea din Stanford s-a dezvoltat
rapid, a putut s ă angajeze profesori dintre cei mai renumi ți, devenind ast ăzi nu numai una dintre cele
mai mari universit ăți din SUA, ci și un adev ărat centru de ini țiativ ă pentru promovarea unor proiecte și
tehnologii de vârf.
In orice proiect de mai mare amploare este implicat ă o idee organizatoric ă, dar mai trebuie s ă
existe și un “geniu tehnic”. Dac ă pentru Silicon Valley Terman a fost “organizatorul ”, Shockley a fost
cel care a cel care a adus “scânteia tehnologic ă”, declan șând o cascad ă de descoperiri care marcheaz ă
în fond principalele momente ale evolu ției microelectronicii. De aceea, cu temei, el este considerat
cofondator al Silicon Valley-ului.
In 1956 Schockley a strâns în jurul s ău opt tineri foarte dota ți cu care a venit în Silicon Valley
pentru a întemeia aici o adev ărat ă industrie a semiconductorilor. Doi dintre ace știa, Robert Noyce și
Gordon Moore, (împreun ă cu al ții) înfiin țeaz ă în 1957 o divizie a firmei Fairchild, și anume Fairchild
semiconductor. Cu Shockley se lucra îns ă destul de greu, el neavând receptivitate la ideile noi ale
acestor tineri str ăluci ți. A șa se face c ă tinerii se despart de cel ce îi adusese, preluând ei de fapt sarcina
întemeierii adev ăratei industrii a semiconductorilor în Silicon Vall ey. Contribu ția lui Shockley nu este
atât direct ă, dar el a adus s ămân ța crea ției și a ini țiativei ce va duce la ascensiunea rapid ă a zonei.
Unul din punctele nodale ale acestei ascensiuni o c onstituie descoperirea de c ătre Noyce în
1959 a circuitului integrat. “Am avut ideea, m ărturise ște autorul, a combin ării mai multor tranzistoare,
rezisten țe, diode pe aceea și pastil ă de siliciu”. Ceva similar a gândit și Jack Kilby de la Texas
Instruments, doar c ă el a ales germaniu ca element pe care s ă fie integrate circuitele electrice. Ambii au
fost recunoscu ți drept co-inventatori ai circuitului integrat, car e a atras noi firme pentru a exploata
posibilit ățile de valorificare industrial ă a recentei descoperiri.
Mul ți asociaz ă începutul propriu zis al existen ței industriale a zonei cu noua inven ție. Cipul de
siliciu, minuscul, înlocuia tranzistorii eterogeni oferind c ăile unei produc ții electronice eficiente.
Înaintea acestui moment, în Silicon Valley erau pu ține companii produc ătoare de computere. Pân ă la
aceast ă dat ă computerul implica existen ța unor circuite grele ce ocupau o camer ă întreagă, sau mai
bine spus o sal ă întreag ă. De aceea, aceste calculatoare erau pu ține și plasate în ora șe mari, precum
Boston, Philadelphia, Los Angeles. Acum se între țes cerin țele industriei semiconductorilor cu cele ale
computerelor. Circuitul integrat este solicitat tot mai mult pentru calculatoarele mai mici, destinate
tehnologiei spa țiale și militare. El asigur ă noi perspective dezvolt ării masive a industriei computerelor,
iar aceasta, la rândul ei, atrage dup ă sine o sporire a produc ției de semiconductori.

Intel Corporation – Microprocesorul
In 1968, nemul țumi ți de modul cum mergeau lucrurile la Fairchild Semic onductor, Robert Noyce si
Gordon Moore s-au gândit s ă înfiin țeze propria companie. Primul nume la care s-au gând it cei doi a
fost Moore Noyce, dup ă numele fondatorilor. Dar prietenii i-au avertizat c ă numele seam ănă prea mult
cu “more noise” (mai mult zgomot)- foarte nepotrivi t pentru o firm ă în domeniul electronicii. A șa c ă

4numele ales a fost Intel, prescurtarea de la "inte grated electronics". S-a dovedit ulterior c ă numele a
fost luat de la un lan ț de moteluri, nume pentru care Moore și Noyce au cump ărat drepturile.
In primul an Intel a ob ținut profituri de 2.672$. Un an mai târziu compania s-a axat pe
produc ția de memorii, primul s ău produs comercial fiind o memorie RAM statica de 6 4 de bi ți, astfel
încât veniturile au crescut sim țitor.
In 1969, Moore și Noyce au primit vizita, apoi istoric ă, a firmei japoneze Busicom, ce era pe
cale s ă dezvolte un calculator de birou. Busicom dorea ca Intel s ă proiecteze 12 cipuri specializate
pentru aceasta. Compania nu avea nici banii, nici f or ța de munc ă necesar ă pentru acest proiect. Totu și,
încrez ători c ă se vor gândi la ceva, Intel accept ă contractul. Inginerul Ted Hoff a avut o idee str ălucit ă:
în loc s ă se proiecteze 12 cipuri, s ă se proiecteze un singur cip prev ăzut cu utilit ăți generale de calcul
ce poate func ționa în 12 moduri diferite. Noyce și Moore au îmbr ățișat solu ția lui Hoff. Acela și lucru l-
a f ăcut și Busucom și au decis s ă finan țeze proiectarea cipului. Intel a proiectat un integ rat logic de uz
general programat prin intermediul unor instruc țiuni. Aceasta însemna c ă inteligen ța poate înglobat ă în
cip prin intermediul software-ului, în loc s ă fie “cablat ă” în hardware. Astfel se salveaz ă atât timp cât
și bani. Acest cip a devenit mai târziu 4004.
Echipa de proiectan ți a lui 4004 i-a inclus pe Ted Hoff , Stan Mazor și Frederico Faggin ,
considera ți ast ăzi inventatorii microprocesorului. Multe din concep tele introduse le-au împrumutat de
la calculatoarele mari ale acelor zile. Dar resurse le lor erau limitate: pentru a aduce un computer la
dimensiunile unui cip trebuiau reduse dimensiunile c ăilor de date interne și externe de la 16 la 4 bi ți.
Acest design minimiza num ărul de tranzistori ce erau necesari pentru unit ățile de stocare și execu ție și
făceau posibil ă înglobarea pastilei într-o capsul ă cu 16 pini, cea mai mare împachetare disponibil ă
atunci. Prin contrast, procesoarele Pentium necesit ă o capsul ă cu 296 de pini și un bus extern de 64 de
bi ți. Reducerea unui CPU la dimensiunile unui cip a în semnat și c ă dispozitivele ieftine pot deveni
programabile, lucru ce a redus sim țitor eforturile de design al produselor și noilor func ționalit ăți. F ără
a fi necesar ă o compatibilitate înapoi cu calculatoarele precede nte, cei de la Intel au creat un set de 45
de instruc țiuni, multe dintre ele familiare și programatorilor de azi. Spre deosebire de codific area
instruc țiunilor în acea vreme (OPCODE-ul pe 16 bi ți la minicalculatoare) echipa a f ăcut codificare pe
8 bi ți. Aceast ă codare compact ă asigura utilizarea cu maxim ă eficien ța a ROM-ului de 256 de octe ți
disponibil pentru memorarea programelor; întregul c od al calculatoarelor Busicom trebuia s ă încap ă în
4 astfel de ROM-uri, deci 1Kb. Proiectare lui 4004 a fost terminat ă în 1971 .
De Indat ă Intel și-a dat seama c ă a realizat o mare descoperire. Dar Busicom de ținea drepturile
pentru aceast ă inven ție. In aceast ă situa ție Intel a cump ărat drepturile pentru 4004 de la Busicom
pentru suma de 60.000$. In scurt timp Busicom a dat faliment.
In prezent microprocesorul este considerat printre primele 10 inven ții din domeniul tehnologiei
americane, al ături de becul electric, telefon și avion.
In ideea logicii programabile, Intel s-a angajat la un nou contract, de data aceasta pentru firma
Datapoint. De aceasta data trebuia proiectat un con troler video. Astfel a ap ărut 8008, considerat o
versiune pe 8 bi ți a lui 4004. Din p ăcate controlerul cu 8008 era prea lent. Intel a diz olvat echipa de
proiectare și a încercat s ă vând ă noul microprocesor ca o anex ă pentru memoriile sale SRAM de
1kilobit, în ideea logicii programabile. Spre surpr inderea firmei, vânz ările au crescut spectaculos. Intel
a ref ăcut echipa și astfel, în 1974 , a ap ărut 8080. In jurul microprocesorului 8080 a fost co nstruit
primul calculator personal!

Prima încercare de calculator personal – ALTAIR și Bill Gates.

5In anii 50 calculatoarele erau mari și foarte scumpe. Un astfel de calculator, (mainfram e) ocupa
câteva camere și costa sute de mii de dolari. Avea nevoie de o arm at ă de tehnicieni și de ingineri
pentru între ținere și operare. Avea nevoie de temperatur ă constant ă, ceea ce implica o foarte
costisitoare instala ție de climatizare. Accesul la o astfel de ma șina se f ăcea, de obicei, prin
intermediari. Oamenii de știin ță și inginerii doreau un calculator la care s ă poat ă lucra ei în șiși, care s ă
fie mai mic, mai ieftin și mai u șor de între ținut. Apari ția circuitului integrat a f ăcut posibil ă apari ția
unui astfel de calculator – minicalculatorul. Atunc i când IBM-ul s-a decis s ă nu intre pe aceast ă nou ă
piață a l ăsat un întreg segment de pia ță la dispozi ția altor companii, ca de exemplu Digital Equipment
Corporation, care a devenit în scurt timp leader. D EC a înfiin țat pia ța de minicalculatoare în 1965,
odat ă cu introducerea lui PDP-8 (prescurtare de la Progr am Data Processor). Costa 18.500 de dolari, în
pre ț fiind inclus și un terminal teletype (tastatur ă + imprimant ă). Digital a numit aceast ă ma șin ă “small
computer”. Presa, în c ăutarea unui nume mai atractiv, a denumit ma șina minicomputer.
Minicomputerul era o ma șin ă puternic interactiv ă. In loc de cartele perforate, utilizatorul comunic a cu
calculatorul via tastatur ă – o idee nou ă la acea vreme.
Dup ă apari ția microprocesorului, în 1971, a devenit evident ur m ătorul pas: construirea unui
întreg calculator având ca unitate central ă microprocesorul. Dar acest pas nu a fost f ăcut de companii
ca IBM sau DEC, ci de pasiona ții de electronic ă și calculatoare, ce visau s ă aib ă un calculator al lor.
Unul dintre ace știa se numea Ed Roberts. Acesta avea o energie enor m ă și un apetit insa țiabil
pentru mâncare și informa ție. Atunci când era interesat de un subiect Roberts citea tot ceea ce g ăsea în
bibliotec ă despre acel subiect. De asemenea lui Roberts îi pl ăcea s ă se joace cu tot felul de piese și
subansambluri electronice. A intrat în Air Force ca s ă înve țe mai multe despre electronic ă, iar apoi a
înfiin țat o companie numit ă Model Instrumentations and Telemetry Systems. Mai târziu cuvântul
Model va fi înlocuit cu Micro. La început sediul fi rmei era în garajul s ău, de unde Roberts vindea
echipament electronic pentru racheto-modele și emi ță toare radio pentru aeromodele, prin po ștă. In
1969 Roberts se mut ă din garaj într-un fost restaurant și investe ște tot capitalul firmei în pia ța de
calculatoare de birou. MITS a fost prima companie î n Statele Unite care a construit kituri de
calculatoare de birou. Afacerea era bun ă, MITS crescând pân ă la 100 de angaja ți. Dar, la începutul lui
1970 Texas Instruments a intrat și ea pe pia ța calculatoarelor de birou, la fel ca și alte companii. A
urmat r ăzboiul pre țurilor și MITS nu a mai putut s ă concureze.
In 1974, MITS avea mai mult de un sfert de milion de dolari datorii. In încercarea disperat ă de
a-și salva compania de la faliment Roberts s-a decis p rofite de apari ția microprocesoarelor, și s ă
construiasc ă kituri de calculatoare pentru pasiona ți. Roberts știa c ă 8008 este prea lent, a șa c ă s-a bazat
pe noul cip, 8080. Noul cip putea cu certitudine su porta un mic calculator. Sau cel pu țin a șa credea
Roberts. El s-a decis s ă vând ă kitul cu 397$. Numai 8080 costa 350$, dar Roberts a reu șit s ă ob țin ă de
la Intel un pre ț de 75$, datorit ă cantit ății mari de cipuri estimat ă a fi vândut ă.
Cu toate c ă ma șina avea un pre ț, nu avea un nume. Lui Roberts nu prea îi p ăsa de nume. Cu
numele încă în aer, Roberts și mica sa echip ă de ingineri au început construc ția prototipului. In curând
a fost contactat de Les Solomon, editor tehnic la r evista Popular electronics (un fel de Tehnium), care
căuta un fapt mai deosebit pentru coperta revistei. S olomon îl cuno ștea pe Roberts și auzise despre
planul acestuia de a construi un kit de home comput er. Acesta a zburat la Albuquerque, unde î și avea
sediul MITS, pentru a vorbi cu Roberts. Ar putea fi gata prototipul pân ă la sfâr șitul anului? Roberts l-a
asigurat pe Solomon c ă da.
Dup ă ce s-a întors la New York, Solomon a încercat timp de zile întregi s ă g ăseasc ă un nume
pentru calculator. Intr-o noapte, a întrebat-o și pe feti ța sa de 12 ani, care se uita la televizor la “Star
Trek”. De ce nu îi spui “Altair” a spus aceasta. Er a steaua spre care se îndrepta nava Entreprise . Lui
Roberts, un fan al romanelor SF i-a pl ăcut numele. De și fiica lui Solomon a botezat calculatorul,

6Roberts a fost acela care a folosit primul termenul de “calculator personal” în campania publicitar ă
pentru Altair. “Am încercat s ă construiesc o ma șin ă mic ă pe care s ă ți-o po ți permite s ă o cumperi și
care s ă nu par ă o juc ărie”, spunea acesta.
Înainte ca Popular electronics să poat ă publica articolele despre Altair, Solomon avea nev oie
să vad ă prototipul pentru a se convinge c ă acesta func ționa conform specifica țiilor. Roberts a trimis
singurul prototip care func ționa la New York, într-un colet po ștal, cu trenul. Coletul nu a ajuns
niciodat ă. Primul calculator personal din lume pierdut în tr anzit! Solomon era cuprins de panic ă. Era
prea târziu s ă schimbe coperta pentru luna ianuarie și nici nu mai era suficient timp pentru construirea
altui calculator. Inginerii de la MITS au montat în grab ă LED-uri și comutatoare pe o carcas ă de metal
goal ă și au trimis-o la New York Este ceea ce a ap ărut pe coperta revistei!
Articolul despre Altair descria arhitectura calcul atorului: acesta avea numai 256 de octe ți de
memorie, dar era prev ăzut cu 18 sloturi pentru memorie adi țional ă, și astfel se putea ajunge la
4Kbytes. Nu exista monitor sau tastatur ă. Deoarece nimeni nu dezvoltase un limbaj de nivel înalt
pentru microprocesorul 8080, Altair putea fi progra mat numai în cod ma șin ă a lui 8080. Acest lucru se
făcea prin intermediul comutatoarelor bipozi ționale, fiecare comutator introducând un bit. Altai r
răspundea prin intermediul LED-urilor de pe panou.
Când a ap ărut Altair existau o duzin ă de limbaje de nivel înalt disponibile pentru mainf rame-uri
sau minicalculatoare. Aceste limbaje fuseser ă proiectate pentru diferite feluri de aplica ții. Primul
limbaj larg acceptat a fost FORTRAN, sau formula tr anslation. Dezvoltat de o echip ă de la IBM în
1956 FORTRAN era larg folosit în mediile știin țifice dar presupunea o programare greoaie. Alt limb aj
era COBOL (common business-orieted language). Era f olosit mai ales pentru baze de date pe
mainframe-uri. Era, ca și FORTRAN-ul, dificil de folosit. Dar BASIC-ul era u șor de înv ățat.
Roberts a decis în vara lui 1974 c ă BASIC va fi limbajul lui Altair. Dar Intel nu s-a a șteptat
niciodat ă ca microprocesorul s ău, 8080, s ă fie folosit pentru un microcalculator; unii ingine ri i-au spus
lui Roberts c ă nu cred c ă este posibil ă scriere unui interpretor de BASIC pentru 8080.
Cu toate acestea interpretorul a fost scris de doi tineri, Bill Gates și Paul Allen, ace știa doi
înfiin țând o companie, devenit ă ulterior cea mai mare firm ă produc ătoare de software: Microsoft.

Primul calculator personal – Apple
Altair nu era de fapt un calculator personal; era u n kit și costa cam scump. Steven Jobs și
Stephan Wozniak erau prieteni și doreau sa-și cumpere un asemenea aparat, dar nu aveau bani. Se
cunoscuser ă înc ă din școala primar ă. Apoi, via ța i-a desp ărțit. Amândoi au vrut s ă urmeze cursurile
unor universit ăți, dar, din diferite motive, dup ă un an, doi, au renun țat, fiecare revenind în Silicon
Valley, primul angajându-se la firma Atari , cel ălalt la Hewlett-Packard. Dintre cei doi, Wozniak av ea
scânteia inven ției. D ăduse dovad ă deja dovad ă de precocitate în acest domeniu. Prezentase ni ște
proiecte la diferite târguri destinate crea ției juvenile și de fiecare dat ă avusese succes. Jobs era
“organizatorul”. In via ța celor doi garajul lui Jobs avea s ă joace un rol foarte important.
In lipsa mijloacelor financiare necesare achizi țion ării unui Altair, Wozniac și-a propus s ă
construiasc ă el un aparat propriu, mai ieftin. A “eliberat” cev a material electronic de la firma unde
lucra construind un nou microcalculator, cu care s- a prezentat la o expozi ție. Dar ca s ă prezin ți în
cadrul unei expozi ții un asemenea produs trebuia s ă oferi garan ții ca po ți fabrica cel pu țin 50. Jobs și-a
vândut Wolkswagenul, Woz – prietenul s ău – un vechi calculator și a șa au f ăcut rost de ceva bani.
Construirea calculatoarelor a avut loc în garajul l ui Jobs, care acum, era plin cu semiconductori, cip –
uri, material plastic, etc. Acolo au fost fabricate cele 50 de microcalculatoare care erau mai ieftine –
250 de dolari – și aveau avantajul c ă sunt compacte.

7 Primele 50 de calculatoare au fost duse la un maga zin și s-au vândut cu repeziciune. Jobs și
Wozniak au restitui un credit pe care îl luaser ă între timp și au putut, de asemenea, recupera banii pe
Wolkswogen și pe calculator. Dar, mai ales, și-au dat seama c ă pia ța absoarbe, c ă garajul în care
asamblaser ă totul devenise neînc ăpător. Nu inten ționau s ă se lanseze în afaceri, dar voiau s ă pun ă la
dispozi ția oamenilor noua descoperire.
Când Jobs și Wozniak și-au dat seama c ă noul lor computer – Apple – era un produs viabil, pe
care lumea dorea s ă-l cumpere, au mers la șefii lorde la firmele Atari și Hewlett-Packard. Jobs a
încercat s ă-l conving ă pe Nolan Bushnell, fondator al lui Atari și creator al primului joc video, c ă noul
tip de microcomputer va avea un viitor str ălucit. Dar computerele nu figurau pe liniile de pro duc ție ale
firmei și Bushnell chiar l-a ironizat pe Jobs. In 1983, Bus hnell î și aminte ște discu ția avut ă cu Jobs:
“Am o idee de un produs despre care știu c ă ar putea s ă aib ă o pia ță cam de 10 milioane $, mi-a spus
Jobs. Ha, ha, ha! O pia ță de 10 milioane. Ce noi suntem o companie pentru 10 milioane? Nu știam,
continu ă fondatorul lui Atari, c ă în 1982 vânz ările de calculatoare personale vor atinge cifra inc redibil ă
de 5,4 miliarde dolari”.
Răspunsul primit de Wozniak de la mai marii lui Hewle tt-Packard a fost și mai întrist ător. Aici
nici m ăcar nu s-au interesat de calit ățile și viitorul microcomputerului, ci de actele și calificarea lui
Wozniak: “Nu are o facultate, nu are nici un fel de calificare certificat ă printr-o diplom ă în domeniul
proiect ării de calculatoare” a fost r ăspunsul care motiva refuzul (birocra ția este o boal ă mai r ăspândit ă
decât pare la prima vedere!).
Cum nimeni nu era dispus s ă fabrice noul tip de computer, Jobs și Wozniak au fost nevoi ți s ă
întemeieze o firm ă pentru a produce ei în șiși calculatorul personal. Dar pentru aceasta le treb uiau bani
și un plan de afaceri ca lumea. Șansa l-a scos în fa ță pe Armas Markkula, fost șef cu prospectarea
pie ței la Intel Corporation. Acesta formeaz ă în 1976 împreun ă cu cei doi firma Apple, el contribuind
cu aproape 100.000 de dolari, la care se adaug ă un credit de 250.000 luat de la Banca Americii.
Apple Computer, a lansat calculatorul Apple I (cu un pre ț de 695$ ). Acest sistem era format
dintr-o placa de circuit principal, fixat ă în șuruburi pe o bucata de placaj. Nu con ținea carcasa și sursa
de alimentare. Nu au fost produse decât câteva cal culatoare de acest tip și, din câte se aude, ele au fost
vândute ulterior colec ționarilor la pre țuri ce dep ăș eau 20.000$. Calculatorul Apple II, ap ărut în anul
1977, a ajutat s ă fie stabilit standardul pentru aproape toate calcu latoarele mai importante ce i-au
urmat, inclusiv pentru IBM PC.
In anul 1980 lumea microcalculatoarelor era domin ă de dou ă tipuri de sisteme de calcul. Unul
dintre acestea, Apple II, avea o mul țime de utilizatori loiali și o baz ă software gigantic ă, care se
extindea cu o vitez ă fantastic ă. Cel ălalt tip, sistemele CP/M, nu includea un singur sis tem, ci toate
celelalte sisteme care se dezvoltaser ă din ini țialul MITS Altair. Aceste sisteme erau compatibile între
ele și aveau drept însu șire comun ă folosirea sistemului de operare CP/M. Toate aceste sisteme erau
produse de o mul țime de companii și vândute sub nume diferite. Pentru majoritatea di ntre ele, aceste
companii foloseau acela și software și acelea și pl ăci de extensie. De remarcat faptul c ă nici unul dintre
aceste sisteme nu era compatibil PC sau MAC (Apple) , cele dou ă standarde care domin ă pia ța în
prezent.

Calculatorul personal IBM
La sfâr șitul anului 1980, IBM a hot ărât s ă intre pe pia ța calculatoarelor personale care practica
pre țuri mici, pia ță care se extindea rapid. Compania a hot ărât ca sistemul s ă fie proiectat de
departamentul Entry Systems, din Boca Raton, Florid a. Acest mic grup era format din doisprezece
ingineri și proiectan ți afla ți sub conducerea lui Don Estridge. Proiectantul șef al echipei era Lewis

8Eggebrecht. Acest departament a proiectat primul P C adev ărat al companiei IBM. (IBM consider ă c ă
sistemul 5100, ap ărut in 1975, era mai degrab ă un terminal programabil inteligent, decât un calcu lator
veritabil. Aproape to ți ace ști ingineri lucraser ă la proiectul System 2/3 DataMaster, predecesorul d irect
al calculatorului IBM PC. Proiectul calculatorului personal a fost influen țat în mare m ăsura de
proiectul DataMaster. In proiectul sistemului DataM aster, monitorul și tastatura erau integrate in
ansamblu. Din cauz ă c ă aceste caracteristici impuneau unele restric ții, ele au devenit unit ăți externe –
cu toate c ă dispunerea tastelor și proiectul circuitului electric erau copiate de la DataMaster.
Si alte p ărți ale sistemului IBM PC erau copiate de la DataMast er, cum ar fi magistrala de
extensie ( și sloturile de intrare /ie șire), care con ținea nu numai acela și conector cu 62 de pini, dar
respecta și aceea și asignare a semnalelor la pini. Aceast ă copiere a fost posibil ă deoarece calculatorul
personal folosea acela și controller de întreruperi și circuit DMA ca si sistemul DataMaster. Pl ăcile de
extensie proiectate deja pentru DataMaster au putut fi u șor reproiectate pentru a putea fi utilizate și la
PC.
DataMaster folosea un microprocesor 8085 (succesor al lui 8080), cu capacitatea de adresare de
maxim 64K și o magistral ă intern ă și extern ă de 8 bi ți. Acest lucru a determinat echipa de proiectare a
calculatorului personal s ă foloseasc ă microprocesorul Intel 8088 (un 8086 cu magistral ă extern ă de 8
bi ți). Magistrala extern ă. de 8 bi ți și compatibilitatea la nivel de limbaj de asamblare a permis ca 8088
să fie u șor de conectat în sistemele DataMaster anterioare. In plus 8086/88 era în acel moment singurul
procesor pe 16 bi ți func țional.
Don Estridge și echipa lui au finalizat repede proiectul noului s istem și specifica țiile sale
tehnice. Pe lâng ă faptul c ă a împrumutat diverse elemente de la calculatorul S ystem 2/3 DataMaster,
echipa a studiat și pia ța calculatoarelor, ceea ce a influen țat enorm proiectul IBM PC. Proiectan ții au
căutat s ă respecte standardele care dominau pia ța, au înv ățat din p ărțile bune ale acestor sisteme și au
incorporat în noul PC toate caracteristicile sistem elor care avuseser ă succes, ad ăugând și ceva in plus
pe lâng ă acestea. Deoarece studiase pia ța cu aten ție, IBM a realizat un sistem care s-a încadrat perf ect
in locul ce r ămăsese neocupat.
IBM a trecut la fabricarea calculatorului cu inten ția de a-l lansa pe pia ță într-un an, folosind
proiectele existente și utilizând cât se poate de multe componente de la furnizorii externi.
Departamentului Entry System i-a fost acordat ă autonomia și acesta a preferat s ă-și culeag ă resursele
din afara companiei, decât s ă respecte toate procedurile birocratice care cereau s ă se foloseasc ă numai
resursele interne IBM. De exemplu, compania a cont ractat limbajele pentru calculatorul personal si
sistemul de operare de la o mica firma numit ă Microsoft. Ini țial IBM a discutat cu compania Digital
Research, care proiectase sistemul CP/M, dar se par e c ă aceasta n-a fost interesat ă de propunere.
Microsoft a acceptat ideea și, în felul acesta, a devenit una dintre cele mai m ari companii produc ătoare
de software din lume. Utilizarea furnizorilor exter ni a fost, de asemenea, o invita ție adresat ă pie ței
specifice de a participa la sus ținerea noului calculator – și aceasta a acceptat.
Odat ă cu lansarea calculatorului IBM PC, pe 12 august 19 81, într-o miercuri, în industria
microcalculatoarelor și-a f ăcut apari ția un nou standard. De atunci, au fost vândute sut e de milioane de
calculatoare compatibile PC, iar PC a devenit o fam ilie imens ă de calculatoare și periferice. Pentru
aceast ă familie a fost scris mai mult software decât pentr u orice alt sistem aflat pe pia ță .

Pia ța calculatoarelor compatibile IBM, dup ă 15 ani
In cei peste cincisprezece ani care au trecut de l a lansarea primului IBM PC au intervenit multe
schimb ări. De exemplu, calculatorul compatibil IBM a progr esat de la sistemul bazat pe
microprocesorul 8088, de 4,77 MHz, la sistemele baz ate pe microprocesorul Pentium, de 3 GHz, care
sunt de aproape 10.000 de ori mai rapide decât ini țialul IBM PC ( ținând cont de viteza efectiva de

9lucru, nu doar de frecventa ceasului). Calculatoru l personal original avea numai dou ă unit ăți de
dischet ă dubl ă fa ță , fiecare putând s ă memoreze câte 160K utilizând sistemul de operare D OS 1.0, in
timp ce sistemele moderne de ast ăzi ofer ă cu u șurin ță un spa țiu de stocare de sute de gigaocteti pe
hard-disc. In industria calculatoarelor s-a încet ățenit regula c ă performan țele procesoarelor și
capacitatea de memorare pe disc se dubleaz ă la fiecare doi-trei ani. De la debutul industriei
produc ătoare de calculatoare personale, aceast ă regul ă nu a dat semne de schimbare.
Pe lâng ă performante și capacitatea de stocare, o alt ă schimbare major ă ap ărut ă de atunci este
aceea c ă IBM nu a r ămas unicul produc ător de sisteme compatibile PC. Desigur, IBM a inve ntat
standardul compatibil – PC și continu ă s ă stabileasc ă standarde pe care sistemele compatibile le
respect ă, dar nu mai domin ă pia ța ca înainte. In industria produc ătoare apar standarde stabilite și de
alte companii și organiza ții. Sute de produc ători de calculatoare realizeaz ă sisteme compatibile IBM,
ca s ă nu mai pomenim despre miile de produc ători de echipamente periferice, ale c ăror componente
extind și îmbun ătățesc sistemele “compatibile PC”.
Sistemele compatibile PC au cunoscut o dezvoltare înfloritoare nu numai datorit ă faptului c ă
hardware-ul putea fi u șor asamblat, ci și pentru c ă sistemul de operare nu era livrat de IBM, ci de o
companie ter ță , Microsoft. Nucleul sistemului de operare este co mponenta BIOS (Basic Input Output
System) și, la rândul s ău, poate fi ob ținut de la firme ter țe, cum sunt Phoenix, AMI și al ții. Aceasta a
permis și altor produc ători s ă ob țin ă sistemul de opere de la Microsoft și s ă-și vând ă propriile lor
sisteme compatibile. Faptul c ă DOS a împrumutat cele mai bune caracteristici atât de la CP/M, cât și
de la UNIX are, probabil, o strâns ă leg ătura cu volumul de software care a devenit disponib il. Mai
târziu, în urma succesului pe care l-au inregistrat sistemele Windows si OS/2, au ap ărut și mai multe
motive pentru ca produc ătorii de software s ă scrie programe pentru sistemele compatibile PC.

1

Microprocesoare, microcontrolere – Prelegere 1

1. Modelul calculatorului cu dou ă blocuri
În cele ce urmeaz ă vom folosi ca punct de plecare implementarea MIPS cu un singur ciclu de
ceas prezentat ă în „Hennessy și Patterson – Organizarea și proiectarea calculatoarelor – interfa ța
hardware/software”. În implementarea cu un singur c iclu se folosesc dou ă blocuri de memorie, unul
pentru cod și unul pentru date. În figura urm ătoare dreptunghiul ro șu eviden țiaz ă blocul de memorie de
date:

figura 1
Capacitatea de memorare a acestui bloc este de 4GB. Pentru simplitate, în continuare vom
considera c ă acesta este singurul bloc de memorie care trebuie implementat. Implementarea cu
memorie de cod și memorie de date va fi tratat ă în prelegerea urm ătoare.
Implementarea MIPS (redus) a fost f ăcut ă în FPGA în cadrul cursului de organizarea
calculatoarelor. Dezavantajele implement ării în FPGA constau în costul mare al modulului FPG A și
capacitatea mic ă de memorare. În loc de FPGA putem construi circui te integrate (ASIC) pe baza
descrierilor VHDL și schematic deja existente. Evident, dorim o imple mentare cu cât mai pu ține
circuite integrate, ideal unul singur. Considerând densitatea de integrare oferit ă de tehnologia de
realizare a circuitelor integrate, de ajungem la co ncluzia c ă putem implementa pe un singur chip tot
sistemul, mai pu țin blocul de memorie. Acest fapt se datoreaz ă în principal limit ărilor tehnologice .
Blocul de memorie de date MIPS are capacitatea de 4 GByte=4x8Gbit=32Gbit dar în 2016, în
momentul în care a fost scris ă aceasta sec țiune, cel mai mare chip DRAM are capacitatea de mem orare
de 16Gbit.
Chiar dac ă am reu și integrarea întregului bloc de memorie, ceea ce se va întâmpla într-un an
sau doi, o astfel de solu ție ar avea un pre ț foarte ridicat . În practic ă exist ă îns ă multe aplica ții care au
nevoie doar de câ țiva zeci de KB de memorie. Dac ă ar exista numai chip-uri cu 4GB de memorie, o

2
aplica ție care are nevoie doar de câ țiva zeci de KB ar costa nejustificat de mult. În ac est caz o solu ție
scalabil ă ar fi mult mai potrivit ă. Un exemplu de solu ție scalabil ă îl constituie calculatoarele
compatibile IBM PC. Un astfel de sistem are memoria implementat ă pe pl ăcu țe DIMM cu diverse
capacit ăți de memorare. Utilizatorul î și alege configura ția în func ție de aplica țiile pe care le va rula și
de pre țul pe care și-l poate permite, dar are oricând posibilitatea un ei extensii ulterioare.
Un al treilea motiv care pledeaz ă împotriva integr ării blocului de memorie împreun ă cu
procesorul pe un singur chip îl constituie raportul memorie fix ă (ROM)/memorie volatil ă (RAM). În
toate sistemele de calcul trebuie s ă existe atât memorie fix ă (PROM, EPROM, FLASH) pentru a
memora secven ța de ini țializare (Boot) și, eventual, programul de aplica ție cât și memorie volatil ă
(RAM) pentru variabile. Problema este c ă raportul ROM/RAM depinde de tipul aplica ției pentru care
a fost construit sistemul. Un sistem de uz general, cum este un PC, are nevoie de foarte pu țin ROM și
de mult RAM. Tipic, într-un PC exist ă 128KB ROM pentru BIOS și 4GB de RAM. Un sistem dedicat
cum este calculatorul unui automobil are nevoie de mult ROM și pu țin RAM.
Datorit ă celor trei motive expuse anterior o prim ă solu ție la problema implement ării cu cât mai
pu ține circuite integrate const ă în divizarea sistemului de calcul în dou ă blocuri: procesor și memorie.
Gradul de integrare actual permite integrarea proce sorului pe un singur chip. În schimb blocul de
memorie va fi alc ătuit din mai multe circuite integrate. În continuar e vom prelucra schema din figura 1
pentru a ob ține o schem ă cu dou ă blocuri: blocul procesor care con ține tot ce este în figura 1 în afara
dreptunghiului ro șu și blocul de memorie de date din interiorul dreptung hiului ro șu. Astfel se ob ține
schema din figura 2. Cele dou ă blocuri se interconecteaz ă prin intermediul adreselor, datelor și
semnalelor de control MemRd# și MemWr#.
În figura 2 procesorul se conecteaz ă cu blocul de memorie prin intermediul a 64 de cone xiuni
de date: 32 pentru fluxul de date procesor →memorie (scriere) plus 32 pentru fluxul
memorie →procesor (citire). Este de dorit ca num ărul de conexiuni între cele dou ă blocuri s ă fie cât
mai mic deoarece un num ăr mare de conexiuni înseamn ă chipuri cu mul ți pini, ceea ce implic ă costuri
mai mari și cablaje de dimensiuni mari.

figura 2
figura 3
În cazul schemei din figura 2 reducerea num ărului de pini se poate face dac ă cele dou ă căi de
date unidirec ționale se înlocuiesc cu o singur ă cale bidirec țional ă. Astfel rezult ă schema din figura 3.
Reducerea num ărului de pini atât pentru procesor cât și pentru memorie se face pe seama unei cre șteri
minore a complexit ății driverelor de ie șire aferente pinilor de date, a șa cum se va ar ăta în continuare.
Aceast ă schema bloc este valabila în cazul oric ărui procesor, nu numai pentru MIPS.
Comunica ția între procesor și memorie se face prin intermediul a mai multor con ductori electrici: fire
sau trasee de cablaj.
Mai mul ți conductori prin intermediul c ărora se transmite informa ție de acela și tip se
nume ște magistral ă.

3
Transferurile între procesor și memorie se fac prin intermediul magistralelor de date, de adrese și
de control:
• Transferul datelor între procesor și memorie se face prin intermediul magistralei de date .
• Loca ția de memorie cu care se face transferul este ident ificat ă prin adres ă. Adresa se transmite
de la procesor la blocul de memorie prin intermediu l magistralei de adres ă.
Totalitatea adreselor pe care le poate genera proce sorul pe pinii de adrese se nume ște spa țiu de
adrese procesor .
Procesorul „ știe” c ă la fiecare adres ă generat ă exist ă o loca ție și c ă fiecare loca ție are o
adres ă. Din punct de vedere procesor nu exist ă adres ă f ără loca ție, și nici loca ție cu mai multe
adrese!
• La o adres ă procesorul poate executa dou ă opera ții: citirea loca ției de la acea adres ă și scrierea
în loca ția de la adresa respectiv ă. Tipul transferului (scriere în memorie sau citire din memorie
de exemplu) cât și alte informa ții se precizeaz ă prin intermediul magistralei de control . Într-o
prim ă aproxima ție magistrala de control va con ține dou ă semnale, RD# și WR# din figura 3:
– Dac ă RD# = 0 și WR# = 1, opera ția ini țiat ă de procesor este de citire memorie ,
– Dac ă RD# = 1 și WR# = 0, opera ția ini țiat ă de procesor este de scriere memorie .
– Dac ă RD# = 1 și WR# = 1, procesorul nu folose ște memoria deoarece execut ă activit ăți
interne.
Așa cum s-a precizat anterior, introducerea unei sing ure conexiuni de date între procesor și
memorie permite înjum ătățirea num ărului de pini de date ai procesorului, ai memoriei cât și a
num ărului de conexiuni de date între aceste dou ă blocuri. Conexiunea de date bidirec țional ă
func ționeaz ă numai dac ă se modific ă driverele de ie șire aferente pinilor de date. Pentru
simplitate, de și știm c ă deocamdat ă este imposibil, vom presupune c ă blocul de memorie este alc ătuit
dintr-un singur circuit integrat.
Mai întâi vom considera opera ția de scriere. În cazul scrierii sursa datelor este procesorul iar
destina ția este memoria. Scrierea bitului k în memorie se face ca în figura 4, pe calea: logic a intern ă a
procesorului → PDout k → intrarea driverului PO → ie șirea driverului PO → pinul Dk al procesorului
→ linia k a magistralei de date DB k → pinul Dk al memoriei → intrarea driverului MI → ie șirea
driverului MI → logica intern ă a memoriei. Schema din figura 4 se repet ă pentru orice bit de date.
În mod asem ănător se face și citirea; în acest caz sursa datelor este memoria iar destina ția este
procesorul. Calea pe care se face citirea bitului k este prezentat în figura 5:
figura 4
figura 5
Reamintim c ă o poart ă logic ă, un driver, registru, num ărător, etc. genereaz ă la ie șire fie valoarea logic ă
‚0’, fie valoarea logic ă ‚1’. O astfel de ie șire „vorbe ște” tot timpul spunând fie ‚0’ fie ‚1’. Dac ă
procesorul nu ar face decât scrieri schema din figu ra 4 ar fi suficient ă: procesorul „vorbe ște” tot timpul
prin intermediul driverului PO (Processor Out) iar memoria ascult ă cu driverul MI (Memory In).

4
Asem ănător, dac ă procesorul ar face numai citiri memoria ar vorbi t ot timpul cu driverul MO iar
procesorul ar asculta cu PI (figura 5). Dar transfe rul de date procesor-memorie presupune atât scriere
cât și citire (în momente de timp diferite, desigur), mo tiv pentru care calea de date pentru bitul k va
ar ăta ca în figura 6:
figura 6
Din p ăcate implementarea din figura 6 nu poate func ționa. De exemplu, dac ă procesorul
dore ște s ă scrie ‚1’ în memorie, aceast ă valoare va apare la ie șirea driverului PO. Dar în acela și timp
driverul MO din memorie genereaz ă la ie șire ‚0’ sau ‚1’, chiar dac ă opera ția ini țiat ă de procesor este
scriere (un driver obi șnuit genereaz ă tot timpul la ie șire o valoarea logic ă). Aceast ă valoare va interfera
cu ‚1’-ul generat de procesor. Dac ă valoarea generata la ie șirea driverului MO este ‚0’, care va fi
valoarea logica pe linia k a magistralei de date? Este ca și cum dou ă persoane doresc s ă converseze dar
amândou ă vorbesc simultan. Pentru ca dialogul s ă fie posibil trebuie ca atunci când o persoan ă
vorbe ște cealalt ă s ă tac ă.
Prin analogie, pentru ca transferul de date proceso r-memorie s ă fie posibil prin intermediul
unui singur set de fire trebuie ca atunci când proc esorul „vorbe ște” prin intermediul driverului PO,
driverul MO din memorie s ă „tac ă”. În cazul citirii memoria va vorbi prin MO iar dr iverul PO din
procesor va „tace”. În concluzie este nevoie de un tip driver care s ă spun ă ‚0’ sau ‚1’ ca orice circuit
logic obi șnuit dar suplimentar s ă știe s ă „tac ă”. Circuitele logice care știu s ă „tac ă” sunt circuitele
logice cu ie șire 3-state .
În concluzie, pentru a se putea executa atât scrier ea memoriei cât și citirea acesteia, driverele
PO și MO trebuie s ă fi de tip 3-state. Implementarea cu astfel de drivere este prezentat ă în figura 7.

figura 7
2. Modulul de tip memorie
În figura 8a este prezentat ă schema de principiu a unui modul de memorie, schem ă ce nu ține
seama de tipul modulului sau de modul în care resp ectivul modul este realizat tehnologic. Din punct
de vedere logic un modul de memorie poate fi privit ca o mul țime de loca ții, numite în continuare
loca ții de memorie.

5
Oricare loca ție din interiorul modulului de memorie poate fi scr is ă sau citit ă. Tipul opera ției
efectuate asupra unei loca ții, scriere sau citire, se specific ă prin intermediul pinilor RD# (read) și
WR# (write). Loca ția care va fi citit ă sau scris ă este stabilit ă în mod univoc de valorile logice de pe
pinii de adres ă ai modulului de memorie, A m-1- A0. Prin intermediul acestor pini se precizeaz ă adresa
loca ției în cadrul modulului .
Adresa loca ției în cadrul modulului se va numi în continuare ad resa fizic ă. Să nu se confunde
adresa fizic ă cu adresa generat ă de procesor!
Adresa fizic ă selecteaz ă loca ția de memorie care va fi scris ă sau citit ă: loca ția 0 este selectat ă
când pinii de adresa ai modulului au valoarea A m-1 – A0 =0…00, loca ția 1 este selectat ă când A m-1-
A0=0…01, etc. În general, loca ția k este loca ția selectat ă când pinii de adres ă ai modulului de memoria
au valoarea k.
Num ărul de loca ții de memorie din interiorul modulului este 2 m, unde m este num ărul de linii
de adres ă. Capacitatea de memorare a unui modul de memorie se specific ă cu formula CM=2 m x d,
adic ă respectivul modul este alc ătuit din 2 m loca ții, fiecare loca ție fiind alc ătuit ă din d bi ți.
Fie k loca ția selectat ă prin intermediul pinilor de adres ă. Citirea loca ției k înseamn ă transferul
informa ției din loca ția k pe pinii D 0-Dd-1. În cazul citirii D 0-Dd-1 sunt ie șiri din modulul de memorie.
Scrierea loca ției k înseamn ă transferul informa ției prezente pe pinii D 0-Dd-1 în loca ția k; în acest caz
D0-Dd-1 sunt intr ări. Rezult ă c ă pinii de date D 0-Dd-1 sunt bidirec ționali, adic ă la fiecare pin D i se
conecteaz ă intern cele dou ă drivere MI și MO, ca în figura 8b:

figura 8

Semnalul CE# (Chip Enable, # – activ ‚0’) controleaz ă activarea modulului: dac ă CE# este
inactiv (adic ă ‚1’) nu se face nici scriere, nici citire și con ținutul tuturor loca țiilor r ămâne neschimbat.
De asemenea, semnalul CE# controleaz ă starea driverelor 3-state : dac ă CE# este inactiv (‚1’ logic),
acestea sunt în starea de impedan ță ridicat ă. Când CE# este ‚1’ spunem c ă circuitul este în starea
IDLE .
În concluzie, func ționarea modulului este controlat ă de semnalele RD# (read), WR# (write) și
CE#. În func ție de starea acestor semnale sunt posibile trei mod uri de lucru, descrise în tabelul
urm ător.
CE# RD# WR# Mod
0 0 1 READ – Citire loca ție
0 1 0 WRITE – Scriere loca ție
0 0 0 IDLE = Inactiv. La unele module se face scriere
0 1 1 IDLE
1 x x IDLE

6
Numele semnalelor de control nu sunt standardizate. Astfel, în loc de CE# se mai folose ște CS# (Chip
Select), RD# este sinonim cu OE# (Output Enable) ia r WR# este sinonim cu WE# (Write Enable).
Denumirile CE#, OE# și WE# sunt întâlnite mai des, a șa c ă de acum încolo se vor folosi aceste nume.
Obs: în starea IDLE consumul de putere al modulului est e o cincime din consumul în st ările READ
sau WRITE.

3. Blocul de memorie.
În scop didactic, vom considera un exemplu „de juc ărie” bazat pe un procesor cu 4 pini de
adres ă și module de memorie de tipul celor descrise în subc apitolul anterior, adic ă module de memorie
cu pini de adres ă, pini de date bidirec ționali și pinii de control CE#, WR# și RD#. Procesorul cu 4 pini
de adres ă poate genera 16 adrese. La acest procesor se poate conecta un modul de memorie cu 16
loca ții conform schemei clasice de conectare din figura 3: pinii de adres ă ai procesorului se conecteaz ă
la pinii de adres ă ai memoriei, datele procesor la datele memoriei, R D# la RD# și WR la WR#.
Conectarea procesorului cu 4 adrese cu memoria de 1 6 loca ții este prezentat în figura 9.
Conexiunile AP 0 – AM 0, AP 1 – AM 1, AP 2 – AM 2, AP 3 – AM 3 dintre pinii de adres ă ai
procesorului și pinii de adres ă ai memoriei fac ca loca ția de memorie i (i=0..15) să fie selectat ă când
adresa generat ă de procesor este are valoarea i; se spune c ă loca ția de memorie i a primit adresa
procesor i. Coresponden ță adres ă local ă – adres ă procesor este prezentat ă în tabelul din figura 9.
În figura 9 conectarea procesor – memorie este foar te simpl ă, natural ă, deoarece num ărul de
loca ții din care este alc ătuit modulul de memorie este egal cu num ărul de adrese pe care le poate
genera procesorul. Cum se va face conectarea proces or – memorie dac ă în loc de memorii cu 16 loca ții
dispunem numai de memorii cu 4 loca ții?
A A A A
P P P P
3 2 1 0
Procesor
RD#
WR#
Data A0A1A2A3
Data Bus A A A A
M M M M
3 2 1 0
Memorie 16
locatii
CE#
RD#
WR#
Data

figura 9

Un modulul de memorie cu 4 loca ții de memorie are 2 pini de adres ă. În exemplul urm ător
blocul de memorie va fi alc ătuit din dou ă module de 4 loca ții . Dac ă unei loca ții de memorie i se aloc ă
o singur ă adres ă procesor vor r ămâne 16-4*2=8 adrese procesor nealocate. Aceast ă situa ție este foarte
frecvent ă, a șa cum se întâmpl ă în cazul calculatoarelor compatibile IBM PC: nici o configura ție nu
este prev ăzut ă cu 16EB de memorie și nici nu va fi prea curând.
Mai întâi vom conecta la procesor primul modul de m emorie cu capacitatea de 4 loca ții.
Schema de conectare porne ște de la schema din figura 9. La fel ca în figura 9 datele procesor se
conecteaz ă la datele memoriei, RD# la RD# și WR la WR#. Problema apare la pinii de adres ă:

7
deoarece memoria are 2 pini de adres ă se pot face doar conexiunile AP 0 – AM 0 și AP 1 – AM 1. Schema
preliminar ă de conectare este prezentat ă în figura urm ătoare:

figura 10 Memorie1 AM[1:0]
00
01
10
11 AP[3:0]
00 00
0001
0010
0011
01 00
0101
0110
0111
10 00
1001
1010
1011
11 00
1101
1110
1111
Din figur ă se observ ă c ă pinii procesor AP3 și AP2 și pinul CE# al memoriei au r ămas neconecta ți.
În exemplul anterior din figura 9 CE#-ul memoriei e ste tot timpul activ deoarece orice adres ă
ar genera procesorul, loca ția de memorie care prime ște respectiva adres ă se afl ă în modulul de
memorie de 16 loca ții: 16 adrese procesor, 16 loca ții de memorie. În figura 10 situa ția este diferit ă:
procesorul genereaz ă 16 adrese dar modulul de memorie este alc ătuit doar din 4 loca ții.
Dup ă cum s-a ar ătat în capitolul anterior, atunci când CE# este ina ctiv modulul de memorie
este în starea IDLE, drivere de date sunt în 3-stat e, modulul fiind decuplat de la magistrala de date.
Ideea este s ă gener ăm CE# din adresele AP3 și AP2 astfel ca memoria 1 r ăspund ă doar la 4 adrese
procesor și s ă fie în IDLE pentru celelalte adrese.
În continuare vom determina care sunt adresele p rocesor ce pot fi alocate celor 4 loca ții de
memorie. Deoarece adresele procesor AP0 și AP1 sunt deja conectate la pinii AM0 și AM1 nu este
posibil ă orice alocare adres ă procesor – loca ție de memorie. Vom detalia acest aspect cu ajutorul
loca ții 00 (cu adresa local ă 0). Loca ția 00 se va selecta dac ă AM0=’0’ și AM1=,0’. Dar conexiunile de
adrese AM0=AP0 și AM1=AP1 deja existente fac ca numai adresele procesor cu AP0=’0’ și AP1=’0’,
adic ă adresele care se termin ă în „00”, să poată selecta loca ția 00. Rezult ă c ă numai adresele procesor
00 00 , 01 00 , 10 00 și 11 00 pot fi alocate loca ției 00b. Aceste aloc ări posibile sunt eviden țiate în figura
10 în partea dreapt ă. Ra ționamentul pe cate l-am f ăcut pentru loca ția 00 poate fi f ăcut și pentru
celelalte 3 loca ții. Astfel loca ția 01 poate primii adresele procesor care se termin ă în 01, adic ă loca țiile
00 01, 01 01, 10 01 și 11 01. În rezumat exist ă 4 adrese procesor candidat pentru orice loca ție de
memorie iar num ărul de aloc ări posibile este 44. În general, num ărul de aloc ări posibile este mm n2)2 (−.
Exist ă îns ă un fapt de care trebuie ținut seama: adresele procesor alocate loca țiilor de memorie
trebuie s ă fie adiacente. Dup ă cum se știe procesorul este prev ăzut cu num ărător de program.
Num ărătorul de program con ține adresa instruc țiunii curente. Dup ă execu ția instruc țiunii curente
num ărătorul de program se incrementeaz ă pentru a trece la instruc țiunea urm ătoare, ceea ce face ca
instruc țiunea urm ătoare s ă se afle la adresa urm ătoare. Dac ă a este o adresa în memoria de cod, atunci
adresa a+1 este adiacent ă adresei a; spunem că adresele a și a+1 sunt adiacente .
Un alt aspect care impune adiacen ța adreselor este alocarea vectorilor; dup ă cum se știe

8
elementele unui vector trebuie s ă stea în memorie la adrese succesive în memoria de date.
Adiacen ță codului și a vectorilor ne oblig ă s ă aloc ăm adresele procesor la rând. Dac ă loca ția 00
prime ște adresa procesor 0000 atunci loca ția 01 trebuie s ă primeasc ă adres ă 0001, loca ția 10 trebuie s ă
primeasc ă adres ă 0010 și loca ția 11 trebuie s ă primeasc ă adres ă 0011.
Procesul prin care loca țiile de memorie dintr-un modul de memorie primesc a drese
procesor se nume ște mapare.
Maparea primei memorii este prezentat ă în figura 11.
figura 11 AP[3..0] CE1#

figura 12 00 00 0
00 01 0
00 10 0
00 11 0
0100 1
0101 1
0110 1
0111 1
1000 1
1001 1
1010 1
1011 1
1100 1
1101 1
1110 1
1111 1
În momentul în care o adres ă procesor se aloc ă unei loca ții de memorie trebuie ca CE#-ul
modulului de memorie c ăruia îi apar ține respectiva loca ție s ă fie activ. Reamintim c ă scrierea ori
citirea unei loca ții de memorie se poate face numai dac ă CE#-ului respectivului modul este activ (‚0’-
logic). De exemplu, dac ă adresa procesor „0000” se aloc ă loca ției „00” din modulul 1, atunci când pe
magistrala de adrese apare combina ția „0000”, CE#-ul memoriei 1 trebuie s ă fie ‚0’ logic.
Dac ă o adres ă nu a fost alocat ă unui modul, atunci când acea adres ă apare pe magistrala de
adrese respectivul modul nu se va activa (CE#= ‚1’) iar valoarea logic ă de pe pinii de adres ă ai
modulului nu conteaz ă deoarece modulul este inactiv. Prin aplic ăm acest ra ționament pentru maparea
din figura 11 se ob ține tabelul al ăturat figurii. Acest tabel nu este altceva decât o tabel ă de adev ăr
pentru func ția CE1#. Func ție se poate implementa folosind metodele clasice de sintez ă logic ă. Pentru
maparea din figura 11 se observ ă c ă CE1# este ‚0’ numai când AP3=’0’ și AP2=’0’, ceea ce conduce
la implementarea CE1# = AP3+AP2. Aceast ă form ă se poate ob ține și prin minimizare. Schema
complet ă pentru maparea din în figura 11 este prezentat ă în figura 12.
În continuare vom mapa al doilea modul de memorie. Adiacen ță codului și a vectorilor impune
ca prima adres ă procesor alocat ă loca ției „00” din memoria 2 s ă fie adiacent ă ultimei adrese procesor
alocate memoriei 1. Din acest motiv loca ția „00” din modulul 2 va primi adresa procesor „010 0”. Tot
din cauza adiacen ței celelalte loca ții vor primi adresele succesive 0101, 0110 și 0111.
Exist ă o regul ă care trebuie întotdeauna respectat ă când se mapeaz ă mai multe memorii:
Regul ă: o adres ă procesor se aloc ă la o singur ă loca ție de memorie sau nu se aloc ă deloc.
Dac ă aceast ă regul ă nu este respectat ă, la citire de la adresa alocat ă multiplu se vor selecta dou ă sau

9
mai multe memorii, memoriile selectate vor încerca s ă impun ă nivelele logice pe magistrala de date iar
rezultanta nu va fi niciuna din date. Este ca și cum dou ă sau mai multe persoane ar vorbi simultan.
Maparea memoriei 2 este prezentat ă în figura 13:

figura 13 AP[3..0] CE1# CE2#
00 00 0 1
00 01 0 1
00 10 0 1
00 11 0 1
01 00 1 0
01 01 1 0
01 10 1 0
01 11 1 0
1000 1 1
1001 1 1
1010 1 1
1011 1 1
1100 1 1
1101 1 1
1110 1 1
1111 1 1
A dou ă memorie se conecteaz ă la procesor la fel ca și prim ă: datele procesor se conecteaz ă la
datele memoriei, RD# la RD# și WR la WR#. Tabel ă de adev ăr pentru func ția CE2# rezult ă din
mapare si este prezentat ă în figura 13. Se observ ă c ă CE2# este ‚0’ numai când AP3=’0’ și AP2=’1’.
Aceast ă observa ție conduce la implementarea 23# 2 AP AP CE += . Schema complet ă a sistemului
format din procesor și cele dou ă memorii este prezentat ă în figura 14.

figura 14
Cele dou ă CE#-uri sunt implementate cu dou ă por ți OR și un inversor. Acestea formeaz ă
decodificatorul de adres ă.
Blocul logic care implementeaz ă toate func țiile CE# dintr-un sistem de calcul formeaz ă
decodificatorul de adres ă.

10
Decodificatorul de adres ă împreun ă cu cele dou ă memorii formeaz ă blocul de memorie . Acest bloc
este încadrat în dreptunghiul ro șu în figura 14.
În final vom vedea cum se implementeaz ă blocul de memorie în sistemele reale unde
procesoarele au cel putin 16 pini de adres ă iar memoriile au capacit ăți minime de ordinul kilo octe ților.
În cazul general vom considera module de memorie cu m pini de adres ă, AM 0-AM m-1, și un procesor
cu n pini de adres ă, AP 0-AP n-1, n≥m.
Un modul de memorie se conecteaz ă cu procesorul dup ă urm ătoarele 2 reguli:
1. Cei m pinii de adres ă ai memoriei se conecteaz ă la pinii de adres ă cu aceia și indice ai
procesorului, adic ă AM 0 cu AP 0, AM 1 cu AP 1, …, AM m-1 cu AP m-1. Pinii de date procesor se
conecteaz ă cu pinii de date ai memoriei, RD# procesor cu RD# memorie și WR# procesor cu
WR# memorie.
2. Memoriei i se aloc ă 2 m adrese procesor (o adres ă pentru fiecare loca ție). Pentru toate cele 2 m
adrese biții superiori AP n-1 – AP m au aceea și valoare pentru ca adresele sa fie adiacente.
Cele 2 m adrese procesor care respect ă condi ția 2 formeaz ă un bloc de adrese. În tabelul urm ător este
prezentat un bloc de adrese generic:
AP n-1 … AP m+1 AP m AM m-1=AP m-1 …… AM 1= AP 1 AM 0= AP 0 Echivalent zecimal
cn-1 … cm+1 cm 0 0…0 0 0 c+0
cn-1 … c m+1 cm 0 0…0 0 1 c+1
cn-1 … c m+1 cm 0 0…0 1 0 c+2
. … . . . . . . …
cn-1 … c m+1 cm 1 1…1 1 0 c+2 m -2
cn-1 … c m+1 cm 1 1…1 1 1 c+2 m -1
În tabel c= c n-1… cm+1 cm.
Aplicarea celor dou ă reguli are 4 consecin țe. Din tabelul
anterior se observ ă c ă:
c1) Adresa cea mai mic ă dintr-un bloc se termin ă în m
de ‚0’. În tabel aceast ă adres ă este adresa c n-1… cm+1 cm 0..00.
c2) Adresa cea mai mare dintr-un bloc se termin ă în m
de ‚1’. În tabel aceast ă adres ă este adresa c n-1… cm+1 cm 1..11.
c3) Adresele dintr-un bloc sunt adiacente : dac ă
adresa a apar ține blocului atunci și adresa a+1 va apar ține
blocului, cu excep ția celei mai mari adrese.
În cazul exemplului de juc ărie considerat anterior blocul
este format din 4 adrese deoarece memoriile au 4 lo ca ții.
Aceste blocurile de adrese sunt prezentate în figur a 15.
c4) CE# depinde numai de bi ții superiori AP n-1 ÷
AP m, bi ți care au o valoare constant ă pe întreg blocul de
adrese. CE# este func ția maxtermen c de variabilele
AP n-1 ÷ AP m. CE# se poate implementa u șor o poart ă OR
sau cu un DEC. În exemplul de juc ărie CE1#(AP3, AP2)
este maxtermenul 0 iar CE2#(AP3, AP2) este maxterme nul
1.
Decodificarea care se face dup ă regulile 1 și 2 se nume ște decodificare complet ă minim ă deoarece
consum ă cele mai pu ține resurse pentru implementare. Cum 99,99% din dec odific ările complete sunt
minime, cuvântul minim ă nu se mai folose ște.

figura 15

11
3. Decodificarea complet ă (minim ă) – exemplu
Procesorul folosit în exemplu are 16 pini de adres ă. Se cere maparea unui modul EPROM de
4KB, tip I2732, începând de la adresa 0000h și a unui modul SRAM de 8KB, tip IDT7164, începând
de la adresa 8000h. Decodificarea va respecta regul ile decodific ării complete minime.
Pentru modulul EPROM calcul ăm num ărul de pini de adres ă ai modulului EPROM: 4K= 4*210 =
22*2 10 =2 12 . Pentru 4K avem nevoie de 12 adrese, de la A0 la A 11. Pentru ca decodificarea s ă fie
complet ă trebuie s ă aloc ăm un bloc de adrese de 4KB:
a) Mai întâi verific ăm dac ă adresa procesor de la care începe alocarea este pr ima adres ă dintr-un
bloc de 212 adrese. Din capitolul anterior știm c ă prima adres ă se termin ă în m=12 de ‚0’.
Verificarea se face scriind adresa procesor 0000h î n baza 2. Adresa 0x0000 scris ă în baza 2
este prima linie în tabelul 1.
b) EPROM-ului i se aloc ă primul bloc de adrese de 4K caracterizat de c=0000. Acest bloc este
marcat cu galben în tabelul urm ător:
tabelul 1
Adresa procesor AP(15:0) CE
EPROM Adresa EPROM AM(11:0)
1
5 1
4 1
3 1
2 1
1 1
0 9 8 7 6 5 4 3 2 1 0 Hexa 1
1 1
0 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0000h 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0001h 0 0 0 0 0 0 0 0 0 0 0 0 1
. . . . . . . . . . . . . . . . … 0 . . . . . . . . . . . .
0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0fffh 0 1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1000h 1 x x x x x x x x x x x x
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1001h 1 x x x x x x x x x x x x
. . . . . . . . . . . . . . . . … . . . . . . . . . . . . .
În practic ă acest tabel nu se construie ște în aceast ă form ă, ci în form ă simplificat ă. În forma
simplificat ă se specific ă prima și ultima adres ă alocat ă modulului ce se mapeaz ă. În cazul EPROM-
ului forma simplificat ă este:
Adresa procesor AP(15:0)= 0000h = 0000 0000 0000 0000b
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0000h
. . . . . . . . . . . . . . . . …
0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0fffh
Prima linie din tabelul în form ă simplificat ă este necesar ă pentru a verifica c ă prima adres ă procesor
alocat ă modulului de memorie se termin ă în m de zero (12 de zero pentru EPROM). Ultima linie es te
necesar ă pentru a verific ă c ă nu este dep ăș it ă zona de adrese alocate pentru maparea modulului. U ltima
adres ă procesor este 0fffh, adres ă care este mai mic ă decât 8000h (prima adresa alocat ă SRAM-ului).
Conform regulii 1 din capitolul precedent A0 proces or se conecteaz ă la A0 memorie, A1 la A1
ș.a.m.d. pân ă la A11. Func ția de selec ție se va sintetiza din bi ții superiori ai adresei procesor, adic ă
AP15 , AP14 , AP13 și AP12 . CE# EPROM trebuie s ă fie ‚0’ logic când AP[15:12]= ”0000”. Implementare a
este f ăcut ă prin intermediul por ții OR4 din pozi ția U1 în figura 16.
Not ă: Figura este desenat ă în modul comprimat. Pentru detalii privind modul comprimat de desenare
al schemelor vezi „ Anexa – desenarea simplificat ă a schemelor ” în aceast ă prelegere.
Pentru modulul SRAM proced ăm la fel ca pentru EPROM. Mai întâi calcul ăm num ărul de pini
de adres ă ai modulului RAM: 8K= 8*2 10 = 2 3*2 10 =2 13 . Pentru 8K avem nevoie de 13 adrese: A 0-A12 .
La fel ca la modul EPROM verific ăm dac ă adresa procesor 8000h de la care începe alocarea e ste prima
adres ă dintr-un bloc. Practic verific ăm dac ă 8000h termin ă în 13 de zero. Adresa 8000h este prima
adres ă din blocul galben din tabelul urm ător și se observ ă c ă se termin ă în 13 de ‚0’. Blocul de adrese

12
alocat SRAM-ului este marcat cu galben în tabelul 2 :
tabelul 2
Adresa procesor AP(15:0) CE
SRAM Adresa SRAM AM(12:0)
1
5 1
4 1
3 1
2 1
1 1
0 9 8 7 6 5 4 3 2 1 0 Hexa 1
2 1
1 1
0 9 8 7 6 5 4 3 2 1 0
. . . . . . . . . . . . . . . . … . . . . . . . . . . . . .
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7fffh 1 x x x x x x x x x x x x x
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8000h 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 8001h 0 0 0 0 0 0 0 0 0 0 0 0 0 1
. . . . . . . . . . . . . . . . … . . . . . . . . . . . . . .
1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 9fffh 0 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 a000h 1 x x x x x x x x x x x x x
1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 a001h 1 x x x x x x x x x x x x x
. . . . . . . . . . . . . . . . … . . . . . . . . . . . . .
La fel ca la EPROM, în practic ă se construie ște forma simplificat ă a acestui tabel:
Adresa procesor AP(15:0)= 8000h = 1000 0000 0000 00 00b
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8000h
. . . . . . . . . . . . . . . . …
1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 9FFFh
Prima linie din tabelul în form ă simplificat ă arat ă c ă prima adres ă procesor alocat ă modulului de
memorie se termin ă în 13 de zero. CE# SRAM trebuie s ă fie ‚0’ logic când AP[15:12] procesor sunt
„100”. Implementarea este f ăcut ă prin intermediul por ților U2 și U3 din figura 16. În tabelul al ăturat
figurii se construie ște harta de alocare a resurselor: între adresele 00 00h și 0fffh se afl ă mapat modulul
EPROM iar între adresele 8000h și 9fffh se afl ă mapat modulul SRAM. Restul adreselor sunt
nealocate. Acest tabel este harta memoriei.

figura 16

A000- FFFF

Nealocat
8000 – 9FFF
SRAM

1000-7FFF

Nealocat
0000 – 0FFF EPROM

Anexa – desenarea simplificat ă a schemelor
In exemplele din capitolul 3 procesorul are doar 4 pini de adres ă iar modulele de memorie doar 4
loca ții. Cum se deseneaz ă schemele în care apar procesoare și module de memorie reala? În figura
urm ătoare este prezentat un procesor real cu 16 pini de adres ă, 8 pini de date, semnalele de control
RD# și WR# precum și alte semnale de control neimportante în momentul de fa ță . Procesorul este
Z80-CPU.
AB13 AB13 AB12 ROM_1
I2732 OE# A[11:0]
D[7:0] CE# U2 AB14
AB15
AB14
1AB[15:0]
U3
RD#
DB[7:0] U1 AB15
RD#
WR#
WR# uP_1
A[15:0]
D[7:0] WR# RD# RAM_2
IDT7164 RD#
WR# A[12:0]
D[7:0]CS1# CS2

13

În figura de mai sus este prezentat și un modul SRAM real cu capacitatea de 2Kx8 cu codu l I2016.
Modulul are 11 pini de adres ă, 8 pini de date și semnalele de control discutate pe larg în capitol ul 2.
În continuare vom conecta memoria la procesor. În figura urm ătoare este prezentat ă prima
conexiune: pinulA0 al procesorului se conecteaz ă prin firul ABUS0 la pinul A0 al memorie:

Numele firului nu este obligatoriu; conexiunile se pot face și f ără s ă denumim firele.
În figura urm ătoare to ți pinii de adresa ai memoriei s-au conectat la pini i corespunz ători ai
procesorului: U1
Z80-CPU 30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
14
15
12
8
7
9
10
13 27
19
20
22
21
28
18
24
16
17
26
25
23
6A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
A11
A12
A13
A14
A15
D0
D1
D2
D3
D4
D5
D6
D7 M1
MREQ
IORQ
WR
RD
REFSH
HALT
WAIT
INT
NMI
RESET
BUSRQ
BUSAK
CLK U24
2016 8
7
6
5
4
3
2
1
23
22
19
18
20
21 9
10
11
13
14
15
16
17 A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
CE
OE
WE D0
D1
D2
D3
D4
D5
D6
D7
U1
Z80-CPU 30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
14
15
12
8
7
9
10
13 27
19
20
22
21
28
18
24
16
17
26
25
23
6A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
A11
A12
A13
A14
A15
D0
D1
D2
D3
D4
D5
D6
D7 M1
MREQ
IORQ
WR
RD
REFSH
HALT
WAIT
INT
NMI
RESET
BUSRQ
BUSAK
CLK ABUS0 U24
2016 8
7
6
5
4
3
2
1
23
22
19
18
20
21 9
10
11
13
14
15
16
17 A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
CE
OE
WE D0
D1
D2
D3
D4
D5
D6
D7

14

Pinii procesor A15-A11 sunt conecta ți la firele ABUS15-ABUS11, fire pentru care cel dea l doilea cap
este momentan neconectat. Aceste fire pot fi folo site ulterior.
În continuare se conecteaz ă pinii de date:

figura 17
Ad ăug ăm înc ă un modul de memorie și conect ăm pinii de date și 4 pini de adres ă: ABUS2
ABUS9
ABUS15 ABUS11 ABUS10 ABUS1
ABUS3
ABUS12 ABUS7
ABUS8 ABUS6 U24
2016 8
7
6
5
4
3
2
1
23
22
19
18
20
21 9
10
11
13
14
15
16
17 A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
CE
OE
WE D0
D1
D2
D3
D4
D5
D6
D7 ABUS0
ABUS5
ABUS14 U1
Z80-CPU 30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
14
15
12
8
7
9
10
13 27
19
20
22
21
28
18
24
16
17
26
25
23
6A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
A11
A12
A13
A14
A15
D0
D1
D2
D3
D4
D5
D6
D7 M1
MREQ
IORQ
WR
RD
REFSH
HALT
WAIT
INT
NMI
RESET
BUSRQ
BUSAK
CLK ABUS4
ABUS13
ABUS5
DBUS3 ABUS1
ABUS9
ABUS15
DBUS7 ABUS11 ABUS3
DBUS1 ABUS12 ABUS2
DBUS4 DBUS0 ABUS10
DBUS6 U1
Z80-CPU 30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
14
15
12
8
7
9
10
13 27
19
20
22
21
28
18
24
16
17
26
25
23
6A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
A11
A12
A13
A14
A15
D0
D1
D2
D3
D4
D5
D6
D7 M1
MREQ
IORQ
WR
RD
REFSH
HALT
WAIT
INT
NMI
RESET
BUSRQ
BUSAK
CLK DBUS5 ABUS7
ABUS8 ABUS4
ABUS14 U24
2016 8
7
6
5
4
3
2
1
23
22
19
18
20
21 9
10
11
13
14
15
16
17 A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
CE
OE
WE D0
D1
D2
D3
D4
D5
D6
D7 ABUS0
ABUS6
DBUS2 ABUS13

15

Schema în acest moment este destul de complicat ă, de „plin ă de fire”. Dac ă am conecta și ceilal ți pini
de adres ă schema ar deveni și mai complicat ă. Dac ă pe schem ă sunt prea multe fire, func ționalitatea
este ascuns ă de aceste fire.
O solu ție posibil ă în astfel de cazuri este conectarea prin nume: dou ă fire cu acela și nume se
consider ă conectate. În figura urm ătoare este schema anterioar ă în care s-a folosit foarte mult tehnica
conect ării prin nume (connect by name):

Din p ăcate folosirea exclusiv ă a acestei tehnici nu d ă rezultate prea bune: acum sunt prea pu ține fire!
Este greu s ă ne d ăm seama cum se conecteaz ă al doilea modul RAM (modulul U3).
Solu ția de compromis între desenarea cu multe fire și desenarea cu conectare prin nume este
desenarea cu magistrale. Firele cu nume se unesc în m ănunchiuri numite magistrale, iar magistralele
ac ționeaz ă ca un ghid pentru privire: ABUS5
DBUS3 ABUS1
ABUS9
DBUS6 ABUS15
DBUS7 ABUS11 ABUS3
DBUS1 ABUS12 ABUS2
DBUS4 ?
DBUS0 ABUS10 U1
Z80-CPU 30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
14
15
12
8
7
9
10
13 27
19
20
22
21
28
18
24
16
17
26
25
23
6A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
A11
A12
A13
A14
A15
D0
D1
D2
D3
D4
D5
D6
D7 M1
MREQ
IORQ
WR
RD
REFSH
HALT
WAIT
INT
NMI
RESET
BUSRQ
BUSAK
CLK DBUS5 ABUS7
ABUS8 ABUS4 U3
2016 8
7
6
5
4
3
2
1
23
22
19
18
20
21 9
10
11
13
14
15
16
17 A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
CE
OE
WE D0
D1
D2
D3
D4
D5
D6
D7
ABUS14 U24
2016 8
7
6
5
4
3
2
1
23
22
19
18
20
21 9
10
11
13
14
15
16
17 A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
CE
OE
WE D0
D1
D2
D3
D4
D5
D6
D7 ABUS0
ABUS6
DBUS2 ABUS13
DBUS3
ABUS10 ABUS2
ABUS4
ABUS9
DBUS5 ABUS8 ABUS1
ABUS9 ABUS0
DBUS6 DBUS6
DBUS1 DBUS2
ABUS15 ABUS11 DBUS5
ABUS6 ABUS3
ABUS12
DBUS4 U1
Z80-CPU 30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
14
15
12
8
7
9
10
13 27
19
20
22
21
28
18
24
16
17
26
25
23
6A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
A11
A12
A13
A14
A15
D0
D1
D2
D3
D4
D5
D6
D7 M1
MREQ
IORQ
WR
RD
REFSH
HALT
WAIT
INT
NMI
RESET
BUSRQ
BUSAK
CLK DBUS7 DBUS3
DBUS7 ABUS5
ABUS7 U24
2016 8
7
6
5
4
3
2
1
23
22
19
18
20
21 9
10
11
13
14
15
16
17 A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
CE
OE
WE D0
D1
D2
D3
D4
D5
D6
D7 DBUS6 DBUS0
ABUS5 DBUS5 DBUS4
ABUS14
DBUS2 ABUS3 U3
2016 8
7
6
5
4
3
2
1
23
22
19
18
20
21 9
10
11
13
14
15
16
17 A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
CE
OE
WE D0
D1
D2
D3
D4
D5
D6
D7 DBUS0
ABUS4 DBUS2 ABUS0
DBUS0 DBUS4 DBUS1
ABUS2
ABUS13
DBUS3 ABUS7 ABUS1
DBUS7 ABUS8 DBUS1
ABUS10 ABUS6

16

De și desenarea cu magistrale este solu ția corect ă în cazul sistemelor cu microprocesoare, aceast ă
metod ă este bun ă dac ă avem la dispozi ție un software de desenare, cum este OrCAD. Deoarec e la
examen trebuie s ă desen ăm manual, în continuare se va prezenta o metod ă simpl ă, bazat ă tot pe
magistrale. În loc de mul ți pini de adres ă sau de date vom desena un singur pin vectorial, a șa cum se
face în ISE Xilinx. De exemplu, în loc de de A0, A1 , A2,…, A15 se folose ște A[15:0].
Conectarea pinilor vectoriali la magistrale se face direct. In figura urm ătoare pinul vectorial
S[3:0] se conecteaz ă prin intermediul magistralei BUS[3:0] la pinul vec torial D[3:0]. Aceast ă
conexiune vectorial ă define ște 4 conexiuni simple, scalare. Regula dup ă care se fac aceste conexiuni
este de la dreapta la stânga : cel mai din dreapta pin S se conecteaz ă prin intermediul celui mai din
dreapta fir BUS la cel mai din dreapta pin D. Adic ă S0 se conecteaz ă prin intermediul lui BUS0 la D0.
Apoi se trece la urm ătorul membru de la dreapta la stânga atât la pini c ât și la bus. Conexiunile definite
de regula de la dreapta la stânga sunt scrise în pa rtea dreapt ă a figurii.
S0 ⇔ BUS0 ⇔ D0
S1 ⇔ BUS1 ⇔ D1
S2 ⇔ BUS2 ⇔ D2
S3 ⇔ BUS3 ⇔ D3
Nu este obligatoriu ca pinii vectoriali s ă aib ă aceea și dimensiune:
S0 ⇔ BUS0 ⇔ D0
S1 ⇔ BUS1 ⇔ D1
S2 ⇔ BUS2
S3 ⇔ BUS3
Nici direc ția pinilor sau a magistralei nu este obligatoriu ac eea și. Singura regul ă este regula de la
dreapta la stânga: ABUS[15:0]
ABUS10 ABUS2
ABUS8 DBUS5 DBUS3 DBUS1
DBUS7 ABUS1
ABUS9 ABUS2
ABUS5
DBUS1
DBUS3 ABUS0
ABUS9
ABUS10 DBUS0
DBUS6
ABUS15 ABUS11 ABUS4
ABUS8 ABUS6 ABUS3
DBUS6 ABUS6
ABUS7 ABUS1
DBUS7
ABUS12 ABUS9 U1
Z80-CPU 30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
14
15
12
8
7
9
10
13 27
19
20
22
21
28
18
24
16
17
26
25
23
6A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
A11
A12
A13
A14
A15
D0
D1
D2
D3
D4
D5
D6
D7 M1
MREQ
IORQ
WR
RD
REFSH
HALT
WAIT
INT
NMI
RESET
BUSRQ
BUSAK
CLK DBUS0 DBUS4 ABUS2
ABUS5
ABUS7 DBUS3
ABUS5
DBUS6 DBUS2 DBUS1
DBUS7
DBUS4 DBUS2 U3
2016 8
7
6
5
4
3
2
1
23
22
19
18
20
21 9
10
11
13
14
15
16
17 A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
CE
OE
WE D0
D1
D2
D3
D4
D5
D6
D7 ABUS6
ABUS14 DBUS0
DBUS2 U24
2016 8
7
6
5
4
3
2
1
23
22
19
18
20
21 9
10
11
13
14
15
16
17 A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
CE
OE
WE D0
D1
D2
D3
D4
D5
D6
D7 ABUS3
ABUS4
DBUS5
BUS[7:0] ABUS4 DBUS4
DBUS5 ABUS1
ABUS13 ABUS3 ABUS0
ABUS10 ABUS8 ABUS7 ABUS0
D[3:0] S[3:0] BUS[3:0]
D[1:0] S[3:0] BUS[3:0]

17
S3 ⇔ BUS0 ⇔ D0
S2 ⇔ BUS1 ⇔ D1
S1 ⇔ BUS2 ⇔ D2
S0 ⇔ BUS3
In figura urm ătoare este redesenat ă schema de cuplare a primului modul de memorie din figura 17. În
loc de a conecta adresele și datele prin fire s-a utilizat tehnica pinilor vec toriali si a magistralelor.

Cei 16 pinii de adres ă ai procesorului au fost înlocui ți cu pinul vectorial A[15:0] iar cei 12 pini de
adres ă ai memoriei au fost înlocui ți de pinul vectorial A[11:0]. Conectarea adreselor procesor la
adresele memoriei se face prin intermediul magistra lei AB[15:0]. În figur ă se observ ă conexiunea
uP.A[15:0] ⇔ AB[15:0] ⇔ ROM.A[11:0]. Aceast ă conexiune vectorial ă este echivalent ă cu
urm ătoarele conexiuni simple:
uP.A0 ⇔ AB0 ⇔ ROM.A0 uP.A8 ⇔ AB8 ⇔ ROM.A8
uP.A1 ⇔ AB1 ⇔ ROM.A1 uP.A9 ⇔ AB9 ⇔ ROM.A9
uP.A2 ⇔ AB2 ⇔ ROM.A2 uP.A10 ⇔ AB10 ⇔ ROM.A10
uP.A3 ⇔ AB3 ⇔ ROM.A3 uP.A11 ⇔ AB11 ⇔ ROM.A11
uP.A4 ⇔ AB4 ⇔ ROM.A4 uP.A12 ⇔ AB12
uP.A5 ⇔ AB5 ⇔ ROM.A5 uP.A13 ⇔ AB13
uP.A6 ⇔ AB6 ⇔ ROM.A6 uP.A14 ⇔ AB14
uP.A7 ⇔ AB7 ⇔ ROM.A7 uP.A15 ⇔ AB15
Se observ ă cum o singur ă conexiune vectorial ă a înlocuit 16 conexiuni simple f ăcând desenarea mult
mai u șoar ă.

D[2:0] S[0:3] BUS[3:0]
RD# uP_2
A[15:0]
D[7:0] WR# RD# AB[15:0]
ROM_2
I2732 OE# A[11:0]
D[7:0] CE#
WR#
DB[7:0]

1 Microprocesoare, microcontrolere – Prelegere 2

1. Loca ție de intrare/ie șire (port), interfe țe de intrare/ie șire
Modelul Von Neumann nu precizeaz ă nimic despre modul în care se face transferul de d ate cu exteriorul.
Conform acestui model, sistemul de calcul trebuie s ă con țin ă o reuniune de loca ții, fiecare loca ție fiind
identificat ă prin intermediul adresei sale. Fiecare loca ție poate fi scris ă sau citit ă. Aceast ă reuniunea de
loca ții este folosit ă pentru memorarea programului și a datelor și se nume ște memorie. Implementarea
blocului de memorie s-a f ăcut cu module de memorie datorit ă capacit ății mari a acestor module. Dar
folosirea modulelor de memorie nu reprezint ă singura posibilitate.
O memorie cu capacitatea de o singur ă loca ție poate fi implementat ă cu un registrul paralel-paralel
plus opt drivere 3-state. În figura 1 pentru regi strul paralel-paralel s-a ales circuitul 74LS377 ia r pentru cele
8 drivere 3-state, circuitul 74LS541.

figura 1
Ca orice memorie, memoria din figura 1 trebuie s ă suporte opera țiile de citire, scriere și idle.
Deoarece memoria este alc ătuit ă dintr-o singur ă loca ție, aceasta va primi o singur ă adres ă procesor. Să
presupunem c ă aceast ă adresa este a. Când procesorul va accesa adresa a, fie pentru scriere, fie pentru
citire, pe magistrala de adrese va apare adresa a. Blocul logic „==a” din figura 1 va genera semnalu l EQa#
care va fi activ (‚0’ logic) atunci când pe magist rala de adrese este prezenta combina ția a. Din punct de
vedere al implement ării, EQa# este func ția maxtermen a.
În cazul memoriei cu capacitatea de o loca ție din figura 1 scrierea datelor prezente pe magistrala de
date în registrului paralel – paralel se face prin activarea semnalului CLK_REG aplicat pe pinului CLK . Pe
de alt ă parte, când procesorul scrie la adresa a, pe magistrala de adrese apare combina ția a și semnalul WR#
devine activ. În implementarea din figura 1, când p e magistrala de adrese apare combina ția a, semnalul
EQa# devine activ. Tot ce trebuie f ăcut este s ă ad ăug ăm o poart ă care s ă sesizeze activarea simultan ă a lui
WR# și EQa# și ie șirea acestei por ți s ă o conect ăm la pinul CLK al registrului. Aceast ă poart ă este o poart ă
OR și are referin ța U3 în figura 1.
Pentru a citi datele din memoria de o loca ție trebuie s ă conect ăm ie șirile registrului paralel – paralel D0
D1
D2
D3
D7 D4
D5
D6 D2
D7 D4
D5 D3 D1
D6 D0 ADDRESS BUS
D[7:0] Memorie alcatuita
dintr-o singura locatie
Reg. P-P
OE_DRV# EQa#
VCC
U2 74LS541 OE
I0
I1
I2
I3
I4
I5
I6
I7 Y0
Y1
Y2
Y3
Y4
Y5
Y6
Y7 Q0 ==a Address
Decoder
U3
RD# WR#
WR# Addresses
PROCESSOR
RD#
Data CLK_REG 8x 3-state drivers U4
.
.
.
.
U1 74LS377 G
1D
2D
3D
4D
5D
6D
7D
8D 1Q
2Q
3Q
4Q
5Q
6Q
7Q
8Q CLK

2 la magistrala de date. Conectarea ie șirilor 1Q..8Q ale registrului la magistrala de date se face prin
intermediul a 8 repetoare 3-state grupate în circui tul U2. Când procesorul cite ște de la adresa a, pe
magistrala de adrese apare combina ția a și semnalul RD# devine activ. În implementarea din f igura 1, când
pe magistrala de adrese apare combina ția a, semnalul EQa# devine activ. Deci trebuie s ă ad ăug ăm o poart ă
care s ă sesizeze activarea simultan ă a lui EQa# și RD# și ie șirea acestei por ți s ă o conect ăm la pinul de
activare OE al repetoarelor 3-state. Aceast ă poart ă este o poart ă OR și are referin ța U4 în figura 1.
Este evident c ă o astfel de solu ție nu este practic ă deoarece num ărul de module folosite este enorm;
un bloc de memorie de 1Kx8 ar necesita 2048 de modu le plus logica de decodificare. Exist ă îns ă un mare
avantaj al acestei solu ții: datele înscrise în loca ția de la adresa a sunt disponibile în orice moment pe pinii Q
ai registrului și pot fi folosite în exterior, în diverse scopuri. În exemplul din figura 1 ie șirea 1Q a registrului
este folosit pentru a aprinde un LED.
Solu ția din figura 1 se poate aplica unui num ăr mic de adrese și rezolv ă problema gener ării de
informa ție în exteriorul sistemului . Mai mult, schema sugereaz ă cum se poate solu ționa problema citirii de
informa ție din exterior: se renun ță la conexiunile dintre ie șirile registrului (1Q..8Q) și intr ările driverului 3-
state (A0..A7), ca în figura 2:

figura 2
La fel ca în exemplul anterior, datele înscrise în loca ția de la adresa a vor controla starea anumitor
semnale: de exemplu, pot aprinde sau stinge LED-uri . În schimb citirea de la adresa a ne va permite accesul
la starea intr ărilor I0-I7 ale repetoarelor 3-state, nu la informa ția stocat ă în registrul paralel-paralel. De
exemplu, în urma execut ării instruc țiunii MIPS LW R1, a(R0) în R1 se va afla o copie a intr ărilor
I0..I7. În figura 2 intrarea I0 este folosit ă pentru citirea st ării unui contact. Citirea st ării unor contacte
mecanice este ideea ce st ă la baza realiz ării tastaturii.
Spre deosebire de o loca ție de memorie, în majoritatea cazurilor ceea ce scr iem la adresa a nu va fi
identic cu ceea ce citim de la adresa a: scriem în registru dar citim comutatore. Este evident c ă loca ția de ADDRESS BUS
D0
D2
D3
D4
D5 D1
D6
D7 D4
D5 D0
D2
D7 D1
D6 D3 CLK_REG
U2 74LS541 OE
I0
I1
I2
I3
I4
I5
I6
I7 Y0
Y1
Y2
Y3
Y4
Y5
Y6
Y7 Reg. P-P
EQa#
VCC U3
RD# WR#
8x 3-state drivers U4
.
.
.
.
U1 74LS377 G
1D
2D
3D
4D
5D
6D
7D
8D 1Q
2Q
3Q
4Q
5Q
6Q
7Q
8Q CLK
D[7:0] I1
Input Port Q0 OE_DRV# VCC SW1
WR# MEMORY
RD#
……….
0ADDRESS SPACE Mlast 1last a
MEMORY Output Port
.==a Addresses
PROCESSOR
Data

3 la adresa a nu se mai poate numi loca ție de memorie.
Defini ție: Loca țiile speciale folosite de ma șina Von Neumann pentru transferul datelor cu exteri orul se
numesc loca ții de intrare/ie șire sau, pe scurt, porturi procesor.
În general, în cadrul știin ței calculatoarelor, prin port se în țelege modalitatea prin care o entitate
(bloc sau modul) comunic ă cu exteriorul . De exemplu, dac ă entitatea este un calculator personal, porturile
acestuia sunt porturile USB, seriale, paralele sau PS2. În unele cazuri portul nu implic ă neap ărat un
dispozitiv fizic: la re țele întâlnim no țiune de port TCP.
Dac ă entitatea este un procesor se aplic ă defini ția 1, adic ă un port este o loca ție folosit ă pentru
transferul I/O.
Porturile procesor se clasific ă dup ă cum urmeaz ă:
• Porturi buffer . Un port buffer este o loca ție folosit ă pentru transferul informa ției spre exterior .
Informa ția scris ă în acest tip de port poate fi ulterior citit ă. În exemplul din figura 1 este prezentat un port
buffer.
• Porturi de ie șire . Un port de ie șire este o loca ție folosit ă pentru transferul informa ției spre exterior .
Informa ția scris ă în acest tip de port nu mai poate fi citit ă ulterior. În exemplul din figura 2 registrul
paralel-paralel formeaz ă un port de ie șire.
 Porturile de ie șire con țin elemente de memorare. Un port de ie șire se poate implementa cu un registru
paralel – paralel, paralel-serie sau cu un singur b istabil.
 Înscrierea datelor în loca ția a se face cu o instruc țiune de tipul SW Rt, offset(RS) la MIPS sau
OUT adr_port_out, AL la 80×86.
 Citirea unui port de ie șire nu are sens deoarece lipsesc repetoarele 3-stat e, dar aceast ă opera ție este
posibil ă. Citirea unui port de ie șire va conduce la rezultate imprevizibile deoarece nici un dispozitiv
fizic nu va fi selectat ca urmare a execut ării acestei instruc țiuni.
• Porturi de intrare. Un port de intrare este o loca ție folosit ă pentru transferul informa ției din afara
procesorului. În exemplul din figura 2 repetoarele 3-state formeaz ă un port de intrare.
 Porturile de intrare con țin repetoare 3-state (una sau mai multe).
 Citirea datelor din loca ția a se face cu o instruc țiune de tipul LW Rt, offset(RS) la MIPS sau
IN AL, adr_port_in la 80×86
 Scrierea unui port de intrare nu are sens deoarece lipsesc elementele de memorare, dar aceast ă
opera ție este posibil ă. Scrierea unui port de intrare nu va avea nici un efect.

2. Decodificarea porturilor
Dac ă un port este privit ca o memorie alc ătuit ă dintr-o singur ă loca ție, decodificarea porturilor se
face dup ă acelea și reguli ca decodificarea modulelor de memorie. Dec odificarea complet ă se aplic ă și la
porturi.
Mai întâi vom analiza consumul de resurse pentru de codificarea complet ă a portul buffer din figura
1. Acest port a primit adresa procesor a. Așa cum s-a ar ăta anterior EQa# este func ția maxtermen a. Dac ă
lățimea magistralei de date este 16 iar valoarea lui a este 0xC000, maxtermenul 0xC000=0b1100 0000 0000
0000 are urm ătoarea form ă:

4 EQa# = M0xC000= 0123456789 10 11 12 13 14 15 AAAAAAAAAAAAAAAA +++++++++++++++
Implementarea lui CE# necesit ă o poart ă OR cu 16 intr ări plus dou ă inversoare.
De obicei, o aplica ție necesit ă aproape întotdeauna mai mult de un singur port. În continuare vom
considera un exemplu în care se implementeaz ă 4 porturi de ie șire și 4 porturi de intrare.
Începem cu porturile de ie șire. Solu ția de implementare pentru un port de ie șire se va repeta de 4 ori.
Cele 4 porturi de ie șire se por mapa la adresele 0xC00 0, 0xC00 1, 0xC00 2 și 0xC00 3. Cele 4 func ții EQx#
vor fi func țiile maxtermen corespunz ătoare și se vor implementa dup ă cum urmeaz ă:
0123456789 10 11 12 13 14 15 0123456789 10 11 12 13 14 15 0123456789 10 11 12 13 14 15 0123456789 10 11 12 13 14 15
003 0#003 _002 0#002 _001 0#001 _000 0#000 _
AAAAAAAAAAAAAAAA xC M CEQ AAAAAAAAAAAAAAAA xC M CEQ AAAAAAAAAAAAAAAA xC M CEQ AAAAAAAAAAAAAAAA xC M CEQ
+++++++++++++++= =+++++++++++++++= =+++++++++++++++= =+++++++++++++++= =

Schema celor 4 porturi de ie șire plus logica de decodificare este prezentat ă în figura urm ătoare:

figura 3
Implementarea func țiilor EQC000..3# (indiferent de tehnologie, circuit e MSI sau logic ă programabil ă)
necesit ă destul de multe resurse: 4 func ții OR cu 16 intr ări și 4 func ții NOT. Complexitatea implement ării
din figura 3 poate fi redus ă dac ă partea comun ă a celor trei 4 func ții EQ# se implementeaz ă o singur ă dat ă.
Partea comun ă se va numi CF# și are urm ătoarea form ă:
23456789 10 11 12 13 14 15 # AAAAAAAAAAAAAACF +++++++++++++=
Dac ă folosim CF# în formele celor 4 func ții EQ#, ob ținem: A[15:0]
D[7:0]
OUTSIDE WORLD DATA BUS
U2 74HCT374
D(7..0) 1Q
2Q
3Q
4Q
5Q
6Q
7Q
8Q CLK ADDRESS BUS CLK_REG0
U3 74HCT374
D(7..0) 1Q
2Q
3Q
4Q
5Q
6Q
7Q
8Q CLK
U4 74HCT374
D(7..0) 1Q
2Q
3Q
4Q
5Q
6Q
7Q
8Q CLK
U5 74HCT374
D(7..0) 1Q
2Q
3Q
4Q
5Q
6Q
7Q
8Q CLK U6 ==C000
EQC000#
CLK_REG1 U7 ==C001
EQC001#
CLK_REG2 U8 ==C002
EQC002#
CLK_REG3 U9 ==C003
EQC003#
WR# PROCESSOR
RD# Data Addresses

5 01010101
# 003 0#003 # 002 0#002 # 001 0#001 # 000 0#000
AACF xC M EQC AACF xC M EQC AACF xC M EQC AACF xC M EQC
++= =++= =++= =++= =

Combin ăm func țiile EQ# cu WR# pentru a ob ține semnalele de scriere CLK_REG0… CLK_REG3:
# ###003 #_ :, 3# ###002 #_:, 2# ###001 #_ :, 1# ###000 #_ :, 0
01 101 201 101 0
WR AACF WR EQC REG CLK output Port WR AACF WR EQC REG CLK output Port WR AACF WR EQC REG CLK output Port WR AACF WR EQC REG CLK output Port
+++=+ =+++=+ =+++=+ =+++=+ =

Forme CLK_REG sunt implementate în blocul ADDR.DEC 1 din figura 4. La examen, nu se cere o anumit ă
implementare a SLC-urilor (cu por ți, cu DEC, cu MUX, cu PLD) deoarece implementarea f unc țiilor logice
nu face obiectul acestui curs. Este suficient s ă se figureze un bloc cum este ADDR.DEC1 și s ă se specifice
formele func țiilor implementate în acel bloc.

figura 4
În figura 3 și figura 4 desenarea s-a f ăcut folosind tehnica de comprimare detaliat ă în prelegerea1. La
examen se va folosi numai aceast ă tehnic ă. În cazul porturilor se remarc ă o diferen ța fa ță de memorii:
comprimarea nu se aplic ă semnalelor prin care porturile comunic ă cu lumea exterioar ă, deoarece fiecare
semnal are o alt ă semnifica ție.
Complexitatea implement ării depinde de CF#: cu cât CF# depinde de mai multe adrese, cu atât
func țiile CLK_REG0..3# vor depinde de mai pu ține adrese. Cea mai simpla implementare se ob ține când
porturile se plaseaz ă ca o memorie cu 2k loca ții, unde 2k este cel mai mic num ăr mai mare sau egal cu p,
unde p este num ărul de porturi care se mapeaz ă. De exemplu, dac ă p=5 atunci 2 k=8. Maparea celor 5 porturi
se va face începând cu prima adres ă dintr-un bloc de 8 adrese, adic ă o adresa multiplu de 8.
Ultima parte a exemplului const ă în implementarea a 4 porturi de intrare. Schema ce lor 4 porturi de A11 A12 A13
A9 A10
A6 A7 A8
A2 A3 A5 A14
A4 A15 A[15:0]
CF#
WR#
A1
A0
D[7:0]
OUTSIDE WORLD DATA BUS
U2 74HCT374
D(7..0) 1Q
2Q
3Q
4Q
5Q
6Q
7Q
8Q CLK ADDRESS BUS CLK_REG0
U3 74HCT374
D(7..0) 1Q
2Q
3Q
4Q
5Q
6Q
7Q
8Q CLK
U4 74HCT374
D(7..0) 1Q
2Q
3Q
4Q
5Q
6Q
7Q
8Q CLK
U5 74HCT374
D(7..0) 1Q
2Q
3Q
4Q
5Q
6Q
7Q
8Q CLK CLK_REG1
CLK_REG2
CLK_REG3
WR# PROCESSOR
RD# Data Addresses
ADDR.DEC 1 CF#
Y1
Y2
Y3 WR#
A1
A0 Y0 U1

6 intrare plus logica de decodificare este prezentat ă în figura urm ătoare:

figura 5
Schema din figura 4 și schema din figura 5 sunt par ți ale aceleia și scheme. Cele dou ă scheme nu au
fost desenate împreun ă din considerente de spa țiu. Semnalele din cele dou ă scheme sunt conectate prin
nume: A[15:0] din figura 4 este conectat cu A[15:0] din figura 5, D[7:0] din figura 4 este conectat cu D[7:0]
din figura 5, CF# cu CF#, etc.
Implementarea semnalelor de citire OE_TSD i# este foarte asem ănătoare cu implementarea semnale
de scriere CLK_REG i, doar c ă în loc de WR# se folose ște RD#. De aceea formele pentru
OE_DRV0#…OE_DRV3# se ob țin din formele pentru CLK_REG0.. CLK_REG3 înlocuind WR# cu RD#.
Dup ă înlocuire ob ținem urm ătoarele forme:
Port 0, Input: 01 0 ###_ AARD CF DRV OE +++=
Port 1, Input: 01 1 ###_ AARD CF DRV OE +++=
Port 2, Input: 01 2 ###_ AARD CF DRV OE +++=
Port 3, Input: 01 3 ###_ AARD CF DRV OE +++=
Aceste forme sunt implementate în blocul ADDR.DEC2 din figura 5.
Deoarece spa țiul în care se face maparea celor 4 porturi de intr are este acela și spa țiu în care s-a f ăcut
maparea porturilor de ie șire, ambele blocuri de decodificare folosesc acela și CF#.
Aten ție: De și atât un port de OUT cât și un port de IN au aceea și adres ă, acestea se selecteaz ă ca urmare a
executării unor instruc țiuni diferite. În faza de execu ție instruc țiunea SW R1, 0xC000(R0) provoac ă scrierea
în portul de OUT cu referin ța U2 în figura 4 a con ținutului registrului R1 iar instruc țiunea LW R1,
0xC000(R0) provoac ă înscrierea în R1 a informa ției din exterior citite prin intermediul portului d e IN cu
referin ță U9 în figura 5. Deoarece selec ția oric ărui port de OUT se face când semnalul de control WR # = ‚0’
iar selec ția oric ărui port de IN se face când semnalul de control RD# = ‚0’, rezult ă ca un port de OUT nu se
poate selecta niciodat ă simultan cu un port de IN, chiar dac ă au alocat ă aceea și adres ă procesor.
În exemplele din prelegerea 1 s-a construit un bloc de memorie alc ătuit din dou ă memorii: un modul
EPROM și unul de tip SRAM. Aceste module au fost decodific ate complet. Harta memoriei ob ținut ă în urma U7
74HCT541 OE1 1
OE2 19
A0 2
A1 3
A2 4
A3 5
A4 6
A5 7
A6 8
A7 9Y(7..0) U8
74HCT541 OE1 1
OE2 19
A0 2
A1 3
A2 4
A3 5
A4 6
A5 7
A6 8
A7 9Y(7..0) U9
74HCT541 OE1 1
OE2 19
A0 2
A1 3
A2 4
A3 5
A4 6
A5 7
A6 8
A7 9Y(7..0) U6
74HCT541 OE1 1
OE2 19
A0 2
A1 3
A2 4
A3 5
A4 6
A5 7
A6 8
A7 9Y(7..0) CF#
D[7:0]
OUTSIDE WORLD DATA BUS OE_DRV3# ADDRESS BUS
OE_DRV1# OE_DRV0#
OE_DRV2# ADDR.DEC 2 CF#
Y2
Y1
Y0 RD#
A1
A0 Y3 A1
RD# A0 A[15:0]

7 decodific ării complete este reluat ă în tabelul urm ător, coloana „Decodificare complet ă”.
Decodificare
complet ă Decodificare
complet ă cu
porturi

C003 – FFFF

Nealocat

Nealocat
C000 –C003
4 porturi
A000 – BFFF Nealocat
8000 – 9FFF
SRAM SRAM

1000-7FFF

Nealocat

Nealocat
0000 – 0FFF EPROM EPROM
Maparea celor 4 porturi de ie șire din figura 3 v ăzute ca o memorie cu 4 loca ții se face în spa țiul de adrese
0xC000 – 0xC003. Dup ă maparea porturilor harta memorie este cea din colo ana „Decodificare complet ă cu
porturi”.

Controlere și interfe țe de I/O
Pentru a mic șora num ărul de module necesare implement ării
porturilor acestea se grupeaz ă în interfe țe de intrare/ie șire (IN/OUT
sau I/O). O interfa ță de I/O este alc ătuit ă din mai multe porturi de
diverse tipuri, logica de decodificare plus logica aferent ă activit ății
specifice interfe ței și este implementat ă pe un singur chip.
Interfa ța va fi prev ăzut ă cu CE#, RD# și WR#, pini de adres ă
și pini de date, la fel ca un modul de memorie. Cone ctarea cu
procesorul se face la fel ca pentru modulele de mem orie.
Suplimentar, interfe țele de I/O au terminale (pini) specifice func ției
pe care o îndeplinesc. Aceste terminale pot fi de i ntrare, de ie șire sau
bidirec ționale. Vom lua drept exemplu interfa ță serial ă asincron ă
(UART) deoarece acesta a fost sau va fi studiat ă la cursul
„Comunica ții de date”. Interfa ță serial ă este dotat ă cu pini specifici
ca TxD, RxD, CTS, RTS, etc. În figura 6 este prezen tat ă schema de
principiu a unei interfe țe de I/O.
Din punct de vedere al procesorului interfe țele de I/O func ționeaz ă la fel ca modulele de memorie, adic ă
execut ă opera țiile de citire , scriere și idle. Exist ă o deosebire: în starea IDLE con ținutul tuturor loca țiilor de
memorie r ămâne neschimbat pe când con ținutul porturile din interiorul interfe țelor de de I/O se poate
modific ă sau nu în func ție de activitatea specific ă modulului. De exemplu, la o interfa ță serial ă se
recep ționeaz ă un caracter ce este memorat în registrul de recep ție al interfe ței. Am-1
Dn-1 …….
A1
A0
WR# RD# CS# D1
D0 .ADDRESS LINES DATA LINES.
.
.IN OUT IO

figura 6

8 Majoritatea interfe țelor con țin urm ătoarele 3 porturi:
• Date . Porturile de date sunt folosite de procesor pentr u a schimba informa ție cu exteriorul. De regul ă
o interfa ță este prev ăzut ă cu un port de date de OUT și un port de date de IN.
Interfa ță serial ă are dou ă astfel de porturi: portul de date de transmisie și portul de date de recep ție.
Portul de date de transmisie este un registru paral el – serie în care procesorul scrie data care trebu ie
transmis ă. Logica intern ă a interfe ței detecteaz ă scrierea acestui port și declan șeaz ă automat opera ția
de serializare.
Logica de recep ție monitorizeaz ă pinul RxD (pe care se face recep ția datelor), detecteaz ă începutul
recep ției și apoi memoreaz ă bi ții primi ți serial într-un registru serie – paralel. Acest re gistru este
portul de date de recep ție.
• Control. Portul de control se folose ște pentru configurare. Portul de control este întot deauna port de
OUT. Transmisia serial ă se poate face în mai multe moduri: se pot alege nu m ărul de bi ți de stop,
paritatea, viteza de transmisie. Toate aceste infor ma ții de configurare se scriu in portul de control.
• Stare . Portul de stare se folose ște pentru monitorizarea activit ății interne a interfe ței. Portul de stare
este întotdeauna port de IN. În cazul interfe ței seriale recep ția înseamn ă memorarea bi ții primi ți serial
într-un registru serie – paralel. Cum știe software-ul c ă s-a recep ționat o data? Dup ă terminarea
recep ției logica intern ă a interfe ței seteaz ă un bit in portul de stare. Acest port este citit d e software și
astfel acesta va ști c ă s-a recep ționat o dat ă. Citirea datei din portul de date reseteaz ă automat acest
bit.
Defini ții:
• Controler: Circuitele care controleaz ă fluxul de date între un periferic și microsistem formeaz ă
controlerul acelui periferic . Aceste circuite includ resursele necesare cupl ării la magistralele
microsistemului. Resursele necesare cupl ării la magistralele microsistemului sunt constituit e din
porturile de date, de stare, de control și logica de selec ție a acestor porturi. Termenul de controler se
folose ște pentru periferice, în rest folosindu-se termenul de interfa ță . Pentru tastatur ă vom avea
controler de tastatur ă iar pentru o conexiune serial ă vom avea interfa ță serial ă.
• Driver: Secven ța de instruc țiuni prin intermediul c ăreia se gestioneaz ă traficul de date cu un
periferic se nume ște driver .

3. Arhitectura hardware-software a unei aplica ții cu microprocesor
Procesorul a fost inventat de Ted Hoff la Intel. C iti ți cum a fost inventat microprocesotul în
prelegerea 0.
În continuare vom detalia ideea lui Ted Hoff privit or la contractul cu Busicom: în loc s ă se proiecteze
12 chipuri diferite, s ă se proiecteze un singur chip prev ăzut cu utilit ăți generale de calcul ce poate emula cele
12 chipuri (vezi curs 0). Intel a proiectat o ma șina Von Neumann (un procesor) și a implementat-o pe un
singur chip de siliciu. În jurul acestui procesor s e construie ște un sistem de calcul cu arhitectura de principiu
din figura 7:

9
figura 7
Microsistemul este prev ăzut cu dou ă porturi de intrare de un bit și un port de ie șire, tot de un bit. Porturile de
intrare sunt la adresele a1 și a2 iar cel de ie șire la adresa a3. Acest microsistem execut ă urm ătorul program,
care se traduce în cod ma șin ă și se înscrie în memoria ROM:
–varianta în asamblare MIPS:
again:LW R1, a1(R0)
LW R2, a2(R0)
AND R1, R1, R2
SW R1, a3(R0)
J again –varianta în C:
#include ……
#define a1 0x0100
#define a2 0x0101
#define a3 0x0102

int main(){
char i1,i2,val;

while(1){
i1=inportb(a1);
i2=inportb(a2);
val=i1 & i2;
outportb( a3, val);
}
}
Microsistemul care ruleaz ă acest program se comport ă exact ca o poart ă AND. De remarcat c ă spre
deosebire de o poart ă AND real ă, întârzierea por ții AND „soft” ( emulat ă) este mult mai mare, fiind egal ă cu
timpul de execu ție al buclei „while(1)”. O poart ă AND real ă are o întârziere de ordinul nanosecundelor pe
când o poart ă soft are o întârziere de ordinul microsecundelor. Dac ă aplica ția în care se folose ște o astfel de
poart ă admite o astfel de întârziere, aceast ă solu ție are un mare avantaj: func ționalitatea se poate
modifica doar prin schimbarea programului. Dac ă se dore ște o poart ă OR în loc de poarta AND, în
programul înscris în ROM se va înlocui
AND R1,R1, R2
cu
OR R1, R1, R2 .
Exemplu cu emularea unor por ți a fost ales numai din motive didactice. În realit ate nu are sens s ă
folosim un întreg microsistem ca s ă emul ăm o singur ă poart ă. Dar dac ă m ărim num ărul de porturi și scriem
un program cu aceea și structur ă, dar care face mai multe calcule, putem emula oric e bloc logic sau aritmetic
fără s ă fie nevoie s ă folosim logic ă MSI (por ți, sumatoare, DEC, MUX, bistabile, registre, num ărătoare, etc.)
Aceasta însemna c ă inteligen ța poate fi înglobat ă în aplica ție prin intermediul software-ului, în loc s ă fie
“cablat ă” în hardware. Astfel se salveaz ă atât timp cât și bani. Procesor pe un singur chip proiectat de Int el RD#
WR#
Data Addresses
PROCESSOR ==a1
&&
RD#='0'Address Bus
TI1
D0 SLC
==a2
&&
RD#='0'I2
SLC
ROM
Memory RAM
Memory RD#
WR#
T
D0
D[7:0] RD# RD#
D Q
FD Out D0
WR# ==a3
&&
WR#='0'

10 pentru Busicom s-a numit I4004.
Ideea emul ării func țiilor logice a condus la dispozitive specializate c are fac numai acest lucru. Un
astfel de dispozitiv se nume ște PLC (Programmable Logic Controler); în român ă se folose ște termenul de
automat programabil. În figura urm ătoare este prezentat un PLC „mini”, cu 8 intr ări și 4 ie șiri:

În prezent PLC-urile pot gestiona sute de intr ări și sute de ie șiri și dispun de limbaje proprii de programare.

4. Clasificarea microprocesoarelor
În prezent procesorul este implementat cu un singur circuit integrat. Un circuit integrat care
con ține numai procesorul se nume ște microprocesor.
În momentul apari ției microprocesorului densitatea mic ă de integrare a obligat ca un microsistem s ă
fie realizat multe module: microprocesor, memorii R OM, memorii RAM, interfe țe de I/O. Microsistemele
se realizau prin interconectarea acestor module, i ar configura ția (cât RAM, cât PROM, ce interfe țe)
depindea de destina ția microsistemului. Realizarea microsistemul în ace st mod ofer ă flexibilitate.
Ulterior, cre șterea densit ății de integrare a permis realizarea unui microsiste m pe un singur chip. Un
astfel de chip, în func ție de complexitate, se nume ște fie microcontroler, fie SoC – System on a Chip și
aste alc ătuit din procesor, ROM, RAM, num ărătoare programabile, interfe țe seriale, porturi de I/O,
multiplexoare analogice, DAC, ADC, PWM, toate pe ac ela și circuit integrat. Microcontrolerele sunt
arhitecturi de complexitate mic ă: tipic, un microcontroler con ține un procesor pe 8 sau 16 bi ți cu frecven ță
ceasului de ordinul zecilor de MHz, câ țiva KB de RAM, câ țiva zeci de KB de flash ROM și cost ă $2 – $10.
În schimb un SoC con ține un procesor pe 32 de bi ți cu frecven ță ceasului de ordinul sutelor de MHz pân ă la
1GHz, GPU, sute de KB de ROM și RAM și cost ă zeci de dolari.
Apari ția microcontrolelor a f ăcut ca problema interconect ării modulelor aproape s ă dispar ă. Totu și
microcontrolerele sunt arhitecturi rigide și de multe ori apare necesitatea unor extensii. De cele mai multe ori
memoria RAM este insuficient ă. În acest caz unele microcontrolere admit conectar ea de modulele
suplimentare în exterior iar interconectarea r ămâne în sarcina proiectantului. Ast ăzi microcontrolerele sunt
prezente în televizoare, cuptoare cu microunde, ma șini de sp ălat, automobile și multe altele.
În 1974 Ed Roberts a construit Altair bazat pe micr oprocesorul Intel 8080. Interpretorul de BASIC
pentru Altair a fost scris de Bill Gates și Paul Allen (vezi curs 0) demonstrând astfel c ă microprocesorul
poate fi folosit și pentru construirea de sisteme de calcul de uz gen eral, nu numai pentru emulare.
Procesoarele care au ap ărut dup ă I8080 (I8086, I80186, I80286, I80386, I486, Pentiu m) au dus la construirea
de calculatoare personale a șa cum le știm ast ăzi. Procesoarele destinate sistemelor de calcul de uz general au
performante deosebite, dar și un pre ț pe m ăsur ă. Astfel de procesoare se numesc procesoare de uz general .

11 În afar ă de procesoarele de uz general și de sistemele încorporate mai exist ă înc ă dou ă familii de
procesoare: de tip DSP (Digital Signal Processors) și de re țea ( Network Processors ).

5. Spa ții de adres ă procesor.
Un criteriu de clasificare a procesoarelor îl const ituie tipul spa țiului de adres ă. Conform modelului
Von Neumann spa țiul de adrese procesor este omogen. O adres ă din spa țiu de adrese poate fi alocat ă unei
loca ții de memorie sau unui port. Procesorul nu poate distinge natura loca ției. Folosirea unei adrese
pentru loca ție de memorie sau pentru port este l ăsat ă la latitudinea proiectantului de sistem.
Aceast ă solu ție se nume ște MAPPED I/O sau von Neumann . Denumirea provine de la urm ătoarea
observa ție: în orice sistem de calcul num ărul adreselor alocate pentru memorarea datelor va f i întotdeauna
mult mai mare decât num ărul celor folosite pentru transferul I/O. Senza ția provocat ă este aceea c ă ini țial tot
spa țiul exterior a fost conceput pentru memorarea datel or și apoi o mic ă parte din el a fost deturnat ă de la
scopul ini țial, fiind folosit ă pentru transferuri I/O. Sau, cu alte cuvinte spa țiul, de I/O a fost proiectat (mapat)
în spa țiul de memorie. Schema bloc a unui astfel de sistem este prezentat ă în prelegerea 1, figura 2.
Transferurile care se fac între procesor și memorie sunt de tip citire loca ție și scriere loca ție:
Pentru un transfer de tip citire loca ție de memorie informa ția vehiculat ă pe cele trei magistrala este:
 pe magistrala de adrese, adresa loca ției implicate în transfer;
 pe magistrala de date, datele furnizate de loca ție;
 pe magistrala de control se precizeaz ă c ă transferul este de tip citire (RD# = 0, WR#=1).
iar pentru un transfer de tip scriere loca ție de memorie este:
 pe magistrala de adrese, adresa loca ției implicate în transfer;
 pe magistrala de date, datele furnizate de procesor ;
 pe magistrala de control se precizeaz ă c ă transferul este de tip scriere (WR# =0, RD#= 1).
Aceast ă solu ție prezint ă avantaje și dezavantaje.
Avantaj: atât transferurile I/O cât și transferurile cu memoria folosesc acela și set de instruc țiuni
(instruc țiuni puternice, cu multe moduri de adresare).
Dezavantaje: Un prim dezavantaj , apare ca urmare a faptului c ă procesorul nu poate distinge
natura loca ției, memorie sau port. Poate dezavantaj este mult s pus, mai potrivit fiind complica ție. Aceasta
complica ție are consecin țe la nivel HLL iar solu ția a dus la apari ția cuvântului volatile în limbajele C, C++,
C# și Java.
Pentru a în țelege exact în ce const ă problema s ă consider ăm urm ătorul exemplu: s ă presupunem c ă
adresa a din figura 2 are valoarea 0x1234. Un procesor RISC cu spa țiu omogen de adrese va accesa orice
loca ție de memorie cu instruc țiuni de tip LW și SW cum ar fi LW Rt, 0x1234(R0) sau SW Rt, 0x1234(R0) .
Cum acces ăm loca ția de la adresa 0x1234 în C? Din p ăcate nu exist ă nici o modalitate s ă-i spume
compilatorului s ă plaseze o variabil ă la o adres ă anume. În C putem îns ă s ă acces ăm loca ția de la adresa
0x1234 prin intermediul unui pointer pe care îl ini țializ ăm cu 0x1234:
unsigned char * Port_in = ( unsigned char *) 0x1234;
unsigned char Port_val;

Port_val = *Port_in;
În figura 2 pe bitul 0 al portului de intrare este conectat comutatorul SW1. S ă presupunem în continuare c ă
trebuie s ă a ștept ăm cât timp cât comutatorul este închis, adic ă atâta timp cât bitului 0 din portul de la adresa
0x1234 este ‚0’- logic:

12 while ( (*Port_in & 1) == 0) {}
Compilatorul traduce bucla while in urm ătoarea secven ță în asamblare MIPS:
rep:
LW R1, 0x1234(R0)
ANDI R1, R1, 1
BEQ R1, R0, rep
Dar compilatorul optimizeaz ă codul. Sunt posibile urm ătoarele tipuri de optimiz ări:
• păstreaz ă variabile in registre.
• elimin ă accesele redundante la memoria principal ă.
• schimb ă ordinea atribuirilor.
Prin optimizarea transferurilor cu memoria, codul a nterior se transform ă astfel:
LW R1, 0x1234(R0)
ANDI R1, R1, 1
rep : BEQ R1, R0, rep
Compilatorul știe c ă o loca ție de memorie nu se poate modifica dac ă nu este scris ă, a șa c ă este
suficient s ă o citeasc ă o singur ă dat ă. Dac ă bitul 0 este ‘0’ logic se va intra în bucl ă infinit ă iar dac ă nu, va
continua în secven ță .
Dar loca ția de la adresa 0x123 este de fapt un port de intra re! Porturile de intrare î și pot schimba
valoarea în orice moment în func ție de lumea exterioar ă! Compilatorul îns ă nu știe ca exist ă porturi. În
modelul von Neumann nu exist ă porturi! Solu ția este să-i spunem compilatorului ca loca ția de la adresa
0x1234 poate s ă-și schimbe valoarea în orice moment, f ără s ă fie scris ă de procesor. Pentru aceasta in C,
C++, C# și Java exist ă cuvântul rezervat volatile . Opera țiile cu o variabil ă declarat ă volatile nu se
optimizeaz ă, așa c ă în codul ma șin ă rezultat va apare prima variant ă, cea neoptimizat ă. Tot ce avem de f ăcut
este ca declara ția:
unsigned char * Port_in = ( unsigned char *) 0x1234;
să se rescrie ca:
volatile unsigned char * Port_in = ( unsigned char *) 0x1234;
Variabilele declarate cu volatile nu sunt optimiza te de compilator!
Declara ția anterioar ă cu volatile declar ă un pointer la o variabil ă volatil ă. Exist ă declara ții și pentru
un pointer volatil la o variabila nevolatil ă cât pentru un pointer volatil la o variabil ă volatil ă dar aceste
situa ții nu prezint ă interes.
În exemplul anterior pentru a accesa loca ția cu adresa 0x1234 s-a folosit, din motive de cla ritate, un
pointer cu valoare constant ă. Se poate îns ă și f ără pointer astfel:
while ( (( *(volatile unsigned char *) 0x1234) & 1) == 0) {}
Codul precedent este confuz datorit ă num ărului mare de paranteze. Putem scrie un cod mai cla r dac ă
folosim #define:
#define Port_in_def ( *(volatile unsigned char *)0x1234 );

while ( (Port_in_def & 1) == 0) {}
Pentru accesul la porturi varianta cu define este p referat ă.
În cele discutate mai sus s-a ar ătat că în cazul spa țiului omogen de memorie procesorul nu poate

13 detecta dac ă la o adresa se afl ă un port sau o loca ție de memorie, ceea ce constituie o complica ție în HLL. Al
doilea dezavantaj al variantei von Neumann const ă în faptul c ă num ărul de adrese de memorie este
diminuat. Acest fapt nu constituie o problem ă pentru procesoarele cu spatii de adres ă mari, de 4G adrese, dar
poate crea inconveniente dac ă spa țiul este de numai 64KB.
Pentru a m ări spa țiul de adrese a fost imaginat ă o solu ție care presupune dou ă spa ții de adres ă : un
spa țiu de adrese pentru memorare și un spa țiu pentru I/O . În acest caz adresa cap ătă un atribut: de memorie
sau de I/O. Pentru a preciza natura adresei se intr oduce un semnal de separare, semnal ce apar ține
magistralei de control. Acest semnal se poate numi de exemplu M/IO#, ca în figura 8:
Processor Memory
(code + data)
M/IO#=1
Ports
M/IO#=0 Address Bus
Data Bus
RD# M/IO#
WR#

figura 8
Procesorul presupune c ă la fiecare adres ă se afl ă dou ă loca ții: una de memorie și una de I/O (un port). La o
adres ă se pot efectua cele dou ă opera ții: scriere sau citire. Vor exista astfel patru tip uri de transfer.
Informa ția vehiculat ă pe cele trei magistrala pentru fiecare transfer es te :
Transfer de tip citire loca ție de memorie :
 pe magistrala de adrese, adresa loca ției de memorie implicate în transfer;
 pe magistrala de date, datele furnizate de loca ție;
 pe magistrala de control se precizeaz ă că transferul este de tip citire loca ție de memorie: M/IO# =’1’,
RD# = ‚0’, WR# = ‚1’
Transfer de tip scriere loca ție de memorie :
 pe magistrala de adrese, adresa loca ției de memorie implicate în transfer;
 pe magistrala de date, datele furnizate de procesor ;
 pe magistrala de control se precizeaz ă c ă transferul este de tip scriere loca ție de memorie:
M/IO# =’1’, RD# = ‚1’, WR# = ‚0’
Transfer de tip citire loca ție de I/O (port) :
 pe magistrala de adrese, adresa portului implicat în transfer;
 pe magistrala de date, datele furnizate de loca ție;
 pe magistrala de control se precizeaz ă c ă transferul este de tip citire port: M/IO# =’0’, R D# = ‚0’,
WR# = ‚1’
Transfer de tip scriere port :
 pe magistrala de adrese, adresa portului implicat în transfer;
 pe magistrala de date, datele furnizate de procesor ;
 pe magistrala de control se precizeaz ă c ă transferul este de tip scriere port: M/IO# =’0’, R D# = ‚1’,
WR# = ‚0’
Existen ța celor 2 spa ții presupune existen ța a dou ă seturi de instruc țiuni: un set pentru memorie și un set
pentru porturi. De regul ă instruc țiunile pentru porturi sunt mai slabe decât cele pen tru memorie, ceea ce
constituie un dezavantaj. Pentru lucru cu porturi a rhitectura 80×86 are numai 4 instruc țiuni! Instruc țiunile

14 pentru porturi se numesc IN, OUT, MOVX, etc. Toate celelalte instruc țiuni (LW, SW, MOV, ADD, MUL,
etc.) sunt pentru memorie. În faza de execu ție instruc țiunile pentru memorie fac pe M/IO# = ‚1’ iar cele
pentru porturile fac pe M/IO# = ‚0’. Avantajul ace stei solu ții, pe lâng ă cre ștere num ărului de adrese de
memorie, îl constituie u șurin ță cu care se protejeaz ă accesul la porturi în modul user. Încercarea de a executa
o instruc țiune de tip IN sau OUT în mod user va provoca o exc ep ție (vezi curs SO).
Observa ție: Existen ța celor 2 spa ții nu oblig ă în nici un fel utilizatorul s ă foloseasc ă spa țiul de memorie
numai pentru memorare și spa țiul de porturi numai pentru transfer I/O. Exist ă o multitudine de solu ții
practice posibile ca de exemplu:
− atât modulele de memorie cât și porturile sunt mapate în spa țiul de memorie iar spa țiul de I/O nu este
folosit;
− în spa țiul de memorie sunt mapate numai module de memorie iar în spa țiul de I/O se afl ă atât porturi cât
și module de memorie.
Întrebare: Mărirea spa țiului de adrese, conform acestei solu ții, presupune un nou pin de control, M/IO#. Nu
ar fi fost mai simplu s ă se adauge înc ă un pin de adres ă în loc de pinul de control M/IO#?
Mărirea spa țiului de adrese prin introducerea unui nou semnal d e control poate fi folosit ă pentru a
cre ște acest spa țiu de mai multe ori. Am v ăzut ca ad ăugarea unui nou semnal de control dubleaz ă spa țiul de
adrese. Dac ă s-ar introduce dou ă semnale de control spa țiul de adrese s-ar m ări de 4 ori. Un exemplu de
astfel de semnal este C#/D (CODE/DATA) care face di stinc ția între cod și date, a șa cum M/IO# f ăcea
distinc ția între memorie și IO.

Arhitectura HARVARD .
Spa țiul de adrese de memorie este destinat memor ării codului și datelor. Pentru cre șterea vitezei de
prelucrare acest spa țiu se poate diviza în spa țiu de adrese de cod și spa țiu de date. Astfel de arhitecturi sunt
prev ăzute cu dou ă seturi de magistrale: adrese, date, control pentru cod și adrese, date, control pentru spa țiu
de date. Aceast ă arhitectur ă este natural ă în cazul implement ărilor pipeline și este prezentat ă în figura 9.
Code Address Bus Data Address Bus
Data Bus Code Bus
RD# RDC# M/IO#
WR#

figura 9
Aceast ă solu ție permite implementarea pipeline a procesorului. Î n timp ce codul instruc țiunii în faza IF se
încarc ă folosind magistralele spa țiului de cod, transferul datelor generate de instru c țiunea în faza MEM se
face prin intermediul celuilalt set de magistrale. Arhitectura cu spa țiu de cod separat de spa țiu de date și cu
dou ă seturi de magistrale se nume ște arhitectur ă HARVARD. Un exemplu de astfel de procesor este MIP S.
În cazul arhitecturii Harvard apar trei tipuri de t ransferuri cu memoria:
Transfer de tip citire loca ție din memoria de date: este identic cu transferul cu acela și nume de la
arhitectura Von Neumann.

15 Transfer de tip scriere loca ție din memoria de date : este identic cu transferul cu acela și nume de la
arhitectura Von Neumann.
Transfer de tip citire loca ție din memoria de cod :
 pe magistrala de adrese a memoriei de cod, con ținutul num ărătorului de program
 pe magistrala de date a memoriei de cod, datele fur nizate de loca ție;
 pe magistrala de control a memoriei de cod se preci zeaz ă c ă transferul este activ (RDC# = 0).
Si în cazul arhitecturii Harvard este posibil ă dublarea spa țiului de date prin introducerea semnalului M/IO#
(figurat cu albastru în figura 9). Cele 4 organiz ări ale spa țiilor de adres ă procesor, detaliate anterior, sunt
prezentate în figura 10.
Spatiu omogen (Von Neumann)
CBUS: RD#, WR# ADDRESS 2 -1 p
ADDRESS 0 ADDRESS 1 .
.
.ADDRESS 2 -1 m
ADDRESS 2 -1 cADDRESS 0
ADDRESS 0 ADDRESS 1
ADDRESS 1 .
.
.
.
.
.ADDRESS 2 -1 c
ADDRESS 0 ADDRESS 1 .
.
.ADDRESS 2 -1 p
ADDRESS 0 ADDRESS 1 .
.
.
ADDRESS 2 -1 d
ADDRESS 0 ADDRESS 1 .
.
.ADDRESS 2 -1 p
ADDRESS 0 ADDRESS 1 .
.
.ADDRESS 2 -1 d
ADDRESS 0 ADDRESS 1 .
.
.Memorie
Cod Cod Porturi
Porturi Date Date CBUS: RD#, WR#, M/IO#
Modified Harvard
CBUS: RD#, WR#, D/C#, M/IO# Harvard
CBUS Code: RDC# (Read Code)
CBUS Data: RD#, WR# figura
10

6. Module master, module slave.
Din cele ar ătate pân ă acum rezult ă c ă un sistem de calcul va fi construit din mai multe module:
− pentru calcul : procesoare, coprocesoare. Procesorul implementat pe un singur circuit integrat (CI) se
nume ște microprocesor, pentru a-l distinge de procesorul implementat cu mai multe CI. Deoarece în
prezent nu mai exist ă procesoare implementate cu mai multe CI, denumiril e procesor și microprocesor
înseamn ă acela și lucru.
− pentru stocarea datelor : memorii ROM, PROM, EPROM, RAM etc.
− pentru transferul I/O : interfe țe seriale, paralele, video etc.
− pentru transferul datelor : DMA, procesoare de I/O.
− pentru calcul + transferul I/O: microcontrolere.
Fiecare modul îndepline ște o anumit ă func ție. Pentru a îndeplini respectiva func ție circuitul va avea o

16 anumit ă arhitectur ă intern ă: ALU, unitate de comand ă, registre interne. Aceast ă arhitectură trebuie cunoscut ă
pentru a putea programa respectivele module; progra marea se face de regul ă în limbaj de nivel înalt (C/C++)
și uneori în limbaj de asamblare.
Deoarece modulele sunt circuite integrate VLSI ace ste dou ă denumiri se pot folosi una în locul
celeilalte.
Pentru a realiza un sistem de calcul cu circuite VL SI apare necesitate interconect ării modulelor.
Interconectarea se face prin intermediul magistrale lor. Exist ă configura ții de sisteme de calcul cu magistral ă
unic ă sau cu mai multe magistrale. Practic aproximativ 9 0% din circuitele VLSI au fost concepute pentru
conectarea pe principiul magistralei unice.
Din punct de vedere al pozi ției fa ță de magistral ă, pe durata unui transfer, modulele se clasific ă în
module surs ă sau emi ță tor și module destina ție sau receptor.
Modulul surs ă este acel modul care dicteaz ă nivelele logice pe respectiva magistral ă (are conectate
ie șirile unor drivere sau por ți la magistral ă). Se mai spune c ă modulul surs ă depune informa ția pe magistral ă.
Pe durata unui transfer exist ă un singur modul surs ă!
Modul destina ție este acel modul care preia informa ția (are conectate intr ările unor drivere sau por ți
la magistral ă) și o vehiculeaz ă intern. Pe durata unui transfer, teoretic, ar pute a exista mai multe module
destina ție. Practic exist ă unul singur.
Din punct de vedere al ini țiativei transferului modulele se clasific ă în module master și module slave:
Modulul master este surs ă pentru magistralele de adrese și de control.
Modulul slave este destina ție pentru cele dou ă magistrale.
Exist ă module care sunt numai master (procesorul), module care sunt numai slave (memoria) și
module care pot fi la un moment dat master iar ulte rior slave (DMA).
In general, pentru a caracteriza un transfer, trebu ie precizat modulul master, modulul slave, sursa
datelor (cine este sursa pentru magistrala de date) cât și destina ția acestora. De exemplu, în transferul de tip
citire din memorie procesorul este master și destina ție a datelor iar memoria este slave și surs ă de date.

1
Microprocesoare, Microcontrolere –Prelegere 3

1. ATMEGA16
Una dintre cele mai populare familii microcontroler e este ATmega de la Atmel. În aceast ă
prelegere va fi prezentat un reprezentat al acestei familii, și anume ATmega16. În schema bloc din figura
1 se identific ă urm ătoarele blocuri:
• CPU pe 8 bi ți;
• 16KB memorie flash pentru program;
• 1KB octe ți de memorie RAM pentru date;
• 512 octe ți de memorie EEPROM
• 32 de linii I/O bidirec ționale adresabile individual sau în grupe de 8 (4 p orturi I/O);
• 3 num ărătoare programabile;
• USART full duplex;
• bloc de întreruperi cu 20 de surse de întrerupere;
• generator de ceas încorporat.

figura 1

Organizarea memoriei
Arhitectura AVR, din care face parte și ATmega16, este o arhitectur ă RISC de tip Hardvard. Astfel
ATmega16 este prev ăzut cu spa ții de adres ă separate pentru program și date, a șa cum se prezint ă în figura
2. ATmega16 este prev ăzut cu 3 tipuri de memorie: de cod, de date și EEPROM.
Memoria de program. ATmega16 con ține 16KB de memorie flash pentru memorarea programu lui.
Deoarece toate instruc țiunile AVR au o lungime de 16 sau 32 de bi ți, aceast ă memorie are organizarea
8Kx16.
Memoria de date SRAM. Memoria de date este accesat ă la nivel de octet și este organizat ă în 3 sec țiuni:
32 de registre generale, 64 de registre pentru tran sferurile de I/O (porturi) și 1024 de loca ții de RAM.
Acest spa țiu de memorie suport ă 5 moduri de adresare: direct, indirect, indirect c u deplasament, indirect
cu predecrementare și indirect cu postincrementare. Registrele R26 – R3 1 se cupleaz ă dou ă câte dou ă și
formeaz ă registrele duble (de 16 bi ți) X, Y și Z, folosite pentru adresarea indirect ă.

2
figura 2
Zona de memorie 0x0020-0x005f este alc ătuit ă din 64 de registre I/O. În aceast ă zon ă sunt mapate cele 4
porturi, registrele de control și stare aferente celor trei timere, interfe ței seriale, stack pointer și alte
resurse ce vor fi detaliate ulterior. Structura ace stei zone este prezentat ă în datele de catalog, la pagina
334.
O variant ă de ATmega16, și anume ATmega162, permite ad ăugarea de memorie de date în
exteriorul microcontrolerului. În momentul în care se plaseaz ă memorie în spa țiul extern de cod porturile
A și C se transform ă în magistrale de date și de adres ă.
Memoria EEPROM. Atmeg16 con ține 512 octe ți de memorie EEPROM.
Setul de instruc țiuni ISA.
Trece ți în revist ă modurile de adresare și instruc țiunile ATmega16, din datele de catalog. Descrierea
arhitecturii AVR este disponibil ă la adresa http://www.atmel.com/images/doc0856.pdf . De și setul de
instruc țiuni nu constituie subiect de examen, cunoa șterea lui este necesar ă pentru depanarea programelor.

2. Porturile A, B, C și D.
ATmega16 comunic ă cu exteriorul prin intermediul a 32 de pini organi za ți în 4 grupe notate A, B,
C și D. În fiecare grup ă sunt 8 pini numerota ți de la 0 la 7. Configura ția terminal ă a microcontrolerului
ATmega16 este prezentat ă în figura urm ătoare:

3
La proiectarea oric ărui microcontroler trebuie luat ă o decizie: câte porturi s ă fie de porturi de
ie șire și câte porturi de intrare. La aceast ă întrebare este foarte greu de r ăspuns deoarece depinde de
aplica ție: exist ă aplica ții în cere este nevoie de multe porturi de ie șire și pu ține porturi de intrare și
aplica ții în care este invers. Solu ția cea mai bun ă este s ă lăsăm utilizatorul s ă aleag ă cum s ă anume s ă fie
folosit un pin procesor: pentru ie șire sau pentru intrare. Solu ția de principiu este prezentat ă în figura
urm ătoare:

figura 3
La pinul PIN al microcontrolerului se poate conect a fie o ie șire, fie o intrare. Ie șirea este un bit
dintr-un port de tip buffer și este implementat cu o pereche bistabil-driver 3-s tate. Portul buffer este
prezentat în prelegerea 2- fig. 1 (mai pu țin LED-ul). Implementarea ie șirii este încercuit ă de un
dreptunghi albastru din figura 3. Referin ța bistabilului este U1_i iar cea a driverului 3-sta te este U2_i.
Intrarea este un bit dintr-un port de intrare impl ementat prin driver-ul 3-stare cu referin ța U5_i și
este încercuit de dreptunghiul verde din figura 3. Portul de intrare este prezentat în prelegere 2-fig . 2,
partea dreapt ă.
Comutatorul S1_i decide cine anume se cupleaz ă la pinul PIN al microcontrolerului: ie șire OUT
din portul buffer sau intrarea IN din portul de in trare. Acest comutator este un comutator electronic
DB[i] TU5_iD QU1_i
WR_OUT RD_OUT
RD_PIN DB[i] OUT
DB[i] Internal Data Bus DB[7:0] TU2_i
PIN
IN S1_i

4comandat. În figur ă S1_i a fost reprezentat ca un comutator mecanic pe ntru a-i eviden ția rolul. Semnalele
WR_OUT, RD_OUT și RD_PIN sunt generate de decodificatorul de adrese .
În continuare vom rafina decizia privitoare la num ărul de porturi de intrare și de ie șire. La
ATmega16 exist ă 32 de structuri ca cea din figura 3 grupate în 4 g rupuri de 8. Pentru o mai mare
flexibilitate fiecare comutator este comandat indiv idual în loc de o comand ă per grup de 8. O singur ă
comand ă per grup de 8 pini duce la doar 16 configura ții posibile: toate cele 4 grupe sunt porturi de ie șire
(OOOO), 3 porturi de ie șire și un port de intrare (OOOI), OOIO, OOII, …, IIII. O singur ă comand ă per
grup de 8 face imposibil ă o configura ție cu 20 de ie șiri și 12 intr ări. Configurarea individual ă a fiec ărui
pin face posibila orice configura ție de tip n ie șiri și 32-n intr ări (n=1..32).
Comanda comutatorului se face cu un bit dintr-un al treilea port. Acest port este de tip buffer și are
binecunoscuta structur ă bistabil – driver 3-state. Bitul din portul de com and ă este încercuit de un
dreptunghi ro șu în figura urm ătoare:

figura 4
In figura 4 în locul comutatorului cu dou ă c ăi s-a folosit un comutator cu o singur ă cale deoarece se
implementeaz ă mai simplu. Comutatorul cu o singur ă cale este un driver 3-state. Cu acest tip de
comutator portul de intrare este tot timpul conecta t la pin.
Toate cele 32 de structuri I/O sunt identice din pu ncte de vedere al func ției de baz ă și anume digital
I/O. Cele 32 de structuri sunt împ ărțite în 4 grupe de 8 bi ți deoarece la procesorul AVR l ățimea c ăii de
date este de 8 bi ți. Nu exist ă diferen țe hardware între grupe sau între membrii unui grupe . În figura 4 este
prezentat ă structura asociat ă pinului PX i. X este una din literele A, B, C sau D iar i este o cifra în
intervalul 0..7. Schema detaliat ă a acestei structuri este prezentat ă în capitolul 12 din documenta ția
ATmega16. Pentru fiecare pin exist ă îns ă și o func ție alternativ ă, func ție ce depinde de pin. În acest
moment nu vom trata func ția alternativ ă.
TU5_iS1_iD QU1_i
PXiRD_DAT_X
WR_DAT_X RD_DIR_X
WR_DIR_X DB[i]
DB[i]
RD_PINX
PORTX[i]
DB[i] DB[i] DDRX[i]
DB[i] Internal Data Bus DB[7:0]
PINX[i] TU4_i
D QU3_i
Di Do Synchro TU2_i

5Pinul PX i din figura 4 este controlat de dou ă porturi procesor de tip buffer și un port procesor de
intrare: PORTX i, PINX i și DDRX i.
• PORTX i este un bit dintr-un port procesor de tip buffer, a șa cum s-a discutat anterior. PORTX i
este semnalul OUT din figura 3.
• PINX i este un bit dintr-un port procesor de intrare. PIN X i este semnalul IN din figura 3. În
structura portului de intrare remarc ăm un bloc care nu apare anterior, și anume blocul de
sincronizare. Acest bloc are rolul de a reduce prob abilitatea de apari ție a fenomenului de
metastabilitate . Metastabilitatea a fost discutat ă la curs. Ceea ce trebuie re ținut este efectul
secundar al blocului de sincronizare și anume o întârzierea dou ă pulsuri de ceas a semnalului
aplicat pe pinul PX i. Mai precis, citirea pinului PX i nu genereaz ă valoarea curent ă a semnalului
aplicat pe acest pin, ci valoarea care era pe acest pin acum dou ă pulsuri de ceas.
• DDRX i este un port procesor de tip buffer și controleaz ă comutatorul S1_i din figura 4. DDR este
abrevierea lui Data Direction Register . Comutatorul S1_i este de fapt un driver 3-state d ar a fost
desenat ca un comutator pentru ca rolul sau s ă fie mai u șor de în țeles.
Semnalele WR_DAT_X, RD_DAT_X, WR_DIR_X, RD_DIR_X și RD_PIN sunt generate de
decodificatorul de adrese.
În prelegerea 2 s-a definit portul ca blocul prin c are o entitate comunic ă cu exteriorul. În cazul unui
microcontroler se pot eviden ția dou ă entit ăți: procesorul din interiorul microcontrolerul și
microcontrolerul însu și. Din acest motiv apar dou ă categorii de porturi: porturile procesor discutate în
prelegerea 2 și porturile microcontroler. Porturile procesor se v or mai numi registre IO iar denumirea de
porturi se va folosi cu prec ădere pentru porturile microcontroler. Porturile A, B, C și D ale
microcontrolerului se mai numesc porturi digitale i ar porturile PORTX, PINX și DIRX sunt porturi
procesor sau registre IO.
Fiind porturi buffer, PORTX și DDRX pot fi atât scrise cât și citite în orice moment. Deoarece
PINX este port de intrare are sens doar citirea ace stuia. În exemplele urm ătoare vom folosi portul digital
A format din PORTA, PINA și DDRA. Adresele de port (adic ă adresa folosit ă în instruc țiunile IN și
OUT) pentru portul digital A sunt PINA=0x19, DDRA=0 x1A și PORTA=0x1B, Codul în limbaj de
asamblare pentru opera țiile care se pot executa întotdeauna cu portul digital A sunt:
;scriere PORTA cu valoarea din R0. Bitul i din R 0 se scrie în bistabilul U1_i din
;figura 4 .
out 0x1B, R0

;citirea lui PORTA în R1. Bitul i din U1 se cite ste prin driverul 3-state U2_i.
in R1, 0x1B

;scriere DDRA cu valoarea din R0. Bitul i din R0 se scrie în bistabilul U3_i.
out 0x1A, R0

;citirea lui DDRA în R1. Bitul i din U3 se cites te prin driverul 3-state U4_i.
in R1, 0x1A

;citirea st ării pinilor PA. Starea pinului PAi se citeste prin driverul U5_i.
in R2, 0x19
Folosirea adreselor porturilor duce la un cod greu de urm ărit. Codul devine mult mai clar dac ă în loc de
numere se folosesc nume. Pentru acesta este nevoie de directiva .EQU care are în asamblare rolul lui
#define din C:
.EQU PORTA = 0x1B
.EQU DDRA = 0x1A
.EQU PINA = 0x19

6 ;scriere PORTA
out PORTA, R0

;citirea lui PORTA
in R1, PORTA

;scriere DDRA
out DDRA, R0

;citirea lui DDRA.
in R1, DDRA

;citirea st ării pinilor PA.
in R2, PINA

În C numele celor trei registre dintr-o grup ă este identic cu numele folosit în datele de catalo g.
Pentru grupa A acestea sunt PORTA, PINA, DDRA. Aces te nume sunt declarate în headerul io.h. Codul
în limbajul C pentru opera țiile care se pot executa întotdeauna cu portul digital A sunt:

#include <avr/io.h>
//adresele porturilor sunt definite în io.h

unsigned char data;

//scriere PORTA
PORTA=data;

//citirea lui PORTA
data=PORTA

//scriere DDRA
DDRA=data;

//citirea lui DDRA.
data=DDRA;

//citirea st ării pinilor PA.
data= PINA;

Dac ă DDRX i este ‚0’ comutatorul S_i
este deschis iar schema din figura 4
devine echivalent ă cu schema din Error!
Reference source not found. . Valoarea
logic ă a pinului PX i este stabilit ă din
exterior și poate fi citit ă prin intermediul
repetorului 3-state U5_i, ceea ce
transform ă acest repetor într-un port
microcontroler de intrare . Pentru portul
de intrare trebuie ținut ă seam ă de
întârzierea dou ă pulsuri de ceas introdus ă
de blocul de sincronizare. Suplimentar,
PORTX i func ționeaz ă ca o loca ție de
memorie, f ără ca valoarea înscris ă în
bistabilul U1 s ă apar ă pe pinul PX i.
De și toate cele 5 opera ții discutate
anterior sunt posibile, codul pentru configurarea și utilizarea portului digital A ca port de intrare con ține
doar 2 opera ții. Acest cod este prezentat în continuare:

figura 5 Di Do Synchro PXiRD_DAT_X
WR_DAT_X DB[i]
PORTX[i]
DB[i]
DB[i] DDRX[i]='0' Internal Data Bus DB[7:0]
RD_PINX PINX[i] TU2_iTU5_iD QU1_i

7//Portul A este port de intrare
#include <avr/io.h>

unsigned char data;

//în sec țiunea de ini țializare
DDRA=0b00000000; //sau DDRA=0;

//citire port A
data=PINA;

Dac ă DDRX i este ‚1’ comutatorul este închis iar schema din fig ura 4 devine echivalent ă cu schema din
figura 6. În figur ă ie șirea Q a bistabilului U1_i se conecteaz ă la pinul PX i, ceea ce transform ă acest portul
digital într-un port de ie șire al microcontrolererului . De și toate cele 5 opera ții discutate anterior sunt
posibile, codul pentru configurarea și utilizarea portului digital A ca port de ie șire con ține doar 3 opera ții.
Codul se afl ă în partea dreapt ă a figurii.

figura 6 //Portul A este port de iesire
#include <avr/io.h>

unsigned char data;

//în sec țiunea de ini țializare
DDRA=0b11111111;//sau DDRA=0xff;

//scriere port A
PORTA=data;

//citire port A
data=PORTA;

Din schem ă se observ ă c ă data înscris ă în bistabilul U1_i poate fi citit ă și prin intermediul repetorului 3-
state U5_i cu data = PINA . Dac ă vreodat ă este necesar ă citirea prin intermediul lui U5_i, trebuie ținut ă
seam ă de întârzierea de dou ă pulsuri de ceas introdus ă de blocul de sincronizare. Practic, data scris ă în
PORTX nu poate fi citit ă mediat prin PINX, ci trebuie a șteptat dou ă instruc țiuni.
Chiar dac ă direc ția se stabile ște pentru toat ă grupa X cu o singur ă instruc țiune, aceasta nu înseamn ă
că to ți pinii sunt obligatoriu de IN sau to ți sunt obligatoriu de OUT. De exemplu, dac ă
DDRA=0b1111010 atunci PA0 și PA2 sunt pini de intrare iar PD1, PD3, PD4, PD5, PD6 și PD7 sunt
pini de ie șire.
Pentru porturile procesor nu este posibil accesul î n scriere sau citire la nivel de bit, dar exist ă
instruc țiuni care pot set sau reseta individual fiecare bit .

3. Extensia porturilor
Atmega 16 este prev ăzut cu 32 de pini ce pot fi programa ți ca intr ări sau ca ie șiri. Exist ă unele
aplica ții unde 32 de pini IO nu sunt suficien ți. O solu ție pentru aceste aplica ții este alegerea unui
microcontroler cu mai mul ți pini IO. Evident, pre țul unui asemenea microcontroler este mai mare. În
general microcontrolerele cu mai mul ți pini au și alte resurse mai bogate (ROM, RAM, etc.), drept p entru PXiInternal Data Bus DB[7:0] WR_DAT_X RD_DAT_X
PORTX[i]
DB[i] DB[i]
DB[i] DDRX[i]='1'
RD_PINX PINX[i] TU2_iT
U5_iD QU1_i
Di Do Synchro

8care pre țul mai mare nu se datoreaz ă numai unui num ăr mai mare de pini IO. Dac ă aplica ția necesit ă doar
mai mul ți pini IO, restul resurselor fiind suficiente, este nevoie de o extensie de porturi.

Extensie de porturi de ie șire cu registre serie-paralel
Transferul informa ției în porturile de ie șire suplimentare se face serial. Acest tip de trans fer
folose ște doar 2 pini ai microcontrolerului. Circuitul fo losit pentru implementarea transferului serial este
registrul serie – paralel . Registrul serie – paralel, abreviat în continuare registrul SP, a fost prezentat în
cadrul cursului „Proiectarea sistemelor digitale”/ ”Digital Systems Design”. În figura urm ătoare este
prezentat un registru SP pe 4 bi ți cu reset.

figura 7 Clock QA QB QC QD
│ qa qb qc qd
└→┐ qa qb qc qd
│ SDI qa qb qc
t
Vom nota valorile ie șirilor QA, QB, QC și QD înainte de apari ția frontului ridic ător al lui CLK cu
qa, qb, qc și qd. Pe frontul ridic ător al lui „Clock” valoarea logic ă a semnalului „Serial data in” – SDI este
înscris ă în bistabilul FFA și apare pe ie șirea QA. Noua valoare a lui QA nu va apare imediat, ci dup ă un
timp; acest timp este timpul de r ăspuns al bistabilului. Tot pe frontul ridic ător al lui „Clock” valoarea lui
QA înainte de apari ția frontului ridic ător al lui CLK, adic ă qa, se înscrie în bistabilul FFB și apare pe
ie șirea QB. Asem ănător, qb apare pe Qc iar qc apare pe Qd. Acest compo rtament este rezumat în partea
dreapt ă a figurii precedente.
Pentru extensia de porturi de ie șire se va folosi registrul serie-paralel 74HCT164 p rodus ini țial de
Texas Instruments. În momentul de fa ța registrul este fabricat de mai mul ți produc ători. Datele de catalog
pentru 74HCT164 sunt disponibile la http://www.ti.com/lit/gpn/cd74hct164 . În figura urm ătoare este
prezentat ă structura intern ă a registrului:

Fa ță de structura clasic ă a registrului din figura 7 registrul 74HCT164 dife r ă foarte pu țin: Deosebirile sunt
minore și constau în nume diferite ale semnalelor și în num ărul de bistabile:
─ „Serial Data in ” din figura 7 este un AND între semnalele A și B .
─ „Clock ” din figura 7 se nume ște CP – Clock .
─ „Clear ” din figura 7 se nume ște MR – Master Reset.
─ În figura 7 registrul SP este alc ătuit din 4 bistabile iar la 74HCT164, din 8 bistabi le.

9Schema extensiei de porturi de ie șire este prezentat ă în figura urm ătoare:

figura 8
Num ărul de ie șiri de extensie este 16, ob ținute cu dou ă circuite 74HCT164 cascadate. Cascadarea
face ca dou ă registre de 8 bi ți s ă se comporte ca un registru de 16 bi ți. Pentru cascadarea se fac
urm ătoarele conexiuni:
─ Ie șirea Q7 a circuitului U5 se conecteaz ă la intr ările seriale de date A și B ale circuitului U6.
Registrul de 16 bi ți care se formeaz ă este prezentat în figura urm ătoare:

─ Intrarea CP a lui U5 este conectat ă cu intrarea CP a lui U6. Semnalul care controleaz ă ambele
intr ările CP se nume ște chiar CP.
Pentru ca înscrierea în orice circuit care con ține bistabile – registre de orice tip, num ărărtoare – să se fac ă
corect trebuie s ă se respecte frecven ța maxim ă a ceasului, lățimea minim ă a pulsului de ceas t W și timpii
de set-up și hold. Ace ști timpi sunt eviden ția ți în figura 9:
Perioada T a ceasului. În datele de
catalog de obicei se specific ă frecven ța
maxim ă a ceasului.
Lățimea pulsului de ceas t W este
timpul minim cât semnalul de ceas trebuie s ă
aib ă valoarea ‚1’. Știind pe T și pe tW se poate
calcula tZ, timpul minim cât semnalul de ceas
trebuie s ă aib ă valoarea ‚0’
Timpul de setup t su este intervalul de
timp în care datele trebuie s ă fie stabile (adic ă s ă nu se modifice) înainte de frontul ridic ător al ceasului.
Timpul de hold t H este intervalul de timp în care datele trebuie s ă fie dup ă frontul ridic ător al
ceasului. U5
74HCT164
A1
B2
CP 8Q0 3
Q1 4
Q2 5
Q3 6
Q4 10
Q5 11
Q6 12
Q7 13
MR 9IC1
ATMega16-DIP40
PB0/(XCK/T0) 1
PB1/(T1) 2
PB2/(INT2/AIN0) 3
PB3/(OC0/AIN1) 4
PB4/(SS) 5
PB5/(MOSI) 6
PB6/(MISO) 7
PB7/(SCK) 8
RESET 9
XTAL2 12
XTAL1 13
PD0/(RXD) 14
PD1/(TXD) 15
PD2/(INT0) 16
PD3/(INT1) 17
PD4/(OC1B) 18
PD5/(OC1A) 19
PD6/(ICP) 20
PD7/(OC2) 21 VCC 10
GND 11
GND 31 PA7/(ADC7) 33 PA6/(ADC6) 34 PA5/(ADC5) 35 PA4/(ADC4) 36 PA2/(ADC2) 38
PA3/(ADC3) 37 PA1/(ADC1) 39 PA0/(ADC0) 40
PC0/(SCL) 22 PC1/(SDA) 23 PC2/(TCK) 24 PC3/(TMS) 25 PC4/(TDO) 26 PC5/(TDI) 27 PC6/(TOSC1) 28 PC7/(TOSC2) 29 AVCC 30 AREF 32
OUT1 OUT0
OUT4 OUT3 OUT2
OUT7 OUT6 OUT5
OUT9 OUT8
OUT12 OUT11 OUT10
OUT15 OUT14 OUT13
CP U6
74HCT164 A1
B2
CP 8Q0 3
Q1 4
Q2 5
Q3 6
Q4 10
Q5 11
Q6 12
Q7 13
MR 9
VCC VCC
SD

figura 9

10 Conform datelor de catalog ale circuitului 74HCT16 4, pentru Vcc=4,5 V și gama de temperatur ă –
40 oC .. 85 oC, avem: fMAX =24 MHz , tW=20 ns tsu=15 ns și th =4 ns . Din fMAX și tW se calculeaz ă tZ= 27
ns. Pentru ca scrierea registrelor s ă se fac ă corect trebuie respecta ți ace ști timpi.
Ideea dup ă care func ționeaz ă schema din figura 8 este ca s ă valoarea care trebuie înscris ă în portul
extern de ie șire s ă apar ă bit cu bit pe intr ările A și B ale registrului serie-paralel. Pentru aceasta A și B se
conecteaz ă la un pin dintr-un port digital al microcontroleru lui. În exemplu acest pin este PC7. Evident,
PC7 trebuie configurat ca pin de ie șire. Dup ă scrierea lui PC7 trebuie generat un front ridic ător pe CP.
Pentru generarea ceasului se va folosi PC6, configu rat ca ie șire.
Scrierea registrelor se face sub controlul programului executat de procesor. Deoarece data serial ă
SD și clockul serial CP sunt generate prin execu ția unor instruc țiuni, respectarea timpilor de setup și hold
este responsabilitatea programului. Pentru a asigur a respectarea timpilor de setup și hold avem nevoie de
anumite informa ții despre modul în care microcontrolerul execut ă instruc țiunile. Prima informa ție se
refer ă la num ărul de impulsuri de ceas necesare pentru execu ția unei instruc țiuni. În datele de catalog se
specifică c ă se execut ă o instruc țiune pe fiecare impuls de ceas. Urm ătoarea informa ție de care avem
nevoie este frecven ță ceasului procesor. Vom folosi frecven ța utilizat ă la laborator, și anume 8MHz.
Perioada ceasului procesor T CLKP corespunz ătoare frecven ței de 8MHz este 1/8MHz=125ns.
Secven ța de instruc țiuni executat ă pentru scrierea unui bit și timingul generat de execu ția acestei
secven țe este prezentat ă în figura urm ătoare:
setbit(PORTC,7);
or
clrbit(PORTC,7);
setbit(PORTC,6);
clrbit(PORTC,6);123

figura 10
1. În variabila data de tip întreg se memoreaz ă datele care trebuie înscrise în registrele U5 și U6.
Reamintim ca la ATmega16 un întreg se reprezint ă pe 16 bi ți.
Bitul i din data se va scrie în portul C, bitul 7. Dac ă data (i) = ‚1’ se va executa
setbit(PORTC,7); iar dac ă data (i) = ‚0’ se va executa clrbit(PORTC,7); . Execu ția acestei
instruc țiuni se face pe frontul ridic ător al pulsului de ceas procesor CLKP notat E1 în f igura 10.
Efectul execut ării instruc țiunii este eviden țiat de s ăgeata 1 în figura 10.
2. Pe urm ătorul front ridic ător (E2 în figur ă) al lui CLKP se execut ă instruc țiunea
setbit(PORTC,6); Execu ția acestei instruc țiuni produce un front ridic ător al semnalului CP.
Aceasta instruc țiune are ca efect scrierea cu ‚1’ a bitului 6 din p ortul C. Ceilal ți bi ți din portul C
rămân neschimba ți. Efectul execut ării instruc țiunii este eviden țiat de s ăgeata 2 în figura 10.

11 În acest moment se poate verifica dac ă este respectat timpul de setup al registrului U1. Acest timp
este respectat deoarece între generarea SD și frontul ridic ător al lui CP trece un impuls de ceas
procesor, adic ă 125ns, iar tsu este 15 ns. Dac ă tsu at fi fost mai mare ca perioada ceasului
procesor, ar fi fost necesar ă inserarea de instruc țiuni f ără efect între scrierea bitului 7 din portului
C (SD) și frontul ridic ător al lui CP. De regul ă instruc țiunea f ără efect folosit ă în astfel de situa ții
este instruc țiunea nop .
3. Pe frontul E3 al ceasului procesor se aduce CP în ‚0’ prin execu ția instruc țiunii
clrbit(PORTC,6); . Aceasta instruc țiune are ca efect scrierea cu ‚0’ a bitului 6 din p ortul C.
Efectul execut ării instruc țiunii este eviden țiat de s ăgeata 3 în figura 10. CP trebuie scris cu ‚0’
pentru a putea genera un nou front ridic ător la urm ătoarea scriere. Din figur ă se observ ă c ă CP
este ‚1’ pe durata unui puls de ceas procesor, adic ă 125ns, ceea ce face ca t W= 20 ns (vezi figura 9)
să fie respectat.
4. Un nou ă scriere a portului extern E poate începe cel mai d evreme dup ă frontul E3. Nici datele,
nici CP nu se pot modifica mai devreme de 125 ns. D in acest motiv datele înscrise în portul C
rămân stabile cel pu țin dou ă perioade de ceas procesor, ceea ce face ca s ă se respecte timpul de
hold th=4ns. Din acela și motiv va fi respectat și t Z=27ns.
Înscrierea serial ă a extensiei de porturi de ie șire se face cu urm ătorul program:
#define SD 7
#define CP 6

unsigned int data;
uint8_t i;
……
PORTC=0b00––;
DDRC =0b11––;
………
for (i=15;i>=0;i–){
//genereaz ă bitul i din data
if (data & 1<<15)
setbit(PORTC, SD);
else
clrbit(PORTC, SD);

//genereaz ă puls CP
setbit(PORTC, CP);
clrbit(PORTC, CP);
data<<=1;
}
……
Avantajul metodei seriale const ă în num ărul mic de pini microcontroler, doi, necesari pentr u a
ob ține 16 ie șiri suplimentare. Exist ă îns ă și un poten țial dezavantaj: timpul necesar înscrierii seriale e ste a
informa ției este mult mai mare. Un singur bit necesit ă aproximativ 10 instruc țiuni cod ma șin ă, ceea ce
înseamn ă 10×16=160 instruc țiuni pentru un int. Timpul necesar pentru a scrie 1 6 bi ți este 160×125 ns=
20 us (dac ă frecven ța ceasului procesor este 8MHz). Cum de cele mai mul te ori ie șirile sunt folosite
pentru a comanda dispozitive lente, cum ar fi motoa re, relee, LED-uri, 20 us este perfect acceptabil.
Exist ă îns ă și o problem ă poten țial ă cu implementarea din figura 8. Problema este eviden țiat ă de
urm ătoarea situa ție: dac ă variabila data are valoarea 0b 1000 000 0000 0000 înscrierea în registrul SP se
va desf ășura ca în tabelului urm ător:

12 timpul CP SD OUT0 OUT1 OUT2 OUT3 …
t0 0 1 0 0 0 0
t1 ↑1 1 1 0 0 0
t2 ↑2 0 0 1 0 0
t3 ↑3 0 0 0 1 0
t4 ↑4 0 0 0 0 1

Din tabel se observ ă comportamentul poten țial periculos al ie șirilor OUT15…OUT0: pân ă când se
transfer ă serial to ți bi ții variabilei data și se ajunge în starea final ă 10…0000 se trece prin st ările
tranzitorii 0…0001, 0…0010, 0…0100, … Fiecare star e intermediar ă înseamn ă un puls pe una din
ie șirile OUT0, OUT1,…OUT14 (‚1’ ro șu în tabelul de mai sus). Acest comportament poate fie s ă nu
conteze, fie s ă fie inadmisibil, în func ție de destina ția ie șirii.
De exemplu, dac ă ie șirea OUT0 din figura 8 porne ște sau opre ște un motor este obligatoriu ca
aceasta s ă nu prezinte pulsuri ca cele din tabelul de mai sus . Chiar dac ă pulsul este foarte scurt, de ordinul
microsecundelor, un impuls de pornirea a unui motor chiar și scurt poate avea consecin țe imprevizibile.
Dac ă îns ă OUT0 controleaz ă un LED, este neimportant dac ă acesta lumineaz ă câteva microsecunde
deoarece nimeni nu poate observa un impuls a șa de scurt.
În concluzie schema din figura 8 este bun ă pentru a controla LED-uri dar nu este bun ă pentru a
controla motoare. În continuare se va prezenta o sc hem ă care elimin ă cele dou ă probleme eviden țiate
anterior.

Extensie de porturi de ie șire cu registre dublu stagiu
Problema impulsurilor tranzitorii care apar în proc esul de serializare se rezolv ă prin folosirea a
dou ă registre. Primul registru este un registru serie-p aralel (SP), la fel ca cel din figura 8. Evident, l a
ie șirile acestui registru vor apare pulsuri tranzitori i.
Însa vom ad ăuga un al doilea registru de tip paralel-paralel (P P) în care vom înscrie informa ția din
registrul SP. Informa ția din registrul SP se memoreaz ă în registrul PP pe un alt semnal de ceas. Cât timp
datele se înscriu serial în registrul SP, ie șirile sunt generate din registrul PP. Astfel, orice tranzi ția a
ie șirilor registrului SP generat ă de serializare nu se observ ă la ie șire. Dup ă ce serializarea s-a terminat
datele se transfer ă din registrul SP în registrul PP și apar la ie șire.
O implementare cu dou ă registre este destul de complicat ă dar din fericire exist ă circuite care
încapsuleaz ă registrele SP și PP într-un singur circuit integrat. Un astfel de circuit este 74AHCT594.
Date de catalog pentru acest circuit sunt disponibi le la http://www.ti.com/lit/ds/symlink/sn74ahct594. pdf
Structura acestui circuit este prezentat ă în figura urm ătoare:

13
figura 11
Circuitul este alc ătuit din dou ă stagii. Primul stagiu este registrul SP din interi orul dreptunghiului ro șu din
figura 11. Stagiul SP este foarte asem ănător ca structur ă cu registrul SP 74HCT164 din exemplu anterior.
Deosebirile sunt minore și constau în nume diferite ale semnalelor și în num ărul de bistabile:
─ Intrarea serial ă de date se nume ște SER .
─ Ceasul serial se nume ște SRCLK – Shift Register Clock.
─ Resetul registrului SP se nume ște SRCLR – Shift Register Clear
─ Ie șirea QH’ a ultimului bistabil din lan țul serial este disponibil ă pe un pin al circuitului pentru a
permite construc ția de registre pe mai mult de 8 bi ți prin cascadare.
Al doilea stagiu este alc ătuit din registrul PP din interiorul dreptunghiului alabastru din figura 11. Acesta
memoreaz ă datele de la ie șirile registrului SP din primul stagiu. Memorarea s e face pe frontul ridic ător al
semnalului RCLK . Resetul registrului PP este RCLR
În figura 12 este prezentat ă implementarea extensiei de porturi de ie șire, varianta serial ă cu
registre dublu stagiu. Num ărul de ie șiri de extensie este 16, ob ținute cu dou ă circuite 74AHCT594
cascadate. Cascadarea face ca dou ă registre de 8 bi ți s ă se comporte ca un registru de 16 bi ți. Pentru
cascadarea se fac urm ătoarele conexiuni:
─ Ie șirea serial ă QH’ a circuitului U1 se conecteaz ă la intrarea serial ă de date SER a circuitului U2
și astfel se formeaz ă registrul de 16 bi ți.
─ Intr ările SRCLK ale celor dou ă circuite 74AHCT594 sunt conectate la pinul PC5 al lui
ATmega16. Semnalul generat pe PC5 se nume ște SHCP – Shift Clock Pulse.
─ Intr ările RCLK ale celor dou ă circuite 74AHCT594 sunt conectate la pinul PC6 al lui ATmega16.
Semnalul generat pe PC6 se nume ște STCP – Store Clock Pulse.

14
figura 12
Registrele duble rezolv ă problema impulsurilor tranzitorii dar mai exist ă înc ă o problem ă care apare
la punerea sub tensiune. La laborator s-a ales fol osirea resetului intern iar setarea aleas ă este ca acesta s ă
fie activ 64 ms. Cât timp este în reset procesorul nu execut ă instruc țiuni iar registrele DDRX și PORTX
sunt ini țializate cu ‚0’, ceea ce face ca toate porturile di gitale s ă fie porturi de intrare. Din acest motiv
valoarea logic ă pe to ții pinii digitali care sunt conecta ți numai cu intr ări externe fluctueaz ă, fiind când ‚0’
când ‚1’, dup ă cum s-a ar ătat la laborator.
Pinii PC6 și PC5, adic ă ceasurile registrului, vor fluctua pe durata reset ului procesor iar aceste
fluctua ții pot produce înscrierea de date aleatoare în regi strul serie-paralel. Deoarece scopul schemei din
figura 12 este comanda motoarelor, înscrierea de da te aleatoare nu este permis ă. Evitarea acestui fenomen
se face prin ad ăugarea a rezisten țelor R1 și R2 care au rolul de a ține la ‚0’ semnalele STCP și SHCP pân ă
când procesorul iese din reset și programeaz ă registrelor DDRX și PORTX.
Nici conectarea la ‚0’ a semnalelor STCP și SHCP nu este suficient ă deoarece evit ă înscrierea de
date aleatoare în registrele U1 și U2 pe perioada resetului, dar nu modific ă valoarea ini țial ă stabilit ă la
punerea sub tensiune. Dac ă dorim s ă controlam motoare, valoarea la reset a ie șirilor portului extern
trebuie s ă fie ‚0’. Pentru aceasta trebuie ca la punerea sub tensiune semnalul aplicat pe intr ările de reset
RCLR ale celor dou ă registre s ă fie ‚0’ o perioada de timp iar apoi s ă devin ă inactiv (adic ă ‚1’). ‚0’-ul
generat la punerea sub tensiune va reseta registrul PP. Acest ’0’ este generat de grupul R3-C1 din fig ura
12. Acest grup RC asigur ă un ‚0’ suficient de lung ca toate ie șirile Q s ă se ini țializeze cu ‚0’.
Ultima etap ă este scrierea programului care face scrierea seria l ă în registrele dublu stagiu. Pentru ca
scrierea registrelor s ă se fac ă corect trebuie respecta ți timpi t W, t Z, tSU și t H. Conform datelor de catalog
ale circuitului 74AHCT594, pentru Vcc=4,5 V și gama de temperatur ă -40 oC .. 85 oC, avem: fMAX =95
MHz , tW=5,5 ns tsu=3,8 ns și th =2 ns . Din fMAX și tW se calculeaz ă tZ= 5 ns. Cum o instruc țiune se
execut ă în 125 ns (dac ă frecven ța ceasului procesor este 8MHz) oricare din ace ști timpi va fi respectat.
Înscrierea serial ă a extensiei de porturi de ie șire se face cu urm ătorul program:
#define SD 7
#define STCP 6
#define SHCP 5

unsigned int data;
uint8_t i; IC1
ATMega16-DIP40
PB0/(XCK/T0) 1
PB1/(T1) 2
PB2/(INT2/AIN0) 3
PB3/(OC0/AIN1) 4
PB4/(SS) 5
PB5/(MOSI) 6
PB6/(MISO) 7
PB7/(SCK) 8
RESET 9
XTAL2 12
XTAL1 13
PD0/(RXD) 14
PD1/(TXD) 15
PD2/(INT0) 16
PD3/(INT1) 17
PD4/(OC1B) 18
PD5/(OC1A) 19
PD6/(ICP) 20
PD7/(OC2) 21 VCC 10
GND 11
GND 31 PA7/(ADC7) 33 PA6/(ADC6) 34 PA5/(ADC5) 35 PA4/(ADC4) 36 PA2/(ADC2) 38
PA3/(ADC3) 37 PA1/(ADC1) 39 PA0/(ADC0) 40
PC0/(SCL) 22 PC1/(SDA) 23 PC2/(TCK) 24 PC3/(TMS) 25 PC4/(TDO) 26 PC5/(TDI) 27 PC6/(TOSC1) 28 PC7/(TOSC2) 29 AVCC 30 AREF 32
SD
OUT0
OUT1
OUT2
OUT3
OUT4
OUT7 OUT6 OUT5
OUT9 OUT8
OUT11 OUT10
OUT14 OUT13 OUT12
OUT15
R2
5K R1
5K
STCP
VCC U1
74HCT594
SER 14
SRCLK 11
SRCLR 10 RCLK 12
RCLR 13 QA 15
QB 1
QC 2
QD 3
QE 4
QF 5
QG 6
QH 7
QH'9U2
74HCT594
SER 14
SRCLK 11
SRCLR 10 RCLK 12
RCLR 13 QA 15
QB 1
QC 2
QD 3
QE 4
QF 5
QG 6
QH 7
QH'9
VCC VCC
SHCP
+C1
10uF 5K
R3

15 ……
PORTC=0b000––;
DDRC =0b111––;
……
for (i=15;i>=0;i–){
//genereaz ă bitul i din data
if (data & 1<<15)
setbit(PORTC, SD);
else
clrbit(PORTC, SD);

//genereaz ă puls SHCP – shift
setbit(PORTC, SHCP);
clrbit(PORTC, SHCP);
data<<=1;
}
//genereaz ă puls STCP – store
setbit(PORTC, STCP);
clrbit(PORTC, STCP);
……
În ultimele dou ă capitolele metoda serial ă a fost folosit ă pentru a cre ște num ărul de ie șiri ale
sistemului, dar la fel de bine poate fi folosit ă pentru a cre ște num ărul de intr ări.

Extensie de porturi de intrare cu registre paralel – serie
Cre șterea num ărului de intr ări se face cu registre paralel-serie. Registrul înc arc ă informa ția paralel
de pe pinii de date D i și apoi o deplaseaz ă. Modul de lucru – înc ărcarea paralel ă sau deplasare – este
stabilit prin intermediul unei intr ări, de exemplu PE – Parallel enable. Pe intrarea D a oric ărui bistabil se
conecteaz ă un comutator electronic cu dou ă c ăi, ca în figura urm ătoare:

figura 13
Toate comutatoarele SW sunt controlate de PE. În fi gura 13 comutatoarele sunt în pozi ția corespunz ătoare
înc ărc ării paralele (PE=’1’). Pe primul puls de ceas fieca re bistabil încarc ă informa ția din exterior de pe
pinii D i corespunz ător. Apoi PE devine ‚0’ și comutatoarele SW conecteaz ă intr ările D ale bistabililor ca
în figura urm ătoare:

În aceast ă configura ție bistabilele sunt conectate astfel încât formeaz ă un registru de deplasare. Evident,
comutatoarele SW i nu sunt comutatoare mecanice ci multiplexoare MUX2. D Q
RCU0
DS
CP SW0 D0
SW1 D Q
RCU1 D1
SW2 D Q
RCU2 D2
DS D Q
RCU0
CP SW0
SW SPDT D0
SW1
D Q
RCU1 D1
SW2
D Q
RCU2 D2

16 Registrul paralel- serie pe care îl vom folosi în exemplul urm ător are codul 74HCT166. Datele de
catalog pentru acest circuit sunt disponibile la http://www.ti.com/lit/ds/symlink/cd74hct166.pdf . Circuitul
con ține 8 bistabile și are urm ătoarea configura ție terminal ă:
– D0-D7 intr ări de date pentru înc ărcare paralel ă.
– DS intrare serial ă de date
– Q7 ie șire serial ă
– PE intrare mod: PE =’0’ pentru înc ărcare paralel ă, PE =’1’ pentru deplasare
– CP intrare de ceas
– CE (clock enable) intrare de validare a ceasului. Dac ă CE =’1’ impulsurile de ceas vor fi ignorate.
– MR reset asincron activ ‚0’.
În figura urm ătoare este prezentat ă schema extensiei de porturi de intrare realizat ă cu dou ă circuite
74HCT166:

figura 14
În figura 14 este prezentat ă implementarea extensiei de porturi de intrare. Num ărul de ie șiri ale
extensiei este 16, ob ținute prin cascadarea a dou ă circuite 74HCT166. Cascadarea face ca dou ă registre de
8 bi ți s ă se comporte ca un registru de 16 bi ți. Pentru cascadarea se fac urm ătoarele conexiuni:
─ Ie șirea serial ă Q7 a circuitului U8 se conecteaz ă la intrarea serial ă de date DS a circuitului U7 și
astfel se formeaz ă registrul de 16 bi ți.
─ Intr ările CP ale celor dou ă circuite 74HCT166 sunt conectate la pinul PC6 al l ui ATmega16.
Semnalul generat pe PC6 se nume ște CP – Clock Pulse.
─ Intr ările PE ale celor dou ă circuite 74HCT166 sunt conectate la pinul PC5 al l ui ATmega16.
Semnalul generat pe PC5 se nume ște PE# .
─ Ie șirea serial ă a registrului de 16 bi ți este pinul Q7 a circuitului U7. Ie șirea serial ă se conecteaz ă la
pinul PC7 al microcontrolerului și se nume ște SD.
Pentru ca citirea registrelor s ă se fac ă corect trebuie respecta ți timpi t W, t Z, t SU și t H. Conform datelor
de catalog ale circuitului 74HCT166, pentru Vcc=4, 5 V și gama de temperatur ă -40 oC .. 85 oC, avem:
fMAX =24 MHz , tW=20 ns tsu=25 ns și th =2 ns . Din fMAX și tW se calculeaz ă tZ= 21.6 ns. Cum o
instruc țiune se execut ă în 125 ns (dac ă frecven ța ceasului procesor este 8MHz) oricare din ace ști timpi va
fi respectat.
Citirea extensiei de porturi de intrare se face cu urm ătorul program: IC1
ATMega16-DIP40
PB0/(XCK/T0) 1
PB1/(T1) 2
PB2/(INT2/AIN0) 3
PB3/(OC0/AIN1) 4
PB4/(SS) 5
PB5/(MOSI) 6
PB6/(MISO) 7
PB7/(SCK) 8
RESET 9
XTAL2 12
XTAL1 13
PD0/(RXD) 14
PD1/(TXD) 15
PD2/(INT0) 16
PD3/(INT1) 17
PD4/(OC1B) 18
PD5/(OC1A) 19
PD6/(ICP) 20
PD7/(OC2) 21 VCC 10
GND 11
GND 31 PA7/(ADC7) 33 PA6/(ADC6) 34 PA5/(ADC5) 35 PA4/(ADC4) 36 PA2/(ADC2) 38
PA3/(ADC3) 37 PA1/(ADC1) 39 PA0/(ADC0) 40
PC0/(SCL) 22 PC1/(SDA) 23 PC2/(TCK) 24 PC3/(TMS) 25 PC4/(TDO) 26 PC5/(TDI) 27 PC6/(TOSC1) 28 PC7/(TOSC2) 29 AVCC 30 AREF 32
VCC
SD U8
74166 CP 7Q7 13
DS 1 CE 6 D0 2D1 3D2 4D3 5D4 10 D5 11 D6 12 D7 14
MR 9PE 15
CP VCC IN1
IN0 IN3
IN2 IN6
IN5
IN4 IN9
IN8
IN7 IN11
IN10 IN14
IN13
IN12 IN15
PE# U7
74166 CP 7Q7 13
DS 1 CE 6 D0 2D1 3D2 4D3 5D4 10 D5 11 D6 12 D7 14
MR 9PE 15

17 #define nPE 5
#define CP 6
#define SD 7

unsigned int data;
uint8_t i;
……
PORTC=0b000––;
DDRC =0b 011––;
……
// Registrul PS configurat pentru înc ărcare paralel ă
clrbit(PORTC, nPE);

// încarc ă paralel datele IN0 – IN15
// genereaz ă puls de ceas
setbit(PORTC, CP);
clrbit(PORTC, CP);

// Registrul PS configurat pentru deplasare seri e
setbit(PORTC, nPE);
data=0;

for (i=15;i>=0;i–){
//încarc ă SD în bitul i din data
if (PINC & 1<<SD)
data |= 1<<0;

//genereaz ă puls de ceas
setbit(PORTC, CP);
clrbit(PORTC, CP);

data<<=1;

// Asteapt ă propagarea prin sincronizator
nop; nop;
}
……

4. Conectarea cu interfe țe IO
Pân ă acum s-a ar ătat cum se poate m ări num ărul de pini IO ai microcontrolerului. Exist ă îns ă
aplica ții care necesit ă conectarea la microcontroler a unor interfe țe de IO. Așa cum s-a detaliat in
prelegerea 2, subcapitolul „Interfe țe IO”, o interfa ță IO este prev ăzut ă cu pinii de control CE#, RD# și
WR#, pini de adres ă și pini de date, la fel ca un modul de memorie. Cone ctarea cu procesorul se face la
fel ca pentru modulele de memorie. La fel ca memor iile, interfe țele IO sunt concepute s ă se conecteze cu
procesoare prin intermediul magistralelor de adrese , de date și de control.
Dar marea majoritate a microcontrolerelor nu sunt p rev ăzute cu aceste magistrale. Din acest motiv
interfe țele IO se vor conecta la porturile microcontrolerul ui la fel cum s-au ad ăugat porturi externe în
exemplele precedente. Porturile microcontrolerului se vor comporta ca mag istrale sub controlul
programului. În figura urm ătoare se prezint ă modul de conectarea la microcontroler a unei inter fe țe IO:

18
figura 15
Interfa ță din figur ă are doi pini de adres ă – A0 și A1 – și pinii de control CE#, RD# și WR. Ea va
fi tratat ă ca o memorie RAM cu 4 loca ții. Deoarece interfa ță din figur ă este singura care se conecteaz ă la
microcontroler, CE#-ul ei este tot timpul activ. Pi nii RD# și WR sunt for țați la ‚1’ în faza de ini țializare
din pentru a nu fluctua, a șa cum s-a explicat anterior.
Pentru a scrie func țiile care fac citirea și scrierea mai este nevoie s ă știm timingul interfe ței.
Timingul interfe țelor de IO este identic cu timingul modulelor de me morie. În prima prelegere s-a detaliat
modul în care se cupleaz ă module de memorie ROM și RAM la un microprocesor. În acel moment nu s-a
făcut nici o referire la timingul transferurilor cu m icroprocesorului. Pentru a putea cupla memorii și/sau
interfe țe IO la procesoare trebuie cunoscute caracteristici le de timp ale acestora și derularea în timp a unui
acces procesor la memorie.
În figura urm ătoare este prezentat timingul simplificat al unei scrieri în memorie:

figura 16
Scrierea memoriei se aseam ănă conceptual cu scrierea bistabilului din figura 9: datele trebuie s ă fie
stabile atât înainte cât și dup ă momentul scrierii. Fa ță de scrierea unui bistabil, scrierea memorie prezin t ă
dou ă deosebiri:
• Scrierea bistabilului se face pe frontul ridic ător al lui CLK. În schimb, scrierea memorie se face pe
un impuls negativ al lui WR#. Durata acestui impuls este t PWE în figura 16. Durata lui t PWE difer ă
de la memorie la memorie, valoarea sa tipic ă fiind în plaja 30-70ns.
• Timpii t SU și t H ai bistabilului spun cât trebuie s ă fie stabil ă intrarea D fa ță de CLK. Dar memoria
mai are, în afar ă de date, și adrese. Varianta simplificat ă a timingului din figura 16 specific ă
aceea și timpi de setup și hold atât pentru adrese cât și pentru date. R1
5K
R2
5K VCC VCC IC1
ATMega16-DIP40
PB0/(XCK/T0) 1
PB1/(T1) 2
PB2/(INT2/AIN0) 3
PB3/(OC0/AIN1) 4
PB4/(SS) 5
PB5/(MOSI) 6
PB6/(MISO) 7
PB7/(SCK) 8
RESET 9
XTAL2 12
XTAL1 13
PD0/(RXD) 14
PD1/(TXD) 15
PD2/(INT0) 16
PD3/(INT1) 17
PD4/(OC1B) 18
PD5/(OC1A) 19
PD6/(ICP) 20
PD7/(OC2) 21 VCC 10
GND 11
GND 31 PA7/(ADC7) 33 PA6/(ADC6) 34 PA5/(ADC5) 35 PA4/(ADC4) 36 PA2/(ADC2) 38
PA3/(ADC3) 37 PA1/(ADC1) 39 PA0/(ADC0) 40
PC0/(SCL) 22 PC1/(SDA) 23 PC2/(TCK) 24 PC3/(TMS) 25 PC4/(TDO) 26 PC5/(TDI) 27 PC6/(TOSC1) 28 PC7/(TOSC2) 29 AVCC 30 AREF 32 IO Interface U5
A0 8
A1 7
CE 18
RD 20
WR 21
D0 9D1 10 D2 11 D3 13 D4 14 D5 15 D6 16 D7 17 A0
A1
RD#
WR#
D6 D7
D4 D5
D3
D0 D1 D2 '0'

19 Secven ță de ini țializare este:
#define nWR 3
#define nRD 2

#include <avr/io.h>

// Portul C este de port de ie șire pentru a evita fluctua țiile
DDRC=0b11111111; //sau DDRC=0xff;

// WR#=’1’, RD#=’1’, A1=’0’, A0=’0’,
PORTA=0b–-1100;

// Pinii 3-0 din portul A sunt ie șiri, restul depinde de aplica ție
DDRA =0b–-1111; //- = neprecizat, depinde de restul aplica ției
Func ția de scriere este:
void WR_Data (uint8_t addr, uint8_t data){

//la momentul t1 din figura 16 asert ăm adresele și datele
addr &= 0b00000011;
PORTA &= 0b11111100;
PORTA |= addr;

PORTC = data;

//delay tSU cu c ăte nop-uri este nevoie
nop; nop; … nop;

//WR#=‘0’
clrbit(PORTA,nWR);

//delay tPWE cu c ăte nop-uri este nevoie
nop; nop; … nop;

//WR#=‘1’
setbit(PORTA,nWR);

//delay tH cu c ăte nop-uri este nevoie
nop; nop; … nop;

return ;
}
Vom continua cu diagramele de timp pentru citirea m emoriei. Pentru a în țelege mai u șor aceste
diagrame trebuie cunoscut ă structura intern ă a modulelor SRAM. În cazul opera ției de citire schema
(foarte) simplificat ă a unei memorii SRAM asincrone este prezentat ă în figura urm ătoare:

figura 17

20 Figura eviden țiaz ă dou ă c ăi de propagare a informa ției de la intrare la ie șire:
1. Calea albastr ă de la adrese prin matricea de memorare și prin driverele 3-state, la ie șirile
Dout.
2. Calea verde de la semnalele de control prin driverele 3-state l a Dout.
În datele de catalog apar în majoritatea cazurilor dou ă diagrame de timp pentru cele dou ă c ăi.
Diagrama de timp pentru calea albastr ă eviden țiaz ă r ăspunsul datelor la modificarea adreselor în
cazul în care driverele 3-state sunt active, adic ă ie șirea por ții NOR din figura 17 este ‚1’. Pentru ca ie șirea
por ții NOR s ă fie ‚1’ trebuie ca CE#=’0’, RD#=’0’ și WE#=’1’. Aceste semnale au aceste valori cu
mult timp înainte de tranzi ția adresei . În acest caz ne a ștept ăm ca dup ă un timp la ie șire să apar ă
con ținutul loca ției selectate de nou ă adres ă. Acest timp se nume ște t AA (access time from addresses ) și
este suma dintre timpul de r ăspuns al matricei de memorare și timpul de propagare intrare-ie șire prin
driverele 3-state. Valoarea tipic ă a lui t AA pentru memoriile uzuale este în plaja 50-100 ns. D iagrama de
timp pentru calea albastr ă este prezentat ă în figura urm ătoare:

figura 18
Diagrama din figura 18 ne spune c ă memoria SRAM asincron ă se comport ă ca o „magazie”: dac ă dorim
un obiect de pe un raft trebuie s ă a ștept ăm pân ă când operatorul magaziei aduce acel obiect.
A doua diagram ă de timp eviden țiaz ă cum comut ă ie șirile memoriei din 3-state în starea activ ă
(‚0’ sau ‚1’) și invers. Diagrama este prezentat ă în ipoteza c ă toate semnalele sunt stabile cu mult timp
înainte de activarea semnalului care va controla ie șirea și intrarea în 3-state. În figura urm ătoare semnalul
care controleaz ă ie șirea este RD# iar semnalele stabile sunt adresele, CE# și WR#:

figura 19
Pentru ca 3-state-ul ie șirii s ă depind ă numai de RD# trebuie ca CE#=’0’ și WR#=’1’. În esen ță diagrama
de timp din figura 19 este diagrama de timp a unui driver 3-state controlat de RD#: ie șirea va trece în
starea activ ă dup ă activarea lui RD# și va reveni în 3-state dup ă inactivarea lui RD#. Aceste tranzi ții nu
se fac instantaneu, ci necesit ă timp. Timpul de trecere din 3-state în activ este notat t LZCE Timpul de
trecere din activ în 3-state este notat t HZCE . De regul ă ace ști timpi nu sunt egali .
Pentru a eviden ția r ăspunsul ie șirii la tranzi ția CE#, în ipoteza c ă atât adresa cât și RD# sunt
stabile cu mult timp înainte de activarea lui CE#, ar fi necesar ă înc ă o diagram ă de timp. Deoarece aceast ă

21 diagram ă are aceea și alur ă cu cea din figura 19, nu va mai fi prezentat ă. Mai mult, în datele de catalog
furnizate de mai mul ți produc ători diagramele din figura 18 și din figura 19 sunt contopite într-o singur ă
diagram ă.
Înainte de a prezenta diagrama de timp pentru citir e mai trebuie discutat un ultim aspect. În cazul
citirii, este obligatorie respectarea strict ă a urm ătoarei reguli: pe o magistral ă nu poate exista la un
moment dat decât cel mult o surs ă! Existen ța simultan ă a dou ă sau mai multe surse poart ă numele de
coliziune . În momentul coliziunii pe magistrala de date ie șirile a dou ă sau mai multe module (de exemplu
de procesor și de memorie) sunt active. Altfel spus, exist ă dou ă module care „vorbesc” simultan.
Coliziunea duce rareori la distrugerea driverelor de ie șire aferente celor dou ă module, dar are ca
efect un vârf de consum, care poate provoca prin in termediul sursei de alimentare comutarea fals ă a
dispozitivelor logice ac ționate pe front cum ar fi bistabile, num ărătoare sau registre. Mai mult, aceste
comut ări se manifest ă aleator îngreunând mult procesul de punere la punc t al microsistemului.
Coliziunile apar datorit ă tranzi ției adresei. Vom analiza cazul din figura urm ătoare:

figura 20
În figur ă procesorul execut ă dou ă citiri consecutive, prima la adresa Address1 și a doua la
Address2. Vom presupune c ă Address1 și Address 2 sunt alocate la dou ă module de memorie: Address1
este alocat ă modulului 1 de memorie iar Address2 modulului 2. D in acest motiv CE1# este activ cât timp
pe magistrala de adres ă este prezent ă Address1 iar CE2# pentru Address2, ca în figur ă. Pentru a
simplifica expunerea, în figura 20 întârzierile int roduse de SLC-urile care genereaz ă CE#-urilor au fost
ignorate. De asemenea vom presupune c ă RD# este activ în momentul tranzi ției de la Address 1 la
Address 2. În momentul schimb ării adresei de la Address 1 la Address 2 CE1# se va dezactiva iar CE2#
se va activa, deoarece func țiile CE se sintetizeaz ă din adres ă (vezi prelegerea 1). Inactivarea lui CE1# va
face modulul 1 s ă se deselecteze, adic ă s ă-și treac ă ie șirile în 3-state. Trecerea în 3-state nu se face
instantaneu, ci dup ă timpul t HZCE din figura 19. Activarea lui CE2# va face modulul 2 s ă se selecteze,
adic ă s ă-și activeze ie șirile. Trecerea în starea activ ă nu se face instantaneu, ci dup ă timpul t LZCE din
figura 19. Dac ă tLZCE este mai mic decât t HZCE , cum se întâmpl ă frecvent, pentru scurt timp va apare
coliziune. Coliziunea este eviden țiat ă cu ro șu în figura 20.
Pentru ca sistemul s ă func ționeze f ără coliziuni, se impune un anumit timing al semnalulu i RD#
generat de procesor. Mai exact, trebuie ca RD# s ă fie inactiv în momentul schimb ării adresei, ca in figura
urm ătoare:

22

figura 21
Procesorul inactiveaz ă semnalul RD# cu t W2 înainte de schimbarea adresei și îl inactiveaz ă cu t W1 dup ă
schimbarea adreselor. Astfel modulul 1 se va dezactiva înainte ca modulul 2 s ă se activeze și astfel
coliziunea va fi evitat ă.
Știind timingul opera ției de citire memorie și ținând seama de coliziune, procesoarele genereaz ă
adresele și semnalele de control ca în figura urm ătoare. Comportarea în timp a celor 3 magistrale în cazul
unei citiri memorie se nume ște ciclu de citire.

figura 22
1. Citirea memoriei începe la t 1 cu asertarea adresei.
2. Se a șteapt ă t W1 pân ă la t 2 pentru evitarea coliziunii cu o posibil ă citire anterioar ă.
3. La t 2 se activeaz ă RD#.
4. Se a șteapt ă pân ă tARD la t 3 când datele din loca ția a c ărei adres ă se afl ă pe magistrala de adrese
devin disponibile pe pinii de date.
5. Imediat dup ă t 3 procesorul cite ște datele.
6. Procesorul inactiveaz ă RD#. Suntem la t 4.
7. Se a șteapt ă t W2 pân ă la t 5 pentru evitarea coliziunii cu o posibil ă citire ulterioar ă.
Func ția care cite ște o loca ție din interfa ță conform diagramei de timp din figura 22 este:
uint8_t Rd_data(uint8_t addr){
//data este o variabila care va memora data citi t ă
//pân ă la încheierea secven ței de citire
uint8_t data;

// între accese portul C este port de ie șire.
// Pentru citirea portului extern portul C trebu ie s ă fie port de intrare.
DDRC=0;

//la momentul t1 din figura 22 asert ăm adresele
addr &= 0b00000011;
PORTA &= 0b11111100;
PORTA |= addr;

23 //delay tW1 cu câte nop-uri este nevoie
nop; nop; … nop;

//RD#=‘0’
clrbit(PORTA,nRD);

//delay max(tARD, tAA-TW1) cu câte nop-uri este nevoie
nop; nop; … nop;

//a șteapt ă ca data extern ă s ă se propage prin sincronizator
nop; nop;

//cite ște data
data=PINC;

//RD#=‘1’
setbit(PORTA,nRD);

//delay tW2 cu câte nop-uri este nevoie
nop; nop; … nop;

// S-a terminat citirea portului extern.
// Între accese portul C este port de ie șire.
DDRC=0xff;

return data;
}

1

Microprocesoare, microcontrolere – Prelegere 4
Pentru a în țelege modul de conectare al unui periferic la un mi crosistem, este nevoie de o
descriere exact ă a unui periferic. Perifericul ales în acest scop e ste tastatura, deoarece este întâlnit ă
aproape în multe aplica ții și prezint ă o problematic ă specific ă. Pentru început se va descrie
comportarea unui contact mecanic ca parte a unui ci rcuit electric.
1. Problema contactului mecanic
Orice tastatura este alc ătuit ă din contacte mecanice cu revenire (taste, push but tons), plus logica
aferent ă. O variant ă de schema care converte ște starea unui contact mecanic în semnal electric e ste
prezentat ă în figura 1. Atâta timp cât tasta este neap ăsat ă, tensiunea Up este egal ă cu tensiunea la
bornele sursei, adic ă 5V, iar atunci când este ap ăsat ă este egal ă cu c ăderea de tensiune pe comutatorul
închis, adic ă 0V (comutator ideal). Teoretic, evolu ția în timp a tensiunii Up ar trebui s ă arate ca în
figura 2:

figura 1

5 volti
0 volti Tasta apasata Tasta
neapasata Tasta
neapasata Up

figura 2

Tensiunea Up va fi citit ă de microcontroler prin intermediul unui bit al unu i port de intrare: dac ă tasta
este neap ăsat ă se va citi ‚1’ logic iar dac ă este ap ăsat ă, ‚0’ logic. În exemplul urm ător pentru citirea
st ării contactului vom folosi bitul 0 din portul A (PA 0), dar se poate folosi orice port și orice bit din
port. În general, la ap ăsarea unei taste programul care ruleaz ă pe microcontroler trebuie s ă execute o
secven ță de instruc țiuni. De exemplu, dac ă tasta este ‚→’ (s ăgeat ă dreapta), secven ța de instruc țiuni
executat ă la ap ăsare va produce deplasarea cursorului. Evident, ace ast ă secven ță trebuie executat ă când
se cite ște un ‚0’ pe de pe PA0. Codul C este:
if ( (PINA & 1)==0 ){
// deplaseaz ă cursor la dreapta
}
Din p ăcate codul de mai sus nu func ționeaz ă corect. Atâta timp cat tasta este neap ăsat ă citirea bitului 0
din portul A va genera ‚1’ logic, ca în figura urm ătoare:
Up Actiune
1111111100
figura 3 5V S
Up

2 Imediat ce se detecteaz ă un ‚0’ (zeroul ro șu în figura 3), se execut ă secven ța de instruc țiuni necesar ă
deplas ării cursorului la dreapta. Aceast ă secven ță are durata marcat ă cu eticheta „Ac țiune” în figura 3.
Procesoarele și microcontrolere disponibile în prezent au viteze de prelucrare de peste 1 milion de
opera ții pe secund ă, astfel c ă ac țiunea ce trebuie efectuat ă la ap ăsarea tastei se va executa în cel mult
câteva milisecunde. Dup ă executarea ac țiunii, cel mai probabil se va citi din nou starea t astelor pentru
a se executa urm ătoarea ac țiune. Deoarece ap ăsarea unei taste dureaz ă cel pu țin 0,1 secunde,
urm ătoarea citire a lui PA0 va genera un ‚0’ și ac țiunea se va executa înc ă o dat ă. De fapt ac țiunea
(deplasarea cursorului la dreapta) se va executa pr obabil de zeci de ori.
Pentru ca ac țiunea s ă se desf ăș oare o singur ă dat ă, este necesar ă detectarea frontului coborâtor
al semnalului Up. Pentru a detecta un front trebuie f ăcute dou ă citiri succesive ale lui PA0 . Dac ă
prima citire genereaz ă un ‚1’, iar cea de-a doua un ‚0’, înseamn ă c ă între cele dou ă citiri exist ă un front
coborâtor.
La fiecare execu ție a buclei while(1) se face o citire a lui PA0. O citire se face la ex ecu ția
curent ă iar cealalt ă citire provine de la execu ția precedent ă. Cele dou ă citiri succesive care genereaz ă
secven ță „10” sunt scrise cu ro șu în figura 3. Secven ță C pentru detectarea frontului coborâtor este:
int main(){
unsigned char sample_ante = 1;
unsigned char sample_now = 1;

DDRA=0; //Portul A este configurat ca port de in trare

while (1){ //bucla principala
//…
sample_ante = sample_now;
sample_now = PINA;

if ( (sample_ante & 1<<0)==1
&&
(sample_now & 1<<0)==0 ){
// deplaseaz ă cursor la dreapta
}
//……

}//end while
}//end main

Secven ță de mai sus ar trebui s ă detecteze frontul coborâtor al lui Up și cursorul at trebui s ă se
deplaseze dreapta o singur ă dat ă. În realitate nu este a șa!
Dac ă se vizualizeaz ă cu osciloscopul modul de varia ție al tensiunii Up la ap ăsarea tastei, urmat ă
de eliberarea acesteia, se ob ține forma de und ă din figura 4. De regul ă, atât la ap ăsare cât și la eliberare
vibra ția contactelor din care este alc ătuit ă tasta genereaz ă un tren de impulsuri. Num ărul și durata
acestor pulsuri este aleatoare.
0 – 10 ms 0 – 10 ms 5 volti
0 voltiZona de
instabilitate
la apasare Zona de
instabilitate
la eliberare

figura 4

3 În exemplu tensiunea Up este generat ă de tasta ‚ →’ (s ăgeat ă dreapta) și este citit ă prin intermediul
portului A, bitul 0. În cazul cel mai defavorabil p rocesorul va sesiza toate fronturile coborâtoare al e
tensiunii Up și astfel va mi șca cursorul de 5 ori la ap ăsarea tastei , →’ și de 3 ori la eliberarea acesteia
(conform situa ției din figura 4). Astfel mi șcarea cursorului observat ă de utilizator va fi aleatoare.
Impulsurile suplimentare parazite trebuie eliminate pentru a ajunge la forma de und ă din figura
2. Opera ția de cur ățire se nume ște deparazitare în româna și debouncing în englez ă. Eliminarea
impulsurilor parazite se poate face fie prin mijloa ce soft, fie hard.
O variant ă de schem ă care face deparazitarea prin mijloace
hardware este prezentat ă în figura 5. Deoarece aceast ă metod ă a
fost probabil tratat ă la alte cursuri, nu vom mai insista asupra ei.
Metoda hard de deparazitare din figura 5 necesit ă 3
componente. Cum într-o aplica ție probabil este nevoie de mai
multe taste, num ărul de componente necesare se multiplic ă cu
num ărul de taste utilizate. Un num ăr mare de componente
înseamn ă cablaj mai mare, pre ț de cost mai mare și fiabilitate
mai mic ă. Pentru a evita aceste inconveniente se va folosi o
metod ă software pentru deparazitarea contactelor mecanice.
O metoda software foarte simpl ă de deparazitare este ca cele
dou ă citiri succesive ale lui PA0 s ă se fac ă la un interval de timp
mai mare decât durata maxim ă a instabilit ății. Datorit ă a ștept ării, pe durata instabilit ății se va face cel
mult o citire. Mai întâi vom analiza zona de instab ilitate la ap ăsare din figura 5. Aceast ă zona este
detaliat ă în figura 6 a și b.
Cum citirea portului și ap ăsarea tastei sunt evenimente asincrone, citirea în zona de instabilitate se
poate face cel mai devreme imediat dup ă primul front coborâtor, ca în figura 6 a.
ti Delay 1
a) 0 0
Delay

figura 6 ti Delay 1
b) 1 0
Delay

Citirea anterioar ă, situat ă la stâng ă în figura va fi în zona în care tasta este neap ăsat ă și va genera un
‚1’ iar cea ulterioar ă, aflat ă la dreapta în figur ă, va fi în zona în care tasta este ap ăsat ă și va genera un
,0’.
Citirea în zona de instabilitate se poate face cel mai târziu imediat înainte de ultimul front
coborâtor, ca în figura 6 b. Și în acest caz citirea anterioar ă se face zona în care tasta este neap ăsat ă și
va genera un ‚1’ iar cea ulterioar ă va fi în zona în care tasta este ap ăsat ă si va genera un ‚0’.
În concluzie orice citire în zona de instabilitate va avea o citire de ‚1’ înainte de zona de
instabilitate și o citire de ‚0’ dup ă de zona de instabilitate. Dac ă citirea în zona de instabilitate va
genera un ‚1’, vom ob ține secven ță …1 10… iar dac ă va genera un 0, vom ob ține secven ța …1 00….
Bitul scris cu ro șu reprezint ă citirea în perioada de instabilitate. Este posibil ca s ă nu se fac ă nici o
citire pe durata instabilit ății și atunci vom ob ține secven ță …10…
figura 5

4 O analiz ă similar ă a zonei de instabilitate la eliberare ne arat ă c ă secven ță generat ă în acest caz
este fie …0 11…, fie …0 01, fie ..01… .
În concluzie, dac ă cele dou ă citiri succesive ale lui PA0 se fac la un interval de timp mai mare
decât durata maxim ă a instabilit ății, secven ța valorilor citite este ..11 10 00…00111.. . Aceast ă secven ță
con ține un singur un singur front coborâtor.
Pentru a implementa metoda descris ă mai sus mai avem de rezolvat generarea intervalulu i de timp
dintre dou ă citiri. În acest sens vom folosi ideea din laborat orul 2 – blink. Orice aplica ție micro con ține
o bucl ă infinit ă. Execu ția codului din aceast ă bucl ă necesit ă un anumit timp. Timpul de execu ție a
buclei poate fi folosit pentru generarea sau m ăsurarea intervalelor de timp. Aceast ă metoda este
aproximativ ă. De exemplu, dac ă o execu ție a buclei while(1) necesit ă cel pu țin 5 ms, atunci pentru a
face o nou ă citire trebuie a șteptat 3 itera ții. Trei itera ții înseamn ă 3x5ms=15ms> 10ms. 10 ms este
durata maxim ă a instabilit ății. Codul C care detecteaz ă ap ăsarea tastei este:
#define DELAY 3

int main(){
unsigned char sample_ante = 1;
unsigned char sample_now = 1;
unsigned char loop_cnt=0;

DDRA=0; //Portul A este configurat ca port de in trare

while (1){ //bucla principala
//…
if (loop_cnt== DELAY){ //citirile se fac din 15 ms in 15 ms
loop_cnt=0;
sample_ante = sample_now;
sample_now = PINA;

if ( (sample_ante & 1<<0)==1 && (sample_now & 1<<0)==0 ){
// deplaseaz ă cursor la dreapta
}
}
//……
loop_cnt++;
}//end while
}//end main

Codul marcat mai sus cu verde este detectorul de fr ont coborâtor, copiat din programul anterior. Acest
cod nu se mai execut ă la fiecare execu ție a buclei principale, ci la fiecare a treia execu ție.
Programul de detec ție a ap ăsării unei taste poate fi folosit pentru mai multe ta ste. În figura
urm ătoarea este prezentat ă schema de conectare a dou ă taste la portul A pe pinii PA0 și PA1:

5 Codul care detecteaz ă ap ăsarea celor dou ă taste este prezentat în continuare:
#define DELAY 3

int main(){
unsigned char sample_ante = 1;
unsigned char sample_now = 1;
unsigned char loop_cnt=0;

DDRA=0; //Portul A este configurat ca port de in trare

while (1){ //bucla principala
//…
if (loop_cnt==DELAY){ //citirile se fac din 15 ms in 1 5 ms
sample_ante = sample_now;
sample_now = PINA;

if ( (sample_ante & 1<<0)==1 && (sample_now & 1<<0)==0 )
// actiuni pentru BTN0 ap ăsat

if ( (sample_ante & 1<<1)==1 && (sample_now & 1<<1)==0 )
// actiuni pentru BTN1 ap ăsat
}
//……
//……
loop_cnt++;
}//end while
}//end main
În exemplele anterioare pentru fiecare tast ă s-a alocat un pin microcontroler. Aceast ă metod ă
poate fi folosit ă în cazul unui num ăr mic de taste (1 – 6), dar devine inoperant ă dac ă num ărul acestora
este mare. De exemplu pentru 100 de taste, ca în ca zul tastaturii PC-ului, ar fi nevoie de un
microcontroler cu cel pu țin 100 de pini.

2. Dispunerea matriceal ă
În cazul unui num ăr mare de taste dispunerea acestora se face matriceal , ca în figura 7.
Tastatura din figur ă este o tastatur ă de calculator de
buzunar cu 16 taste, 10 pentru cifre, 4 pentru oper a țiile
aritmetice, egal și ‚C’ pentru reini țializare. Dispunerea în
matrice face ca num ărul de conexiuni s ă fie 8 în loc de 16.
În general, n taste dispuse matriceal au nevoie de n2
conexiuni.
Fiecare tast ă conecteaz ă electric o linie cu o coloan ă:
conexiunea dintre L0 și C0 se poate face numai prin
ap ăsarea tastei ‚0’, conexiunea dintre L0 și C1 se poate
face numai prin ap ăsarea tastei ‚1’, etc. Reciproc, dac ă am
putea proiecta un mecanism prin care s ă detect ăm dac ă o
linie este conectat ă cu o coloan ă, am identifica imediat ce
tast ă este ap ăsat ă: dac ă L0 este conectat cu C0 înseamn ă
că este ap ăsat ă tasta ‚0’, dac ă L0 este conectat cu C1 înseamn ă c ă este ap ăsat ă tasta ‚1’, etc.
figura 7 4



L3 5

C0 9

C1 6

/
… 8
… 2
… 1

C
… TASTATURA
=
… L2 +

C2 0

L1
*
… 3

C3 7
… L0

6
figura 8
figura 9 ⇓

figura 10

<=

figura 11
Pentru a identifica ce tast ă este ap ăsat ă, vom conecta liniile și coloanele în a șa fel încât pentru
fiecare tast ă s ă se formeze un circuit ca cel din figura 1. Pentru aceasta, fiecare coloan ă se conecteaz ă
printr-o rezisten ță la Vcc și fiecare linie se conecteaz ă la mas ă prin intermediul unui comutator, ca în
figura 8. Dac ă închidem comutatorul S1 și deschidem celelalte comutatoare (S2, S3, S4), cir cuitul A
din figura 8 devine echivalent cu circuitul B din f igura 9.
În circuitul B din figura 9, liniile L1, L2 și L3 sunt neconectate (în aer) ceea ce face ca tast ele
conectate la aceste linii s ă nu poat ă influen ța starea coloanelor, chiar dac ă sunt ap ăsate. Afirma ția
anterioar ă este adev ărat ă dac ă nu se apas ă simultan mai mult de 2 taste. Dac ă este a șa, circuitul B
devine echivalent cu circuitul C din figura 11.
Dac ă analiz ăm circuitul C se observ ă 4 circuite de tipul celui din figura 1. Acest circ uit se
redeseneaz ă, pentru a eviden ția cele 4 circuite elementare și se ob ține circuitul D din figura 10.
În concluzie, pentru a determina starea tastelor co nectate la linia L0 (0, 1, 2 și 3), vom conecta la
masa pe L0 și vom l ăsa în aer pe L1, L2 și L3. Apoi vom analiza starea coloanelor: dac ă este ap ăsat ă
tasta ,0’ coloana C0 va fi ‚0’, dac ă este ap ăsat ă tasta ,1’ coloana C1 va fi ‚0’, dac ă este ap ăsat ă tasta ,2’
coloana C2 va fi ‚0’ iar dac ă este ap ăsat ă tasta ,3’ coloana C3 va fi ‚0’.
Asem ănător, se poate determina starea tastelor conectate l a linia 1 – ‚4’, ‚5’, ‚6’, și ‚7’. Pentru
aceasta, vom conecta la masa pe L1 și vom l ăsa în aer pe L0, L2 și L3 iar apoi vom analiza starea
coloanelor: dac ă este ap ăsat ă tasta ,4’ coloana C0 va fi ‚0’ , dac ă este ap ăsat ă tasta ,5’ coloana C1 va fi
‚0’, etc. La fel se procedeaz ă pentru liniile 2 și 3. A4
.
..

.
..
L3 5
.
..
9
.
..
C0 C1 6
.
..
/
.
.. 8
.
.. 2
.
.. 1
.
..
C
.
.. TASTATURA
=
.
.. L2 +
.
..
C2 0
.
..
L1
*
.
.. 3
.
..
C3 7
.
.. S1
L0
S2
S3
S4 => R1
4k7 R2
4k7 R3
4k7 R4
4k7 VCC VCC VCC VCC VCC VCC VCC VCC
B4



L3 open 5

C0 9

C1 6

/
… 8
… 2
… 1

C
… TASTATURA
=
… L2 open +

C2 0

L1 open
*
… 3

C3 7
… L0=0V R1
4k7 R2
4k7 R3
4k7 R4
4k7
0 1 2 3R1
4k7 R2
4k7 R3
4k7 R4
4k7
DVCC
C0 VCC
C1 VCC
C2 VCC
C3 VCC VCC VCC VCC
CC1 2

C3 1

C2 C0 0
… 3

L0=0V R1
4k7 R2
4k7 R3
4k7 R4
4k7

7 În concluzie, pentru a determina starea unei taste se conecteaz ă la mas ă linia la care este
conectat ă respectiva tast ă, celelalte linii se las ă în aer și apoi se analizeaz ă starea coloanei la care este
onectat ă tasta: dac ă coloana este ‚0’ tasta este ap ăsat ă iar dac ă este ‚1’ este neap ăsat ă.
În continuare, se dore ște proiectarea unui bloc logic care s ă determine automat dac ă este
ap ăsat ă o tast ă și să genereze codul acesteia conform unei codific ări impuse ca cerin ță de proiectare.
Pentru ca determinarea tastei ap ăsate s ă se fac ă automat de c ătre un bloc logic este necesar ă înlocuirea
comutatoarelor mecanice S1 – S4 cu comutatoare elec tronice comandate. În esen ța este necesar un
circuit care s ă conecteze ie șirea sa la mas ă sau s ă o lase neconectat ă. O poart ă normal ă, cu ie șire
totem-pole, are ie șirea conectat ă prin intermediul a dou ă re țele de comutatoare electronice, unul între
ie șire și Vcc iar cel ălalt între ie șire și GND. Din acest motiv por țile normale nu sunt adecvate pentru
înlocuirea comutatoarelor mecanice.
Circuitele numerice care pot fi configurate s ă ofere la ie șire și starea neconectat sunt circuitele cu
ie șire 3-state sau circuitele open drain. Cum pinii mi crocontrolerului ATMega16 sunt controla ți de un
repetor 3-state, în continuare ne vom referi la ace ast ă variant ă. Dac ă controlul unui circuit 3-state este
inactiv ie șirea va fi neconectat ă (în aer), ambele re țele din interiorul por ții fiind blocate. Cum toate cele
4 porturi ATmega sunt prev ăzute cu por ți 3-state, nu sunt necesare circuite suplimentare p entru a
ob ține starea decuplat (open) a unei linii.

3. Gestiunea tastaturii
Codul tastei se va genera conform tabelului urm ător. Se observ ă c ă tastele au fost dispuse astfel
încât codul se ob ține din concatenarea num ărului liniei (reprezentat în baza 2) la care este c onectat ă
tasta cu num ărul coloanei (reprezentat în baza 2) la care este conectat ă tasta. Concatenarea este
echivalenta cu formula: Cod=Linia * 4 +Coloana.
tabelul 1
Tasta ap ăsat ă Pe linii se trimite:
L3 L2 L1 L0 Stare coloane:
C3 C2 C1 C0 Tasta conecteaz ă: Codul generat
Linia Coloana
‚0’ z z z 0 1 1 1 0 010 =00 2 010 =00 2 00 00
‚1’ z z z 0 1 1 0 1 010 =00 2 110 =01 2 00 01
‚2’ z z z 0 1 0 1 1 010 =00 2 210 =10 2 00 10
‚3’ z z z 0 0 1 1 1 010 =00 2 310 =11 2 00 11
‚4’ z z 0 z 1 1 1 0 110 =01 2 010 =00 2 01 00
‚5’ z z 0 z 1 1 0 1 110 =01 2 110 =01 2 01 01
‚6’ z z 0 z 1 0 1 1 110 =01 2 210 =10 2 01 10
‚7’ z z 0 z 0 1 1 1 110 =01 2 310 =11 2 01 11
‚8’ z 0 z z 1 1 1 0 210 =10 2 010 =00 2 10 00
‚9’ z 0 z z 1 1 0 1 210 =10 2 110 =01 2 10 01
‚+’ z 0 z z 1 0 1 1 210 =10 2 210 =10 2 10 10
‚-‚ z 0 z z 0 1 1 1 210 =10 2 310 =11 2 10 11
‚*’ 0 z z z 1 1 1 0 310 =11 2 010 =00 2 11 00
‚:’ 0 z z z 1 1 0 1 310 =11 2 110 =01 2 11 01
‚=’ 0 z z z 1 0 1 1 310 =11 2 210 =10 2 11 10
‚C’ 0 z z z 0 1 1 1 310 =11 2 310 =11 2 11 11
În continuare se va prezenta algoritmul prin care s e genereaz ă codul unei taste în cazul ap ăsării
acesteia. Generarea presupune dou ă etape:

8 1. Prima etap ă presupune scrierea unei func ții care scaneaz ă tastatura pentru a determina dac ă
exist ă vreo tast ă ap ăsat ă. Dac ă da, se va întoarce codul tastei conform tabelei de mai sus iar
dac ă nu, se va întoarce o combina ție nealocat ă, de exemplu 7Fh. Numele acestei func ții va fi
kbscan( ) .
2. În etapa a doua se apeleaz ă repetat kbscan pentru a determina momentul ap ăsării unei tastei.
Codul tastei trebuie s ă se genereze doar o singur ă dat ă, la ap ăsare. Se va folosi metoda
detaliat ă anterior pentru un singur pushbuton. În aceast ă faz ă se face și deparazitarea soft.
Din punct de vedere hardware conectarea tastaturii necesit ă numai un port, a șa cum se arat ă în figura
12.

figura 12
Vom folosi portul A pe care îl vom configura dup ă cum urmeaz ă:
• Patru pini din portul A, și anume PA4..PA7, se vor folosi pentru a trimite co dul de scanare al
liniilor: ZZZ0, ZZ0Z, Z0ZZ, 0ZZZ, unde Z înseamn ă c ă 3-state. Pentru a ob ține aceste 4 combina ții
bi ții 7:4 din PORTA se vor înscrie cu „0000”. Aceast ă valoare nu se mai modific ă. Pentru ca numai
un singur bit din 4 s ă fie zero iar ceilal ți Z, trebuie ca un singur repetor 3–state din port s ă fie activ.
Repetoarele 3-state sunt controlate de registrul I/ O DDRA. Cele 4 perechi de combina ții folosite
sunt centralizate în tabelul urm ător:
PORTA7:4 0000
DDRA7:4 0001 0010 0100 1000
PA7:4 ZZZ0 ZZ0Z Z0ZZ 0ZZZ
Deoarece pentru pinii PA7:4 ne intereseaz ă numai configura ția de tip OUTPUT, pentru simplitate,
în figura 12 partea de citire reprezentat ă de PINA și citirea PORTA nu a mai fost figurat ă. Vezi
structura porturilor la ATmega în prelegere 3 și laborator 3. D QU47
FD D4
D5
D6
D7
. .. 4.
..
PA1 -.
..
L3 PA7 5.
..
C0 9.
..
C1 6.
..
/.
.. 8.
..
PA2 2.
.. 1.
..
C.
.. TASTATURA PA0 =.
..
C2 L2 PA6 +.
.. 0.
..
L1 PA5
*.
.. 3.
..
C3 PA3 7.
.. L0 PA4 R1
4k7 R2
4k7 R3
4k7 R4
4k7 VCC VCC VCC VCC
TU35
TU36
TU37
TU38 T
U40 T
U41 T
U42 T
U43 DDRA4
DDRA5
DDRA6
DDRA7
PORTA7 PORTA4
PORTA5
PORTA6
D1 D0
D2
D3
D[7..0] Internal Data Bus ATmega D QU44
FD
D QU45
FD
D QU46
FD

9 • Ceilal ți patru pini din portul A, și anume PA0..PA3, se vor folosi pentru a citi stare a coloanelor.
Deoarece pentru pinii PA3:0 ne intereseaz ă numai configura ție de tip INPUT, pentru simplitate, în
figura 12 partea de scriere reprezentat ă de PORTA și DDRA nu a mai fost figurat ă.
În esen ță scanarea tastaturii presupune trimiterea combina țiilor ZZZ0, ZZ0Z, Z0ZZ, 0ZZZ pe
linii. Pentru a trimite aceste combina ții, este necesar s ă manipul ăm informa ția din PORTA și DDRA.
Dup ă fiecare combina ție trimis ă se verific ă starea coloanelor. Dac ă cel pu țin o coloan ă este activ ă
restul combina țiilor nu se mai trimit, se calculeaz ă codul tastei ap ăsate, urmat ă de întoarcerea acestuia.
Scanarea tastaturii se va face cu func ția char kbscan() , dup ă urm ătorul algoritm:
P1. Se face PORTA=0b00000000
P2. Se trimite ‚0’ pe linia L0. DDRA=0b00010000 .
P3. Cite ște starea coloanelor cu col=PINA .
P4. Testeaz ă dac ă s-a citit cel pu țin un ‚0’:
• Dac ă DA, exist ă cel pu țin o tast ă ap ăsat ă pe linia pe care s-a trimis ‚0’ și vom trece la
→P6.
P5. Deplaseaz ă DDRA la stânga. Dup ă prima deplasare DDRA va fi „0010 0000”, dup ă a doua
deplasare va fi „0100 0000”, dup ă a treia va fi „1000 0000” iar dup ă a patra, „0000 0000”
• Dac ă în DDRA este 0000 0000, înseamn ă c ă s-a trimis zero pe toate liniile și nu s-a
citit nici un zero de pe coloane. RETURN 0x7f.
• Dac ă DDRA este diferit de 0, → P3
P6. Execut ă conversia de la codurile de scanare la codul taste i ap ăsate, conform tabelul 1. De
exemplu, dac ă DDRA=0010 0000 iar col = 1011 este ap ăsat ă tasta numeric ă 6 și este necesar ă
conversia: 0010,1011 → 0110. Dup ă conversie, RETURN codul ob ținut prin conversie.
Implementarea func ției kbscan se va face la laborator, unde se vor da mai multe detalii de
implementare.
În etapa a dou ă trebuie rezolvat ă problema impulsurilor parazite generate de vibra ția contactului
mecanic și trebuie generat codul tastei ap ăsate. Pentru a genera codul tastei o singur ă dat ă, la ap ăsare,
se aplic ă metoda utilizat ă la detectarea frontului c ăzător (vezi figura 3 plus explica țiile aferente): se
consider ă dou ă scan ări succesive cu kbscan și se detecteaz ă secven ță tast ă neap ăsat ă – tast ă ap ăsat ă.
Pentru tast ă neap ăsat ă kbscan va întoarce 0x7f iar pentru tast ă ap ăsat ă ceva diferit de 0x7f. La fel ca în
cazul unui singur contact, cele dou ă scan ări se fac la un interval de tip mai mare decât dura ta
instabilit ății.
Codurile generate de scanarea continu ă a tastaturii sunt prezentate în figura 13: 0X7F
0X7F
0X7F 0X7FCOD
COD CODDELAY DELAY DELAY DELAY DELAY DELAY

figura 13

Generarea codului tastei se va face prin metoda det ec ției de front cu urm ătorul program:

10 #define NOKEY 0x7f
#define DELAY 3

int main(){
char code_ante = NOKEY ;
char code_now = NOKEY ;

unsigned char kbhit = 0;
char kbcode;

unsigned char loop_cnt=0;

while (1){ //bucla principala
//…
if (loop_cnt==DELAY){ //citirile se fac din 15 ms in 15 ms
loop_cnt=0;

code_ante = code_now;
code_now = kbscan();
if ( code_ante == NOKEY && code_now != NOKEY){
kbhit=1;
kbcode=code_now;
}
}
//……
//consuma codul
if (kbhit){
kbhit=0;
//prelucreaza kbcode; de exemplu afi șeaza-l
}
//……
loop_cnt++;
} //end while
} //end main

Tehnica detect ării apari ției unui eveniment prin testare periodic ă, în bucl ă, se
nume ște polling .

Observa ții: exist ă situa ții în care pooling-ul tastaturii nu func ționeaz ă. Să presupunem c ă în bucla
while(1) are ramuri pe care prelucrarea dureaz ă mai mult decât o ap ăsare de tast ă (0,1s). În acest caz
se pot pierde ap ăsări ale tastelor. S ă presupunem c ă dup ă ce s-a detectat ap ăsarea unei taste se fac
calcule care dureaz ă, s ă zicem, o secund ă. În acest timp tasta ap ăsat ă este eliberat ă și se apas ă o alt ă
tast ă (eventual aceea și). Când se reia scanarea tastaturii se a ștept ă o noua tranzi ție 0x7f → cod, adic ă o
nou ă ap ăsare, fără ca pentru tasta ap ăsat ă pe durata prelucr ării de durat ă să se fi întors vreun cod. În
general, o astfel de problem ă poate ap ărea ori de câte ori o resurs ă hardware trebuie
monitorizar ă în bucl ă.
Solu ția acestei probleme const ă în folosirea unei metode bazat ă pe întreruperi, metod ă ce va fi
prezentat ă într-o prelegerea viitoare.

1
Microprocesoare, Microcontrolere –Prelegere 5

1. Temporizatoare și num ărătoare (Timerer and counters). Generalit ăți.
Performan ța marii majorit ăți a programelor dezvoltate în cadrul disciplinelor de programare a fost
evaluat ă prin intermediul complexit ății temporare și spa țiale. Un program este cu atât mai performant cu
cât ocup ă mai putin ă memorie și ruleaz ă mai repede. Criteriul timpului minim de execu ție se aplic ă și
pentru programele de emulare hardware a func țiilor logice, cum sunt cele implementate în laborat oarele 3
și 4. Exist ă îns ă multe aplica ții specifice microcontrolerelor în care acest crite riu nu se aplic ă. Este cazul
programului care f ăcea s ă clipeasc ă un LED în laboratorul 2 – blink. Cerin ță obligatorie în acest caz este
ca LED-ul s ă clipeasc ă o dat ă pe secund ă, nu cât de repede se poate. Aceasta cerin ță ne oblig ă s ă
măsur ăm scurgerea timpului. Marea majoritate a aplica țiilor pentru microcontrolere necesit ă măsurarea
tipului: cât timp înc ălzim mâncarea la cuptorul cu microunde, cât tip spa l ă rufele ma șina de sp ălat, etc.
Pân ă în prezent se pot imagina dou ă modalit ăți de m ăsurare a timpului. Ambele modalit ăți se
bazeaz ă pe acela și principiu: executarea de c ătre procesor a unei instruc țiuni cod ma șin ă necesit ă un timp
bine precizat. În consecin ță, dac ă procesorul a executat n instruc țiuni timpul scurs se afl ă prin însumarea
timpilor de execu ție a celor n instruc țiuni.
Prima modalitate de a m ăsura trecerea timpului a fost folosit ă în laboratorul blink. Programul
blink este reluat în continuare:
#define P 125000L
#define DF 50L
#define TH (P*DF/100)
//125L = 1ms

int main(){
volatile long i;
DDRA=0xff;
i=0;

while(1){
if(i==0)
PORTA=1; //aprinde LED-ul

if(i==TH)
PORTA=0; //stinge LED-ul

i++;
if(i==P)
i=0; //a trecut o secunda
}
}
În acest program trecerea timpului este m ăsurat ă prin intermediul num ărului de execu ții ale buclei
principale while(1) . Din p ăcate, chiar și din acest exemplu simplu, se observ ă c ă timpul de execu ție al
buclei nu este întotdeauna acela și. Orice execu ție a buclei înseamn ă executarea instruc țiunilor scrise cu
negru bold. Exist ă îns ă o bucl ă în care se execut ă suplimentar instruc țiunea care aprinde LED-ul, o a doua
bucla în care se stinge LED-ul și o a treia bucl ă în care se face i=0 . Aceste trei bucle for avea un timp de
execu ție diferit de timpul de execu ția a celorlalte 124997 de bucle. În cazul clipirii LED-ului aceast ă
diferen ță între timpii de execu ție este imposibil de observat și poate fi acceptat ă.
În anumite cazuri îns ă situa ția este mult mai proast ă. În continuare este prezentat ă o posibil ă
structur ă a buclei principale:

2int main(){
while (1){
//cite ște intr ările i1,i2,…ik. Consum ă Tin
if (i1 ……) //Consum ă Tv1
//calcul 1; Consuma Tc1

if (i2 ……) //Consum ă Tv2
//calcul 2; Consuma Tc2

//……
if (ik ……) //Consum ă Tvk
//calcul k; Consuma Tck

//actualizeaz ă ie șirile. Consum ă Tout
}//end while 1
}
Mai întâi programul cite ște intr ările i1, i2,.., ik. Citirea intr ărilor necesit ă timpul Tin . Apoi fiecare intrare
este testat ă pentru a vedea dac ă este îndeplinit ă o condi ție specific ă. Executarea unui test consum ă timpul
Tv i (timp de verificare pentru intrarea i). În func ție de rezultatul testului se execut ă sau nu anumite
calcule. Timpul consumat pentru executarea calculul ui i se noteaz ă Tc i. În final se actualizeaz ă ie șirile,
opera ție care consum ă timpul Tout . Dac ă toate condi țiile din instruc țiunile if sunt evaluate la fals, timpul
de execu ție este cel mai mic cu putin ță și are valoarea:
T min =Tin +Tv 1+Tv 2+…+Tv k+Tout
În schimb, dac ă toate condi țiile din instruc țiunile if sunt evaluate la adev ărat, timpul de execu ție este cel
mai mare cu putin ță și are valoarea:
Tmax =Tin +Tv 1+Tc 1+Tv 2+Tc 2+…+Tv k+Tc k+Tout = Tin +Tv 1+Tv 2+…+Tv k+Tout + Tc 1+Tc 2+…+Tck =
= T min + Tc 1+Tc 2+…+Tc k.
Din analiza anterioar ă rezult ă c ă pot exista varia ții mari între timpul minim și cel maxim de execu ție a
buclei.
A doua modalitate de a m ăsura trecerea timpului este s ă execut ăm o bucl ă for cu corpul vid,
cum ar fi for(i=0; i<125000UL; i++){} . Aceast ă metoda este mult mai precis ă dar are
dezavantajul c ă atât timp cât se num ără nu se mai pot executa alte ac țiuni deoarece toat ă for ța de calcul a
procesorului este folosit ă în ciclul for . Cu toate acestea metoda este uneori utilizat ă, în special pentru
intervale mici de timp, de ordinul microsecundelor sau al zecilor de microsecunde.
Ambele metode de m ăsurare a timpului prezentate anterior prezint ă dezavantaje: ori sunt foarte
imprecise, ori consum ă for ță de calcul. Rezolvarea acestei probleme se bazeaz ă pe modul în care oamenii
execut ă ac țiuni la anumite momente de timp: ceasul cu alarm ă sau temporizatorul cu alarm ă. De
exemplu, pentru a înc ălzi mâncarea cinci minute la cuptorul cu microunde set ăm temporizatorul la cinci
minute iar când acesta ajunge la zero se va activa o alarm ă sonor ă. Putem executa orice alt ă ac țiune cât
timp func ționeaz ă temporizatorul dar când auzim alarma ne vom întrer upe activitatea curent ă, vom
executa ac țiunea cerut ă de scurgerea timpului programat și apoi ne vom relua activitatea întrerupt ă.
La microcontrolere rolul ceasului sau al temporizat orului este îndeplinit de num ărătoare iar
rolul alarmei este îndeplinit de sistemul de întrer uperi. Întreruperile se vor trata într-o prelegere viitoare.

32. Structura general ă a unui counter/timer
Măsurarea trecerii timpului necesit ă num ărătoare. Un num ărător binar este o ma șin ă secven țial ă
Moore la care starea urm ătoare se ob ține din starea prezent ă la care se adun ă sau se scade unu. Dac ă se
adun ă 1 spunem c ă num ărătorul num ără înainte iar dac ă se scade 1 spunem c ă num ărătorul num ără
înapoi. Schimbarea st ării num ărătorului are loc pe unul din fronturile semnalului d e ceas (de regul ă pe
frontul ridic ător). Astfel, num ărătorul va avea:
• intrare de ceas – CLK (clock),
• n ie șiri: Q[n-1:0] și
• intrare de direc ție . Aceast ă intrare se poate numi UP sau U/D. Pentru UP = ‚1’ num ărătorul
num ără în sens cresc ător iar pentru UP = ‚0’, în sens descresc ător.
În afar ă de intrarea de ceas CLK și ie șirile Q, num ărătorul mai poate fi înc ărcat paralel, la fel ca un
registru. Pentru înc ărcare paralel ă sunt necesare:
• n intr ări de date D[n-1..0] și o
• intrare de control a înc ărc ării LD – Load . Ideea este s ă putem seta valoarea st ării urm ătoare a
num ărătorului indiferent de valoarea st ării prezente. Setarea se face prin activarea intr ării LD .
Valoarea st ării urm ătoare se stabile ște prin intermediul a celor n intr ări de date D[n-1..0] . De
exemplu, dac ă la un num ărător pe 3 bi ți se adaug ă înc ărcarea paralel ă se poate ob ține secven ța:
…→ 000 → 001 → 101 → 110 →111 → 000 → ….Starea 101 s-a ob ținut prin înc ărcare paralel ă.
Dac ă înc ărcare paralel ă nu ar fi fost activ ă pe starea 001, în loc de 101 starea urm ătoare ar fi fost
010.
Încărcarea paralel ă permite generarea de intervale de timp programabil e tip temporizator. De
exemplu, dac ă se dore ște ca aplica ția s ă a ștepte un interval de timp de 1 ms iar perioada ceas ului
CLK este de 1 μs, se încarc ă num ărătorul cu valoarea 1000, num ărătorul începe s ă numere înapoi
și dup ă 1000 de impulsuri de ceas atinge valoarea zero. În tre momentul înc ărc ării și momentul
atingerii valorii zero trece 1 ms.
În afar ă de semnalele trecute în revist ă anterior, un num ărătorul mai poate fi prev ăzut cu:
• Intrare de validare a num ărării – CE (Clock Enable). Dac ă CE este ‚0’ num ărătorul ignor ă
semnalul de ceas și î și conserv ă starea.
• Intrare de ștergere CLR -Clear. Dac ă CLR este activ, starea num ărătorului devine 0…000, adic ă
toate ie șirile Q devin zero. Intr ările CLR și LD pot fi de tip sincron sau asincron, în func ție de
implementare.
• TC – Terminal Count. Este o ie șire activ ă pe durata st ării finale. Dac ă num ărătorul num ără înainte
starea final ă este starea în care to ți bi ții num ărătorului au valoarea ‚1’ iar dac ă num ărătorul
num ără înapoi este starea în care to ți bi ții sunt ‚0’. Aten ție : dup ă ce un num ărător atinge starea
final ă num ărarea nu se opre ște ci continu ă cu prima stare. De exemplu, un num ărător binar pe doi
bi ți num ără înainte astfel: … → 00 → 01 → 10 → 11 → 00 → 01 → 10 → 11 → 00 →……. „00”
este prima stare iar „11” este starea final ă. Semnalul TC este activ o perioad ă de ceas din 2 n
perioade. În exemplul anterior TC este activ din 4 în 4 perioade de ceas. În momentul în care
num ărătorul trece din starea final ă în prima stare spunem c ă num ărătorul cicleaz ă, adic ă începe un
nou ciclu de num ărare.
Num ărătorul generic prezentat mai sus se conecteaz ă la un sistem cu microprocesor. Modul în care se
face aceast ă conectare este detaliat în continuare.

41.1 Conectarea num ărătorul cu procesorul
Num ărătorul se mapeaz ă în spa țiul de adrese al procesorul la fel ca un registru paralel-paralel
și astfel num ărătorul devine un port buffer. Portul buffer a fost p rezentat în prelegerea 2, figura 1.
Scrierea acestui port înseamn ă înc ărcarea paralel ă a num ărătorului iar citirea înseamn ă citirea st ării
num ărătorului.
În figura 1este prezentat ă conectarea unui num ărător pe 8 bi ți la
un procesor cu magistrala de date tot de 8 bi ți.
Decodificatorul de adrese ADDRESS DECODER genereaz ă
semnalele WR_CNT și RD_CNT. Semnalul WR_CNT se
activeaz ă când procesorul execut ă o scriere la adresa alocat ă
num ărătorului iar semnalul RD_CNT se activeaz ă când
procesorul execut ă o citire la adresa alocat ă num ărătorului.
Decodificarea adreselor și decodificatorul de adrese sunt
prezentate pe larg în prelegerile 1 și 2.
Cele spuse anterior sunt adev ărate dac ă num ărul de bi ți ai
num ărătorului este egal cu l ățimea magistralei de date a
procesorului. Deoarece ATmega16 are magistrala de d ate de 8
bi ți, rezult ă c ă num ărătorul trebuie s ă aib ă tot 8 bi ți. Exist ă îns ă
multe aplica ții pentru care 8 bi ți nu sunt suficien ți. În acest caz
num ărătorul se va implementa pe 16. Un num ărător pe 16 bi ți va
ocupa dou ă adrese procesor.

1.2 Prescalerul
Urm ătoarea sec țiune a schemei de conectarea a num ărătorului la procesor o constituie sec țiunea de
generare și selec ție a ceasului de num ărare.
Așa cum s-a discutat anterior, m ăsurarea timpului scurs este o opera ție necesar ă în marea majoritate a
aplica țiilor de control. Intervalele de timp care trebuies c m ăsurate variaz ă de câteva microsecunde la
minute sau ore. În cele ce urmeaz ă vom presupune c ă semnalul de ceasul microcontrolerului are frecven ță
de 10MHz (perioada de 100 ns), deoarece marea major itate a microcontrolerelor au frecven ța ceasului în
jurul acestei valori. Un num ărător pe 8 bi ți evolueaz ă în plaja 0 – 255 și astfel intervalul maxim de timp
care poate fi m ăsurat f ără ca num ărătorul s ă cicleze este 255*100ns=25,5 μs. Acurate țea măsur ării este de
un impuls de ceas, adic ă 100 ns.
Pentru a m ăsura intervale de timp mai mari exist ă dou ă solu ții: s ă m ărim num ărul de bi ți pe care se
face num ărarea la 16, 24 sau 32 de bi ți sau să sc ădem frecven ța ceasului num ărătorului. Cre șterea
num ărului de bi ți pe care se face num ărarea are dezavantajul cre șterii complexit ății hardware-ului iar
sc ăderea frecven ței are dezavantajul sc ăderii preciziei. De exemplu, dac ă am sc ădea frecven ță ceasului de
num ărare de la 10 MHz la 5 MHz perioada ar cre ște de la 100 ns la 200 ns. În acest caz precizia ar fi de
200 ns, adic ă la jum ătate.
Solu ția aleas ă de to ți produc ătorii de microcontrolere este sc ăderea frecven ței ceasului
num ărătorului deoarece în majoritatea aplica ții nu sunt necesare simultan o precizie mare și un interval de
timp mare. Ce sens ar avea ca timpul de sp ălare la o ma șina de sp ălat sau timpul de înc ălzire la un cuptor
cu microunde s ă fie m ăsurat cu o precizie de 100 ns? În acest caz o preci zie de o zecime de secund ă este
mai mult decât suficient ă.
figura 1

5Pentru sc ăderea frecventei, ceasul de num ărare se ob ține se prin divizarea ceasului procesorului u o
putere a lui 2, fiind uzuale frecven țele fCLK_CPU /8, fCLK_CPU /64, fCLK_CPU /256, fCLK_CPU /512 și fCLK_CPU /1024.
Aceste frecven țe nu sunt standard și difer ă de la produc ător la produc ător și chiar de la microcontroler la
microcontroler, chiar dac ă sunt fabricate de acela și produc ător. Blocul care divizeaz ă ceasul procesor la 8,
64, …, 1024 se nume ște prescaler . Aceast ă denumire este folosit ă de to ți produc ătorii de
microcontrolere. În figura 2 este prezentat prescal erul precum și celelalte blocuri din sec țiunea de
generare și selec ție a ceasului de num ărare.
figura 2
Urm ătorul element din sec țiunea de generare și selec ție a ceasului de num ărare este un multiplexor
care prime ște la intrare ceasul procesor plus ceasurile ob ținute prin divizarea ceasului procesor și
genereaz ă la ie șire ceasul num ărătorului, notat CLK CNT . Acest multiplexor se nume ște MUX în figura 2.
Intr ările de selec ție ale multiplexorului MUX sunt conectate la un por t de ie șire, fiind astfel sub controlul
software-ului. Portul de ie șire prin care se selecteaz ă ceasul de num ărare constituie portul de control al
num ărătorului și este denumit PORT CONTROL în figura 2. Pentru sel ec ția ceasului de num ărare nu
sunt necesari to ți bi ții portului de control; ceilal ți bi ții vor controla func ții ce vor fi discutate în scurt timp.
În afar ă de m ăsurarea scurgerii timpului mai exist ă o opera ție care trebuie implementat ă în multe
aplica ții micro, și anume num ărarea evenimentelor externe. Un exemplu îl constituie num ărarea
persoanelor care au intrat într-un magazin. Pentru aceasta, la intrarea magazinului se monteaz ă un senzor
care ofer ă un impuls la fiecare trecere a unei persoane. Aces t impuls, numit în continuare CLK
EXTERN , poate fi folosit de un num ărător pentru contorizarea evenimentelor. Pentru aceas t ă opera ție
num ărătorul trebuie s ă numere înainte. Semnalul CLK EXTERN necesit ă o intrare suplimentar ă în
multiplexorul MUX din figura 2.

1.3 Indicatorul de ciclare (Timer overflow – TOV)
Urm ătoarea opera ție implementat ă de toate num ărătoarele din microcontrolere o constituie extensia
software a num ărului de ranguri pe care se face num ărarea. Așa cum s-a precizat anterior num ărătorul

6num ără pe 8 sau 16 bi ți. În figura 1 num ărătorul num ără pe 8 bi ți, ceea ce înseamn ă c ă valoarea maxim ă
pe care o poate atinge este 255. Pentru a putea num ăra mai mult de 255 de impulsuri de ceas software-ul
trebuie s ă detecteze când s-a atins starea final ă 255 și apoi s ă incrementeze o variabil ă. Aceast ă variabil ă
constituie extensia software a num ărătorului. Astfel num ărul de impulsuri de ceas va fi contorizat de
variabila software concatenat ă cu num ărătorul hardware.
Pentru ca lucrurile s ă fie mai clare se va considera urm ătoarea analogie : dispunem doar de un
cronometru care indic ă numai secundele și se cere s ă m ăsur ăm timpul în secunde, minute și ore.
Cronometru este un ceas analogic care are numai sec undar. Solu ția evident ă în acest caz este s ă
monitoriz ăm continuu cronometru și la fiecare trecere a limbii prin 60 s ă not ăm pe o hârtie c ă a mai
trecut un minut. Pe hârtie putem s ă ținem eviden ța timpului scurs în minute și ore iar secundele sunt
indicate de cronometru.
Dezavantajul acestei solu ții este c ă necesit ă monitorizarea continu ă a cronometrului, adic ă nu
trebuie s ă ne dezlipim ochii de pe acesta. Evident, aceast ă solu ție este inacceptabil ă. Solu ția corect ă este
să dot ăm cronometrul cu alarm ă și s ă desf ăș ur ăm alte activit ăți în paralel cu num ărarea. Când auzim
alarma întrerupem activitatea curent ă, actualiz ăm timpul pe hârtie și apoi ne relu ăm activitatea
întrerupt ă. Alarma este un indicator acustic care devine act iv când secundarul trece prin 0. Indica ția
acustic ă r ămâne activ ă pân ă când este ap ăsat un buton de anulare. Mai întâi ne vom ocupa de alarm ă.
Num ărătorul din microcontroler este cronometrul din exemp lu anterior cu deosebirea c ă starea
final ă a cronometrului este 60 iar cea a num ărătorului este 255 (dac ă num ărarea se face pe 8 bi ți). În ceea
ce prive ște indicatorul care precizeaz ă trecerea prin starea final ă, num ărătorul are o deja o ie șire numit ă
TC – Terminal Count – care semnalizeaz ă ca num ărătorul se afl ă în starea final ă. Descrierea ie șirii TC s-
a f ăcut la începutul acestui capitol.
Problema cu TC este c ă acesta este activ doar pe starea final ă, adic ă pe durata unui singur impuls
de ceas, ceea ce este prea pu țin. În analogia cu cronometrul cu alarm ă este ca și cum alarma ar fi activ ă
doar o secund ă. Cum timpul de execu ție al buclei principale while(1) poate fi și de ordinul zecilor de
milisecunde, generarea alarmei din TC necesit ă circuitele logice din figura urm ătoare:

7Data Bus
CLK CPU/8
CLK CPU/32
CLK CPU/1024
RD
WRADDR. BUS
…RD_CNT
ENBFF1RD_STAT

figura 3
Ieșirea TC a num ărătorului se conecteaz ă la intrarea validare CE a unui bistabil care are i ntrarea D
conectat ă la constanta ‚1’ și intrarea CLK la ceasul num ărătorului. Când num ărătorul ajunge în starea 255
semnalul TC devine activ astfel încât urm ătorul front al ceasului va înscrie ‚1’-ul în bistabil. I e șirea
bistabilului va r ămâne ‚1’ indiferent de valoarea ulterioar ă a lui TC. Bistabilul care indic ă ciclarea este
notat TOV (Timer OV erflow) și referin ța lui este FF1 în figura 3. Acest bistabil este bit ul i dintr-un port
de intrare/ie șire al microsistemului și are alocat ă o adres ă în spa țiul de adrese procesor. Acest port
constituie portul de stare al num ărătorului.
Decodificatorul de adrese ADDRESS DECODER genereaz ă semnalele RD_ STAT și WR_STAT.
Semnalul RD_STAT se activeaz ă când procesorul execut ă o citire de la adresa alocat ă portului de stare
iar WR_STAT atunci când se execut ă scriere. De remarcat c ă scrierea bitului i din portul de stare nu se
face în mod obi șnuit, adic ă valoarea scris ă devine noua stare a bistabilului. Scrierea obi șnuită se face prin
intermediul intr ării D a bistabilului, dar în cazul bistabilului FF 1 intrarea D este conectat ă permanent la
‚1’, dup ă cum s-a discutat anterior. Deoarece intrarea D nu este liber ă, semnalul WR_STAT va ac ționa
asupra intr ării CLR – Clear. Dac ă portul de stare ar fi alc ătuit numai din bistabilul FF1, ar fi suficient s ă
conect ăm WR_STAT la intrarea CLR. Astfel scrierea portului de stare cu orice valoare ar duce la
ștergerea lui FF1. Dar, a șa cum vom vedea în continuare, portul de stare mai conține și alt bistabil. În
acest caz scrierea ar șterge ambele bistabile. Pentru a șterge un anume bistabil se impune o condi ție
suplimentar ă: bitul i din portul de stare se va șterge doar dac ă este scris cu valoarea ‚1’. Adic ă FF1 se va
șterge dac ă simultan semnalul de scriere WR_STAT și bitul i al magistralei de date sunt ‚1’. Aceast ă
condi ție este implementat ă prin intermediul por ții AND din figura 3. În concluzie ștergerea bitului i din
portul de stare se face dac ă valoarea scris ă în bitul i este ‚1’. În cazul în care se scrie ‚0’, bitul i rămâne
nemodificat.
În rezumat, solu ția problemei m ăsur ării timpului cu cronometru are dou ă componente: alarm ă la
cronometru și întrerupere activit ății curente când se aude alarm ă. Alarm ă la num ărător se nume ște TOV
și a fost implementat ă în figura 3 iar întreruperile vor fi tratate în pr elegerea urm ătoare.

8Chiar dac ă alarma TOV a fost implementat ă pentru a fi folosit ă de sistemul de întreruperi asta nu
înseamn ă c ă aceasta nu poate fi folosit ă și în polling. TOV este un bit dintr-un port și poate fi citit sau
resetat în orice moment. Pentru ca polingul s ă poat ă fi folosit este obligatoriu ca între dou ă citiri ale
num ărătorului s ă nu treac ă mai mult de un ciclu de num ărare.
Bitul TOV nu este indispensabil pentru polling dar simplific ă scrierea software-ului ce
implementeaz ă metoda polling. Ca o parantez ă, vom ar ăta cum se poate determina intervalul de timp
între dou ă evenimente cu un cronometru care are numai secunda r și alarm ă la 60 de secunde. Vom
considera urm ătorul exemplu:
Eveniment: e 0 e1 e2 e3
Indica ție cronometru: 0 20 50 30…
TOV: 0 0 0 1…
Minute pe hârtie: 0 0 0 1…
Interval între citiri: 0 20 30 40…
1. Cronometrul porne ște de la 0. Pornirea cronometrului este evenimentul e0.
2. Evenimentul e1 se produce la 20s. Intervalul de tim p între e1 și e0 este 20-0=20s.
3. Evenimentul e2 se produce la 50s. Intervalul de tim p între e2 și e1 este 50-20=30s.
4. Evenimentul e2 se produce la 30s. Dac ă am calcula intervalul de timp între e2 și e3 ob ținem 30-
50=-20. Valoarea negativ ă indic ă ciclarea cronometrului. În cazul în care a avut lo c ciclarea între
cele dou ă citiri intervalul de timp între citiri se calculea z ă ca 30+60-50=40.
În cazul 4 se observ ă c ă ciclarea cronometrului poate fi detectat ă în dou ă moduri: diferen ța de timp între
dou ă citiri succesive este negativ ă sau TOV este ‚1’. Software-ul poate detecta ciclar e prin oricare din
metode dar metoda cu TOV este un pic mai simpl ă. Pân ă când va fi introdus sistemul de întreruperi vom
folosi metoda TOV atât în curs cât și la laborator.
În final vom calcula durata ciclului de num ărare. Vom relua analogia dintre un cronometru care
are numai secundar și num ărător. Un ciclu al cronometrului înseamn ă parcurgerea de c ătre secundar a
întregului cadran. Durata unui ciclu este egal ă cu num ărul de diviziuni ale cadranului înmul țit cu timpul
necesar parcurgerii unei diviziuni. Cronometrul are cadranul împ ărțit în 60 de diviziuni iar parcurgerea
unei diviziuni dureaz ă o secund ă. Astfel un ciclu cronometru este egal cu 60*1s=60s =1min. Un
num ărător este un cronometru care are N diviziuni iar par curgerea unei diviziuni este se data de perioada
ceasului de num ărare T CLK_CNT . Durata unui ciclu num ărător este T cycle =N* T CLK_CNT . Prescalerul
genereaz ă ceasul de num ărare T CLK_CNT prin divizarea cu p a ceasului procesor T CLK_CPU . Atunci putem
scrie c ă
TCLK_CNT = p* T CLK_CPU Rel. 1
Dac ă înlocuim pe T CLK_CNT în durata ciclului de num ărare Tcycle =N* T CLK_CNT ob ținem:
Tcycle = p * N * T CLK_CPU Rel. 2
Rela ția Rel. 2 este rela ția fundamental ă cu perioade a num ărătoarelor . Știind c ă T=1/ f sau f=1/T putem
ca în Rel. 2 să înlocuim perioadele cu frecven țele corespunz ătoare:
Tcycle = p * N * T CLK_CPU
CPU CLK cycle fNpf_1*1=
În final ob ținem:

9cycle CPU CLK fNp f **_= Rel. 3
Rela ția Rel. 3 este rela ția fundamental ă cu frecven țe a num ărătoarelor. În continuarea expunerii se vor
folosi rela țiile 1-3.
Aten ție : Rela țiile 1-3 sunt adev ărate numai dac ă ceasul num ărătorului CLK_CNT este un semnal
periodic. CLK_CNT este periodic dac ă se ob ține prin divizarea cu p a ceasului procesor CLK_CPU.
CLK_CNT poate s ă nu fie periodic dac ă este generat extern (CLK EXTERN în figura 2 și în figura 3).

3. Num ărătorul (Timer/Counter) 0 la ATmega16
ATmega16 este prev ăzut cu 2 num ărătoare pe 8 bi ți (0 și 2) și un num ărător pe 16 bi ți. Oricare
num ărător (timer/counter în documenta ție) poate fi configurat s ă numere fie impulsuri interne (timer), fie
impulsuri externe (counter). Cele trei num ărătoare pot fi programate s ă func ționeze în 4 moduri: normal,
CTC, PWM rapid și PWM corect. Pe lâng ă informa ția care urmeaz ă este obligatoriu s ă parcurge ți
din datele de catalog capitolele 14, 15, 16 și 17. Pentru început se va prezenta num ărătorul 0.

3.1 Modul normal
Schema num ărătorului 0 în modul normal este prezentat în figura urm ătoare:

figura 4
În figur ă s-au reprezentat numai blocurile active în modul n ormal. Schema este foarte asem ănătoare cu
schema de principiu din figura 3. Blocurile care ap ar în ambele figuri sunt num ărătorul, prescalerul,
portul de control TCCR0 (Timer/Counter Control Regi ster) și indicatorul TOV0. De remarcat c ă
indicatorul TOV a fost absorbit în blocul de contro l „Control Logic”. Ceasul num ărătorului este generat
de blocul „Clock Select”. Prescalerul este comun nu m ărătoarelor 0 și 1 și este prezentat în figura
urm ătoare.

10
figura 5
Ceasul num ărătorului 0 este generat la ie șirea multiplexorului din dreptunghiul ro șu. Prin intermediul
acestui multiplexor se poate selecta fie ceas exter n, fie un ceas intern derivat din ceasul procesor. În
esen ța acest multiplexor este multiplexorul MUX din figu ra 3, dar cu mai multe op țiuni. Prin intermediul
a trei bi ți din TCCR0 (registrul de control al num ărătorului 0) – CS00, CS01 și CS02 – ceasul
num ărătorului 0 poate fi ceasul procesorului, ceasul proc esorului divizat cu 8, 64, 256 sau 1024, frontul
ridic ător sau frontul coborâtor al semnalului de num ărare extern T0 sau constanta ‚0’. Selectarea
constantei zero înseamn ă num ărător oprit.
Modul în care func ționeaz ă num ărătorul 0 se selecteaz ă prin intermediul bi ților WGM01 și
WGM00 din TCCR0. Ace ști bi ți sunt marca ți cu verde în figura 5. Pentru modul normal ace știa trebuie
să fie 0. În toate modurile de operare se definesc co nstantele BOTTOM, TOP și MAX TOP (pe scurt
MAX). BOTTOM ca cea mai mic ă valoarea pe care o poate avea num ărătorul și are valoarea 0x00. MAX
ca cea mai mare valoarea pe care o poate avea num ărătorul și are valoarea 0xFF. Valoarea TOP depinde
de modul în care func ționeaz ă num ărătorul.
Bi ții COM01 și COM00 vor fi discuta ți în capitolul urm ător.
Modul normal este cel mai simple mod de operare. În acest mod num ărătorul num ără liber, adic ă
este un num ărător modulo 256 . Direc ția de num ărare este numai înainte, f ără ca s ă se execute vreodat ă
ștergerea num ărătorului. Starea curent ă a num ărătorului se ob ține din starea anterioar ă la care se adun ă 1,
cu o excep ție: dup ă starea MAX (0xFF) urmeaz ă starea BOTTOM (0x00). În modul normal indicatorul
TOV0 (Timer/Counter Overflow Flag) va fi setat în a cela și ciclu de ceas în care num ărătorul devine 0. În
acest caz TOV0 se comport ă ca un al nou ălea bit, cu excep ția faptului c ă este doar setat în hardware, f ără
a fi și șters. Ștergerea se poate face de software. Indicatorul TO V0 este disponibil prin intermediul bitului
0 din registrul de stare TIFR. Acest bit este marca t cu ro șu în figura urm ătoare:

figura 6
Modul normal este folosit frecvent pentru contoriz area evenimentelor externe. În continuare se va

11 prezenta structura acestei aplica ții.

3.2 Aplica ție de contorizare evenimente externe cu Timerul 0 î n modul normal
Pentru contorizarea evenimentelor externe este nev oie de un semnal care s ă î și schimbe valoarea
la apari ția unui evenimentului. Num ărătorul va contoriza num ărul de fronturi ale respectivului semnal.
Acest semnal trebuie aplicat pe pinul T0 al microco ntrolerului ATMega16. Pentru împachetarea DIP40
pinul T0 este pinul 1. Acest pin trebuie programat ca intrare, adic ă DDRB(0) trebuie s ă fie ‚0’.
Este posibil ca s ă se contorizeze fie fronturile ridic ătoare, fie fronturile coborâtoare ale semnalului
de num ărare. Pentru ca num ărarea s ă se fac ă pe front ridic ător bi ții CS02:CS00 trebuie s ă aib ă valoarea
„111” iar pentru frontul coborâtor valoarea „110”.
Dup ă cum s-a precizat anterior num ărul de bi ți pe care se face num ărarea trebuie extins în
software deoarece num ărătorul num ără doar pe 8 bi ți. Extensia software se face cu ajutorul bitului de
stare TOV0: când num ărătorul cicleaz ă, adic ă trece din starea 255 în starea 0, bitul TOV0 este setat
automat de hardware. Deci de fiecare data când TOV0 este ‚1’ înseamn ă c ă s-au mai num ărat 256 de
evenimente. Astfel num ărul de evenimente ap ărute este dat de:
num ărul de apari ții ale lui TOV0 *256 + valoarea curent ă a num ărătorului.
În program trebuie s ă monitoriz ăm pe TOV0 și când acesta devine ‚1’ vom incrementa o variabil ă numit ă
de exemplu cnt_hi. Apoi vom șterge imediat pe TOV0 pentru a captura urm ătoarea tranzi ție. Vom
presupune c ă evenimentele ce se contorizeaz ă apar suficient de rar astfel încât TOV0 s ă fie setat cel mult
o dat ă pe durata de execu ție a unei itera ții a buclei while(1) . Într-o prim ă aproxima ție extensia software
se implementeaz ă prin intermediul urm ătorului program:

12 //Application – Event Counter
include <avr/io.h>
int main(){

unsigned char cnt_hi=0;
unsigned int cnt;

// ┌──┬ Normal mode
TCCR0=0b0 000 0111 ;
// ││ └┴┴─ External clock source on T0 pin, ↑
// └┴───── Normal port operation, OC0 disconnected .
TCNT0=0;

while (1){

if (TIFR & 1<<TOV0){ // TOV0 is an alias for integer 0 in avr/io.h
TIFR |= 1<<TOV0; // Clear TOV0
cnt_hi++;
}

cnt = cnt_hi*256 + TCNT0;

//use cnt

}//end while
}//end main
Programul de mai sus pare corect dar de fapt exist ă o situa ție în care gre șește. Aceast ă situa ție este
urm ătoarea:
while (1){
//cnt_hi=0x02, TCNT0=0xFF, TOV0=0
if (TIFR & 1<<TOV0){
TIFR…
}
//cnt_hi=0x02, TCNT0=0x00, TOV0=1
cnt = cnt_hi*256 + TCNT0;

Să presupunem c ă înainte de executarea instruc țiunii if variabila cnt_hi=0x02, TCNT0=0xFF și TOV0=0 .
Deoarece TOV0 este ‚0’, corpul if -ului nu se execut ă. Dar imediat dup ă if apare un front ridic ător al lui
T0 și num ărătorul trece din 0xFF în 0x00 iar TOV0 devine ‚1’. D eoarece suntem exact dup ă if , cnt_hi
rămâne nemodificat; acesta va fi incrementa la urm ătoarea itera ție a buclei while(1).
În concluzie, înainte de a calcula pe cnt avem cnt_hi=0x02, TCNT0=0x00 și TOV0=1 . Cu aceste
valori ob ținem cnt=2*256+0 . Aceast ă valoare este evident gre șit ă, valoarea corect ă fiind cnt=3*256+0 .
Aceast ă situa ție a ap ărut deoarece incrementarea num ărătorului și executarea programului sunt dou ă
procese independente ce se execut ă în paralel . Schimbarea valorii num ărătorului se poate face în timpul
execu ției oric ărei instruc țiuni din program.
Solu ția evident ă în acest caz este s ă ținem seama de valoarea lui TOV0 atunci când calcul ăm
valoarea lui cnt :
if (TIFR&1)
cnt = (cnt_hi+1)*256 + TCNT0;
else
//cnt_hi=0x02, TCNT0=0x00, TOV0=1
cnt = cnt_hi *256 + TCNT0;

Din p ăcate nici aceast ă modificare nu rezolv ă problema deoarece num ărătorul se poate incrementa exact
înainte de calcularea lui cnt pe ramura else . Pentru a corecta aceasta deficien ță vom face o copie a
num ărătorului înainte de instruc țiunea if . Cu aceste dou ă modific ări programul de contorizare evenimente
este urm ătorul:

13 //Application – Counter
int main(){
unsigned char cnt_hi=0, cnt_lo_copy;
unsigned int cnt;

TCCR0=0b0 000 0111 ; TCNT0=0;
while (1){
//t 1: //cnt_hi=0x02, TCNT0=0xFF, TOV0=0
if (TIFR & 1){ //TIFR bit 1 is OCF0
TIFR |= 1;
cnt_hi++;
}
//t 2
cnt_lo_copy = TCNT0;
//t 3
if (TIFR&1)
cnt = (cnt_hi+1)*256 + TCNT0;
else
//t 4
cnt = cnt_hi * 256 + cnt_lo_copy;

//use cnt

}//end while
}//end main
Incrementarea num ărătorului, adic ă situa ția cnt_hi=0x02, TCNT0=0x00 și TOV0=1 poate apare
în oricare din momentele de timp t 2, t 3 sau t 4. Dac ă incrementarea apare la t 2 sau la t 3, atunci când se
execut ă if -ul TOV0 va fi ‚1’ și valoarea calculat ă a lui cnt va fi cea de pe ramura then . Aceast ă valoare
este corect ă deoarece tine seama de faptul c ă TOV este ‚1’.
Dac ă atunci când se execut ă if -ul TOV0 este ‚0’ atunci calculul lui cnt se face pe ramura else .
Pentru a anula efectul unei posibile increment ări a num ărătorului la t 4 cnt se calculeaz ă cu copia
num ărătorului, copie care a fost f ăcut ă când valoarea lui TOV0 era 0.
În concluzie programul de mai sus calculeaz ă întotdeauna corect cnt .

3.3 Modul CTC – Clear Timer on Compare Match
Anterior s-a f ăcut o analogie între num ărător și un cronometru care indic ă doar secundele.
Deosebirea consta în valoarea st ării finale: starea final ă a cronometrului este 60 iar cea a num ărătorului
este 255 (dac ă num ărarea se face pe 8 bi ți). Se spune c ă num ărătorul num ără modulo 256 iar cronometru
modulo 60.
În multe aplica ții este necesar ă executarea periodic ă a anumitor ac țiuni. Astfel de aplica ții provin
din domeniul transmisiei datelor. Problema în astfe l de aplica ții este c ă periodicitatea ac țiunilor nu
coincide cu perioada cicl ării num ărătorului. Mai întâi vom stabili care este perioada c icl ării
num ărătorului, adic ă perioada semnalului TC. Secven ța de num ărare este urm ătoarea:
Num ărător: 0, 1, 2,……,254, 255 , 0, 1, 2,……,254, 255 , 0, 1, 2,……,254, 255 ,..
TC: 0, 0, 0,……, 0, 1, 0, 0, 0,……, 0, 1, 0, 0, 0,……, 0, 1,..
TOV: 0, 0, 0,……, 0, 0, 1, 1, 1,……, 0, 0, 1, 1, 1,……, 0, 0,..
Analizând secven ță de mai sus se observ ă c ă TC apare pe starea final ă 255. De la o starea 255
pân ă la urm ătoarea stare 255 num ărătorul trebuie s ă numere 256 de impulsuri de ceas CLK CNT . N-ul
timer/counterului 0 în modul normal este 256. Dac ă în Rel. 2 înlocuim pe N cu 256, ob ținem perioada lui
TC și implicit a lui TOV:
Tcycle = p * N * T CLK_CPU = 256* p* T CLK_CPU
Așa cum s-a precizat anterior, aceast ă perioad ă nu este adecvat ă într-o mul țime de aplica ții. „Nu
este adecvat ă” nu înseamn ă c ă num ărarea modulo 256 nu poate fi folosit ă, numai c ă necesit ă

14 monitorizarea continu ă a num ărătorului. De exemplu, dac ă ac țiunile cerute de aplica ție trebuie executate
din 50 în 50 impulsuri de num ărare CLK CNT atunci aceste ac țiuni trebuie executate pe st ările 49, 99, 149,
249, 43, etc. Cum TOV se activeaz ă doar pe starea 0, acesta nu poate fi folosit ca in dicator și nu ne mai
rămâne decât s ă monitoriz ăm continuu num ărătorul. Monitorizarea continu ă înseamn ă c ă nu mai putem
executa și alte ac țiuni, a șa c ă aceast ă solu ție este rareori acceptat ă.
În acest caz solu ția este ca num ărătorul s ă nu mai numere modulo 256 ci modulo N, valoarea N
fiind programabil ă. Pentru exemplu anterior, secven ța de num ărarea modulo 50 este:
Num ărător: 0, 1, 2,……,48, 49 , 0, 1, 2,……,48, 49 , 0, 1, 2,……,48, 49 , ..
EQ: 0, 0, 0,……, 0, 1, 0, 0, 0,……, 0, 1, 0, 0, 0,……, 0, 1, ..
Pentru a putea num ăra modulo N programabil ad ăug ăm un comparator, un registru plus alte elemente ce
vor fi discute imediat. În datele de catalog ale mi crocontrolerului modul de num ărare modulo N se
nume ște CTC – Clear Timer on Compare Match. Timerul 0 va func ționa în modul CTC dac ă în portul de
control bi ții de mod WGM0(1:0) = „10”.
Componentele timerului 0 active în modul CTC sunt p rezentate în figura urm ătoare:

figura 7
1. Registrul în care se memoreaz ă valoarea maxim ă din secven ța de num ărare se nume ște OCR0 . Acest
registru este conectat la procesor ca port buffer. Valoarea scris ă în acest registru este comparat ă cu
starea num ărătorului de c ătre comparatorul de egalitate „=” în figura 7. OCR0 și comparatorul de
egalitate sunt încadrate de dreptunghiul ro șu din figura 7.
2. Ultimul element al modului de num ărare modulo N variabil îl constituie blocul de semnalizare a
egalit ății. Acest bloc are aceea și structura ca blocul care semnalizeaz ă TOV și se nume ște OCF0
(Output Compare Flag). Acest indicator va fi setat în ciclu de ceas ce urmeaz ă dup ă detectarea
egalit ății dintre starea num ărătorului și registrul OCR0. Indicatorul OCF0 poate fi doar se tat de
hardware. Ștergerea se poate face de software prin înscrierea cu ‚1’. Indicatorul OCF0 este accesat
prin intermediul bitului 1 din registrului TIFR. Ac est bit este marcat cu verde în figura 6.
În modul CTC num ărătorul num ără înainte pân ă când starea sa devine egal ă cu con ținutul registrului
OCR0. Dup ă ce are loc egalitatea, pe urm ătorul front al ceasului num ărătorul este șters și ajunge în starea
BOTTOM (0x00). Con ținutul registrului OCR0 define ște valoarea maxim ă pân ă la care se num ără și se
nume ște valoarea TOP în datele de catalog. Astfel num ărătorul 0 va num ără în mod CTC astfel: 0, 1, 2,

15 TOP-1, TOP, 0, 1, …. În acest mod num ărătorul 0 devine un num ărător modulo TOP+1. Cum valoarea
TOP este programabil ă, în modulul CTC num ărătorul 0 este un num ărător modulo programabil. O
aplica ție a timerului 0 în mod CTC va fi prezentat ă în capitolul Error! Reference source not found. .
În plus în figura 7 apare un bloc nou numit generat or de form ă de und ă. Generatorul de form ă de und ă
este încadrat în dreptunghiului albastru din figura 7. Blocul de generare a formei de und ă controleaz ă
ie șirea Output Compare (OC0/PB3) disponibila pe pinul 4 la ATmega16. Prin intermediul blocului de
generare a formei de und ă și a pinului OC0 activitatea timerului zero se poate vedea în exterior direct,
fără interven ția software-ului, ceea ce mic șoreaz ă timpul de r ăspuns al sistemului.
Blocul de generare a formei de und ă poate fi configurat în func ție de bi ții COM01 și COM00 din
TCCR0. Ace ști bi ți sunt marca ți cu albastru în figura 5. Semnifica ția bi ților COM01 și COM00 din
TCCR0 este diferit ă în func ție de modul în care func ționeaz ă timerul. Dac ă modul de lucru este normal
sau CTC , atunci semnifica ția acestor bi ți este:
1. COM0(1:0)=00. OC0 este deconectat. OC0 este controlat de PORTB.
2. COM0(1:0)=01. OC0 î și schimb ă valoarea ( Toggle ) când comparatorul detecteaz ă egalitate
între starea num ărătorului și registrul OCR0.
3. COM0(1:0)=10. OC0 este șters ( Clear ) când comparatorul detecteaz ă egalitate între starea
num ărătorului și registrul OCR0..
4. COM0(1:0)=11. OC0 este setat ( Set ) când comparatorul detecteaz ă egalitate între starea
num ărătorului și registrul OCR0.
Pentru ca pinul OC0/PB3 s ă fie sub controlul blocului de generare a formei de und ă trebuie ca bi ții
COM0(1:0) ≠00 și direc ția lui PB3 să fie out (DDR3=,1’).

3.4 Ceas digital cu timerul 0
În mule aplica ții trebuie să ținem eviden ța timpului. Un ceas ține eviden ța timpului scurs în ore,
minute și secunde, un cronometru ține și eviden ță zecimilor de secund ă și exist ă situa ții când evidenta
trebuie ținut ă în unit ăți de 0,2 sau 0,5 secunde. Astfel rezolu ția cu care se măsoar ă timpul poate fi o
secund ă, o zecime de secund ă, 0,2 secunde etc.
Ob ținerea acestei rezolu ții se face cu un semnal periodic cu perioada T r (r de la rezolu ție). În mod
ideal, T r se genereaz ă cu un timer/counter care cicleaz ă exact la T r, adic ă T r = Tcycle . Din p ăcate perioada
Tcycle cu care cicleaz ă un timer pe 8 bi ți este de cele mai multe ori mai mic ă decât T r. Conform rela ției
Rel. 2, T cycle = p * N * T CLK_CPU . Cel mai mare p pentru un timer din ATmega16 este 1024 iar cel mai
mare N pentru un timer pe 8 bi ți este 256. Referitor la T CLK_CPU , dac ă se dore ște for ța maxim ă de calcul, și
de regul ă se dore ște, trebuie aleas ă frecven ța maxim ă a ceasului procesor, și anume 16MHz. Pentru
fCLK_CPU =16MHz ob ținem T cycle = p * N * T CLK_CPU =1024 * 256 *1/16MHz=16,39 ms. Evident, aceast ă
valoare este mai mic ă decât rezolu țiile uzuale de 0,1, 0,5 sau 1s discutate anterior.
Deoarece în mod uzual T r > Tcycle , vom forma T r din mai multe cicluri de num ărare T cycle . Astfel
rela ția fundamental ă pentru m ăsurarea timpului cu num ărărtoare este:
Tr=kTcycle Rel. 4

Practic vom incrementa variabila software k la fiecare ciclare a num ărătorului și când aceasta
ajunge la valoarea k știm c ă a trecut timpul T r.

16 Aplica ția care arat ă cum se utilizeaz ă timerul 0 pentru m ăsurarea timpului este un ceas digital la
care separatorul dintre ore și minute clipe ște, fiind jum ătate de secund ă stins, jum ătate aprins. Rezult ă c ă
Tr este 0,5 secunde deoarece la fiecare jum ătate de secund ă trebuie s ă se execute o ac țiune. Un astfel de
ceas digital se poate folosi la cuptorul cu microun de la ma șina de sp ălat, sau ca ceas de mas ă. În
continuare vom ar ăta cum se ob ține Tr= 0,5 sec urmând ca s ă implement ăm orele, minutele și secundele
la laborator.
Frecven ță ceasului procesor pentru aplica ția ceas digital este 9,216 MHz . În mod uzual frecven ța
ceasului procesor este frecven ță maxim posibil ă pe care o suport ă microcontrolerul, adic ă 16 MHz în
cazul ATmega. Aceast ă frecven ță se ob ține însa numai cu un cristal de cuar ț extern, ceea ce înseamn ă un
pre ț de cost mai mare. Frecven ța maxim ă care se poate ob ține cu oscilatorul intern din ATmega (f ără
componente externe) este 8MHZ. Pe bun ă dreptate se pune întrebarea de ce s-a ales frecven ța de 9,216
MHz. Aceast ă frecven ță este necesar ă interfe ței seriale: pentru vitezele standard de emisie și de recep ție
ceasul procesor trebuie s ă fie un multiplu de 16*115200. Frecven ță 9,216Mhz = 480 *16*115200 Hz este
suficient de mare pentru o for ță de calcul decent ă și este și multiplu de 16*115200.
În cele ce urmeaz ă num ărătorul 0 va func ționa în modul CTC. În modul CTC num ărătorul 0 este
num ărător modulo N, adic ă num ără 0, 1, 2, N-1, 0, 1, … , N-1, 0,… Parcurgerea s t ărilor de la 0 la N-1
constituie un ciclu de num ărare. Într-un ciclu num ărătorul num ără N de impulsuri ale ceasului de
num ărare CLK CNT . Valoarea N-1 este valoarea care trebuie înscris ă în OCR.
Pentru a ob ține Tr=0,5 s vom folosi rela țiile Rel. 3 și Rel. 4. Mai întâi vom exprima Rel. 4cu frecven țe:
r cycle
cycle rcycle r f kffk
f fTT kT =⇒=⇒= =1 1,
Dac ă înlocuim f cycle din rela ția de mai sus în rela ția Rel. 3, rezult ă:
kpN fffpNk f f kf pNf f
rCPU CLK
r CPU CLK r cycle cycle CPU CLK = ⇒ = ⇒= =_
_ _ ,
În concluzie putem scrie:
kpN ff
rCPU CLK =_ Rel. 5
În rela ția Rel. 5 folosim fCLK_CPU =9,216MHz și fr=1/0,5s=2Hz:
Hz MHz
ff
rCPU CLK
2216 , 9 _= =9216000/2= (213 32 53 )/2 = 212 32 53
În rela ția Rel. 5 vom c ăuta cel mai mic k, ceea ce este echivalent cu c ăutarea celui mai mare produs pN.
Suplimentar, p trebuie să fie egal cu 1, 8, 64, 256 sau 1024 iar N să fie mai mic ca 256:
k p N=212 32 53= 2 * 32 * 210 * 2 * 5 3 → k=2 * 32=18, p=210 , N=2 * 5 3 = 250 < 2 56
Motivul pentru care se dore ște cel mai mic k va fi precizat în scurt timp.
Programul care implementeaz ă contorizarea ceasul cu clipirea separatorului cu t imerul 0 este:

17 int main(){
unsigned char cycles=0, one_sec=0, sec=0;

// ┌──┬ CTC mode
TCCR0=0b01 00 0101 ;
// ││ └┴┴─ P=1024
// └┴───── Normal port operation, OC0 disconnected .
OCR0=250-1; // N=250

while (1){
//…
// t1
if (TIFR & 1<<OCF0){ // OCF0 este bitul 1 din TIFR. #d efine OCF0 1 in avr/io.h
TIFR |= 1<<OCF0; // clear OCF0
cycles++;

if (cycles==18){ k=18
// a trecut jum ătate de secund ă
cycles=0;
// aprinde sau stinge separatorul
one_sec++;

if (one_sec==2){
one_sec=0;
// a trecut o secund ă
// actualizeaz ă secunde, minute, ore
// folose ște timpul (de exemplu afi șează-l)
}
}
}
// t2
//…
}//end while
}//end main
În acest moment vom explica de ce se dore ște o valoare cât mai mic ă pentru k. Din rela ția Rel. 4
Tr= k * Tcycle rezult ă Tcycle =Tr/k. Cu cât k este mai mare, cu atât T cycle este mai mic. Indicatorul OCF0 este
setat de hardware la fiecare ciclu de num ărare. Dac ă activarea lui OCF0 se detecteaz ă prin polling , în
bucla principal ă while (1) trebuie s ă se sesizeze c ă OCF0 a devenit 1. Rezult ă c ă timpul maxim de
execu ție a buclei while (1) trebuie s ă fie mai mic decât T cycle , adic ă T max_while(1) < Tcycle =Tr/k. Un k mare
înseamn ă un T max_while(1) mic iar un T max_while(1) mic înseamn ă imposibilitatea de a face toate prelucr ările
cerute de aplica ție. Pentru a avea un T cycle cât mai mare avem nevoie de un k mic.
Pentru a avea timpi de execu ție a buclei principale T max_while(1) > T cycle vom renun ță m la polling și
vom folosim întreruperile, a șa cum se va ar ăta în prelegerea urm ătoare. Chiar dac ă se folosesc
întreruperile, un k mare înseamn ă c ă vom procesorul va fi întrerupt de multe ori și se va pierde for ță de
calcul. Și în cazul întreruperilor este de dorit un k mic.
În exemplul anterior T r=0,5 s iar k= 18. Rezult ă Tcycle = Tr/k = 0,5 s/18=0,027 s = 27 ms. Aceast ă
valoare este perfect acceptabila, deoarece timpul d e execu ție a buclei principale în majoritatea aplica țiilor
se dore ște a fi în jurul valorii de 10 ms. În multe cazuri îns ă valoarea lui T cycle este prea mic ă și nu poate fi
acceptat ă. Un astfel de caz este T r=0,5s, la fel ca în exemplul anterior, dar fCLK_CPU este 10 MHz.
Prin aplicarea rela ției Rel. 5 pentru T r=0,5s și fCLK_CPU =10 MHz ob ținem:
Hz MHz
ff
rCPU CLK
210 _= = 10 7/2= (27 * 57 )/2 = 26 * 57
p * N * k =2 7 * 5 7 = 26 * 53 * 54 → p = 26, N= 53 = 125 < 256, k = 625

18 S-a ob ținut cel mai mare produs p*N dar k=625 ceea ce înseamn ă Tcycle = Tr/k = 0,5 s/625 =0,8ms, ceea ce
este foarte pu țin. Solu ția ar fi s ă folosim timerul 1 pentru care N maxim este 65536. Implementarea cu
timerul 1se face ulterior în capitolul dedicat time rului 1.
În final trebuie analizat ă performan ță implement ării de tip polling. În acest caz prin performan ța
se în țelege acurate țea metodei. Prin defini ție, acurate țea este diferen ță între valoarea m ăsurat ă și valoarea
real ă a cantit ății ce se m ăsoar ă. Evident, acurate țea nu poate fi mai mic ă decât rezolu ția: un ceas digital
care afi șeaz ă orele și minutele are o rezolu ție de un minut. Valoarea minutelor este aceea și și pentru 0
secunde, și pentru 59 de secunde. În concluzie eroarea maxim ă, adic ă acurate țea, este cel pu țin 59 de
secunde.
În cazul num ărătoarelor hardware valoarea m ăsurat ă se exprim ă în Tcycle , a șa c ă rezolu ția este cel
pu țin un T cycle . Într-o prim ă aproximare, acurate țea nu poate fi mai mic ă decât un T cycle . În cazul polling
acurate țea scade (adic ă eroarea cre ște) datorit ă întârzierii dintre momentul în care num ărătorul cicleaz ă și
momentul în care timpul m ăsurat este folosit de software. Momentul în care t impul m ăsurat este folosit
de software este marcat cu
// folose ște timpul (de exemplu afi șează-l)
în programul de la pagina 17.
În programul de la pagina 17 cea mai mic ă întârziere Δmin se ob ține dac ă num ărătorul cicleaz ă
exact înainte de momentul în care este testat OCF0. Acest moment este marcat cu // t1 în programul de la
pagina 17. Cea mai mare întârziere Δmax se ob ține dac ă num ărătorul cicleaz ă exact dup ă de momentul în
care este testat OCF0. Acest moment este marcat cu // t2 în programul de la pagina 17. Δmax este timpul de
execu ție a buclei while(1) plus întârzierea cea mai mic ă discutat ă mai sus și reprezint ă valoarea cu care
scade acurate țea. În concluzie acurate țea m ăsur ării timpului în polling este:
Acc poll =Tcycle + Δmax = Tcycle + Tmax_while(1) + Δmin Rel. 6
Nu uit ăm c ă metoda polling poate fi folosita numai dac ă Tmax_while(1) < Tcycle , dup ă cum s-a ar ătat
anterior. Dac ă îns ă folosim întreruperile în loc de polling, aceast ă restric ție dispare iar acurate țea va
cre ște, a șa cum se va ar ăta în prelegerea urm ătoare.

3.5 Modul fast PWM – fast Pulse Width Modulation
Mai întâi se va explica ce este PWM. Pentru aceasta vom considera programul blink din
laboratorul 2 care f ăcea s ă clipeasc ă un LED. Acest program a fost reluat la începutul a cestei prelegeri, la
pagina 1.
LED-ul conectat pe bitul 0 al portului A va executa la infinit un ciclu aprins-stins. Vom nota cu tA
timpul cât LED-ul este aprins, cu tS timpul cât LED-ul este stins și cu tC=tA+tS durata unui ciclu aprins-
stins. Pe baza timpilor tA, tS și tC vom defini m ărimea numit ă factor de umplere ( duty cycle sau duty
factor în englez ă). Aceast ă m ărime exprim ă în procente durata cât LED-ul lumineaz ă raportat ă la durata
ciclului aprins-stins. Factorul de umplere se calcu leaz ă cu formula:
100
CA
ttD=
În exemplu ini țial din laboratorul 2 timpul tA este egal cu timpul tS, ceea ce face ca factorul de umplere D
să fie 50% ( %50 100 100 100 =+=+==
AAA
SAA
CA
ttt
ttt
ttD ).
Un fenomen interesant apare dac ă reducem durata ciclului aprins-stins de la o secun d ă la 10
milisecunde. În acest caz ochiul nu va mai percepe c ă LED-ul este aprins și apoi stins ci va avea senza ția

19 că LED-ul lumineaz ă la jum ătate din intensitate. Mai exact, dac ă un LED tot timpul aprins lumineaz ă cu
intensitatea LON iar un LED tot timpul stins cu luminozitatea zero, LED –ul care lumineaz ă într-un ciclu
infinit aprins-stins cu factorul de umplere 50% va crea senza ția c ă lumineaz ă cu intensitatea L=LON /2.
Pentru ca s ă apar ă aceast ă senza ție durata tC a ciclului trebuie s ă fie mai mic ă de 20 milisecunde; cea mai
bun ă valoare este aproximativ 10 ms.
Putem modifica cu u șurin ță programul blink de la pagina 1 pentru a genera diferi ți factori de
umplere. Tot ceea ce avem de f ăcut este s ă modific ăm constantele P și DF :
#define P 1250L
#define DF 30L
#define TH (P*DF/100)
//125L = 1ms

Valorile P și DF de mai sus fac ca LED-ul s ă stea aprins numai aproximativ o treime din ciclu a prins-
stins. Dac ă vizualiz ăm pe osciloscop semnalul care controleaz ă LED-ul, ob ținem forma de und ă din
figura urm ătoare:

Linia punctat ă din figur ă indic ă luminozitatea aparent ă a LED-ului. Aceasta este aproximativ 30% din
luminozitatea unui LED aprins tot timpul.
Varia ția factorului de umplere al unui semnal dreptunghiu lar ne permite s ă ob ținem efectele unui
semnal analogic folosind tehnici digitale. Intensit atea LED-ului ar putea fi modificat ă și dac ă în loc s ă-l
aliment ăm la 5V l-am alimenta de la o surs ă de tensiune variabil ă. Tensiunea variabil ă se poate genera cu
un convertor numeric analogic, dar un asemenea bloc are componente analogice, motiv pentru care este
mai scump.
Tehnica varia ției factorului de umplere se nume ște PWM – Pulse Width Modulation. Pe lâng ă
controlul luminozit ății LED-urilor, tehnica PWM este larg folosit ă pentru controlul tura ției motoarelor de
curent continuu.
Programul blink în care s-a implementat PWM-ul pentru controlul l uminozit ății LED-ului se
bazeaz ă pe durata de execu ție a buclei while(1) . Așa cum s-a ar ătat în capitolul 1, timpul de execu ție al
buclei while(1) poate varia foarte mult de la o itera ție la alta. Din acest motiv canalele PWM se
implementeaz ă cu num ărătoare. Num ărătorul plus blocul de generare a formei de und ă implementeaz ă
hardware algoritmul implementat software în program ul blink .
În figura urm ătoare este prezentat ă timerul 0 de la ATmega16 în modul fast PWM. În fi gur ă s-au
reprezentat numai blocurile active în acest mod:

20
figura 8
Figura este aproape identic ă cu schema modului CTC din figura 7, cu excep ția leg ăturii dintre ie șirea
comparatorului și blocul de control.
Timerul 0 in mod fast PWM se comport ă exact ca în modul normal: direc ția de num ărare este
numai înainte, f ără ca s ă se execute vreodat ă ștergerea num ărătorului. Starea curent ă a num ărătorului se
ob ține din starea anterioar ă la care se adun ă 1, cu o excep ție: dup ă starea MAX (0xFF) urmeaz ă starea
BOTTOM (0x00). Diferen ță dintre modul normal și modul fast PWM o face blocul de generare a formei
de und ă „Waveform Genaration”. Acest bloc este marcat cu a lbastru în figura 8.
Blocul de generare a formei de und ă controleaz ă ie șirea Output Compare (OC0). Acest bloc este
configurat în func ție de bi ții COM01 și COM00 din TCCR0 (figura 5). Exist ă 4 posibilit ăți:
1. COM0(1:0)=00. OC0 este deconectat
2. COM0(1:0)=01. Rezervat . Nu se folose ște.
3. COM0(1:0)=10. Mod neinversat : ie șirea OC0 este resetat ă când comparatorul detecteaz ă
egalitate între starea num ărătorului și registrul OCR0 și setat ă pe starea BOTTOM (0x00).
4. COM0(1:0)=11. Mod inversat : ie șirea OC0 este setat ă la egalitate și resetat ă pe BOTTOM.
Pentru ca ie șirea OC0 s ă asculte de blocul de generare a formei de und ă aceasta trebuie programat ă ca
ieșire digital ă, adic ă trebuie ca DDRB(3) s ă fie ‚1’. Suplimentar trebuie ca COM0(1:0)=”10” sa u „11”.
Dac ă blocul de generare este configurat în modul neinve rsat, ie șirea OC0 va avea timingul din
figura urm ătoare:

21
figura 9 0Tt2T 3T 4T 5T 012345Counter
Aten ție: liniile oblice din figur ă nu reprezint ă un semnal analogic ramp ă ci reprezint ă starea
num ărătorului. În partea dreapt ă este prezentat ă evolu ția num ărătorului. Starea num ărătorului s-a
reprezentat cu culoare bleu. La momentul t=0 starea num ărătorului este 0. Aceast ă valoare nu se modific ă
pân ă la apari ția frontului activ al semnalului de ceas. La moment ul T primul front activ al ceasului
determin ă num ărătorul s ă treac ă în starea 1. Starea 1 nu se modific ă pân ă la urm ătorul front de la 2T. La
2T num ărătorul trece în starea 2 ș.a.m.d. În partea stâng ă a figurii liniile oblice sunt de fapt alc ătuit ă din
256 de linii orizontale care nu se mai pot distinge din cauza rezolu ției limitate.
Semnalul OCn din figura 9 este generat conform teh nicii PWM: dac ă valoarea din OCR se apropie
de 255 factorul de umplere va cre ște c ătre 100% iar dac ă OCR scade spre 0, factorul de umplere se va
duce și el c ătre 0%. Acest semnal poate fi folosit în exterior a controla luminozitatea unui LED sau tura ția
unui motor DC sau BLDC.
În exemplul urm ător se va configura timerul 0 pentru a aprinde un L ED exact cum o f ăcea
programul blink .
În acest exemplu frecven ță ceasului microcontrolerului este fCLK_CPU = 14,4 MHz . Frecven ța PWM
trebuie s ă fie în plaja 50 – 200Hz (20ms – 5 ms), de prefera t cât mai aproape de 100Hz. Pentru ca s ă
parcurg ă un ciclu num ărătorul num ără 256 de impulsuri ale ceasului de num ărare CLK CNT . Astfel c ă N
din Rel. 3 este 256 iar Rel. 3 devine:
fCLK_CPU = p*N*fcycle = 256* p* fcycle → pffCPU CLK
cycle *256 _= Rel. 7
Calcul ăm fcycle pentru valorile posibile ale lui p. Valorile lui p pentru timerul 0 sunt 1, 8, 64, 256 și 1024:
fcycle1024 = f CLK_CPU /256/1024 = 14.400.000Hz /256/1024 = 54,9Hz
fcycle256 = f CLK_CPU /256/256 = 14.400.000Hz /256/256 = 219,7Hz
Cea mai apropiat ă valoare de 100Hz este 54.9 ob ținut ă pentru p=1024 . Aceast ă valoare este în plaja 50 –
200Hz.
Deoarece la examen nu sunt permise mijloace electro nice de calcul vom încerca aflarea lui p evitând
împ ărțiri laborioase. Mai mult, cu excep ția cazurilor când se impune un anume T cycle , putem aproxima pe
p in loc s ă îl calculam cu exactitate. În acest exemplu se cer e ca fcycle să fie în plaja 50-200Hz, a șa c ă o
eroare de 5% nu este o problem ă.
Mai întâi vom determina dac ă fCLK_CPU se divide la 3, 9, o putere a lui 10 (de obicei 1 000,
1.000.000) sau o putere a lui 2 (de obicei 1024). D ac ă scriem 14,4 MHz ca 14.400.000Hz se vede imediat

22 că acest num ăr se divide la 10000. Putem scrie c ă 14.400.000 = 144 * 10000=144*10 5. Cum 144=12 2
rezulta c ă 14.400.000 = 144 * 10000=12 2 10 5=(3*4)2(2*5) 5=32 24 25 55=29 32 55. Acum împ ărțirea la
256=2 8 este imediat ă: (29 32 55)/28=2 32 55. Astfel se evit ă împ ărțirea clasic ă la 256. În continuare avem
de împ ărțit 2 32 55 la 256. În acest caz putem face o aproximare: ( 2 32 55)/256 = (2 53 32 52)/256 =
(250 32 52)/256 ≅32 52=9 25=225. Se observ ă c ă rezultatul aproximat 225 este foarte apropiat de
rezultatul exact 219,7. Înc ă o data preciz ăm c ă aproxim ările se pot folosi numai dac ă nu se impune
un anume T cycle .
Schema de conectare a LED-ului la microcontroler es te urm ătoarea:

figura 10
Programul pentru p=256 este urm ătorul:
int main(){
// ┌──┬─ Fast PWM
TCCR0=0b0 110 1101 ;
// ││ └┴┴─ clk
I/O /1024
// └┴───── Set OC0 on BOTTOM, Clear on compare .

OCR0=128; //50% Duty cycle

setbit(DDRB,3); //OC0 pin is output. Mandatory !

while (1){
//……
}//end while

}//end main
În exemplul anterior ie șirea OC0 controlat ă de num ărătorul 0 în mod fast PWM a fost folosit ă
pentru a controla intensitatea unui LED. Acela și mecanism poate fi folosit pentru a controla inten sitatea a
7 LED-uri, adic ă a unui afi șor 7 segmente. Schema de conectare a unui afi șor 7 segmente a c ărui
intensitate este controlat ă PWM este prezentat ă în figura urm ătoare:

23
figura 11
Schema din figura 11 are la baza figura 2 din labor atorul 4. Diferen ța const ă în modul de conectare a
anodului comun la VCC. În figura 2 din laboratorul 4 anodul comun este conectat permanent la VCC si
astfel intensitatea luminoas ă a oric ărui segment este fix ă și maxim posibil ă. În figura 11 anodul comun se
conecteaz ă la VCC prin intermediul unui comutator electronic. Comutatorul electronic este necesar
deoarece OC0 în mod ie șire poate furniza un curent maxim de 20 mA iar afi șorul are nevoie de un
curentul maxim de 140 mA. Comutatorul sub comanda p inului OC0 conecteaz ă sau nu anodul comun la
VCC. Când OC0 = ‚0’ anodul comun este conectat la V CC și afi șorul va lumina iar când OC0=’1’ anodul
comun este deconectat și afi șorul va fi stins. Factorul de umplere al lui OC0 va determina intensitate
afi șorului 7 segmente.
Programul care controleaz ă intensitatea afi șorului este aproape identic cu programul care
controleaz ă intensitatea LED-ului din figura 10 cu o deosebire : LED-ul lumineaz ă când OC0=’1’ iar
afi șorul lumineaz ă când OC0=’0’. Din acest motiv blocul de generare a formei de und ă este configurat în
mod invers, ca mai jos:
// ┌──┬─ Fast PWM
TCCR0=0b0 111 1101 ;
// ││ └┴┴─ clk
I/O /1024
// └┴───── Reset OC0 on BOTTOM, Set on compare .

La examen nu este necesar s ă proiecta ți comutatorul electronic; este suficient s ă desena ți dreptunghiul
reprezentat cu linie întrerupt ă în figura 11. În interiorul dreptunghiului este ob ligatoriu s ă apar ă pinii
VCC, nCMD și CA.
Ultimul mod de lucru al timerului 0 este modul phase corect PWM . Deoarece acest mod are sens
numai dac ă num ărătorul este prev ăzut cu cel pu țin dou ă canale PWM și numai pentru o gam ă redus ă de
aplica ții, acest mod nu va mai fi discutat și nu constituie subiect de examen.

4. Timer/Counter-ul 2
Num ărătorul 2 seam ănă foarte mult cu num ărătorul 0. Diferen ță const ă în modul în care este
utilizat ceasul extern de num ărare. Blocul în care se proceseaz ă acest semnal este prescalerul. În figura
12a este reluat prescalerul timerului 0 iar în sec țiunea b) a figurii este prezentat prescalerul timer ului 2. În
ambele figuri ceasul extern și a fost marcat cu ro șu iar cel intern cu albastru.

24 La timerul 0 ceasul extern T0 este procesat în bloc ul numit „Synchronization” în figura 12a. Acest
bloc folose ște ceasul procesorului clk I/O pentru a analiza ceasul extern T0 și genereaz ă la ie șire un puls fie
pentru frontul ridic ător al lui T0, fie pentru cel coborâtor, în func ție de programare. Din figur ă se observ ă
că semnalul rezultat din ceasul extern T0 devine ceas ul num ărătorului 0 f ără a mai putea fi divizat de
prescaler.
La timerul 2 îns ă fie semnalul extern TOSC1, fie clk I/O sunt mai întâi divizate și apoi devin ceas
pentru timerul 2. Ceasul extern TOSC1 se poate divi za la fel ca și clk I/O .
Aten ție: oscilatorul care genereaz ă ceasul TOSC1 este optimizat pentru cristale cu fre cven ța de 32,768
kHz. Folosirea altei frecven țe nu este recomandat ă.

figura 12
Dac ă ambele timere folosesc doar ceasul intern clk I/O apare o diferen ță minor ă în ceea ce prive ște factorii
de divizate. La ambele timere factorii de divizare sunt 1, 8, 64, 256 și 1024 dar la timerul 2 apar
suplimentar și factorii 32 și 128.
În cazul în care timerul 2 folose ște semnalul extern de num ărare se spune c ă acesta func ționeaz ă
în mod asincron. De și este relativ simplu, modul asincron al timerul 2 nu constituie subiect de examen și
nici o problem ă nu va necesita acest mod pentru rezolvare.
Registrele timerului 2 (TCCR2 și OCR2) au exact aceea și structur ă ca registrele TCCR0 și OCR0
asociate timerului 0. Semnifica ția bi ților este identic ă în aceste registre cu excep ția celor trei bi ți CS care
controleaz ă prescalerul. Modurile de lucru normal, CTC, fast P WM și phase correct PWN sunt și ele
identice la cele dou ă timere. Indicatorii timerului 2 sunt TOV2 și OCF2. Ace știa au aceea și semnifica ție
ca TOV0 și OCF0 și se pot accesa prin intermediul bi ților 7 și 6 din TIFR (figura 6).

25 5. Timer/Counter-ul 1
Exist ă aplica ții, cum ar fi m ăsurarea intervalelor de timp, pentru care un num ărător pe 8 bi ți este
insuficient. O aplica ție care are nevoie de m ăsurarea intervalelor de timp este turometrul electr onic. Din
acest motiv aproape toate microcontrolerele sunt pr ev ăzute cu unul sau mai multe num ărătoare pe 16 bi ți.
La ATmega16 num ărătorul pe 16 bi ți este num ărătorul 1. În figura urm ătoare este prezentat ă schema bloc
a acestui num ărător:

figura 13
De și la prima vedere pare complicat ă, schema con ține elemente care au fost deja întâlnite și
prezentate la timerul 0 și 2. Pentru început se observ ă că blocul de selec ție a ceasului și blocul de control
sunt foarte asem ănătoare cu cele ale timerului 0. Timerele 0 și 2 con țineau un bloc de compara ție și un
bloc de generare form ă de und ă. Timerul 1 con ține dou ă blocuri de compara ție (marcate cu ro șu în figura
13) și dou ă blocuri de generare form ă de und ă (marcate cu albastru).
Deoarece atât num ărătorul cât și registrele de compara ție sunt pe 16 bi ți iar magistrala procesorului
este pe 8 bi ți citirea și scrierea acestora ridica probleme. Pentru a în țelege natura acestor probleme și
modul de rezolvare vom considera citirea st ării num ărătorului pe durata num ărării.
Dorim s ă citim starea unui num ărători pe 16 bi ți mapat ca dou ă porturi de intrare/ie șire într-un sistem
cu l ățimea magistralei de date de 8 bi ți. De exemplu, dac ă num ărătorul este în starea 0x46FF și se dore ște
citirea acestuia, poate apare urm ătoarea situa ție:
1. Se cite ște octetul inferior și anume 0xFF.
2. Num ărătorul prime ște impuls de ceas și trece în starea 0x46FF +1 = 0x4700

26 3. Se cite ște octetul superior și anume 0x47.
Se observ ă c ă s-a citit valoarea 0x47FFh în loc de 0x46FF sau 0x 4700.
La ATmega rezolvarea acestei probleme se face în ha rdware: se adaug ă registrul suplimentar
TEMP ca în figura urm ătoare:

figura 14
Num ărătorul pe 16 bi ți este mapat ca dou ă porturi: Counter High (TCNT1H) ce con ține bi ții superiori
15:8 ai num ărătorului și Counter Low (TCNT1L) ce con ține bi ții inferiori 7:0. În momentul în care
procesorul cite ște TCNT1L, partea superioar ă TCNT1H este automat transferat ă în registrul TEMP. Când
se cite ște TCNT1H procesorul va citi valoarea din TEMP și nu din TCNT1H. Registru TEMP plus citirea
în ordinea inferior – superior face ca citirea s ă se fac ă corect. Pentru a în țelege mai exact acest mod de
operare vom relua exemplul anterior care genera un rezultat incorect:
1. Num ărătorul este în starea 0x46FF
2. Se cite ște octetul inferior și anume 0xFF. Automat, pe acela și impuls de ceas, în registrul
TEMP se transfer ă 0x46
3. Num ărătorul prime ște impuls de ceas și trece în starea 0x46FF +1 = 0x4700
4. Se cite ște octetul superior din registrul TEMP, și anume 0x46.
Se observ ă c ă s-a citit în mod corect valoarea 0x46FF.
Scrierea num ărătorului se face dup ă acela și principiu. Mai întâi se scriu bi ții superiori 15:8 la
adresa TCNT1H. Ace ști bi ți sunt scri și în registrul TEMP, nu în num ărător. Apoi se scriu bi ții inferiori
7:0 la adresa TCNT1L. Bi ții sunt scri și direct în num ărător și simultan cu scrierea acestora registrul
TEMP se transfer ă în TCNT1H. Pe lâng ă scrierea num ărătorului acela și principiu se aplic ă și la scrierea
registrelor de compara ție OCR1A și OCR1B.
Un bloc specific num ărătorului 1 este blocul de captur ă. Acesta este marcat cu verde în figura 13.

5.1 Registrul de captur ă
Num ărătoarele sunt precise deoarece num ărarea se face hardware. Utilizarea num ărătorului se
face îns ă de c ătre software iar acest proces este, cel pu țin în acest moment, relativ imprecis. De exemplu,
să presupunem c ă dorim s ă înc ălzim mâncarea la cuptorul cu microunde timp de 5 mi nute. Dup ă ce set ăm
valoarea de 5 minute și eventual puterea, vom ap ăsa butonul Start. Semnalul de butonul Start se va
conecta la un pin al unui port de intrare. În bucla principal ă programul va citi starea acestui semnal. Dac ă
valoarea citit ă indic ă buton, ap ăsat va începe contorizarea timpului. Deoarece citir ea st ării se face in bucla
while(1) precizia cu care se detecteaz ă momentul ap ăsării este dat de timpul de execu ție al acestei
bucle, timp care poate fi de ordinul zecilor de mil isecunde. Aceea și imprecizie apare și la contorizarea
timpului scurs; aceast ă contorizare se face prin citirea st ării indicatorului TOV sau OCF. Cum ace ști

27 indicatori se citesc tot în bucla principal ă apare și aici o imprecizie egal ă cu timpul de execu ție a buclei,
adic ă alte zeci de milisecunde. O eroarea cumulat ă chiar de o zecime de secund ă este perfect acceptabil ă
în cazul cuptorului cu microunde sau a ma șinii de sp ălat. Exist ă îns ă aplica ții în care o astfel de eroare
este intolerabil ă. O astfel de aplica ție este m ăsurarea perioadei unui semnal.
Măsurarea precis ă a perioadei unui semnal se face prin metoda ampren tei de timp (time stamp).
Pentru a exemplifica m ăsurarea perioadei vom considera construirea unui tu rometru electronic. Pe volanta
motorului se monteaz ă un senzor care ofer ă un puls la fiecare rota ție complet ă a motorului, notat „Puls de
la traductor – PT” în figura 15. Perioada acestuia este notat ă Tx în figur ă.

figura 15
Pentru a calcula perioada semnalului PT se folose ște metoda ceasului pentru m ăsurarea duratei
unei activit ăți sau fenomen: ne not ăm timpul la care a început activitatea și timpul la care aceasta s-a
sfâr șit și apoi facem diferen ță celor doi timpi. Num ărătorul joac ă rolul ceasului. În figura 15 prima
perioad ă a lui PT începe când num ărătorul este în starea 1 și se termin ă când este în starea 9. Perioada
Tx a lui PT este 9-1=8 perioade ale ceasului num ărătorului. Pentru un T num de 1us ob ținem Tx=8 us.
Măsurarea perioadei lui TP se face în continuu. Pentr u urm ătoarele perioade diferen ță timpilor este 17-
9=8 și 24-17=7.
Desigur, valoarea 8 are scop didactic. În realitate tura ția unui motor variaz ă între 600 și 6000 de
rota ții pe minut, ceea ce însemn ă 10 – 100 rota ții pe secund ă, adic ă o perioad ă între 100 ms și 10 ms.
Dup ă cum s-a ar ătat anterior monitorizarea în bucla a butonului Sta rt și a indicatorului TOV sau OCF are
o precizie de ordinul zecilor de milisecunde. Un in terval de timp de 10 ms nu poate fi m ăsurat printr-un
procedeu care are precizia de câteva ori mai proast ă decât m ărimea de m ăsurat.
Măsurarea perioadei prin metoda diferen ței de timp necesit ă memorarea timpului la care s-a
produs un eveniment. În acest scop este necesar un registru în care s ă se memoreze sau s ă captureze
starea num ărătorului în momentul producerii evenimentului. Capturarea se face de hardware pentru a
elimina imprecizia software-ului discutat ă anterior . Acest registru se nume ște Input Capture Reg-
ICR . Schema bloc a unit ății de captur ă din structura timerului 1 este prezentat ă în figura 16. Elementele
din schema bloc care nu apar țin direct blocului de captur ă sunt reprezentate cu gri în figur ă. Registru x 24 17 9 1 Tx Tnum
0Numarator 21 5 43 9 8 6 7 10 12 11 Puls de
la
traductor – PT
19 18 17 16 15 14 13 27 26 25 24 23 22 21 20 31 30 29 28

28
figura 16
Semnalul extern care semnaleaz ă evenimentul poate fi aplicat pe pinul ICP1 sau, al ternativ, prin
intermediul comparatorului analogic. Amprentele de timp pot fi ulterior utilizate pentru calculul
frecven ței, a factorului de umplere și a altor caracteristici ale semnalului extern.
În momentul în care apare un front (un eveniment) p e pinul ICP1 (Input Capture Pin) sau la ie șire
comparatorului analogic și respectivul front este de tipul celui programat s ă fie recunoscut de detectorul
de front „Edge detector” se declan șeaz ă captura. Captura înseamn ă c ă valoarea pe 16 bi ți a num ărătorului
1 este scris ă în registrul ICR1 (Input Capture Register). Se spu ne c ă starea num ărătorului este capturat ă în
registru. Practic în registru se face „o poz ă” a num ărătorului. Indicatorul ICF1 (Input Capture Flag) este
setat pe acela și impuls de ceas pe care starea num ărătorului se scrie în registru. Acesta devine ‚1’ în
momentul apari ției frontului programat al lui ICP1. Structura indi catorului ICF este aceea și cu cea a
indicatorilor TOV și OCF.
Citirea valorii pe 16 bi ți din ICR1 prezint ă aceea și problem ă ca și citirea st ării num ărătorului:
citirea ICR1 poate interfera cu captura și astfel ajungem s ă citim primul octet din valoarea capturii
precedente și al doilea octet din valoarea nou capturat ă. Evitarea acestei situa ții se face ca în cazul
citirii/scrierii num ărătorului, cu ajutorul registrului TEMP.
Citirea valorii pe 16 bi ți a registrului ICR1 se face citind mai întâi octet ul inferior ICR1L urmat ă
de citirea octetului superior ICRH1. Când se face c itirea octetului inferior octetul superior este cop iat în
TEMP. Când procesorul cite ște locația ICR1H datele vor fi furnizate din registrul TEMP .
Exist ă aplica ții care nu utilizeaz ă blocul de captur ă. În acest caz registrul ICR1 poate fi folosit
pentru a defini valoarea TOP a num ărătorului. Scrierea registrului se va face prin inter mediul lui TEMP,
așa cum a fost justificat anterior.
Configurarea timerului 1 se face prin intermediul a dou ă registre de control: TCCR1A și
TCCR1B. aceste dou ă registre sunt prezentate în figura urm ătoare:

29
figura 17
Blocul de generare și selec ție a ceasului de num ărare pentru timerul 1 este identic cu cel al timeru lui 0 și a
fost prezentat în figura 5. Bi ții CS12:CS10 au aceea și semnifica ție ca bi ții CS02:CS00 de la timerul 0.
Perechea de bi ți COM1A1 și COM1A0 controleaz ă generatorul de form ă de und ă A din figura 13
iar perechea COM1B1 și COM1B0 controleaz ă generatorul de form ă de und ă B. Semnifica ția bi ților
dintr-o pereche, oricare ar fi ea, este identic ă cu semnifica ția bi ților COM01 și COM00 de la timerul 0.
Semnifica ția perechii COM01 – COM00 a fost prezentat ă în capitolele anterioare.
Bitul 7 din registrul de control B – ICNC1 (Input Noise Canceler) – dac ă este setat (‚1’ logic )
activeaz ă blocul de anulare a zgomotului de pe semnalul de d eclan șare a capturii. Acest bit este marcat cu
ro șu în figura 16. Când anulatorul de zgomot este acti vat, semnalul aplicat pe pinul de intrare ICP1 (Inp ut
Capture Pin) este filtrat. Func ția de filtrare cere ca patru e șantioane succesive ale semnalului ICP1 s ă fie
egale pentru ca ie șirea filtrului s ă-și schimbe valoarea. Astfel pulsurile ICP1 mai mici ca durat ă decât
patru perioade de ceas CPU vor fi eliminate. Ca un efect lateral, atunci anulatorul de zgomot este act ivat
opera ția de capturare este întârziat ă cu patru cicluri de ceas.
Bitul 6 din registrul de control B – ICES1 (Imput Capture Edge Select) – selecteaz ă care front
este folosit pentru a declan șa captura. ICES1 = ‚0’ selecteaz ă frontul coborâtor iar ICES1 = ‚1’ selecteaz ă
frontul ridic ător. Acest bit este marcat cu albastru în figura 16 .
În continuare vom discuta modurile de lucru ale num ărătorului 1. Acestea sunt în principiu
acelea și ca cele de la num ărătoarele 0 și 2: normal, CTC, fast PWM și phase corect PWM. Deoarece
num ărătorul 1 num ără pe 16 bi ți și are dou ă unit ăți de comparare plus registrul de captur ă, exist ă mai
multe moduri CTC și PWM. În total sunt 14 moduri de lucru, prezentate în Tabelul 1. Modul de lucru este
setat prin intermediul bi ților WGM13:0 marca ți cu verde în figura 17.
Tabelul 1
Mode WGM13 WGM13 WGM13 WGM13 Timer/counter mode of opperation TOP Update of
OCR1x TOV1 Flag Set
on
0 0 0 0 0 Normal 0xFFFF Immediate MAX
4 0 1 0 0 CTC OCR1A Immediate MAX
12 1 1 0 0 CTC ICR1A Immediate MAX
5 0 1 0 1 Fast PWM, 8 bit 0x00FF BOTTOM TOP
6 0 1 1 0 Fast PWM, 9 bit 0x01FF BOTTOM TOP
7 0 1 1 1 Fast PWM, 10 bit 0x03FF BOTTOM TOP
14 1 1 1 0 Fast PWM ICR1 BOTTOM TOP
15 1 1 1 1 Fast PWM OCR1A TOP BOTTOM
1 0 0 0 1 Phase Correct PWM, 8 bit 0x00FF TOP BOTTO M
2 0 0 1 0 Phase Correct PWM, 9 bit 0x01FF TOP BOTTO M
3 0 0 1 1 Phase Correct PWM, 10 bit 0x03FF TOP BOTT OM
10 1 0 1 0 Phase Correct PWM ICR1 TOP BOTTOM
11 1 0 1 1 Phase Correct PWM OCR1A TOP BOTTOM
8 1 0 0 0 Phase and Frequency Correct PWM ICR1 BOTTOM BOTTOM
9 1 0 0 1 Phase and Frequency Correct PWM OCR1A BOTTOM BOTTOM

30
Modul 0 este modul normal . În acest mod num ărătorul 1 num ără de la 0x0000 la 0xffff. Pe
impulsul de ceas care urmeaz ă st ării 0xfff num ărătorul cicleaz ă în starea 0x0000 și seteaz ă indicatorul
TOV1 ce poate fi citit și resetat prin intermediul bitului 2 din TIFR (figu ra 6).
Modurile 4 și 12 sunt moduri CTC : în modul 4 valoarea TOP este valoarea din registr ul OCR1A
iar în modul 12 de valoarea din registrul ICR1. Cân d starea num ărătorului este egal ă cu con ținutul
registrului OCR1A se seteaz ă bitul OCF1A iar când este egal ă cu con ținutul registrului OCR1B se seteaz ă
bitul OCF1B. Ace ști bi ți pot fi citi ți și reseta ți prin intermediul bi ților 4 și 3 din TIFR (figura 6).
Modurile 5, 6, 7, 14 și 15 sunt moduri fast PWM . Deoarece num ărarea pe 16 bi ți conduce la
perioade PWM mari, în modurile 5, 6, 7 num ărarea se face doar pe 8, 9 respectiv 10 bi ți. În modurile 14
și 15 num ărarea se face pân ă când num ărătorul ajunge la valoarea din ICR1, respectiv OCR1A dup ă care
se reseteaz ă.
Indicatorii (flagurile) timerul 1 se pot citi și reseta prin intermediul bi ților 5:2 din portul de stare a
timerelor TIFR, prezentat în figura 5. Bitul 2 – TOV1 – este setat când num ărătorul 1 cicleaz ă. Bi ții 3 și 4
– OCF1B și OCF1A – sunt seta ți când starea num ărătorului de vine egal ă cu valoarea înscris ă în OCR1A
sau OCR1B iar ICF1 este setat când s-a f ăcut o captur ă în ICR1.
În continuare se va prezenta un program care calcul eaz ă tura ția unui motor folosind registrul de
captur ă.

5.2 Turometru cu timerul 1

Frecven ță ceasului microcontrolerului este F CLK_CPU = 8 MHz, ceea ce înseamn ă o perioad ă
TCLK_CPU =1/(8MHz) =1/8 μs=125 ns.
În acest exemplu tura ția motorului variaz ă între 600 și 6000 de rota ții pe minut. Se cere ca precizia
calculului s ă fie minim 10 rpm (rota ții pe minut) pe tot domeniul de varia ție a tura ției.
Mai întâi calcul ăm frecven ța minim ă și maxim ă a motorului:
• Frecven ța minim ă se ob ține la tura ția de 600 rpm. Dac ă tura ția este 600 rota ții pe minut num ărul
de rota ții pe secund ă este 600rpm/60s=10 rota ții pe secund ă. Fiind exprimat ă în num ăr de rota ții
pe secund ă, aceasta este frecven ța minim ă a motorului: fmin_rspeed =10 Hz → Tmin_rspeed =1/10Hz =
100 ms
• Frecven ța maxim ă se ob ține la 6000 rpm: 6000 rpm → 6000/60 =100 rps → fmax_rspeed =100 Hz
→Tmax_rspeed =1/100Hz = 10 ms
Pentru a determina frecven ța ceasului num ărătorului vom calcula diferen ță dintre perioada
corespunz ătoare celei mai mari tura ții, adic ă 6000 rpm, și perioada urm ătoarei tura ții distincte. Aceast ă
tura ție corespunde celei mai mari tura ții minus precizia impus ă (10 rpm). Valoarea acesteia este
6000 rpm –10 rpm = 5990 rpm. Pentru 5990 rpm calcul ăm perioada: 5990 rpm → 5990/60 = 99,83 rps →
fmax_rspeed-10 = 99,83 Hz → Tmax_rspeed =1/(99,83 Hz) = 10,0167 ms. O precizie de 10 rpm im plic ă o precizie
de m ăsurare a perioadei de 10,0167 ms – 10 ms = 16,7 μs.
Pentru a sesiza o diferen ță de 16,7 μs ceasul de num ărarea trebuie să aib ă perioada mai mic ă de 16,7
μs, adic ă TCLK_CNT <16,7 μs. Aceast ă rela ție implic ă:
TCLK_CNT = p * T CLK_CPU < 16,7 μs → p < 16,7 μs / T CLK_CPU → p < 16,7 μs / 125 ns → p < 133

31 Valorile posibile ale lui p sunt 1, 8, 64, 256, 102 4. Cea mai apropiat ă valoare de 133 este 64. Astfel
ob ținem:
TCLK_CNT = 64*125 ns= 8000 ns =8 μs
În final verific ăm c ă pentru T CLK_CNT = 8 μs num ărătorul nu cicleaz ă în cazul celei mai mari perioade,
adic ă pentru T min_rspeed =100 ms:
100 ms / 8 μs = 100000 /8=12500 < 2 16
Valoarea de 12500 este mai mic ă decât 216 =65536 și în concluzie perioada T CLK_CNT = 8 μs este
acceptat ă.
Perioada de rota ție a motorului se calculeaz ă ca diferen ța dintre dou ă amprente de timp succesive. O
amprenta de timp se ob ține prin capturarea valorii num ărătorului TCNT1 în ICR1 pe frontul ridic ător al
semnalului de la senzorul de tura ție. Cele dou ă amprente se vor numi s1 și s2. Diferen ța s2-s1 este
exprimat ă în perioade T CLK_CNT :
Trspeed = (s2-s1) * T CLK_CNT = (s2-s1)*8 μs = (s2-s1)*8*10 -6s
Frecven ța de rota ție este:
frspeed =1/ T rspeed =1/[(s2-s1)*8*10 -6s]=10 6/[(s2-s1)*8] Hz
Tura ția motorului in rpm este:
Tura ția în rpm = f rspeed *60 =60*10 6/[(s2-s1)*8]=7.500.000/(s2-s1) rpm
Aceasta este formula tura ției pe care o vom folosi în programul urm ător:

int main(){
unsigned long s1,s2;
unsigned long rpm=0UL;

// ┌┬─ Normal Mode
TCCR1B=0b0 1000 011 ;
// │ └┴┴─ clk
I/O /64
// └────── ICES1=1: capture on rising edge .
// ┌┬─ Normal Mode
TCCR1A=0b000000 00 ;

while (1){
if (TIFR & 1<<ICF1){ // ICF1 is an alias for integer 5 in avr/io.h
TIFR |= 1<<ICF1; //clear ICF1
s1=s2;
s2=( unsigned long )ICR1;
s2=s2>=s1? s2: s2+(1<<16); //corectia lui s2 nu este de fapt necesara
rpm=7500000UL/(s2-s1);
}
}//end while
}//end main

5.3 Măsurarea duratei unui impuls
În exemplul anterior ambele e șantioane au fost f ăcute pe frontul ridic ător al semnalului exterior
„Puls de la traductor – PT”. Exist ă îns ă aplica ții în care este necesar ca un e șantion s ă fie f ăcut pe un front
iar cel de-al doilea pe cel ălalt front. O astfel de aplica ție este m ăsurarea duratei unui impuls.
În acest exemplu se cere m ăsurarea duratei pulsului PT din figura urm ătoare. În figur ă primul
eșantion notat se face pe frontul ridic ător al lui PT iar cel de-al doilea, pe frontul cobo râtor. Primul
eșantion este notat sr – sample rising iar cel de-al doilea sf (sample falling). Durata impulsului se

32 calculeaz ă ca diferen ța între cele dou ă e șantioane. Aceast ă diferen ță este sf – sr =11T num – 3Tnum = 8 T num
în figur ă.

Deoarece eșantioanele se iau fac pe fronturi diferite, dup ă ce se face prima captur ă trebuie
schimbat frontul pe care se face captura. Cea mai c lar ă implementare folose ște o SFSM (vezi laboratorul
8) cu dou ă st ări. Pe prima starea se face captura pe frontul ridi c ător iar pe cea de-a doua, cea pe front
coborâtor. Suplimentar, pe starea a doua se calcule az ă durata impulsului. Implementarea cu SFSM este
urm ătoarea:
#define SAMPLE_RISING 1
#define SAMPLE_FALLING 2

int main(){
unsigned char state = SAMPLE_RISING;

unsigned long sr, sf, delta;
// ┌┬─ Normal Mode
TCCR1B=0b0 1000 –;
// └────── ICES1=1: captur ă pe frontul ridicator.
TCCR1A=0b000000 00 ;
// └┴─ Normal Mode

while (1){
if (TIFR & 1<<ICF1){ // #define ICF1 5 in avr/io.h
TIFR |= 1<<ICF1; //clear ICF1

switch (state){
case SAMPLE_RISING:
sr = (unsigned long)ICCR1;
clrbit(TCCR1B, ICES1);
state = SAMPLE_FALLING;
break ;

case SAMPLE_FALLING :
sf = (unsigned long)ICCR1;
setbit(TCCR1B, ICES1);
state = SAMPLE_RISING;
sf = sf>=sr? sf: sf+(1<<16);
delta = sf – sr;
//use delta
break ;
}// end switch
}
}//end while
}//end main

5.4 Ceas digital cu timerul 1
În capitolul 3.4-Ceas digital cu timerul 0 s-a anal izat cazul T r=0,5s și fCLK_CPU =10 MHz. În acest
caz s-a ar ăta c ă T cycle =0,8 ms, valoare mult prea mic ă. Dac ă îns ă se folose ște timerul 1 T cycle va sc ăde ă
mult deoarece ne permitem valori mult mai mari pent ru N (N=2 16 =65536). Dac ă reluam calculele pentru
Tr=0,5s și fCLK_CPU =10 MHz ob ținem: Tnum
Numarator 21 5 43 8 6 7 10 9 12 11 13 Puls de la
traductor – PT
Fe Re

33 Hz MHz
ff
rCPU CLK
210 _= = 10 7/2= (27 * 5 7 )/2 = 2 6 * 5 7
p * N * k =2 7 * 5 7 = 26 * 56 * 5 → p = 26, N= 56 = 15625 < 65536, k = 5
Implementarea cu timerul 1 este:
int main(){
unsigned char cycles=0, one_sec=0, sec=0;

// ┌┬─ CTC Mode
TCCR1B=0b000 01 011 ;
// └┴┴─ clk
I/O /64
// ┌┬─ CTC Mode
TCCR1A=0b000000 00 ;
OCR1A=15625-1;

while (1){
//…
if (TIFR & 1<<OCF1A){ // OCF1A is an alias for integer 4 in avr/io.h
TIFR |= 1<<OCF1A; // clear OCF1A

if (cycles==5){ k=5
// a trecut jum ătate de secund ă
cycles=0;
// aprinde sau stinge separatorul
one_sec++;

if (one_sec==2){
one_sec=0;
// a trecut o secund ă
// actualizeaz ă secunde, minute, ore
// afi șeaz ă timpul
}
}

//…
}
}//end while
}//end main
Pentru T r=0,5s și fCLK_CPU =10 MHz cu timerul 1 ob ținem T cycle = Tr/k = 0,5 s/5 =0,1s, ceea ce
este foarte bine.
Timerul 1 permite în anumite cazuri cea mai bun ă implementare a unui ceas digital, adic ă
implementarea în care k=1. Un astfel de caz exemplu l din capitolul 3.4 unde T r=0,5 iar
fCLK_CPU =9,216MHz. Pentru un timer pe 8 bi ți N<256 iar pentru un timer pe 16 bi ți N<65536.
Dac ă relu ăm calculele din capitolul 3.4 cu restric ția N<65536 în loc de N<256, ob ținem:
Hz MHz
ff
rCPU CLK
2216 , 9 _= =9216000/2= (213 32 53 )/2 = 212 32 53
Constanta p trebuie să fie 1, 8, 64, 256 sau 1024 iar N să fie mai mic ca 65536:
k p N=212 32 53= 210 22 32 53 → p=210 , N=22 32 53 = 4500 < 65536
To ți factorii primi au fost folosi ți pentru p și N, a șa c ă în acest caz ob ținem k=1.
Implement ările anterioare s-a f ăcut cu timerul 1. Este îns ă pu țin probabil ca timerul 1 s ă fie liber.
Acest timer este cel mai performant timer și probabil va fi folosit în alte scopuri, cum ar fi calculul
frecven ței unui semnal extern. Pentru calculul frecven ței de obicei timerul trebuie setat în modul normal
pentru ca N să aib ă cea mai mare valoare cu putin ță , și anume 2 16 . Cum ceasul digital cere alt ă valoare

34 pentru N, dac ă avem de implementat calculul frecven ței unui semnal extern nu mai putem implementa și
ceas digital. Exist ă îns ă o metod ă pentru care acurate țea este mai mic ă dar pentru care nu este necesar ca
Tr să fie multiplu de T cycle .

6. Ceas digital, metoda 2
A doua metodă de implementare a ceasului digital se folose ște când descompunerea lui fCLK_CPU /fr
conduce la o valoare mare a lui k și automat la o valoare mic ă pentru T cycle . O valoare mic ă pentru T cycle
înseamn ă un timp mic pentru bucla while(1) . Din aceste motive vom renun ță la condi ția Tr=k * Tcycle
folosit ă pân ă acum.
Ideea metodei pe care o vom folosi este u șor de în țeles prin intermediul urm ătoarei analogii. S ă
presupunem c ă avem un dispozitiv de m ăsurare a timpului care emite un semnal luminos sau sonor din 25
în 25 de secunde. În afar ă de acest semnal dispozitivul nu are nici un alt si stem de semnalizare a timpului
scurs. Se cere s ă măsuram timpul scurs în minute.
Solu ția acestei probleme este u șor de imaginat. Știm c ă de fiecare dat ă când apare semnalul de la
dispozitiv au trecut 25 de secunde. La prima activa re au trecut 25 de secunde, la a doua activare au t recut
50 iar la a treia au trecut 75. Valoarea 75 înseamn ă că a trecut primul minut și 15 secunde din al doilea
minut. La a patra activare a trecut un minut și 15+25 = 40 secunde din al doilea minut. Eviden ța timpului
scurs în func ție de activ ările semnalului este urm ătoarea:
Nr. apar ție
semnal (q) Secunde scurse Minute scurse (m)
0 0 0 – 60 < 0 0
1 0 + 25 = 25 25 – 60 < 0 0
2 25 + 25 = 50 50 – 60 < 0 0
3 50 + 25 = 75 75 – 60 = 15>0 1
4 15 + 25 = 40 40 – 60 < 0 1
5 40 + 25 = 65 65 – 60 = 5>0 2
6 5 + 25 = 30 30 – 60 < 0 2
Ideea este s ă acumulam cicluri de num ărare pân ă când valoarea cumulat ă devine mai mare ca T r. Fie q
num ărul de cicli pentru care suma acumulat ă devine pentru prima dat ă mai mare ca T r:

rCPU CLK
CPU CLK r
r CPU CLK r cycle ffqpN TTqpN T qpNT TqT _
__ ≥ ≥ ≥ ≥
Dac ă not ăm
rCPU CLK
ff_ cu NPPR – num ărul de pulsuri de ceas procesor necesare pentru T r, avem:
NPPR qpN ≥
În rezumat, dup ă terminarea unui ciclu de num ărare acumul ăm p*N pulsuri și compar ăm valoarea
acumulat ă cu NPPR. Dac ă am acumulat mai multe pulsuri decât NPPR actualiz ăm timpul scurs, sc ădem
din num ărul de pulsuri acumulate NPPR pulsuri și păstr ăm diferen ța pentru urm ătoarea T r.
Dac ă vrem s ă folosim num ărătorul 0 în mod fast PWM pentru fCLK_CPU =10 MHz trebuie s ă
ob ținem o valoare a lui T cycle în jurul valorii de 10 ms. Dac ă refacem calculele din capitolul „Modul Fast
PWM” pentru fCLK_CPU =10MHz rezult ă c ă cel mai bun p este 256. Pentru p=256 ob ținem T cycle =6,5 ms.
Avantajul metodei 2 const ă în faptul c ă num ărătorul poate fi folosit în scop dublu: PWM și baz ă
pentru implementarea ceasului. Pentru aceast ă variant ă de ceas digital alegem T r=1s. In acest caz
NPPR=10Mhz/1Hz=10.000.000
Implementarea in C este urm ătoarea:

35 int main(){
unsigned long pulses_clk_cpu =0UL;
// ┌──┬ FAST PWM Mode
TCCR0=0b0 100 1100 ;
// ││ └┴┴─ p=256
// └┴───── Normal port operation, OC0 disconnected.

while (1){
if (TIFR & 1<<TOV0){ // TOV0 este definit in avr/io.h
TIFR |= 1<<TOV0; // clear TOV0

pulses_clk_cpu += 256UL*256UL; //p*N
if (pulses_clk_cpu >= 10000000UL){
pulses_clk_cpu = pulses_clk_cpu – 10000 000UL;

//update time
//display time
}
}
}//end while
}//end main
Exist ă îns ă și un dezavantaj al metodei 3 și anume o sc ădere suplimentar ă a acurate ței. Dac ă în
exemplul anterior în care dispuneam de dispozitiv d e m ăsurare a timpului care emite un semnal din 25 în
25 de secunde vrem s ă afi șă m minutele, constat ăm c ă minutul 1 este afi șat pentru prima dat ă când timpul
scurs este 1minut și 15 secunde. Eroarea suplimentar ă este în acest caz de 15 secunde.
Sc ădere suplimentar ă a acurate ței de maxim un ciclu de num ărare T cycle . Aceast ă valoare trebuie
adăugat ă la acurate țea calculat ă conform rela ției Rel. 5.
Acc poll_metoda1 = Tcycle + Tmax_while(1) + Δmin
Acc poll_metoda2 = Acc poll_metoda1 +Tcycle = 2Tcycle + Tmax_while(1) + Δmin Rel. 8
În exemplul anterior T cycle este 6.5ms. O imprecizie suplimentar ă de 6,5ms este perfect acceptabil ă pentru
cuptoare cu microunde și ma șini de sp ălat dar este inacceptabil ă pentru un cronometru sportiv.

1

Microprocesoare, microcontrolere – Prelegere 6, înt reruperi

Pân ă în prezent producerea evenimentelor externe, cum a r fi ap ăsarea unui buton, este sesizat ă de
software prin citirea în bucla principal ă while(1) a unui port de intrare la care este conectat
respectivul buton. Testarea periodic ă a st ării unui semnal extern se nume ște polling . Metoda polling nu
func ționeaz ă în cazul a dou ă categorii de evenimente: evenimente frecvente și evenimente urgente .
Un eveniment este considerat frecvent data intervalul de timp minim între doua apari ții este mai
mic decât durata maxim ă de execu ție a buclei principale. De exemplu, dac ă un timer cicleaz ă la 2 ms iar
durata maxim ă de execu ție a buclei principale este 5 ms atunci ciclarea ti merului este considerat ă un
eveniment frecvent. Dac ă acela și timer ar cicla la 10 ms iar bucla principala s-ar executa tot în maxim 5
ms, atunci ciclarea nu ar mai fi un eveniment frecv ent. Un eveniment frecvent este ciclarea
num ărătorului cu care s-a implementat ceasul la laborator . Cum în bucla principal ă se face un test per
eveniment, metoda polling nu func ționeaz ă deoarece nu poate prelucra toate apari țiile unui astfel de
eveniment.
Un eveniment este considerat urgent dac ă timpul de r ăspuns la apari ția evenimentului trebuie s ă
fie foarte mic: de exemplu sun ă telefonul. Chiar dac ă un astfel de eveniment este relativ rar, trebuie s ă
răspundem urgent pentru c ăci altfel am pierde apelul. Detectarea evenimentelo r se face prin citirea unui
port de intrare la care este conectat semnalul care produce evenimentul. Deoarece citirea portului de
intrare se face in bucla while(1) timpul de r ăspuns al sistemului la apari ție unui eveniment este dat
de timpul de execu ție al buclei. Acest timp este de regul ă de ordinul zecilor de milisecunde, dar în
anumite aplica ții poate ajunge și la zecimi de secund ă. Un timp de r ăspuns chiar de o zecime de secund ă
este perfect acceptabil ă în cazul cuptorului cu microunde sau a ma șinii de sp ălat. Exist ă îns ă aplica ții în
care un timp de r ăspuns a șa mare este intolerabil . O astfel de aplica ție este afi șajul multiplexat ce va
fi prezentat la sfâr șitul acestei prelegeri.
Din defini țiile evenimentelor frecvente și urgente se observ ă c ă raportarea se face la timpul de
execu ție a buclei principale: cu cât timpul de execu ție al buclei principale este mai mare, cu atât mai
multe evenimente devin frecvente și/sau urgente.
Chiar dac ă scriem software-ul în a șa fel încât să nu existe evenimente frecvente sau urgente
pollingul este foarte contraproductiv și ineficient .
Este contraproductiv deoarece nu se pot folosi func ții de bibliotec ă. Utilizarea func țiilor de
bibliotec ă poate cre ște mult durata de execu ție a buclei principale.
Este ineficient deoarece se pierde timp cu testarea st ării resursei hard. În cazul tastaturii testarea
trebuie să se fac ă la 0.1 secunde sau mai repede. Dac ă timp de un minut nu se apas ă nici o tast ă,
aplica ția face totu și 600 de teste, irosind for ță de calcul. Dezvoltarea aplica țiilor în acest stil devine
aproape imposibil ă dac ă num ărul de resurse hardware care trebuie monitorizate e ste mare. Într-o
aplica ție real ă trebuie monitorizate cel pu țin dou ă sau trei timere, tastatura și o interfa ță serial ă.
Solu ția la aceast ă problem ă ar fi ca secven ța de instruc țiuni care trebuie executat ă la
apari ția unui eveniment s ă fie lansat ă automat, de hardware, imediat dup ă apari ția
evenimentului.
În cazul ceasului din prelegerea 5 activarea lui OC F0 trebuie s ă întrerup ă execu ția programului,
să for țeze execu ția secven ței TIFR|=1<<OCF0; soft_cnt++;… și apoi să reia execu ția programului
întrerupt. Vezi exemplu cu telefonul care sun ă când ne sp ălăm pe din ți.
Avantajele acestei solu ții sunt majore: tratarea unui eveniment se face aut omat la activarea unui

2semnal hardware iar software–ul este degrevat de op era ția de testare. Astfel se pot folosi func ții de
bibliotec ă și nu se mai pierde timpul cu citirea în bucl ă a st ării resursei.
Se ridic ă 3 întreb ări:
1. Cum va ști procesorul c ă a ap ărut un eveniment extern (de exemplu, OCF0=1 sau s-a ap ăsat o
tast ă)?
2. Cum un eveniment extern poate for ța execu ția unei secven țe de instruc țiuni?
3. Cum va relua execu ția programului întrerupt?

1. Sistem de întreruperi cu vectorizare software.
Solu ția const ă în a prevede procesorul cu o intrare pentru întrer upere în cazul apari ției unui
eveniment extern. Semnalul ce se aplic ă pe aceast ă intrare apar ține magistralei de control și se nume ște
INT sau INTR .
Introducerea lui INT r ăspunde la întrebarea: „Cum va ști procesorul c ă a ap ărut un
eveniment extern?”
Activarea semnalului de întrerupere trebuie s ă suspende execu ția programului și s ă transfere
controlul unei secven țe de instruc țiuni. Aceasta secven ță de instruc țiuni o vom numi în continuare rutin ă
de tratare întrerupere (Interrupt Service Routine – ISR). Dup ă terminarea rutinei de întrerupere trebuie
să se transfere controlul programului întrerupt.
În concluzie, ca urmare a activ ării semnalului de întrerupere, trebuie s ă se desf ăș oare urm ătoarea
secven ță de evenimente:
1. Procesorul termin ă de executat instruc țiunea curent ă.
2. Procesorul salveaz ă informa țiile necesare relu ării ulterioare a programului întrerupt. Informa ția
ce trebuie obligatoriu salvat ă este num ărătorul de program – PC. Unele procesoare salveaz ă
numai PC, altele salveaz ă PC plus PSW. Exist ă și procesoare care salveaz ă PC plus toate
registrele.
3. PC se încarc ă cu o adres ă fix ă, cablat ă. Aceast ă adres ă se va numi în continuare vector de
întrerupere și se va nota cu addr_fix . Vectorul de întrerupere difer ă de la procesor la procesor.
Se observ ă c ă secven ța de opera ții ce trebuie executat ă în cazul în care semnalul INT se
activeaz ă este aproape identic ă cu fazele execu ției instruc țiunii CALL addr pentru familia Intel (vezi
curs Arhitectura calculatoarelor) sau JAL addr pentru MIPS (vezi curs Organizarea calculatoarelor).
În cazul MIPS aceast ă secven ță de opera ții este implementat ă în hardware prin o mic ă
modificare a procesorul. În figura 1 este prezentat ă implementarea MIPS (redus) din Hennessy și
Patterson (vezi curs Organizarea Calculatoarelor).

3
figura 1
Modificarea const ă în ad ăugarea unui MUX2 vectorial, ca în figura 2. Selec ția multiplexorului
ar trebui s ă fie chiar semnalul INT. In scurt timp vom vedea c ă nu trebuie folosit INT ci un semnal
derivat din INT, și anume INT*. Dac ă INT* este ‚0’, codul instruc țiunii se ob ține din memoria de
program. În caz contrar codul instruc țiunii este o valoare cablat ă, valoare care este codului ma șin ă al
instruc țiunii JAL addr_fix . Cu alte cuvinte, tratare a unei întreruperi const ă în execu ția
instruc țiunii JAL addr_fix imediat dup ă activarea liniei INT.

figura 2
Aten ție! Aceast ă instruc țiune nu apare niciunde în codul din memoria program !
Aten ție! Execu ția instruc țiunii JAL addr_fix ca urmare a activ ării semnalului INT* difer ă pu țin de

4execu ția normal ă a acestei instruc țiuni. Execu ția normal ă a instruc țiunii JAL addr_fix se face când
codul ma șin ă al acestei instruc țiuni este înc ărcat din memoria program. Diferen ța const ă în valoarea
salvat ă în registrul 31: la execu ția normal ă se salveaz ă PC+4 iar la execu ția for țat ă ca urmare a activ ării
INT se salveaz ă PC. Urm ări ți execu ția detaliat ă a instruc țiunii JAL ca urmare a activ ării INT în
prezentarea asociat ă cursului (4int.ppt).
Modificarea din figura 2 este de principiu. Pentru a fi func țional ă sunt necesare și alte
modific ări, a șa cum se va detalia în continuare. Pentru procesoar ele din familia INTEL tratarea
întreruperii este asem ănătoare, numai c ă în loc de JAL se folose ște instruc țiunea CALL .
Este evident c ă un singur semnal de întrerupere nu este suficient. Fiecare periferic ar trebui s ă
avertizeze procesorul despre modificarea st ării sale printr-un semnal de întrerupere propriu. R ezult ă c ă
sunt necesare atâtea semnale de întrerupere câte pe riferice sunt. Cum num ărul de periferice difer ă de la
un sistem la altul în func ție de aplica ție, rezult ă c ă este foarte greu de prev ăzut în faza de proiectare a
procesorului num ărul de semnale de întrerupere. Din acest motiv proc esorul este prev ăzut cu un singur
semnal de întrerupere. Ori de câte ori apare o cere re de întrerupere IRQ (Interrupt Request), indifere nt
de la ce periferic, semnalul INT trebuie activat. Î n figura urm ătoare este prezentat un sistem cu patru
surse de întrerupere:
• IRQ_KB de la tastatur ă
• IRQ_Timer0 de la timerul 0
• IRQ_UART de la interfa ța serial ă
• IRQ_ADC de la convertorul analog-numeric.
INT
RD#
T
WR# A[m-1..0]
D[n-1..0]
D0
PROCESSOR D2
ADDR.
DEC.
T
IRQ_UART DataBus[n-1..0]
TD3
IRQ_ADC IRQ_Timer0 . CS_int_status AddrBus[m-1..0]
IRQ_KB TD1

figura 3
Cererile de întrerupere IRQ sunt active pe ‚1’ logi c. Semnalul INT, activ tot pe ‚1’ logic, se generea z ă
cu o poart ă OR4: ori de câte ori este activ ă o cerere (sau mai multe) se va activa și INT. Pentru a
determina care cerere a determinat activarea liniei INT, se va citi starea liniilor de cerere. Acestea se
grupeaz ă într-un port de intrare: portul de stare cereri în trerupere. În figura 3 selec ția acestui port se
nume ște CS_int_status.
Este important de re ținut c ă:
1) Rutina de întrerupere nu returneaz ă valori. De obicei rutinele (func ții sau proceduri) returneaz ă
valori prin intermediul registrelor de uz general. Programul apelant se a șteapt ă s ă primeasc ă o
valoare într-unul din registre. Dar rutina de între rupere este apelat ă la activarea semnalului INT și

5INT nu a șteapt ă o valoare într-un registru deoarece nu „ știe” ce s ă fac ă cu ea. Dac ă totu și rutina de
întrerupere ar întoarce o valoare, nu ar face altce va decât s ă altereze valoarea dintr-un registru pe
care programul întrerupt îl folose ște. Din aceast ă cauza sistemul se va bloca sau va avea o
comportare imprevizibil ă.
2) Rutina de întrerupere nu admite parametrii. În mod normal, o rutin ă poate fi apelat ă cu
parametrii, ace știa fiind depu și în memorie, de exemplu pe stiv ă. Rutina „ știe” c ă trebuie s ă extrag ă
de pe stiv ă parametrii. În cazul rutinei de întrerupere nu exi st ă un program apelant, apelul f ăcându-
se la activarea unui semnal electric care nu „ știe” s ă depun ă pe stiv ă parametrii. Dac ă rutina de
întrerupere ar fi scris ă cu parametrii, la execu ție aceasta ar scoate de pe stiva parametrii, f ără ca
cineva s ă-i fi depus. Aceast ă ac țiune altereaz ă stiv ă, deoarece se extrage mai mult decât se depune,
și va duce la blocarea sistemului. Cele mai multe compilatoare genereaz ă eroare dac ă o func ție
apelat ă la întrerupere este scris ă cu parametrii sau dac ă returneaz ă ceva .
3) Rutina de întrerupere nu este apelat ă din nici o func ție din program (inclusiv main ). Atunci se
pune problema: cum comunic ă rutina de întrerupere cu restul programului? R ăspunsul este simplu:
prin intermediul variabilelor globale!
În continuare se prezint ă structura de principiu a softului în cazul vectori z ării software:
// secven ța de mai jos se executa pe un procesor ipotetic cu vectorul de
// întrerupere la adresa 0f000h
#include <stdio.h>

void interrupt intr_routine(void){ //sau ISR(void)
// cuvântul cheie „ interrupt ” for țeaz ă generarea codului pentru aceasta func ție
// la adresa fix ă 0xf000
char temp;

temp=read_port(int_status);

if(temp & 1){
//cite ște caracter și depune-l în coada tastaturii;
}

if(temp & 2){
//secven ță de instruc țiuni pentru tratarea cererii de la timer
}

if(temp & 4){
//secven ță de instruc țiuni pentru tratarea cererii de la uart
}

if(temp & 8){
//secven ță de instruc țiuni pentru tratarea cererii de la ADC
}
}//end int routine
.
.
main() {
.//nici o func ție (inclusiv main) nu apeleaz ă int_routine();
.
.
}
Aceast ă solu ție cu un singur vector de întrerupere este folosit ă de microcontrolerele PIC de la firma
Microchip.

62. Sistem de întreruperi cu vectorizare hardware
Metoda vectoriz ării software prezentat ă anterior este foarte simpl ă, dar poate deveni dezavantajoas ă
dac ă num ărul de întreruperi este mare. În exemplu de mai sus codul pentru ADC va fi apelat abia dup ă
ce vor fi testate toate cele trei condi ții anterioare, ceea ce va m ări timpul de r ăspuns în acest caz. Cele
trei teste se vor face chiar dac ă nu exist ă cereri de la tastatur ă , timer și UART. Timpul de r ăspuns poate
deveni nepermis de mare în cazul procesoarelor lent e.
Timpul de r ăspuns se poate îmbun ătăți dac ă func țiile specifice perifericelor vor fi apelate
hardware, nu software. Cu alte cuvinte, în loc de a se for ța codul ma șin ă al instruc țiunii JAL(CALL)
addr_fix vom for ța codul lui JAL(CALL) f(IRQactiv) . Adic ă adresa rutinei de întrerupere se
calculeaz ă de c ătre hardware și va depinde de cererea de întrerupere activ ă. Metoda care implementeaz ă
ideea enun țat ă este:
1. Una sau mai multe linii de întrerupere IRQ se activ eaz ă.
2. Prin intermediul unei por ți OR se activeaz ă linia de întreruperi INT pentru a informa procesor ul
despre apari ția unui eveniment extern, f ără a se preciza ce linie (sau linii) IRQ au provocat activarea
lui INT
3. Procesorul termin ă instruc țiunea în curs de execu ție;
4. Procesorul cere informa ții despre natura evenimentului. Pentru aceasta proc esorul lanseaz ă o
opera ție de citire, numai c ă în loc de semnalul RD# se activeaz ă un nou semnal ce apar ține
magistralei de control, și anume INTA# (interrupt acknowledge). În momentul activ ării INTA#, se
spune c ă întreruperea este acceptat ă. Structura hardware din exteriorul procesorului depune pe
DATA BUS o informa ție caracteristic ă IRQ-ului activ. Asocierea informa ție – IRQ trebuie s ă fie
univoc ă; fiecare IRQ are asociat ă propria sa informa ție. Aceast ă informa ție se mai nume ște
num ărul vectorului de întrerupere sau vector de 8 bi ți (V8). Informa ția vehiculata pe cele 3
magistrale pentru acest tip de transfer este:
− pe magistrala de adrese: nu conteaz ă;
− pe magistrala de date: num ărul vectorului de întrerupere;
− pe magistrala de control: INTA# (sau o combina ție de semnale ce identifica în mod univoc
acest tip de transfer).
Așa cum s-a afirmat anterior, este datoria circuitelo r din exteriorul procesorului s ă asocieze în mod
univoc un vector de 8 bi ți fiec ărei cereri IRQ. În figura 4 este prezentat un exemp lu. Fiecare cerere IRQ
poate fi codificat ă pe 2 bi ți dac ă folosim un codificator de priorit ăți (COP sau PENC). Vectorul de 8 bi ți
este depus pe magistrala de date prin intermediul a 8 por ți repetoare 3-state. Cele 8 repetoare sunt
validate simultan de semnalul INTA#. Deoarece num ărul cereri IRQ prioritare se codific ă de COP pe
doi bi ți, restul de 6 bi ți se conecteaz ă la o valoare constant ă. În exemplu aceast ă valoare este ‚0’ logic.
Astfel vectorii de 8 bi ți genera ți sunt:
0000 00_ 00 b pentru IRQ_KB
0000 00_ 01 b pentru IRQ_Timer
0000 00_ 10 b pentru IRQ_UART
0000 00_ 11 b pentru IRQ_ADC

7D5 AddrBus[15..0]
T
IRQ_KB .
IRQ_ADC INT
T
WR# RD#
TDataBus[7..0]
'0'
T
Priority
Encoder
AB
Y0Y1Y2Y3'0' D4
IRQ_Timer D0
INTA#
PROCESOR '0'
IRQ_UART A[15..0]
TD1 T
'0' D2 D6
'0' D[7..0]
TD3 T
'0' D7

figura 4
6. Procesorul prelucreaz ă num ărul vectorului de întrerupere dup ă o metoda ce difer ă de la procesor la
procesor. În urma prelucr ării rezult ă o valoare de adres ă, valoare care va fi înc ărcat ă în PC. Aceast ă
valoare este vectorul de întrerupere . ATmega calculeaz ă vectorul de întrerupere cu formula
vector_intrerupere=V8*2 . Asem ănător, la I8051 vector_intrerupere=3+V8*8 . Multe
alte procesoare, ca de exemplu Z80 și I80x86, folosesc o tabel ă a vectorilor de întrerupere, vectorul
de 8 bi ți fiind index în aceast ă tabel ă.
7. Procesorul execut ă JAL (CALL) vector_intrerupere , valoarea vectorului de întrerupere fiind
calculat ă la pasul 6. Execu ția acestei instruc țiuni presupune salvarea PC și apoi înc ărcarea acestuia
cu vector_întrerupere .
8. Începe execu ția rutinei de tratare. Rutina de tratare se execut ă deoarece s-a produs un eveniment ce a
activat o linie IRQ și apoi IRQ a activat INT și INT a declan șat execu ția pa șilor 1-7.
Important: execu ția rutinei de tratare trebuie s ă provoace inactivarea IRQ-ul care a declan șat acest
lan ț de evenimente. Se mai spune c ă execu ția rutinei de tratare trebuie s ă satisfac ă cererea. În
caz contrar secven ță declan șat ă de activarea lui IRQ va continua la nesfâr șit și sistemul se va bloca.
9. În momentul în care rutina de tratare se încheie, s punem c ă întreruperea a fost achitat ă. Dac ă
procesorul a salvat pe stiv ă numai PC, rutina de tratare se va încheia cu un RE T. Dac ă îns ă s-a salvat
PC plus alte informa ții, este nevoie de o instruc țiune special ă, care s ă restaureze toate informa țiile
salvate, nu numai PC, a șa cum face RET. Aceast ă instruc țiune special ă se nume ște RETI sau IRET.
De exemplu, 80×86 salveaz ă pe stiv ă CS, IP și flagurile iar instruc țiunea de restaurare se nume ște
IRET. Mai exist ă un motiv pentru care rutina de întrerupere se term in ă cu o instruc țiune special ă,
motiv ce va fi detaliat ulterior.

8În continuare se va prezenta o variant ă de structur ă a softului pentru vectorizare hardware:
void enqueue_char(void) interrupt 0
{………}

void timer(void) interrupt 1
{………}

void uart(void) interrrupt 2
{………}

void ADC(void) interrrupt 3
{………}
.
.
main(){
.//nici o func ție (inclusiv main) nu apeleaz ă rutinele de întrerupere;
.
.
}
Din exemplul de mai sus se observ ă c ă scrierea unei func ții de întrerupere difer ă de scrierea unei func ții
normale prin a apari ția cuvântului cheie interrupt urmat de vectorul de 8 bi ți. Structura interrupt
n spune compilatorului s ă genereze codul ma șin ă al rutinei de întrerupere începând cu adresa f(V8) și
eventual s ă termine aceast ă rutin ă cu instruc țiunea special ă RETI sau IRET. De re ținut c ă sintaxa
interrupt n nu este universal ă, ci depinde de compilator.
La ATmega16 exist ă 21 de cereri de întreruperi, centralizate în tabel ul urm ător. Tabelul este
reprodus din datele de catalog:
tabelul 1

9Așa cum s-a precizat anterior, vectorul de întreruper i la Atmega se calculeaz ă cu formula V8*2. În
tabelul 1 nu apare valoarea lui V8, ci doar num ărul s ău de ordine (în coloana „Vector No.”). V8 se
ob ține sc ăzând unu din num ărul de ordine. Vectorul de întrerupere este valoare a ce se va înscrie în PC,
fiind astfel adresa primei instruc țiuni din rutina de întrerupere. În tabelul 1 vector ul de întrerupere apare
în coloana „Program Address”. Se observ ă c ă „Program Address”= („Vector No.” -1)*2. Aceast ă adresa
este o adres ă de cuvânt de 16 bi ți deoarece memoria de program este organizat ă pe cuvânt, nu pe byte.
În continuare se va descrie cum se declar ă în C o rutin ă de întrerupere pentru ATmeaga16.
Anterior, o rutin ă de întrerupere (ISR) s-a declarat cu:
void nume_ISR (void) interrupt n
De exemplu, ISR pentru timer a fost declarat ă cu
void timer(void) interrupt 1
unde timer este nume_ISR iar este n este 1.
Compilatorul de C din AVR Studio nu folose ște acest stil. Compilatorul folose ște pentru orice rutin ă de
întrerupere macrodefini ția ISR. ISR are nevoie de vectorul de 8 bi ți ca parametru. În continuare se va
prezenta structura softului pentru varianta cu vect orizare hardware rescris pentru ATmega16:
ISR(INT2_vect) //kb irq on external interrup t request INT2
{………} //V8=18 →IntVec =18*2=0x024

ISR(TIMER0_COMP_vect) //V8=19 →IntVect=19*2=0x026
{………}

ISR(USARTRXC_vect) // V8=11 →IntVect=11*2=0x016
{………}

ISR(ADC_vect) // V8=14 →IntVect=14*2=0x01c
{………}
.
.
main()
{
//nici o func ție (inclusiv main) nu apeleaz ă rutinele de întrerupere;
.
}
Pentru a nu fi obliga ți s ă c ăut ăm mereu în documenta ție vectorii V8, acestora le sunt asociate nume
sugestive în headerul io.h. Astfel este posibil s ă scriem
ISR(TIMER0_COMP_vect) în loc de ISR(19).
CONCLUZIE: Conlucrarea între procesor și blocul de întreruperi implic ă un dialog, dialog ce
presupune pe lâng ă transferul de date (num ărul vectorului de întrerupere) și activarea unui semnal ce nu
implic ă vehiculare de date, ci are rol de avertizare, și anume INT. Avertizarea procesorului prin
activarea INT apar ține nivelului de dialog între module.

3. Întreruperi mascabile și nemascabile
Dac ă analiz ăm figura 2, rezult ă c ă activarea semnalului de întrerupere for țeaz ă executarea
instruc țiunii JAL (sau CALL) atâta timp cât acest semnal es te activ. Să presupunem c ă INT este activ și
hardware-ul for țeaz ă executarea instruc țiunii JAL addr_fix . În continuare INT este activ ceea ce
implic ă execu ția instruc țiunii JAL addr_fix a doua oar ă, a treia oar ă ș.a.m.d., pân ă când INT devine
inactiv. Deoarece nu se execut ă nici o instruc țiune din rutina de tratare cererea nu poate fi sati sf ăcut ă,
IRQ-ul nu devine inactiv și nici INT și astfel sistemul de va bloca. Suplimentar, adresa de revenire

10 salvat ă în registru 31 la MIPS se va pierde: prima execu ție a lui JAL addr_fix salveaz ă în registrul 31
adresa de revenire iar urm ătoarele execu ții suprascriu valoarea salvat ă. Urm ătoarele execu ții salveaz ă
chiar addr_fix , ceea ce va face ca adresa original ă de întoarcere s ă se piard ă.
Pentru a evita acest comportament, semnalul de INT care determin ă execu ția JAL addr_fix ,
trebuie for țat în starea inactiv înainte de a se termina execu ția instruc țiunii JAL addr_fix . Astfel JAL
addr_fix se va execut ă o singur ă dat ă. For țarea unui semnal în starea inactiv se mai nume ște inhibare
sau mascare. Mascarea se face cu ajutorul unui bist abil și a unei por ți AND, ca în figura 5 (presupunem
întreruperea activ ă ‚1’). Acest bistabil se va numi în continuare bis tabilul IF ( Interrupt Flag).

figura 5
În cazul vectoriz ării hardware, bistabilul IF poate fi șters de semnalul INTA. Acest semnal este
activ numai pe durata execu ției JAL addr(IRQ_activ) și apare, evident, înainte de terminarea
instruc țiunii.
În general, semnalul INT este dezactivat, mascat, î n urm ătoarele situa ții:
1. Dup ă acceptarea unei întreruperi, pentru a evita execu ția instruc țiunii JAL addr_fix atâta timp cât
INT este activ, a șa cum s-a ar ătat anterior.
2. Dup ă RESET, deoarece sistemul nu a fost ini țializat.
3. Sub controlul programului, prin executarea unei ins truc țiuni speciale, de exemplu DISABLE
INTERRUPTS (DI) sau CLEAR INTERRUPTS (CLI). Execu ția acestei instruc țiuni are ca efect
activarea semnalului CLI# din figura 5.
Reactivarea liniei de întrerupere este absolut necesar ă dup ă încheierea rutinei de tratare pentru ca
procesorul s ă accepte noi întreruperi. La multe procesoare ultim a instruc țiune din rutina de tratare este
RETI. RETI seteaz ă bistabilul IF din figura 5 și reface PC. În hardware reactivarea liniei de într erupere
se face atunci când unitatea de control activeaz ă semnalul STI#. Acest semnal se mai poate activa și ca
urmare a execu ției unei instruc țiuni cum ar fi ENABLE INTERRUPTS (EI) sau SEI (SET
INTERRUPTS). Pereche CLI – SEI este absolut necesar ă pentru marcarea sec țiunii critice, a șa cum se
va vedea în continuare.
Unele procesoare sunt prev ăzute cu înc ă o linie de întrerupere ce nu poate fi mascat ă. De regul ă
aceast ă linie este folosit ă pentru semnalizarea evenimentelor catastrofale, ev enimente ce fac imposibil ă
continuarea execut ării programului (c ăderea iminent ă a aliment ării, eroare paritate memorie). Aceast ă
linie se nume ște de regul ă NMI (Non Maskable Interrupt – întrerupere nemascabil ă). Necesitatea liniei
NMI rezult ă din urm ătorul exemplu: s ă presupunem un bloc de întreruperi cu 8 cereri IRQ0 -IRQ7,

11 IRQ0 de prioritate maxim ă (c ăderea tensiunii). La un moment dat se activeaz ă IRQ7 și se d ă controlul
rutinei aferent ă lui IRQ7 – ISR7. În ISR7 nu este folosit ă nici o instruc țiune de tip EI. Dac ă pe durata
execu ției lui ISR7 se activeaz ă IRQ0, aceasta nu va fi onorat ă. Dac ă ISR7 este suficient de lung ă este
posibil ca alimentarea s ă se întrerup ă înainte de achitarea lui IRQ0. Aceasta situa ție se evit ă prin
introducerea liniei NMI.

4. Sec țiune critic ă
Așa cum s-a explicat anterior, rutina de întrerupere comunic ă cu celelalte func ții, inclusiv main (),
prin variabile globale. Din acest motiv apare un ef ect de care trebuie ținut seama. Acest efect const ă
citirea unei valori incorecte a unei variabile glob ale sau în alterarea valorii acesteia în anumite co ndi ții.
În continuare vom reconsidera o variabil ă global ă numit ă gvar. Variabila gvar este incrementat ă în
rutina de întrerupere asociat ă lui OCF0 și folosit ă în main pentru calculul variabilei rez . În acest
exemplu este folosit ă rutina de întrerupere asociat ă lui OCF0 deoarece OCF0 a mai fost folosit anterior ,
dar ar putea fi orice rutin ă de întrerupere.
Pentru a calcula pe rez variabila gvar trebuie citit ă în main. Deoarece ATmega este o arhitectur ă
cu l ățimea căii de date de 8 bi ți, o variabil ă de tip int din C va necesita un spa țiu de memorie de doi
octe ți (sau mai mult). Astfel variabila gvar de tip int va ocupa dou ă loca ții de memorie aflate la adrese
succesive. Modul în care compilatorul traduce inst ruc țiunea rez=gvar+b este prezentat în partea
dreapt ă a codului C de mai jos.
Deoarece sunt necesare 2 instruc țiuni pentru a citi pe gvar , este posibil ă urm ătoarea secven ță de
evenimente, prezentat ă grafic mai jos. Pentru o prezentare animat ă a acestei secven țe vezi 6int.pptx.

1. Presupunem c ă înainte de executarea instruc țiunii rez=gvar+b valoarea variabilei globale
gvar este 0x12FF .
2. Se execut ă prima citire din memorie
LDS r16, gvar
Deoarece gvar = 0x12FF octetul inferior al acestei variabilei are valoarea 0xFF . Aceast ă
valoare se încarc ă în registrul 16.

12 3. Exact dup ă executarea instruc țiunii LDS r16, gvar flagul OCF0 devine ‚1’. In consecin ță se
va executa rutina de întrerupere.
4. In rutina de întrerupere asociat ă comparatorului timerului 0 variabila global ă gvar este
incrementat ă și ajunge la valoarea 0x13FF .
5. Se revine din rutina de întrerupere și se execut ă instruc țiunea:
LDS r17, gvar+1
Deoarece acum gvar = 0x13FF , octetul superior al acestei variabilei are valoarea 0x13 .
Aceast ă valoare se încarc ă în registrul 17.
6. Deoarece în r16 este 0xFF iar în r17 este 0x13 în calculul lui rez se va utiliza o valoare gre șit ă.
Aceasta se datoreaz ă faptului c ă citire octetului inferior face când gvar are o valoare iar citire
octetului superior se face când gvar are o alt ă valoare. Întreruperea se activeaz ă exact între cele
dou ă citiri din memoria principal ă. Astfel softul are impresia c ă valoarea lui gvar este 0x13FF,
când de fapt valoarea real ă este ori 0x12FF, ori 0x1300.
Pentru a evita comportarea descris ă anterior trebuie ca citirea variabilei gvar în instruc țiunea
rez=gvar+b să nu poat ă fi întrerupt ă. O astfel de sec țiune se nume ște sec țiune critic ă. Pentru ca o
sec țiune a programului s ă nu fie întrerupt ă trebuie ca înainte de intrarea în respectiva sec țiune s ă se
dezactiveze întreruperea, urmând s ă se reactiveze dup ă executarea sec țiunii. Dezactivarea întreruperii se
face cu o instruc țiune de tip CLI (sau DI) iar reactivarea cu o instruc țiune de tip SEI (STI sau EI).
În continuare sec țiunea critic ă este delimitat ă de instruc țiunile CLI – SEI:
CLI
LDS r16, gvar
LDS r17, gvar + 1
SEI
LDS r18, b
LDS r19, b +1
ADD r16, r18
ADC r17, r19
STS rez, r18
STS rez+1, r19
…..

Dac ă la nivel de limbaj de asamblare este u șor de f ăcut neîntreruptibil ă citirea lui gvar , în C este
pu țin mai dificil deoarece nu se poate scrie CLI și SEI în mijlocul unei atribuiri. Aceast ă problema se va
trata la laborator.
Observa ție: Probabilitatea unui scenariu ca cel de mai sus est e extrem de mic ă. Trebuie ca întreruperea
apar ă exact între instruc țiunile:
LDS R16, gvar
LDS R17, gvar+1
Presupunând c ă programul principal are 1000 de instruc țiuni și c ă întreruperea poate apare dup ă
oricare instruc țiune, probabilitatea citiri unei valori inconsisten te este 1/1000. În realitate presupunerea
că întreruperea poate apare dup ă oricare instruc țiune este fals ă, a șa c ă probabilitatea este și mai mic ă
sau chiar zero uneori.
Probabilitatea foarte mic ă (sau zero) a unui asemenea eveniment duce la compo rtarea derutant ă a
unui sistem în care o zon ă critic ă nu a fost protejat ă: sistemul func ționeaz ă foarte bine minute sau ore și
apoi se blocheaz ă, sau sistemul func ționeaz ă perfect, dar dup ă o modificare a softului se blocheaz ă.
Modificarea este perfect ă din punct de vedere logic dar face s ă apar ă efectul zonei critice neprotejate.
Eforturile de depanare se vor concentra asupra ult imei modific ări, care este corect ă logic, și astfel se va
pierde timp pre țios. De aceea:

13 Regul ă: Dac ă o variabila este partajat ă între o rutin ă de întrerupere și restul programului, orice
acces la aceast ă variabil ă în afara rutinei de întrerupere se face protejat. Prin acces se în țelege
scriere sau citire. Protejat înseamn ă CLI înainte de acces și SEI dup ă.

5. Mascarea cererilor de întrerupere
La începutul acestei prelegeri s-a ar ătat c ă mecanismul de întreruperi îmbun ătățește timpul de
răspuns al sistemului la apari ția unui eveniment extern. F ără întreruperi timpul de r ăspuns este timpul
de execu ție al buclei principale iar cu întreruperi este tim pul necesar intr ării în rutina de întreruperi.
Acest timp care este foarte scurt și este egal cu timpul necesar execut ării a dou ă instruc țiuni: trebuie
terminat ă instruc țiunea pe durata c ăreia s-a activat INT și trebuie executat ă instruc țiunea JAL addr_fix.
Acest timp de r ăspuns scurt se ob ține numai dac ă exist ă o singura cerere IRQ activ ă și dac ă aceast ă
cerere nu apare pe durata execu ției unei sec țiuni critice deoarece în sec țiunea critic ă semnalul INT este
mascat. Considerând și existen ță sec țiunilor critice, într-o prima aproxima ție putem spune c ă în cazul
cel mai defavorabil timpul de r ăspuns este timpul de execu ție a celei mai lungi sec țiuni critice plus
timpul de execu ție al instruc țiunii JAL* addr_fix. De aici rezult ă c ă timpul de execu ție a unei sec țiunii
critice trebuie s ă fie cât mai mic, adic ă sec țiunile critice trebuie s ă fie cât mai scurte .
Din p ăcate exist ă situa ții în care timpul de r ăspuns cre ște și mai mult. Astfel de situa ții apar când
sunt active dou ă sau mai multe cereri de întrerupere simultan. În c ontinuare vom analiza trei scenarii .
În primul scenariu vom considera c ă dou ă cereri de întreruperi IRQ i și IRQ j; IRQ i are prioritatea
mai mare decât IRQ j. La un moment cele dou ă cereri devin active simultan. Deoarece IRQ i are prioritate
mai mare, se va intra în rutina de tratate aferenta lui IRQ i, rutin ă ce o vom numi în continuare ISR i.
Execu ția rutinei face ca cererea IRQ i să devin ă inactiv ă, astfel încât dup ă terminarea acestei rutine
singura cerere activ ă este IRQ j. Prin urmare se va intra în rutina de tratate afer enta lui IRQ j, rutin ă ce o
vom numi în continuare ISR j. Din acest exemplu se observ ă c ă execu ția lui ISR j se face dup ă execu ția
rutinei ISR i și astfel timpul de r ăspuns cre ște. De aici rezult ă c ă timpul de execu ție al unei rutine de
întrerupere trebuie s ă fie cât mai mic, adic ă rutinele de întrerupere trebuie s ă fie cât mai scurte .
Situa ția de mai sus nu este îns ă cea mai proast ă. În al doilea scenariu vom ar ăta cum poate fi și
mai r ău. Să consider ăm că la un moment dat sunt active trei cereri de întrer upere IRQ i , IRQ j și IRQ k.
Prioritatea cea mai mare o are IRQ i, apoi urmeaz ă IRQ j iar prioritatea cea mai mic ă o are IRQ k. Vom
considera urm ătoarea secven ță de evenimente:
1. Deoarece IRQ i are prioritatea cea mai mare se trece la executare a rutinei de tratate aferenta lui
IRQ i, rutin ă ce o vom numi în continuare ISR i. Pe durata execu ției lui ISR i cererea IRQ i devine
inactiv ă.
2. ISR i se termin ă. În acest moment sunt active IRQ j și IRQ k. Deoarece IRQ j are prioritatea mai
mare decât IRQ k se trece la executarea rutinei de tratate aferenta lui IRQj, rutin ă ce o vom numi
în continuare ISR j. Pe durata execu ției lui ISR j cererea IRQ j devine inactiv ă dar se reactiveaz ă
IRQ i.
3. ISR j se termin ă. În acest moment sunt active IRQ i și IRQ k. Cum IRQ i are cea mai mare
prioritate se va trece la executarea lui ISR i și ajungem exact în situa ția de la pasul 1.
Secven ța 1-3 de mai sus se poate repeta mult timp ceea ce va face ca IRQ k să nu fie servit ă și astfel
timpul de răspuns pentru cererea IRQ k cre ște foarte mult. Aceast ă situa ție este frecvent ă în cazul
sistemelor de întrerupere cu prioritate fix ă. În astfel de sisteme timpul de r ăspuns pentru cererile de
prioritate mic ă poate crește foarte mult iar în situa ții extreme aceste cereri pot s ă nu mai fi servite de loc.
Solu ția în cazul scenariului 2 este ca cererile de între rupere s ă poat ă fi inhibate selectiv din software:

14 dac ă am inhiba cererile de prioritate ridicat ă atunci cererile de prioritate sc ăzut ă ar avea șanse
mai mari s ă fie servite . Pentru ca solu ția inhib ării selective să func ționeze este necesar ca fiecare cerere
de întrerupere s ă poat ă fi mascat ă individual.
Mecanismul hardware de mascare este acela și ca cel folosit la mascarea liniei INT, adic ă o
poart ă AND și un bistabil D. În figura urm ătoare s-au ad ăugat resursele hardware pentru mascarea
tuturor celor 4 cererilor de întrerupere introduse în figura 4:

figura 6
Vom analiza în continuare mascarea cererii de la ta statura. Dac ă semnalul MASK0 este ‚0’, atunci
ie șirea por ții AND din pozi ția U1 este ‚0’ indiferent dac ă IRQ_KB este activ sau nu. Astfel cererea
IRQ_KB nu mai poate activa linia INT. Semnalul MASK 0 este generat prin intermediul unui bistabil D.
În figura 6 structura poart ă AND – bistabil D se repet ă pentru toate cele 4 cereri de întrerupere. Cele 4
bistabile formeaz ă un port de port de ie șire. Acest port se nume ște port de masc ă și, evident, este sub
controlul software.
În al treilea scenariu vom considera din nou cererile IRQ i și IRQ j din primul scenariu. Acum
îns ă cererile nu mai sunt active simultan. Mai întâi s e activeaz ă IRQ j. Deoarece IRQ j este singura
cerere activ ă se va intra în ISR j. În timpul execu ției ISR j se activeaz ă și cererea de la tastatur ă, IRQ i.
Deoarece execut ăm o ISR linia INT este mascat ă, a șa c ă cererea IRQ i are prioritate mai mare se va
executa abia dup ă ce se termin ă ISR j. În acest caz cererea de prioritate mai mare a șteapt ă terminarea
unei rutine asociat ă unei cereri de prioritate mai mic ă. Dac ă timpul de execu ție a rutinei de prioritate
mic ă este scurt, aceast ă situa ție poate fi tolerat ă. Exist ă îns ă cazuri rare când nu este a șa.
O solu ție posibil ă în acest caz este ca ar fi s ă reactiv ăm linia INT (cu SEI) în rutina de tratare
ISRj. Astfel rutina de prioritate mic ă va fi întrerupt ă dac ă apare o cerere de prioritate mai mare.
Activarea liniei INT într-o rutin ă de tratare întrerupere face ca o rutina de tratare întrerupere să poate fi
la rândul ei întrerupt ă.
Din p ăcate acest mod de lucru poate duce la blocarea sist emului. Dup ă cum s-a amintit anterior,
tratarea unei întreruperi poate fi asimilat ă unui CALL sau JAL generat hardware . Instruc țiunea
JAL – CALL st ă la baza recursivit ății. A șa cum exist ă programe recursive gre șit scrise ce conduc la
blocarea sistemului, tot a șa vor exista anumite secven țe de activare a cererilor de întrerupere ce vor duc e
la blocarea sistemului. S ă presupunem urm ătoarea secven ță de evenimente (recursivitate indirect ă):
1. Semnalul IRQ i se activeaz ă;
2. Se trece la executarea instruc țiunilor din rutina ISR i. În ISRi se folose ște SEI. U2
U3
U4
MASK0
D QU6
FD CS_MSK
IRQ_Timer D QU7
FD
D QU8
FD MASK3 MASK2 MASK1 D1 D2 D3 T
TTT
AB
Y0 Y1 Y2 Y3 T
TTT
Priority
Encoder
WR# AddrBus[15..0]
INT D2 DataBus[7..0]
D4 D3 D[7..0]
RD# D5 A[15..0]
PROCESOR D6 D0 D1 D7
INTA#
'0' '0' '0' '0' '0' '0'
INT
IRQ_ADC IRQ_UART IRQ_KB U1
D QU5
FD D0

15 3. Înainte de terminarea lui ISR i se activeaz ă IRQ j
4. ISRi este întrerupt ă și se trece la executarea rutinei ISR j. Și în ISRj se folose ște SEI.
5. Înainte de terminarea lui ISR j se activeaz ă din nou IRQ i și se trece la pasul 2. Din acest moment
ciclu 2. – 5. se poate repeta la nesfâr șit.
Repetarea la infinit a secven ței IRQ i, ISR i, IRQ j, ISRj, IRQ i, ISR i, IRQ j, ISRj,… poate duce la blocarea
sistemului. Un alt exemplu de blocare îl constituie secven ța IRQ i, ISRi, IRQ i, ISRi etc (recursivitate
direct ă).
Din p ăcate un codificator de prioritate ca cel din figura 4 sau figura 6 nu poate face distinc ția
între cererile de prioritate mai mare și cele de prioritate mai mic ă decât cea a cererii ce este în curs de
tratare . Folosirea instruc țiunii SEI într-o rutin ă de tratare face ca protec ția împotriva recursivit ății
hardware, asigurat ă prin intermediul bistabilului IF, s ă devin ă inefectiv ă. În acest caz protec ția
împotriva recursivit ății trebuie asigurat ă fie de blocul de întreruperi din exteriorul proces orului, fie în
software. În continuare se va discuta varianta soft ware, deoarece la ATmega nu exist ă protec ție
hardware.
Posibilitatea de a masca fiecare cerere de întreru pere permite întreruperea rutinelor de
întrerupere f ără să se ajung ă la blocarea sistemului. Dac ă dorim ca ISR i să fie întrerupt ă de IRQ j, în
ISR i salv ăm starea tuturor m ăș tilor, reset ăm toate m ăș tile, set ăm numai masca corespunz ătoare lui IRQ j
și în final scriem SEI. Astfel numai IRQ j poate s ă întrerup ă pe ISR i. Dac ă vrem ca mai multe ISR-uri s ă
fie întrerupte de diferite IRQ-uri se va face un gr af cu tranzi țiile între ISR-uri ca urmare a activ ării IRQ-
urilor. Pentru ca sistemul s ă nu se blocheze trebuie ca acest graf s ă nu con țin ă bucle .
De și numai în varianta soft mascarea IRQ-urilor este v ital ă pentru a permite întreruperea
rutinelor de întrerupere f ără blocare, aceast ă mascarea este prezent ă în toate sistemele de întreruperi, fie
ele cu protec ție soft sau hard.

6. Sistemul de întreruperi la ATmega16
Starea cererilor de întrerupere se poate citi în so ftware; acestea sunt grupate în mai multe
registre I/O. Indicatorii de stare TOV, OCF, etc. i ntroduse în prelegerea precedent ă au și rolul de cereri
de întrerupere. Starea acestor cereri se poate citi prin intermediul registrul TIFR:

În prelegerea precedent ă și în lucrarea de laborator 9 indicatorilor TOV0 și OCF0 au fost șter și prin
scrierea unui ‚1’. În cazul în care o cerere din TI FR provoac ă intrarea în rutina de tratare asociat ă,
indicatorul sau din TIFR este șters automat de hardware. Ștergerea automat ă la intrarea în rutina de
întrerupere corespunz ătoare se face pentru toate cererile de la timere. Mai multe informa ții despre toate
ace ști indicatori se g ăsesc în datele de catalog.
Așa cum s-a spus în capitolul anterior, Mascarea cererilor de întrerupere , fiecare cerere IRQ
poate fi mascat ă. Registrul de m ăș ti pentru cererile de întrerupere de la timere sunt grupate în registrul
TIMSK:

16
Cererile de întrerupere din TIFR sunt generate de t imere iar acestea se g ăsesc în interiorul
microcontrolerului, la fel ca și sistemul de întreruperi. Exist ă îns ă o categorie de cereri de întrerupere
care au originea în afara microcontrolerului. În ac east ă categorie intr ă 3 cereri externe de întrerupere și
anume INT0, INT1 și INT2. Fiecare dintre aceste cereri trebuie conect at ă la pinul cu acela și nume.
Ace ști pini sunt marca ți cu ro șu în figura urm ătoare:

Cererile de întrerupere externe provoac ă activarea lui INT când devine activ ă (‚0’ logic) s ău în
momentul în care î și schimba valoare. Î și schimb ă valoare înseamn ă apari ția unui front ridic ător, a unui
front coborâtor sau a oric ărui front. Modul în care cererile externe INT0 și INT1 provoac ă întrerupere
este specificat prin intermediul bi ților ISC din registrul I/O MCUCR (MCU Control regis ter):

INT0 este configurat de bi ții ISC01 și ISC00 conform urm ătorului tabel:

Bi ții ISC11 și ISC10 configureaz ă pe INT1 în acela și stil în care ISC01 și ISC00 configureaz ă pe INT0.
Din acest motiv tabelul pentru INT1 nu mai este pre zentat.
În ceea ce prive ște pe INT2, modul s ău de configurare difer ă de modul de configurare a lui INT0

17 și INT1. INT2 este configurat de un singur bit din M CUCSR.

Acest bit este bitul ISC2: dac ă acest bit este ‚1’ întreruperea este activat ă de frontul ridic ător a lui INT2
iar dac ă este ‚0’, de frontul coborâtor.
Modific ările pinului INTi (i=0,1,2) conform program ării prin intermediul bi ților ISC seteaz ă
indicatorul cererii de întrerupere INTFi. Bi ții INTFi sunt cererile de întrerupere. Bi ții INTFi se pot citi
prin intermediul registrului GIFR:

De exemplu, dac ă INT0 a fost configurat ă s ă fie activ ă pe front ridic ător (ISC01=’1’ și ISC00=’1’)
atunci apari ția unui front ridic ător al semnalului aplicat pe pinul INT0 seteaz ă bitul INTF0 din GIFR.
Orice bit INTFi poate fi șters în software dac ă este scris cu ‚1’, în acela și mod ca indicatorii timerelor.
Fiecare cere de întrerupere extern ă INTFi poate fi mascat ă individual. Cele 3 m ăș ti se pot
configura prin intermediul registrului GICR:

Numele m ăș ti din GICR este acela și cu numele semnalului extern de întrerupere (aceas ta fiind o idee
proast ă, deoarece se poate crea confuzie). Dac ă bitul INTi (i=0,1,2) din GICR este ‚1’ cererea INT Fi
este activ ă și poate genera întrerupere. Dac ă INTi este ‚0’ cererea este mascat ă. Cererea INTFi este
automat ștears ă în momentul intr ării în rutina de tratare asociat ă.
Ultimul element al sistemului de întreruperi este f lagul IF din subcapitolul Întreruperi
mascabile și nemascabile . La ATmega16 acest flag se nume ște I și se afl ă în registrul SREG pe pozi ția
7:

7. Aplica ție: Ceas prin întreruperi
În continuare vom relua aplica ția din prelegerea 5, capitolul 3.4, „Ceas digital c u timerul 0”.
Limitarea principal ă a metodei se datoreaz ă faptului c ă implementarea este de tip polling și const ă în
restric ția asupra timpului de execu ție a buclei principale. Aceasta restric ție a fost discutat ă în prelegerea

18 5 și are forma T max_while(1) < Tcycle . Implementarea prin întreruperi elimin ă aceast ă restric ție și timpul de
execu ție al buclei principale poate s ă devin ă oricât de mare. În continuare în partea stâng ă este
prezentat ă implementarea prin polling preluat ă din prelegerea 5 iar în partea dreapt ă este prezentat ă
implementarea prin întreruperi:

int main(){
unsigned char cycles=0;
unsigned char one_sec=0, sec=0;

// ┌──┬ CTC mode
TCCR0=0b01 00 0101 ;
// ││ └┴┴─ P=1024
// └┴─── Normal port operation

OCR0=250-1; // N=250

while (1){
//…
if (TIFR & 1<<OCF0){
TIFR |= 1<<OCF0; //clear OCF0

cycles++;
if (cycles == 18){ k=18
// a trecut 1/2 de secund ă
cycles=0;
// aprinde sau stinge ‚:’
one_sec++;

if (one_sec==2){
one_sec=0;
// a trecut o secund ă
// actualizeaz ă sec…
// folose ște timpul
}
}
}
//…
}//end while
}//end main unsigned char one_sec=0, sec=0;

int main(){
unsigned char cycles=0;
unsigned char one_sec=0, sec=0;

// ┌──┬ CTC mode
TCCR0=0b01 00 0101 ;
// ││ └┴┴─ P=1024
// └┴──── Normal port operation
OCR0=250-1; // N=250

// demascheaz ă cererea de întrerupere
// OCF0 de la timerului 0
TIMSK|=1<<OCIE0;

// seteaz ă IF în SREG
sei(); //echivalent cu setbit(SREG,7);

while (1){
//…
if (TIFR & 1<<OCF0){
TIFR |= 1<<OCF0; //clear OCF0
cycles++;

}
}//end main

ISR(TIMER0_COMP_vect){
static unsigned char cycles=0;

cycles++;
if(cycles == 18){
// a trecut 1/2 de secund ă
cycles = 0;
// aprinde sau stinge ‚:’
one_sec++;

if(one_sec==2){
one_sec=0;
// a trecut o secund ă
// actualizeaz ă sec…
// folose ște timpul
}
}
}//end ISR

Implementarea prin întreruperi se ob ține prin modificarea implement ării polling:
1. Programarea timerului 0 nu se modific ă. Timerul 0 seteaz ă OCF0 la fiecare ciclu. OCF0 este
cererea de întrerupere (irq).
2. Se demascheaz ă cererea de întrerupere prin setarea bitului OCIE0 din TIMSK cu:
TIMSK|=1<<OCIE0;
3. Se demascheaz ă întreruperea procesor prin setarea bitului I din S REG cu sei() ;
4. Setarea lui OCF0 nu se mai testeaz ă în bucla principal ă. Secven ța

19 if (TIFR & 1<<OCF0){
TIFR |= 1<<OCF0;
dispare din main. De instruc țiunea TIFR |= 1<<OCF0; nu mai este nevoie deoarece OCF0
este șters automat de hardware la intrarea în rutina de î ntrerupere.
5. Întreaga secven ța de instruc țiuni pentru gestiunea timpului se mut ă în ISR.
6. Variabila cycles se mut ă din main în ISR. Nici o alt ă func ție nu are nevoie de cycles a șa c ă
aceast ă variabil ă poate fi local ă.
7. Variabilele one_sec și sec necesare gestiunii timpului se mut ă în afar ă oric ărei func ții.
Astfel aceste variabile devin globale. Fiind global e, timpul se actualizeaz ă în ISR și poate fi
folosit și în main.
În final vom discuta acurate țea implement ării prin întreruperi. Conform rela ției 6 din prelegerea 5
acurate țea implement ării ceasului prin polling este
Acc poll =Tcycle + Δmax = Tcycle + Tmax_while(1) + Δmin
Dac ă îns ă setarea lui OCF0 provoac ă întrerupere în loc s ă fie sesizat ă prin polling termenul T max_while(1)
din rela ția de mai sus va fi înlocuit cu T max_int_OCF0 . Timpul T max_int_OCF0 este scurs între momentul set ării
lui OCF0 și momentul intr ării în rutina de întrerupere.
Acest timp depinde mult de implementare. Dac ă în implementare nu exist ă nici o zona critic ă iar
rutina de întrerupere pentru OCF0 este singura ruti n ă de întrerupere, atunci T max_int_OCF0 este practic
timpul necesar termin ării instruc țiunii curente plus timpul execu ției speciale a instruc țiunii jal. Practic
acest timp este de minim 4 pulsuri de ceas procesor (600ns pentru fCLK_CPU =8MHz). Îns ă dac ă avem
zone critice și mai multe rutine de întrerupere atunci T max_int_OCF0 este diferit de la caz la caz dar în cazul
unei proiect ări corecte acest timp ar trebui s ă fie mult mai mic decât T max_while(1) .

8. Afi șaj multiplexat
La începutul acestei prelegeri s-a ar ătat că un timp de r ăspuns chiar de o zecime de secund ă este
perfect acceptabil ă în cazul cuptorului cu microunde sau a ma șinii de sp ălat, dar exist ă situa ții în care un
asemenea timp este intolerabil . Este cazul evenimentelor urgente. O astfel de apl ica ție este afi șajul
multiplexat ce va fi prezentat în continuare.
Vom considera afi șarea cu afi șoare 7 segmente de tip LED. În laboratorul 4 s-a f olosit un
afi șor cu 7 segmente pentru a afi șa cifre. Desigur, aplica ția este interesant ă, dar numai din punct de
vedere didactic. În aplica ții reale un singur afi șor este rareori suficient. În continuare vom consid era un
afi șaj compus din 8 afi șoare cu 7 segmente LED .
Prima variant ă de implementare la care ne gândim este bazat ă pe experien ța anterioar ă: dac ă
pentru a aprinde un afi șor a fost nevoie de un port, pentru 8 afi șoare va fi nevoie de 8 porturi. Metoda
„un afi șor-un port” este util ă pentru cel mult 2 afi șoare. În cazul a opt afi șoare exist ă o metod ă mai
eficient ă, și anume varianta numit ă „afi șaj multiplexat” . Aceast ă variant ă ce necesit ă numai dou ă
porturi.
Afi șoarele construite pentru func ționare multiplexat ă au toate segmentele cu acela și nume, de la
toate afi șoarele, conectate împreun ă. În figura 7 este prezentat modul de conectare a p atru afi șoare.

20 figura 7

Conectarea segmentelor este f ăcut ă pe cablaj dac ă dispunem de afi șoare individuale sau în interiorul
modulului în cazul modulelor special proiectate pen tru afi șare multiplexat ă. Modul de conectare din
figura 7 este folosit și pentru afi șoarele matriceale. În figura 8 este prezentat un af i șor matriceal.
figura 8
În figura 9 este prezentat ă schema electric ă a afi șajului multiplexat:
CA1
d gCA4
ab e DP fc fc d eb a DP g
U1
ELF-512GWA
a11
b7
c4
d2
e1
f10
g5
dp 3CA1 12
CA2 9
CA3 8
CA4 6e DP dacCA2
f b g d gCA3
a eb DP fc
abcedgfdp
L3
L4
L5
L6
L7
L8 CA1 CA2 CA3 CA4 CA5
L1
L2

21
figura 9
Pentru gestionarea multiplexat ă a display-ului cu afi șoare 7 segmente se folosesc urm ătoarele elemente:
CHEI DE TENSIUNE K0-K7. Alimentarea oric ărui afi șor se face prin intermediul unei chei de
tensiune. Cheia de tensiune este un comutator elect ronic comandat. Când comanda este ‚0’ logic,
comutatorul este închis și afi șorul corespunz ător este alimentat. Dac ă comanda este ‚1’ logic,
comutatorul este deschis și afi șorul corespunz ător nu este alimentat și nu va afi șă nimic.
Aten ție : anozii comuni CA i nu pot fi comanda ți direct de microcontroler datorit ă curentului mare
necesar. Dac ă toate segmentele trebuie aprinse (ca în cazul cifr ei 8) și curentul pentru un segment este
20 mA, atunci curentul total este 7*20mA=140mA. Nic i un circuit logic nu poate furniza acest curent!
Selec ția afi șorului prin intermediul portului B . Portul B este configurat ca port de ie șire și comand ă
cele 8 comutatoare K0..K7. Bitul 0 din acest port c ontroleaz ă comutatorul afi șorului 0 (cel mai din
dreapta), bitul 1 comutatorul afi șorului ul 1, etc. În general bitul i, i=0..7, controleaz ă comutatorul
afi șorul i. Afi șorul 7 segmente a c ărui selec ție este ‚1’ va fi complet stins, indiferent de info rma ția
înscris ă în portul ce controleaz ă aprinderea segmentelor.
Controlul aprins/stins al segmentelor prin intermed iul portului A . Portul A este configurat ca port
de ie șire. Acest port de ie șire controleaz ă aprinderea segmentelor. În acest port informa ția ce se va
înscrie a fost dedus ă în laboratorul 4 și este reluat ă în continuare este: K0
VCC
VCC
VCC
VCC
VCC
VCC
VCC
VCC
IC1
ATMega16-DIP40 PB0/(XCK/T0) 1
PB1/(T1) 2
PB2/(INT2/AIN0) 3
PB3/(OC0/AIN1) 4
PB4/(SS) 5
PB5/(MOSI) 6
PB6/(MISO) 7
PB7/(SCK) 8
RESET 9
XTAL2 12
XTAL1 13 PD0/(RXD) 14
PD1/(TXD) 15
PD2/(INT0) 16
PD3/(INT1) 17
PD4/(OC1B) 18
PD5/(OC1A) 19
PD6/(ICP) 20
PD7/(OC2) 21
VCC 10
GND 11 GND 31 PA7/(ADC7) 33 PA6/(ADC6) 34 PA5/(ADC5) 35 PA4/(ADC4) 36 PA2/(ADC2) 38
PA3/(ADC3) 37 PA1/(ADC1) 39 PA0/(ADC0) 40
PC0/(SCL) 22 PC1/(SDA) 23 PC2/(TCK) 24 PC3/(TMS) 25 PC4/(TDO) 26 PC5/(TDI) 27 PC6/(TOSC1) 28 PC7/(TOSC2) 29
AVCC 30 AREF 32
VCC VCC R2 1K VCC START
STOP K1 K2 K3 K4 K5 K6 K7
BC327 VCC
330
Ki U1
A
B
C
D
E
F
G
DP CA0
CA1
CA2
CA3
CA4
CA5
CA6
CA7
8 x 330

22 tabelul 2
CIFRA
AFISATA g f e d c b a HEXA
0 1 0 0 0 0 0 0 40
1 1 1 1 1 0 0 1 79
2 1 1 0 0 1 0 0 64
3 0 1 1 0 0 0 0 30
4 0 0 1 1 0 1 1 1B
5 0 0 1 0 0 1 0 12
6 0 0 0 0 0 1 1 03
7 1 1 1 1 0 0 0 78
8 0 0 0 0 0 0 0 00
9 0 0 1 0 0 0 0 10
Ideea este urm ătoarea: trimitem în portul de segmente informa ția ce vrem s ă fie afi șat ă de
afi șorul 0. Aceast ă informa ția va fi afi șat ă numai de afi șoarele alimentate. Aliment ăm numai afi șorul 0
trimi țând în portul de selec ție combina ția 0b1111 1110. Apoi trimitem informa ția pentru al doilea afi șor
și îl aliment ăm numai pe acesta trimi țând în portul de selec ție combina ția 0b1111 1101, ș.a.m.d. Dup ă
ce aprindem ultimul afi șor, procesul se reia. Acest proces se nume ște baleiere.
Dac ă baleierea afi șoarelor se face repede ochiul nu mai percepe c ă afi șoarele se aprind pe rând.
Astfel se creeaz ă senza ția c ă toate afi șoarele sunt aprinse simultan.
Pentru ca afi șarea multiplexat ă s ă func ționeze corect este necesar s ă se îndeplineasc ă simultan
urm ătoarele 3 condi ții:
1. Baleierea afi șoarelor s ă nu se opreasc ă niciodat ă. În caz contrar se va vedea un singur afi șor
aprins.
2. Baleierea afi șoarelor s ă se fac ă repede. Dac ă nu se face repede, va apare senza ția de pâlpâire.
Pentru ca display-ul s ă nu pâlpâie este necesar ă scanarea acestuia de cel pu țin 50 de ori pe
secund ă. Dac ă afi șajul este alc ătuit din 8 afi șoare, un afi șor va trebui s ă stea aprins cel mult
1/50/8 secunde = 2,5 ms.
3. Afi șoarele s ă stea aprinse intervale de timp egale. Dac ă nu se respect ă aceast ă condi ție,
afi șoarele care stau aprinse mai mult, vor p ărea mai luminoase decât celelalte .
Pân ă în prezent detectarea și tratarea evenimentelor externe s-a f ăcut în polling in bucla principal ă
while(1) . Timpul de r ăspuns al sistemului la apari ția unui eveniment este dat de timpul de execu ție
al buclei, timp care poate ajunge și la zecimi de secund ă. Dac ă schimbarea afi șorului activ s-ar face în
bucla principal ă, nu s-ar respect ă cerin ța 2 – „Scanarea s ă se fac ă repede ”.
Așa cum s-a ar ătat în capitolul 1 din prelegerea 5, timpul de exec u ție a buclei principale variaz ă de
la execu ție la alt ă în func ție de modul în care se execut ă instruc țiunile if, else, switch, etc. Din acest
motiv nu se respect ă cerin ța 3 – „Afi șoarele s ă stea aprinse intervale de timp egale ”.
În cazul afi șajului multiplexat este nevoie de un semnal care s ă apar ă în mod repetat la 2,5ms sau
mai pu țin. Acest eveniment se poate genera prin programare a unuia dintre timere astfel ca acesta s ă
cicleze la 2,5 ms. Ciclarea timerului este înso țit ă de setarea unuia dintre flaguri, TOV sau OCF.
Respectarea cerin țelor 2 și 3 se poate face numai dac ă gestiunea afi șă rii se face de o
subrutin ă apelat ă la intervale de timp egale prin mecanismul de într eruperi.
Ultimul aspect care trebuie discutate prive ște durata minim ă a lui ciclului num ărătorului. Cum la
fiecare ciclu de num ărare se va genera o întrerupere, nu vrem s ă fim întrerup ți prea des pentru a nu irosi
for ță de calcul; intrarea și ie șire din rutina de întrerupere consuma for ță de calcul. Astfel o întrerupere

23 la 1 ms (adic ă de 1000 de ori pe secund ă) ar fi valoarea minim ă a ciclului.

8. Aplica ție: ceas cu afi șaj 7 segmente LED
Așa cum s-a precizat anterior, afi șajul multiplexat are nevoie de un semnal care s ă apar ă în mod
repetat la 2,5ms sau mai pu țin. Acest semnal se va genera prin programarea unui a dintre timere astfel ca
acesta s ă cicleze la cel mult 2,5 ms și la cel pu țin 1 ms. Pentru acest timer 1ms <T cycle ≤ 2,5 ms.
Frecven ță ceasului microcontrolerului în acest exemplu este fCLK_CPU = 7 MHz deoarece
descompunerea sa în factori primi pune probleme în alegerea lui p și a lui N. În continuare vom aplic ăm
rela ția 2 din prelegerea 5 pentru T cycle =2.5 ms și fCLK_CPU = 7 MHz:
Tcycle = p * N * T CLK_CPU
p*N=Tcycle / TCLK_CPU = p*N=T cycle * fCLK_CPU =2.5ms*7MHz= 2.5 * 10 -3 s* 7 * 10 6 Hz =
=17,5* 10 3 =17500=175*100 = 25* 7*100=22*5 4*7
Din descompunerea p*N de mai sus rezult ă o singur ă valoare posibil ă pentru p, și anume 22. Deoarece
valorile lui p pentru timere sunt 1, 8, 32, 64, 128, 256 și 1024 și 4 nu este printre ele, rezult ă c ă nu este
posibil ă ob ținerea unui T cycle = 2,5 ms decât cu timerul 1. Timerul 1 este prea va loros pentru a fi folosit
la o sarcina care ar putea fi îndeplinit ă și de alt timer dac ă modific ăm pu țin T cycle .
Să nu uit ăm îns ă c ă cerin ță pentru T cycle este ca acesta s ă fie mai mic sau egal, nu obligatoriu egal
cu 2,5ms. Un p*N pu țin mai mic ca 17500 se poate descompune astfel încâ t p-ul s ă fie una din valorile
posibile. Cum problema lui 17500 este c ă nu se divide suficient la 2, o vom înlocui cu 1600 0, valoare ce
se divide la 2 de multe ori:
p*N=16000=24*2 3*5 3=27*5 3=26*2*5 3 ⇒ p=2 6=64 , N=2*5 3=250
Pentru p*N=16000 se ob ține p=64 ∈{1, 8, 32, 64, 128, 256, 1024 } și N=250<255. Cu aceste valori
vom calcula T cycle :
Tcycle = p* N CNT /fCLK_CPU = 64* 250/7.000.000=2.28ms
Aceast ă valoare îndepline ște cerin ța ini țial ă ca 1ms < T cycle ≤ 2,5 ms.
Deoarece valorile p=64 și N=250 sunt admise de toate cele 3 timere putem fo losi orice timer
dorim. În continuare vom folosi timerul 0 programat în mod CTC cu p=64 și OCR0=250-1. Acesta va
cicla la 2.28 ms iar indicatorul de ciclare OCF0 va genera întrerupere. În rutina de întrerupere asoci at ă
vom schimba afi șorul activ.
Programul urm ător demonstreaz ă func ționarea afi șă rii multiplexate. Informa ția care trebuie afi șat ă
const ă în valoarea variabilei to_disp de tip long int . În main cifrele valorii variabilei to_disp sunt extrase
în vectorul buf iar vectorul buf este afi șat în rutina de întrerupere. De exemplu dac ă to_disp = 16502389 ,
atunci valorile scrise în buf vor fi: buf [0]= 9, buf [1]=8, buf [2]=3, buf [3]=2, buf [4]=0, buf [5]= 5, buf [6]= 6,
buf [7]=1. Scrierea lui buf se face numai când valoarea variabila to_disp este actualizat ă.
În continuare se va prezenta programul principal, a dic ă func ția main . În main se face configurarea
porturilor, a timerului 0, a sistemului de întrerup eri, se actualizeaz ă variabila to_disp și se scrie în
buffer informa ția ce se afi șeaz ă:

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

//variabile globale folosite in main si în rutina d e intreruperi:
//informa ția ce se dore ște a fi afi șat ă se memoreaz ă in buf
volatile unsigned char buf[]={0,0,0,0,0,0,0,0};

int main(){
long int to_display;
unsigned char update=0;

DDRA=0xff; //PORTA pentru segmente în mod out
DDRB=0xff; //PORTB pentru selec ție afi șor în mod out

// set ări timer 0 pentru întrerupere la 2.28 ms:
// timer 0 in mod CTC, prescaler 64
// ┌──┬─ mod CTC
TCCR0=0b0 000 1011 ;
// ││ └┴┴─ clk
CPU /64
// └┴───── OC0 disconected
OCR0=250-1;

//demascheaz ă întreruperea OCF de la timerului 0
TIMSK|=1<<OCIE0;

// seteaz ă IF în SREG
sei(); //echivalent cu setbit(SREG,7); Ambele fac IF=1 dar sei este mai scurta ;

while (1){

if (…){
to_display =…new value
update=1;
}

if (update){
update=0;
cli()
buf[0]=to_display%10;
to_display/=10;
buf[1]=to_display%10;
sei();

}
//…
}//end while
}//end main
Înainte de a discuta rutina de întrerupere se va ju stifica de ce buf a fost declarat ca volatile . Pentru
volatile vezi prelegerea 2, capitolul 5. Deoarece v ectorul buf este folosit pentru comunicare între main și
ISR, buf trebuie s ă fie variabil ă global ă. Mai mult, este preferabil ca buf trebuie s ă fie declarat ca
volatile . Exist ă îns ă situa ții când volatile este obligatoriu, nu preferabil. S ă presupune c ă main din
exemplul anterior este scris într-un fi șier iar ISR în alt fi șier. Dup ă cum se observ ă, în main vectorul buf
este doar scris și niciodat ă citit. Cum compilarea se face la nivel de fi șier, compilatorul va elimina toate
scrierile în buf deoarece nu are sens s ă scrii o variabil ă dac ă nu o cite ști ulterior. Compilatorul nu are
cum s ă știe c ă citirile se vor face într-un fi șier care va fi compilat ulterior. Pentru a preveni eliminarea
scrierilor lui buf , îl vom declara ca volatile . Dac ă îns ă și main și ISR ar fi în acela și fi șier, situa ția
descris ă mai sus nu ar ap ărea și volatile nu ar fi necesar. Pentru a nu pierde timpul cu ana liza modului în
care se folose ște o variabil ă global ă este preferabil s ă se foloseasc ă întotdeauna volatile .
În continuare se vor prezenta prelucr ările care trebuiesc efectuate în rutina de întrerup ere.
Informa ția pe care se bazeaz ă toate prelucr ările din rutina de întrerupere este num ărul afi șorului activ,

25 adic ă afi șorul alimentat. În continuare aceast ă informa ție se va memora în variabila i. La fiecare apel al
rutinei de întrerupere variabila i se va incrementa modulo 8. Astfel i va evolua la nesfâr șit de la 0 la 7.
Variabila i are dublu rol:
1. Selecteaz ă ce afi șor va fi alimentat . Selec ția afi șorului se va face de c ătre o variabil ă pe care o vom
numi selafis . Rela ția dintre i și selafis este simpl ă: bitul i din selafis este ‚1’ iar to ți ceilal ți bi ți sunt
‚0’. Rela ția dintre i și selafis pentru toate valorile posibile a lui i este prezentat ă în tabelul urm ător:
tabelul 3
Se observ ă ca selafis se poate ob ține din i prin deplasarea selafis =1<<i . Acest mod este
foarte bun pentru procesoarele care dispun de o ins truc țiune care poate deplasa
con ținutul unui registru cu o valoare specificat ă în alt registru ca de exemplu
LSR Wb, Wns, Wnd la PIC 24. Dac ă exist ă o asemenea instruc țiune în setul de
instruc țiuni atunci selafis =1<<i se poate traduce într-o singura instruc țiune cod ma șin ă.
Îns ă arhitectura AVR nu este prev ăzut ă cu o astfel de instruc țiune, a șa c ă selafis =1<<i
trebuie f ăcut ă din i instruc țiuni de deplasare cu o pozi ție . Deplasarea cu i pozi ții este
tradus ă de compilator la fel ca urm ătoarea bucla for , dar mai pu țin eficient:
for(int j=0, selafis=1; j<i; j++){
selafis<<=1;
}
Pentru a nu depinde de eficien ța cu care traduce compilatorul putem scrie noi for -ul de mai sus
sau am putea folosi un switch cu 8 case –uri:
switch(i){
case 0: selafis=0b00000001; break;
case 1: selafis=0b00000010; break;
case 2: selafis=0b00000100; break;
case 3: selafis=0b00001000; break;
case 4: selafis=0b00010000; break;
case 5: selafis=0b00100000; break;
case 6: selafis=0b01000000; break;
case 7: selafis=0b10000000; break;
}
Varianta cu switch este lung ă iar cea cu for are un timp mare de execu ție. Cea mai bun ă
solu ție în acest caz este s ă calcul ăm pe selafis independent de i. Variabilele i și selafis vor fi
calculate independent și vor evolua împreun ă ca în tabelul 3. Se observ ă c ă noua valoarea a lui
selafis se poate ob ține din valoarea anterioar ă prin deplasarea stânga selafis<<= 1, cu
excep ția cazului în care vechea valoare este selafis=0b10000000 .
În finalul discu ției despre primul rol al variabilei i vom preciza c ă selec ția afi șorului nu se face
cu selafis ci de negatul acesteia. Anterior s-a precizat c ă pentru a aprinde un afi șor bitul de
comand ă din portul B trebuie s ă fie 0, așa c ă ~selafis este valoarea ce trebuie înscris ă în portul
B. Desigur v ă pute ți întreba de ce selafis nu are direct valoarea inversat ă, adic ă de ce în loc de
0b00000001 nu folosim 0b11111110 , evitând opera ția de inversare. R ăspunsul este simplu și
prive ște modul de calcul al valorii urm ătoare al lui selafis . G ăsi ți acest r ăspuns!
2. Al doilea rol al variabilei i este de a selecta elementul vectorului buf ce va fi afi șat; acest element
este buf [i]. În portul de segmente (portul A) se va înscrie c onfigura ția de segmente corespunz ătoare
lui buf [i]. Configura ția segmentelor pentru cifrele 0-9 va fi memorat ă în vectorul seg7 []. În acest
vector se memoreaz ă valorile din tabelul 2.
În tabelul urm ător este prezentat un ciclu complet al sistemul de afi șare multiplexat ă:

i selafis
0 00000001
1 00000010
2 00000100
3 00001000
4 00010000
5 00100000
6 01000000
7 10000000

26 ┌─────→ selafis= 1 1 1 1 1 1 1 0
|
i=0
| _ _ _ _ _ _ _ _
|_||_||_||_||_||_||_|| _|
|_||_||_||_||_||_||_| |_ |

buf[ 0]= 2 ──→ seg7[ 2]= gfedcba
0100100

┌─────→ selafis= 1 1 1 1 1 1 0 1
|
i= 1
| _ _ _ _ _ _ _ _
|_||_||_||_||_||_|| _| |_|
|_||_||_||_||_||_|| _| |_|

buf[ 1]= 3 ──→ seg7[ 3]= gfedcba
0110000

┌─────→ selafis= 1 1 1 1 1 0 1 1
|
i= 2
| _ _ _ _ _ _ _ _
|_||_||_||_||_| |_| |_||_|
|_||_||_||_||_||_ ||_||_|

buf[ 2]= 4 ──→ seg7[ 4]= gfedcba
0011001

┌─────→ selafis= 1 1 1 1 0 1 1 1
|
i= 3
| _ _ _ _ _ _ _ _
|_||_||_||_| |_ ||_||_||_|
|_||_||_||_|| _| |_||_||_|

buf[ 3]= 5 ──→ seg7[ 5]= gfedcba
0010010

┌─────→ selafis= 1 1 1 0 1 1 1 1
|
i= 4
| _ _ _ _ _ _ _ _
|_||_||_| |_ ||_||_||_||_|
|_||_||_| |_| |_||_||_||_|

buf[ 4]= 6 ──→ seg7[ 6]= gfedcba
0000010

┌─────→ selafis= 1 1 0 1 1 1 1 1
|
i= 5
| _ _ _ _ _ _ _ _
|_||_||_ ||_||_||_||_||_|
|_||_||_ ||_||_||_||_||_|

buf[ 5]= 7 ──→ seg7[ 7]= gfedcba
1111000

┌─────→ selafis= 1 0 1 1 1 1 1 1
|
i= 6
| _ _ _ _ _ _ _ _
|_| |_| |_||_||_||_||_||_|
|_| |_| |_||_||_||_||_||_|

buf[ 6]= 8 ──→ seg7[ 8]= gfedcba
0000000

┌─────→ selafis= 0 1 1 1 1 1 1 1
|
i= 7
| _ _ _ _ _ _ _ _
|_| |_||_||_||_||_||_||_|
|_| |_||_||_||_||_||_||_|

buf[ 7]= 9 ──→ seg7[ 9]= gfedcba
0010000
Rutina de întrerupere pentru afi șarea multiplexat ă:

27 /************************************************** ******************************
* ISR pentru OCF0
* Adresa de start a acestei rutine este vectorul de întrerupere pentru OCF0,
* adic ă 0x0026 (vezi tabelul 1)
* OCF0 este resetat hardware la intrarea în ruti na de întrerupere
* ************************************************ *****************************/
ISR(TIMER0_COMP_vect) {
// configura ția segmentelor pentru cifrele 0-9 copiat ă din tabelul 2
static unsigned char seg7[]={0x40,0x79,0x24,0x30,0x19,0x12,2,0×78,0,0x10 };

// pentru a-si p ăstra valoarea între apeluri i și selafis trebuie s ă fie
// statice
// i selecteaz ă ce element din buf se afi șeaz ă. Evolueaz ă 0, 1, 2,…,7, 0, 1..
static unsigned char i=0;

// selafis selecteaz ă ce afi șor se alimenteaz ă și evolueaz ă 00000001,
// 00000010, 00000100,…, 100000000, 00000001, 00 000010,…
static char selafis = 1;

unsigned char val;

// scrie în portul de segmente configura ția de segmente corespunz ătoare valorii
// lui buf[i]
val = buf[i];
PORTA = seg7[val]; //sau PORTA = seg7[buf[i]];

//selecteaz ă afi șor
PORTB = ~selafis;

//incrementeaz ă i și for țeaz ă-l în plaja 0-7
i++;
if (8==i)
i=0; // echivalent cu i &= 7;

//deplaseaz ă selafis și for țeaz-o în plaja 00000001 – 10000000
selafis <<= 1;
if (0 == selafis)
selafis=1;

} //end ISR OCF0

1 Prelegere 7
Microprocesoare, microcontrolere – Conectarea micro controlerelor

Mecanismul de întreruperi introdus în prelegerea an terioar ă permite folosirea eficient ă a
resurselor de calcul: în loc s ă a ștept ăm în bucl ă producerea unui eveniment (polling), evenimentul
însu și provoac ă execu ția secven ței de program care trateaz ă evenimentul. For ța de calcul a
procesorului sau a microcontrolerului se poate dove di îns ă insuficient ă dac ă num ărul de evenimente de
tratat este prea mare sau rutinele de tratare durea z ă mult. Cum în general evenimentele sunt generate
de periferice, un num ăr mare de evenimente înseamn ă un num ăr mare de periferice.
Exist ă dou ă solu ții la aceast ă problem ă. Prima soluție const ă în implementarea func țiilor
standard în hardware, în special pentru comunica ție. Astfel microcontrolerele sunt prev ăzute cu
interfe țe seriale asincrone, I2C, SPI sau CAN. A doua solu ție const ă în alocarea unui microcontroler
pentru un periferic (sau un grup de periferice). În continuare vom prezenta a doua solu ție. În cazul
tastaturii aceast ă solu ție înseamn ă c ă se va aloca un microcontroler numai pentru scanare a tastaturii.
Avantajul este evident: tot hardware-ul este realiz at cu un singur circuit integrat care cost ă un euro.
Dar numai scanarea tastaturii nu este suficient ă: dup ă ce microcontrolerul a detectat o tast ă ap ăsat ă ce
va face cu codul acesteia? Acest cod trebuie transm is c ătre alt microsistem, a șa cum se întâmpl ă în
cazul tastaturii PC-ului. Transmiterea codului tast ei ap ăsate se face în 99.99% din cazuri serial.
În continuare se va prezenta un protocol de transmi tere paralel ă a datelor.

1. Transmitere serial ă a datelor. Protocolul PS/2
Unul dintre cele mai simple protocoale seriale este protocolul PS/2. Protocolul PS/2 este folosit
pentru conectarea tastaturii și a mouse-ului la calculatoare compatibile IBM PC. Numele s ău vine de la
seria de calculatoare IBM Personal System/2, introd us ă în 1987. Protocolul PS/2 pentru tastatur ă și
pentru mouse este identic din punct de vedere elect ric dar semnifica ția datelor transmise este diferit ă.
În cazul protocolului PS/2 comunica ția este serial ă, sincron ă și bidirec țional ă. Num ărul de
conexiuni între tastatur ă sau mouse și PC este doi: Data și Clock . În figura urm ătoare este prezentat
conectorul PS/2 mam ă:

La fel ca la orice protocol serial, data este emis ă bit cu bit. Lungimea datei în cazul protocolului P S/2
este de 8 bi ți, adic ă se transmit și se recep ționeaz ă octe ți. Bi ții datei sunt emi și secven țial pe pinul
Data . În afar ă de bi ții datei, pe pinul Clock se genereaz ă clock-ul cu care datele sunt serializate.
Transmiterea clock-ului de serializare face ca prot ocolul s ă fie sincron .
Din punct de vedere al semnifica ției și ordinei bi ților în fluxul serial protocolul PS/2 este identic
cu protocolul serial asincron studiat în cadrul cursului de comunica ții de date. Pe scurt, datele se

2 transmit în formatul bit de start, 8 bi ți de date, bit de paritate impar ă și bit de stop. Paritatea impar ă
înseamn ă c ă bitul de paritate se va pozi ționa astfel încât num ărul de ‚1’-uri din cei 8 bi ți de date plus
bitul de paritate s ă fie impar.
Protocolul PS/2 este bidirec țional , adic ă datele circul ă în ambele sensuri. În cele ce urmeaz ă
tastatura sau mouse-ul se numesc dispozitiv (device ) iar PC-ul se nume ște gazd ă (host). Transmisia
datelor se poate face atât de la dispozitiv la host cât și invers. Cum transmisia de la dispozitiv la host
este predominant ă în continuare vom trata numai aceast ă situa ție.
În cazul transmisiei de la device la host semnalele DATA și CLOCK sunt generate de device și
citite de host. Conexiunea device – host este preze ntat ă în partea stâng ă a figurii urm ătoare iar în
partea dreapt ă este prezentat timingul transmisiei unui octet:

figura 1
Din figur ă rezult ă esen ța protocolului PS/2:
1. Cât timp nu transmit date, atât DATA cât și CLOCK sunt în starea ‚1’.
2. Emi ță torul genereaz ă bitul ce se transmite pe frontul ridic ător a lui CLOCK, cu excep ția bitului de
start.
3. La mijlocul celulei bit, când datele sunt stabile, emi ță torul genereaz ă frontul coborâtor al lui
CLOCK.
4. Receptorul va citi orice bit – de start, de date, d e paritate sau de stop – atunci când datele sunt
stabile, adic ă pe frontul coborâtor al lui CLOCK.
Durata celulei bit este de 60 – 100 μs. De aici rezult ă ca rata de transmitere a bi ților (bitrate) este 10 –
16 kbit. Aceast ă rata este considerat ă mic ă, dar nici nu este nevoie de mai mult în cazul tast aturii sau al
mouse-ului.

Receptorul PS/2
Mai întâi vom implementa recep ția PS/2. A șa cum s-a men ționat anterior, un bitrate de 10 – 16
kbit este considerat ă mic din punct de vedere al transmisiei datelor. Di n punct de vedere al
implement ării cu un microcontroler aceast ă rata este atât de mare încât o implementare pollin g este
practic imposibil ă: ar trebui ca în 60 μs s ă execut ăm dou ă bucle pentru a detecta frontul coborâtor al
lui CLOCK și apoi ar trebui s ă trat ăm bitul recep ționat. Dac ă singura opera ție pe care microcontrolerul
ar trebui s ă o execute este recep ția PS/2 ar fi timp, dar sistemul este prev ăzut cu tastatură sau mouse
pentru a face și altceva în afar ă de recep ția PS2. Din acest motiv sosirea unui bit pe interf a ța PS/2 este
un eveniment urgent și va fi implementat prin mecanismul de întreruperi.

3 Din analiza timingul transferului din figura 1 a re zultat c ă „Receptorul va citi orice bit – de start,
de date, de paritate sau de stop – atunci când date le sunt stabile, adic ă pe frontul coborâtor al lui
CLOCK ". Altfel spus receptorul trebuie s ă reac ționeze la frontul coborâtor al lui CLOCK și, mai
mult, s ă o fac ă urgent. Din acest motiv CLOCK se cupleaz ă la unul din pinii de cerere de întrerupere
INT0-2. DATA se poate cupla pe orice pin. Conectare a semnalelor DATA și CLOCK generate de
dispozitiv se face conform figurii urm ătoare:

În rutina de întrerupere asociat ă lui INT2 se vor citi bi ți sosi ți serial și se vor asambla în variabila
data . Când data este asamblat ă se va pozi ționa pe 1 variabila data_rdy pentru a semnaliza ca s-a
recep ționat un octet. Dac ă în decursul recep ției s-a detectat vreuna din erorile tipice transmis iei seriale
– eroare de încadrare sau de paritate – se va pozi ționa pe 1 variabila pe (parity error) sau fe (framing
error). Și în cazul unei erori data_rdy se va seta pentru a semnaliza o recep ție cu eroare.
O ultim ă observa ție prive ște opera țiile efectuate în ISR la recep ția unui bit. Din figura 1 rezult ă
ca opera țiile sunt diferite în func ție de ce fel de bit sose ște: de start, de date de paritate sau de stop.
Atunci când aceea și intrare necesit ă prelucr ări diferite la momente de timp diferite cel mai sim plu mod
de implementare este o ma șin ă de stare. Ma șina de stare din ISR va func ționa dup ă cum urmeaz ă:
1. A sosit primul bit. Acesta este bitul de start și valoarea sa trebuie s ă fie ‚0’. Dac ă este ‚0’, se
ini țializeaz ă variabilele folosite pe parcursul unui recep ții și se trece la pasul 2. Dac ă nu este
‚0’, avem o eroare de încadrare și trecem la pasul 5.
2. Asambleaz ă 8 bi ți în variabila data . Primul bit este LSB iar ultimul este MSB. La fiec are bit
recep ționat calculeaz ă parity ^= bit_recep ționat . Dup ă ce s-au recep ționat 8 bi ți treci la pasul 3.
3. A sosit bitul de paritate . Calculeaz ă parity ^= bit_recep ționat . Calculeaz ă eroarea de paritate
cu pe = parity ? 0:1 Treci la pasul 4.
4. A sosit bitul de stop : se face data_rdy =1. Dac ă bitul de stop este ‚1’, data a fost recep ționat ă
corect, și se trece la pasul 1 pentru recep ția urm ătorului octet. Dac ă nu, avem o eroare de
încadrare și vom trece la pasul 5.
5. Avem o eroare de încadrare. Eroarea de încadrare poate ap ărea ca urmarea a unui impuls
parazit al semnalului CLOCK. Acest impuls face ca s ă citim un bit în plus, ceea ce duce la
desincronizarea sofului. Aceast ă desincronizare nu se poate corecta de la sine și de aceea este
nevoie de resincronizare. Resincronizarea înseamn ă g ăsirea unui bit de start. Pentru
resincronizare vom m ăsura intervalul de timp între recep ția a doi bi ții consecutivi. Dac ă cei doi
bi ți apar țin aceluia și octet acest interval este de 60-100us, a șa cum este specificat în standardul
PS2.
Un interval de timp mai mare poate s ă apar ă între ultimul bit al unei transmisii (bitul de sto p) și
primul bit (bitul de start) al urm ătoarei transmisii. Standardul PS2 nu specific ă o durat ă anume
între recep ția ultimul bit al unei transmisii și recep ția primul bit al urm ătoarei transmisii dar

4 acest interval este mult mai mare de 100 us. Standa rdul PS2 este folosit pentru tastatura sau
mouse iar rata cu care aceste dispozitive genereaz ă date este mic ă: 10 taste ap ăsate pe secund ă
sau 300 de triplete de date de la mouse. Rezult ă ca la un moment dat va exista o pauza în
transmisia de date care va fi de aproximativ 3 ms. Dup ă aceasta pauza primul bit care sose ște
este un bit de start.
Tratarea erorii conform ideii anterioare se bazeaz ă pe un timer. Ceasul timerului se va seta la 1
us. Dac ă frecven ță ceasul microcontrolerului este de 8MHz, atunci per ioada acestuia este
125ns. Ceasul microcontrolerului va fi divizat cu p pentru a ob ține ceasul de num ărare:
TCLK_CNT =p*T CLK_CPU . Pentru p=8 ob ținem 8*125ns= 1us.
Vom programa timerul 0 în mod normal cu p=8. Pe fiecare front coborâtor al ceasului PS2, în
rutina de întrerupere, test ăm valoarea timerului și apoi îl resetam pentru bitul urm ător. Aceasta
este metoda cronometru pentru m ăsurarea intervalelor de timp. De asemenea trebuie s ă reset ăm
flagul TOV0 deoarece este posibil ca între dou ă transmisii s ă treac ă secunde sau minute (nu se
apas ă nici o tast ă). Durata maxim ă a unei celule bit este 100 us; dac ă observ ăm o valoare de
dou ă ori mai mare (200us) înseamn ă c ă am localizat un bit de start și putem face
resincronizarea. Pentru 200 us valorarea timerului este 200us/1us=200.
Exist ă și o situa ție când este normal s ă avem un timp mai mare de 200 us între dou ă fronturi
coborâtoare: atunci când a ștept ăm un bit de start, adic ă atunci când suntem în starea START. În
acest caz nu se va genera eroare de încadrare.
În continuare este prezentat ă implementarea algoritmului prezentat anterior:
//receptor PS2
//variabile globale folosite în main și în ISR
volatile unsigned char data=0;
volatile unsigned char data_rdy=0;
volatile unsigned char fe=0; //eroare de încadrare – framing error
volatile unsigned char pe=0; //eroare de paritate
// end variabile globale

int main(){
//portul B în mod în mod in
DDRB=0;

//initializare timer 0 in mod normal cu p=64=> T CNT=8us
TCCR0 = 0b00000011;
TCNT0 = 0;

//ini țializ ări pentru INT2: vezi prelegere 6, pagina 17
//INT2 activ pe front coborâtor
MCUCSR &= ~(1<<ISC2);

// schimbarea frontului poate seta flagul aferen t lui INT2;
// șterge o eventual ă cere activ ă
GIFR |= 1<INTF2; // CLEAR INT2 Flag

//demascheaz ă cererea INT2
GICR |= 1<<INT2;

//seteaz ă IF
sei();

while (1){
if (data_rdy){

5 data_rdy=0;
if (fe==0 && pe==0){
… foloseste data
}
else {
//tratare erori
pe=0; fe=0;

}
}
}//end while
}//end main

#define DATA_PIN 1
#define START 0
#define DATA 1
#define PARITY 2
#define STOP 3
#define ERR 4

ISR(INT2_vect){
//starea ma șinii
static unsigned char status=START;

//masca mask este folosita pentru a num ăra bi ții recep ționa ți si pentru
// a asambla bitii receptionati intr-un octet
static unsigned char mask;

//parity este folosit ă pentru calculul parit ăț ii
static unsigned char parity;

//valoarea bitului receptionat
unsigned char bit_rec;

//cite ște bitul curent
bit_rec = PINB & 1<< DATA_PIN;

//determina timpul scurs între dou ă fronturi coborâtoare succesive
//ale ceasului PS2. Daca acest timp este mai mar e de 200 us genereaza
// eroare de incadrare si forteaza starea START .
if( (TCNT0>200 || TIFR|1<TOV0) && status != START ) {
data_rdy=1;
fe=1;
status=START;
}
TCNT=0; TIFR|=1<<TOV0;

switch (status){
case START:
if (bit_rec){
// bitul de start este 1 => eroare
status = ERR;
}
else {//START OK
fe = pe = data = parity = 0;
mask = 1;
status = DATA;
}
break ;

6
//cite ște 8 bi ți de date și asambleaz ă-i în variabila data.
//calculeaz ă paritatea pe m ăsur ă ce sosesc bi ții
case DATA:
if (bit_rec)
data |= mask;
mask <<= 1;
parity ^= bit_rec;
if (mask == 0)
status=PARITY;
break ;

//calculeaz ă paritatea final ă
case PARITY:
parity ^= bit_rec;
pe = parity? 0:1;
status = STOP;
break ;

//verific ă bitul de stop
case STOP:
if ((bit_rec == 0){
// bitul de stop este 0 => eroare
status = ERR;
}
else {
// bitul de stop este OK
status=START;
}
data_rdy=1;
break ;

case ERR:
break ;
}
}

Emi ță torul PS/2
În continuare vom trata emi ță torul PS/2. În figura urm ătoare este prezentat ă schema emi ță torului:

7
În esen ță schema de mai sus este schema de cuplare a tastatu rii din laboratorul 7 la care s-a ad ăugat
sec țiunea pentru emisia serial ă PS/2. Aceast ă sec țiune este foarte simpl ă și const ă în alocarea a doi
pini, PB0 și PB1, pentru semnalele CLOCK și DATA.
Implementarea software porne ște de la programul de scanare a tastaturii și de generare a codului
tastei din laboratorul 7. În loc îns ă s ă afi șă m pe LCD caracterul asociat tastei ap ăsate vom ad ăuga
codul necesar emisiei sale seriale. Analiza timingu l comunica ției PS/2 f ăcut ă anterior a eviden țiat
opera țiile executate de emi ță tor:
1. Pe frontul ridic ător a lui CLOCK emi ță torul genereaz ă bitul ce se transmite (cu excep ția bitului
de start).
2. Emi ță torul genereaz ă frontul coborâtor al lui CLOCK la mijlocul celulei bit, când datele sunt
stabile,.
În rezumat emi ță torul genereaz ă ambele fronturi ale clock-ului iar pe frontul ridi c ător al acestuia
genereaz ă și bitul curent. Cum durata unui bit este 60-100 us iar pentru un bit sunt necesare dou ă
fronturi rezult ă c ă fronturile trebuie generate la 30 – 50 de μs. Frecven ță mare impune ca generarea s ă
se fac ă în rutina de întrerupere asociat ă unui timer. În cele ce urmeaz ă vom alege ca fronturile s ă se
genereze la interval de 40 μs ceea ce impune T cycle = 40 μs. Dac ă aplic ăm rela ția 2 de la pagina 8 din
prelegerea 5 pentru T cycle = 40 μs și fCLK_CPU =8 MHz rezult ă:
Tcycle =p*N*TCLK_CPU → p*N=T cycle / TCLK_CPU = Tcycle *fCLK_CPU = 40 μs *8MHz=
= 40 * 10 -6 s* 8 * 10 6 Hz = 40*8 ==23*5*2 3=26*5
Din descompunerea p*N de mai sus rezult ă p=64 și N=5. Vom folosi timerul 0 în mod CTC cu aceste
valori.
Emisia este în esen ță mai simpl ă decât recep ția. La recep ție a fost nevoie de o ma șin ă de stare
deoarece bi ții recep ționa ți nu sunt trata ți la fel: bitul de start se verific ă doar dac ă este ‚0’, bitul de stop
se verific ă daca este ‚1’, bi ții de date se asambleaz ă in variabila data etc. La emisie to ți bi ții sufer ă un D
… C1
R3
TASTATURA 5

9
… R1
*
… #
… R0 R0
8
… 4
… 1

C
… 7
… C2 C0
R2 R1
R3 C1 C0
C2 C1
C3 C2
C3
C0 1K
VCC
IC2
ATMega16-DIP40 PB0/(XCK/T0) 1
PB1/(T1) 2
PB2/(INT2/AIN0) 3
PB3/(OC0/AIN1) 4
PB4/(SS) 5
PB5/(MOSI) 6
PB6/(MISO) 7
PB7/(SCK) 8
RESET 9
XTAL2 12
XTAL1 13 PD0/(RXD) 14
PD1/(TXD) 15
PD2/(INT0) 16
PD3/(INT1) 17
PD4/(OC1B) 18
PD5/(OC1A) 19
PD6/(ICP) 20
PD7/(OC2) 21
VCC 10
GND 11 GND 31 PA7/(ADC7) 33 PA6/(ADC6) 34 PA5/(ADC5) 35 PA4/(ADC4) 36 PA2/(ADC2) 38
PA3/(ADC3) 37 PA1/(ADC1) 39 PA0/(ADC0) 40
PC0/(SCL) 22 PC1/(SDA) 23 PC2/(TCK) 24 PC3/(TMS) 25 PC4/(TDO) 26 PC5/(TDI) 27 PC6/(TOSC1) 28 PC7/(TOSC2) 29 AVCC 30 AREF 32
VCC 1K
VCC
R9
1K J1
CON4 1
2
3
4
VCC 1K
J2
CON2 1
2VCC 1K
Y1
8MHz C3
15p
C4
15p CLOCK
DATA 2
… 3

B
… 6
… A

R2
0
… C3

8 acela și tratament: sunt emi și! Din acest motiv bi ții de emis sunt agrega ți într-o variabil ă de tip int
(pentru c ă are 16 bi ți) și apoi sunt serializa ți. În continuare este prezentat programul care face emisia:
//emi ță tor PS2
//variabile globale folosite de ISR:
//data de trimis: în data se strâng to ți bi ții: start, data, paritate, stop
volatile unsigned int data=0;

//pe durata emisiei sending este 1
volatile unsigned char sending=0;

main(){
//PB0 și PB1 sunt ie șiri pentru CLOCK și DATA
DDRB=0b00000011;
PORTB=3; //DATA și CLOCK sunt inactive, adic ă ‚1’

//set ări timer 0, Normal mode, timerul este oprit.
TCCR0 = 0b00001000;
OCR0 = 5-1;

// setarea sistemului de întreruperi
TIFR |= 1<<OCF0;
TIMSK|= 1<<OCIE0;
sei(); //IF=1

while (1){
//codul pentru tastatur ă din laboratorul 7
if (loop_cnt==200){
code_ante=code_now;
code_now = kbscan();
if (code_now!=0x7f && code_ante==0x7f){
kbhit=1;
kbcode=code_now;
}
loop_cnt=0;
}

//dac ă exist ă un cod disponibil și nu exist ă emisie în desf ăș urare:
if (kbhit && sending ==0){
//pune kbcode în data ce se va trimite
data = kbcode ;
data &= 0xff;

//adaug ă bitul de start
data<<=1;

//calculeaz ă paritatea
parity=0;
for (i=0;i<=7;i++){
parity = parity ^(kbcode&1);
kbcode >>=1;
}

//adaug ă bitul de paritate
if (parity==0)
data|=0x200;

//adaug ă bitul de stop. Restul de bi ți din data se pun pe ‚1’
data|=0xfc00;

9 sending = 1;
kbhit = 0;
TCCR0=0b00001011; //porne ște timerul cu p=64. Va apare IRQ timer0
}
loop_cnt++;
} //end while
} //end main

ISR(TIMER0_COMP_vect){
#define CLK 0
#define DAT 1
static unsigned char edge_cnt=1;

// creeaz ă frontul ridic ător al lui CLOCK și trimite bitul curent.
// De și la începutul transmisiei CLOCK este deja ‚1’ vom genera un front
// ridic ător invizibil pentru ca sa nu stricam succesiunea f ront
// ridic ător+data, front coborâtor. Acest front invizibil es te marcat cu
// 1 in figura urm ătoare:

figura 2
if ((edge_cnt & 1)==1){ //fronturile ridic ătoare sunt impare în figura 2.
setbit(PORTB,CLK);
if (data&1)
setbit(PORTB, DAT);
else
clrbit(PORTB, DAT);
data>>=1;
}
else
//creeaz ă frontul coborâtor al lui CLOCK.
//fronturile coborâtoare sunt pare în figura 2.
clrbit(PORTB, CLK);

edge_cnt ++;

// pentru ca CLOCK și DATA s ă r ămân ă în ‚1’, dup ă emisia bitului de stop
// trimitem al doisprezecelea bit. Acest bit are valoarea ‚1’.
// Pentru el gener ăm numai frontul pozitiv. Acest front este numerotat
// cu 23 in figura 2. Astfel num ărul de fronturi care trebuie emise este
// 12*2-1=23.
if (edge_cnt == 24){
sending=0;
edge_cnt = 1;
TCCR0=0b00001000; //stop timer
}
}//end ISR

Similar Posts