218
IOAN BURDA MICROPROCESOARE ŞI MICROCONTROLERE Presa Universitară Clujeană 2002

Microprocesoare Si Microcontrolere

Embed Size (px)

DESCRIPTION

microprocessors course in romanian

Citation preview

Page 1: Microprocesoare Si Microcontrolere

IOAN BURDA

MICROPROCESOARE ŞI

MICROCONTROLERE

Presa Universitară Clujeană 2002

Page 2: Microprocesoare Si Microcontrolere

ii

Page 3: Microprocesoare Si Microcontrolere

Moto: … ” Dacă nu voi vedea în mâinile Lui semnul cuielor, şi dacă nu voi pune degetul meu în semnul cuielor, şi dacă nu voi pune mâna mea în coasta Lui, nu voi crede.”

Ioan 19, 20

Page 4: Microprocesoare Si Microcontrolere

iv

Page 5: Microprocesoare Si Microcontrolere

1. Utilitarul Debug. Familia de Microprocesore 80X86 7

2. Programe Simple în Limbaj de Asamblare 19

3. Circuite Specializate Programabile 37

4. Portul Paralel. Aplicaţii Simple 59

5. Programe Residente în Memorie 87

6. Perioada şi Frecvenţa unui Semnal Extern 105

7. Microcontrolerul 68HC11. PcBug 127

8. Voltmetru Digital cu Microcontrolerul 68HC11 161

9. Microcontrolerul PIC 16F84 179

A. Setul de Instrucţiuni al Familiei de Microprocesoare 80X86 197

B. Setul de Instrucţiuni ale Microcontrolerului 68HC11 211

C. Setul de instrucţiuni ale Microcontrolerului PIC 16F84 217

Page 6: Microprocesoare Si Microcontrolere

vi

Page 7: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

7

1. Utilitarul DEBUG. Familia de Microprocesoare 80X86

Această carte este scrisă în "viu grai" cu scopul de a permite unui "simplu cetăţean" accesul la bazele unui domeniu de mare complexitate şi actualitate. Omul, în evoluţia sa, a fost preocupat de realizarea unor unelte cu ajutorul cărora activitatea de zi cu zi să devină mai eficientă. De la primele pietre oferite de natură sau prelucrate sumar şi până la sistemele cu microprocesor încorporat (embedded system) din zilele noastre este un timp atât de lung, încât istoria nu-l poate cuprinde. Astăzi nu putem să ne imaginăm existenţa fără această complexă unealtă. Dar în acelaşi timp, nu putem să nu ne punem întrebări de forma: "Câţi dintre oamenii care au călătorit cu trenul pot proiecta sau construi o locomotivă ?" sau "Câţi dintre oamenii care zboară cu avionul pot proiecta sau construi un avion ?". Din păcate, lucrul acesta este valabil şi în această situaţie şi chiar mai mult, să nu uităm că de data aceasta avem în faţă cea mai complexă şi abstractă unealtă imaginată de mintea omului.

Atunci când vrei ca oamenii să poată înţelege uşor un material trebuie să simplifici lucrurile, uneori poate prea mult. Temele care vor fi prezentate în această carte au fost selectionate pentru a acoperi o cultură minimă în domeniul embedded system şi în acelaşi timp cu gândul la cel care în final va lucra într-un domeniu experimental al fizicii. Tocmai de aceea, în locul unor tabele aride din care poţi afla multe dar nu înveţi nimic, am preferat "graiul viu" desigur, mai puţin exact, dar specific omului.

Toată informaţia de care avem nevoie pentru realizarea aplicaţiilor din această carte este conţinută în embedded system-ul studiat. Din păcate, nu toţi oamenii au abilitatea să descopere singuri informaţile de care au nevoie şi mult prea mulţi cred că singura metodă este învăţatul pe de rost a tot felul de situaţii particulare. Nimeni nu poate obţine performanţe reale în domeniul embedded system fără un efort individual şi liber asumat. Trebuie să ne punem imaginaţia la lucru, să încercăm, să fim creativi. Fără a exclude calităţile native ale fiecăruia, performanţele obţinute vor depinde în mare măsură de numărul de ore de lucru la calculator. În final, vom atinge nivelul de novice în domeniul embedded system printr-un antrenament prelungit care, pentru unii dintre noi, din păcate va fi epuizant.

Cu ajutorul unor programe utilitare, vom descoperi o mare parte din secretele sistemelor cu microprocesor încorporat şi modul în care pot fi utilizate în domeniile experimentale. Prin această metodă ne vom apropia, pas cu pas, de stadiul de novice în domeniul embedded system.

Page 8: Microprocesoare Si Microcontrolere

Utilitarul DEBUG. Familia de Microprocesoare 80X86

8

DEBUG este un program utilitar al sistemului de operare (MS-DOS, Windows xxxx) dintr-un calculator compatibil IBM PC. Accesul la un calculator compatibil IBM PC prin care să "hoinărim" la fel ca într-un oraş, asigură caracterul interactiv al metodei propuse.

De la prompterul MS-DOS (START > PROGRAMS > MS-DOS Prompt), C:\WINDOWS>

lansăm în execuţie utilitarul DEBUG. C:\WINDOWS>debug

Dacă prin comanda anterioară obţinem prompterul “-“, atunci utilitarul DEBUG a fost lansat în execuţie de către sistemul de operare. Prin comanda ? (help), listăm comenzile utilitarului DEBUG. -? assemble A [address] compare C range address dump D [range] enter E address [list] fill F range list go G [=address] [addresses] hex H value1 value2 input I port load L [address] [drive] [firstsector] [number] move M range address name N [pathname] [arglist] output O port byte proceed P [=address] [number] quit Q register R [register] search S range list trace T [=address] [value] unassemble U [range] write W [address] [drive] [firstsector] [number] allocate expanded memory XA [#pages] deallocate expanded memory XD [handle] map expanded memory pages XM [Lpage] [Ppage] [handle] display expanded memory status XS -

Nu ne grăbim să le memorăm; acum ştim cum le putem afla. Cred că cea mai utilă comandă în acest moment este q (quit, abandonăm programul utilitar DEBUG). Aşa că tastăm comanda -q

Page 9: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

9

şi ne reîntoarcem la prompterul MS-DOS. C:\WINDOWS>

Pentru ca aventura să se încheie în Windows, vom tasta în continuare următoarea comandă. C:\WINDOWS>exit

Cu ajutorul editorului NOTEPAD (START > PROGRAMS > ACCESSORIES > NOTEPAD), putem realiza un fişier text, pe care vom face în continuare câteva experienţe. Acest fişier fără a conţine tasta "Enter" va avea următorul conţinut: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz|~

Fişierul va fi salvat cu numele ASCII.TXT în folderul (directorul) Mm (creat de noi, New - Folder) de pe unitatea C:.

Lansăm în execuţie utilitarul DEBUG. De la prompterul MS-DOS tastăm comanda C:\WINDOWS>cd..

(Change Directory), numai dacă nu suntem în directorul rădăcină (acest lucru depinde de configurarea sistemului de operare), de unde trecem în directorul Mm prin următoarea comandă: C:\>cd mm

Obţinem un prompter MS-DOS de forma C:\Mm>

de unde vom lansa în execuţie utilitarul DEBUG. Introducem în continuare următoarele comenzi -nascii.txt -l

care vor determina încărcarea fişierului cu numele ASCII.TXT undeva în memoria internă a calculatorului. Dacă tastăm comanda -d

Page 10: Microprocesoare Si Microcontrolere

Utilitarul DEBUG. Familia de Microprocesoare 80X86

10

putem vedea unde a fost încărcat fişierul în memoria calculatorului şi mai ales sub ce formă. Efectul comenzii anterioare este afişarea conţinutului unei zone de memorie. 1371:0100 21 22 23 24 25 26 27 28-29 2A 2B 2C 2D 2E 2F 30 !"#$%&'()*+,-./0 1371:0110 31 32 33 34 35 36 37 38-39 3A 3B 3C 3D 3E 3F 40 123456789:;<=>?@ 1371:0120 41 42 43 44 45 46 47 48-49 4A 4B 4C 4D 4E 4F 50 ABCDEFGHIJKLMNOP 1371:0130 51 52 53 54 55 56 57 58-59 5A 5B 5C 5D 5E 5F 60 QRSTUVWXYZ[\]^_` 1371:0140 61 62 63 64 65 66 67 68-69 6A 6B 6C 6D 6E 6F 70 abcdefghijklmnop 1371:0150 71 72 73 74 75 76 77 78-79 7A 7B 7C 7D 7E 0E A7 qrstuvwxyz|~.. 1371:0160 D8 02 3A 06 94 D2 75 C9-4E 32 C0 86 04 46 3C 0D ..:...u.N2...F<. 1371:0170 75 02 88 04 89 36 6B D7-89 0E 69 D7 C3 BE 48 DB u....6k...i...H. -

Observăm că zona de memorie afişată pe ecran conţine în totalitate fişierul ASCII.TXT. Pentru realizarea experimentelor din primele şase capitole ale acestei cărţi, cea mai frecventă acţiune este lansarea în execuţie a utilitarului DEBUG.

Figura 1.1. Mediu de lucru tipic pentru primele şase capitole ale cărţii.

Page 11: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

11

După cum se poate vedea în figura 1.1, de regulă lansarea în execuţie este precedată de fixarea directorului utilizat (directorul C:\Mm>), prin intermediul unor comenzi specifice sistemului de operare MS-DOS.

Să nu intrăm în panică, acesta este doar începutul. Mai tîrziu, vom râde de inocenţa noastră de acum. Nu putem înţelege totul de la început, unele lucruri le vom înţelege mai târziu (altele niciodată). Să ne îndreptăm atenţia spre grupul de cifre 1371:0100 (pe un alt calculator este foarte probabil să fie afişat altceva în loc de 1371), probabil suntem într-un oraş, pe strada 1371 în dreptul casei cu numărul 0100 (atenţie, totul este în cod hexazecimal, 00, 01,…,09, 0A, …, 0F, 10, 11,…, 1F, 20, 21,…, FF, 100, 101,…, FFF, 1000, 1001,…, 1FFF , 2000, 2001, …, FFFF). Este uşor de observat că numărul maxim al unei case pe o stradă este FFFFh (h, de la hexazecimal, dacă facem conversia în zecimal în total pot fi 65536 de case pe o stradă).

Conţinutul casei cu numărul 100h de pe strada cu numărul 1371h este numărul 21h, care după cum se poate vedea în zona din partea dreaptă a ecranului, este codul caracterului “!”. Numere despre numere, care ne spun unde se află alte numere, am ajuns într-un oraş de numere.

Vom spune că 21h este codul ASCII (American Standard Code for Information Interchange) al caracterului “!”. De exemplu, codul ASCII al caracterului “A”, este 41h, iar al caracterului “a” este 61h. Dacă privim cu atenţie, putem descoperi şi o regulă: diferenţa între literele mari şi cele mici este 20h. Aşa că, dacă ne mai amintim alfabetul pe care l-am învaţat în primul an de şcoală, nu mai trebuie să reţinem decât numărul 41h. Caracterele asociate numerelor (0, 1, 2, …, 9) sunt codate începând cu “0”, care are codul 30h. Caracterele care au codul mai mic de 20h (20h este codul pentru “SPACE”) sunt caractere de control. Acestea sunt de regulă, netipăribile (le vom relua mai târziu), aşa că ele sunt automat înlocuite cu “.” de către utilitarul DEBUG. Forma caracterelor care au codul mai mare de 7Fh depinde în mare măsură de o aplicaţie concretă. Înainte de a merge mai departe, să comprimăm observaţiile anterioare, printr-o exprimare adecvată. Caracterul “!” are codul ASCII 21h şi în exemplul nostru este înscris în locaţia de memorie cu adresa offset 100h aflată în segmentul de memorie cu adresa 1371h. După cum se poate vedea, cineva (sistemul de operare) a alocat pentru fişierul nostru segmentul de memorie care începe la adresa 1371h. Zona de memorie care nu a fost afectată de încărcarea fişierului nostru şi-a păstrat nealterat vechiul conţinut. În această zonă vom observa cu siguranţă unele caractere netipăribile care au fost înlocuite prin caracterul “.”. Nu vom merge mai departe până nu vom arunca o privire în zona de copyright a memoriei ROM BIOS (Basic Input Output System),

Page 12: Microprocesoare Si Microcontrolere

Utilitarul DEBUG. Familia de Microprocesoare 80X86

12

unde sunt stocate subprograme. Acestea asigură serviciile de bază legate de funcţionarea întregului sistem, adică utilităţile de la marginea oraşului de numere. Prin tastarea următoarelor comenzi (vom găsi indicatorul de la intrarea ipoteticului oraş) -d f000:e000 F000:E000 00 77 61 72 64 20 53 6F-66 74 77 61 72 65 49 42 .ward SoftwareIB F000:E010 4D 20 43 4F 4D 50 41 54-49 42 4C 45 20 34 38 36 M COMPATIBLE 486 F000:E020 20 42 49 4F 53 20 43 4F-50 59 52 49 47 48 54 20 BIOS COPYRIGHT F000:E030 41 77 61 72 64 20 53 6F-66 74 77 61 72 65 20 49 Award Software I F000:E040 6E 63 2E 6F 66 74 77 61-72 65 20 49 6E 63 2E 20 nc.oftware Inc. F000:E050 41 77 03 0C 04 01 01 6F-66 74 77 E9 12 14 20 43 Aw.....oftw... C F000:E060 1B 41 77 61 72 64 20 4D-6F 64 75 6C 61 72 20 42 .Award Modular B F000:E070 49 4F 53 20 76 34 2E 35-31 50 47 00 DB 32 EC 33 IOS v4.51PG..2.3 -d F000:E080 EC 35 EC 38 EC 3C EC 41-EC 47 EC 4E EC 77 61 72 .5.8.<.A.G.N.war F000:E090 2C 43 6F 70 79 72 69 67-68 74 20 28 43 29 20 31 ,Copyright (C) 1 F000:E0A0 39 38 34 2D 39 37 2C 20-41 77 61 72 64 20 53 6F 984-97, Award So F000:E0B0 66 74 77 61 72 65 2C 20-49 6E 63 2E 00 74 77 61 ftware, Inc..twa F000:E0C0 4E 35 53 56 41 20 52 45-56 3A 31 2E 32 20 28 31 N5SVA REV:1.2 (1 F000:E0D0 31 2F 31 31 2F 39 37 29-00 4D 20 2D 20 4E 4F 54 1/11/97).M - NOT F000:E0E0 20 46 4F 52 20 53 41 4C-45 00 00 00 00 00 00 00 FOR SALE....... F000:E0F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ -

Pe un alt calculator vor fi afişate pe ecran alte informaţii. Aşa au apărut calculatoarele compatibile IBM PC. Acum ne putem considera rătăciţi, aşa că, cel mai indicat este să tastăm comanda q. Prompterul MS-DOS C:\mm>

este locul unde ne vom întoarce după fiecare incursiune (vom afla mai târziu de ce) în ipoteticul oraş de numere.

Lansăm din nou în execuţie utilitarul DEBUG şi încărcăm în memorie fişierul ASCII.TXT. Afişăm pe ecran conţinutul memoriei unde a fost încărcat fişierul cu ajutorul comenzii d. De la prompterul utilitarului DEBUG tastăm următoarele linii de comandă: -e 100 "Nu cred ca acest curs o sa-mi influenteze modul de a gindi." -d 100 1371:0100 4E 75 20 63 72 65 64 20-63 61 20 61 63 65 73 74 Nu cred ca acest 1371:0110 20 63 75 72 73 20 6F 20-73 61 2D 6D 69 20 69 6E curs o sa-mi in 1371:0120 66 6C 75 65 6E 74 65 7A-65 20 6D 6F 64 75 6C 20 fluenteze modul 1371:0130 64 65 20 61 20 67 69 6E-64 69 2E 5C 5D 5E 5F 60 de a gindi.\]^_` 1371:0140 61 62 63 64 65 66 67 68-69 6A 6B 6C 6D 6E 6F 70 abcdefghijklmnop 1371:0150 71 72 73 74 75 76 77 78-79 7A 7B 7C 7D 7E 0E A7 qrstuvwxyz|~.. 1371:0160 D8 02 3A 06 94 D2 75 C9-4E 32 C0 86 04 46 3C 0D ..:...u.N2...F<. 1371:0170 75 02 88 04 89 36 6B D7-89 0E 69 D7 C3 BE 48 DB u....6k...i...H.

Page 13: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

13

-

Astfel am învăţat un procedeu de a introduce date în memorie, respectiv de a vedea ce şi unde am introdus. Vom tasta în continuare -w Writing 0005E bytes -q

şi ajungem la locul de plecare, prompterul MS-DOS. Cu ajutorul editorului NOTEPAD redeschidem fişierul ASCII.TXT. Nu cred ca acest curs o sa-mi influenteze modul de a gindi. \]^_`abcdefghijklmnopqrstuvwxyz|~

Este uşor acum de înţeles efectul comenzii w (write) a utilitarului DEBUG. În acest moment, nu putem spune decât că este mult mai comod să ne jucăm cu mouse-ul în Windows xxxx. Dacă noi suntem hotărâţi să atingem nivelul de novice în domeniul embedded system, atunci trebuie să ne întoarcem la prompterul MS-DOS, de unde să lansăm în execuţie utilitarul DEBUG. De la prompterul “-” tastăm comanda -r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0100 NV UP EI PL NZ NA PO NC 1371:0100 4E DEC SI -

şi am ajuns direct pe "biroul primarului" (primarul oraşului de numere). Este momentul să vedem ce are pe birou, sau cu alte cuvinte, care sunt şi ce semnificaţie au regiştrii şi bistabilii de condiţie ai microprocesorului (este vorba de un microprocesor 80X86, sau "Pentium Ţ" produs de firma Intel, eventual un alt microprocesor compatibil cu unul dintre acestea produs de o altă firmă).

Singurele sarcini pe care le execută un microprocesor sunt cele transmise printr-un program. Programul este alcătuit dintr-o succesiune de instrucţiuni (comenzi date microprocesorului) care au drept scop obţinerea unui rezultat util. În reprezentare internă, instrucţiunile sunt un număr binar sau o succesiune de numere binare (compactizate în hexazecimal de utilitarul DEBUG, pentru economia scrierii). Instrucţiunile formează un program în cod-maşină, dacă executarea lor de către microprocesor duce la rezolvarea unei anumite probleme.

Trebuie menţionat că utilitarul DEBUG ne ascunde multe din particularităţile microprocesorului pe care îl avem pe placa de bază (Mother Board), iar modul de lucru al microprocesorului este implicit cel REAL (un microprocesor din familia amintită cu X > 2 poate lucra în unul din modurile: REAL, PROTEJAT,

Page 14: Microprocesoare Si Microcontrolere

Utilitarul DEBUG. Familia de Microprocesoare 80X86

14

VIRTUAL 8086). Limitările aduse de utilitarul DEBUG nu ne împiedică să atingem nivelul propus anterior, cel de novice. Regiştrii microprocesorului sunt, de fapt, un alt fel de locaţii de memorie (care se află în interiorul microprocesorului), mult mai uşor de invocat de programator, deoarece fiecare are un nume (nu o adresă). Vom analiza setul de regiştrii ai microprocesoarelor din familia 80X86, în limita a ceea ce vedem efectiv prin intermediul utilitarului DEBUG, fără a insista la acest nivel asupra excepţiilor fără număr (blestemul compatibilităţii de sus în jos al microprocesoarelor Intel).

Microprocesoarele din familia 80X86 au patru regiştri de uz general, aceştia sunt cel mai des utilizaţi. Fiecare registru de uz general poate fi accesat ca doi regiştrii de 8 biţi (conţinutul acestora este un număr între 00h şi FFh) sau ca un singur registru de 16 biţi (conţinutul acestuia este un număr între 0000h şi FFFFh).

Acumulatorul (AH - AL, AX) are un regim privilegiat şi este intens folosit de majoritatea instrucţiunilor. Registrul de bază (BH - BL, BX) poate fi folosit în calcule de adrese de memorie. Registrul numărător (CH - CL, CX) este invocat cu rol de contor în instrucţiunile repetitive şi de ciclare. Registrul de date (DH - DL, DX) conţine adresa de port pentru instrucţiunile de intrare/ieşire (I/O) sau este folosit în instrucţiunile de înmulţire/împărţire. După cum se poate vedea, conţinutul acestora este numărul 0000h şi nu se modifică în timp. Cu alte cuvinte, utilitarul DEBUG ne crează impresia că microprocesorul este numai la dispoziţia noastră. Microprocesoarele din familia 80X86 (Intel) au patru regiştri speciali de 16 biţi, doi regiştri pointeri şi doi regiştri index. Indicatorul de stivă (Stack Pointer, SP) permite implementarea stivei în memoria principală şi este corelat cu registrul de adresă SS. Pointer-ul de bază (Base Pointer, BP) permite accesul la date în regim de stivă. Index-ul sursă (SI) şi index-ul destinaţie (DI) sunt utilizaţi pentru accesul la date, în special în instrucţiunile de operaţii pe şiruri. Limitările tehnologice din anul 1977 (8086 Intel, primul microprocesor de 16 biţi) şi experienţa anterioară a proiectanţilor cu microprocesoarele de 8 biţi au generat o structură complexă cu cinci regiştri de adresă, dintre care patru de segment. Regiştrii de segment sunt folosiţi în toate calculele de adrese. Fiecare segment defineşte un bloc de memorie de 64 Kbyte în cadrul unui spaţiu de adresă de 1 Mbyte. Segmentul de cod (Code Segment, CS) utilizat în calculul adresei următoarei instrucţiuni de executat lucrează în conjuncţie cu IP. Adresa instrucţiunii ce urmează a se executa se află la adresa fizică add_mem = [CS]*16 + [IP], unde prin [CS] şi [IP] înţelegem conţinutul acestor regiştri. Segmentul de date (Data Segment, DS) este utilizat în general pentru referirile la memorie, aflarea operanzilor şi depunerea rezultatelor (sunt câteva excepţii pe care le vom vedea când vom aborda modurile de adresare ale memoriei). Segmentul de stivă (Stack

Page 15: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

15

Segment, SS) este implicat în toate referirile la memorie care utilizează SP şi BP. Acestea sunt relative la SS, adică adresa se calculează considerând ca segment conţinutul registrului SS. Segmentul suplimentar (Extra Segment, ES) conţine adresa de segment a unui segment de memorie suplimentar. Pointer-ul de instrucţiuni (Instruction Pointer, IP) conţine adresa curentă de offset a instrucţiunii următoare ce urmează a fi executată în cadrul segmentului de cod. Câteva precizări se impun înainte de a merge mai departe. După cum se poate observa în exemplul prezentat, conţinutul regiştrilor de segment este acelaşi 1371h, iar registrul IP conţine adresa offset 100h. Reţinem că un program de aplicaţie în care regiştrii de segment deschid acelaşi segment de memorie, ca şi în acest caz, este un program executabil de tip ".COM", iar dacă sunt deschise cel puţin două segmente de memorie (eventual suprapuse parţial), atunci programul este de tip ".EXE". În cazul nostru, în mod implicit (default) utilitarul DEBUG este pregătit pentru realizarea unui eventual program de aplicaţie de tip ".COM". Bistabilii de condiţie (flag-uri) sunt grupaţi într-un registru de 16 biţi (sau 32 de biţi, pentru X > 2). Numai 8 flag-uri sunt afişate de utilitarul DEBUG. Limitarea este generată de modul REAL în care lucrează microprocesorul şi evident de omniprezenta compatibilitate. Trebuie reţinută semnificaţia acestor flag-uri, deoarece toate deciziile din programele pe care le vom scrie vor depinde de starea acestora. Utilitarul DEBUG afişează flag-urile într-o formă abreviată. De la stânga la dreapta este afişată pe ecran starea următoarelor flag-uri: • overflow (OF), indică o depăşire în aritmetica cu semn, NV – No oVerflow,

OV – OVerflow occurred,

• direction (DF), în cazul operaţiilor pe şiruri; regiştrii SI, DI sunt incrementaţi sau decrementaţi, UP – Direction is UP, DN – direction is DowN,

• interrupt (IF), activează sau dezactivează întreruperile, DI – Interrupts are Disabled, EI – Interrupts are Enabled,

• sign (SF), indică semnul rezultatului unei instrucţiuni, PL – Positive sign, NG – NeGative sign,

• zero (ZF), dacă rezultatul unei operaţii este zero binar se poziţionează pe starea de adevăr, NZ – result was Not Zero, ZR – result was ZeRo,

• auxiliary carry (AF), indică apariţia unui transport sau împrumut auxiliar, NA – No Auxiliary carry, AC – Auxiliary Carry,

• parity (PF), indică dacă numărul de biţi poziţionaţi în 1 ai rezultatului este par, PO – Parity Odd, PE – Parity Even şi

• carry (CF), indică apariţia unui transport sau împrumut, NC – No Carry, CY - CarrY.

Numai cu titlu informativ, putem spune că, pentru microprocesoarele cu X > 2 regiştrii sunt de 32 de biţi. Avem aşadar următoarele abrevieri pentru aceştia: EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, EIP. Au fost suplimentaţi de

Page 16: Microprocesoare Si Microcontrolere

Utilitarul DEBUG. Familia de Microprocesoare 80X86

16

asemenea regiştrii şi/sau bistabilii de condiţie (flag-urile) şi modurile de organizare a memoriei au fost diversificate. Principiul compatibilităţii asigură funcţionarea utilitarului DEBUG pentru oricare din membri familiei de microprocesoare 80X86.

Ultima linie afişată ne arată ce ar urma să execute microprocesorul dacă ar interpreta instrucţiunea de la adresa offset 100h. În acest caz, opcod-ul (operation code) instrucţiunii este 4Eh şi este tradus de utilitarul DEBUG sub forma DEC SI (DECrementează conţinutul registrului SI). Trebuie să facem de la bun început o precizare: după cum se poate vedea, instrucţiunea pentru microprocesor este un opcod (exprimat pe un număr de octeţi). Pentru a nu fi obligaţi să reţinem aceste opcod-uri, utilitarul ne sugerează acţiunea instrucţiunilor printr-un mnemonic (reprezentare simbolică pentru instrucţiune). Aşa că, prin termenul de instrucţiune vom înţelege simultan ambele reprezentări, una internă pentru microprocesor (sub formă de opcod) şi una externă pentru programator, care sugerează acţiunea microprocesorului. Dar mai bine să nu ne aventurăm. Tastăm în continuare următoarele comenzi: -nascii.txt -l -r AX=0000 BX=0000 CX=005E DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0100 NV UP EI PL NZ NA PO NC 1371:0100 4E DEC SI -

şi ne îndreptăm atenţia asupra conţinutului registrului CX. Lungimea fişierului ASCII.TXT este 005Eh, după cum rezultă din comanda

w (Writing 0005E bytes) anterioară. Este bine să reţinem semnificaţia registrului CX în raport cu operaţiile de citire şi/sau scriere ale fişierelor, pe un suport extern de memorie. În acest moment ştim suficiente comenzi pentru a crea cu ajutorul utilitarului DEBUG un mic fişier pe care îl vom numi HELLO.TXT. Vom tasta în continuare următoarele comenzi: -nhello.txt -e 100 "Hello World !" -d 1371:0100 48 65 6C 6C 6F 20 57 6F-72 6C 64 20 21 65 73 74 Hello World !est 1371:0110 20 63 75 72 73 20 6F 20-73 61 2D 6D 69 20 69 6E curs o sa-mi in 1371:0120 66 6C 75 65 6E 74 65 7A-65 20 6D 6F 64 75 6C 20 fluenteze modul 1371:0130 64 65 20 61 20 67 69 6E-64 69 2E 5C 5D 5E 5F 60 de a gindi.\]^_` 1371:0140 61 62 63 64 65 66 67 68-69 6A 6B 6C 6D 6E 6F 70 abcdefghijklmnop 1371:0150 71 72 73 74 75 76 77 78-79 7A 7B 7C 7D 7E 0E A7 qrstuvwxyz|~.. 1371:0160 D8 02 3A 06 94 D2 75 C9-4E 32 C0 86 04 46 3C 0D ..:...u.N2...F<. 1371:0170 75 02 88 04 89 36 6B D7-89 0E 69 D7 C3 BE 48 DB u....6k...i...H. -

Page 17: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

17

Modificăm conţinutul registrului CX, astfel încât să conţină exact numărul de octeţi care au fost introduşi în memorie începând cu adresa offset 100h şi apoi, cu ajutorul conenzii w salvăm aceşti octeţi în fişierul HELLO.TXT. -rcx CX 005E :000D -w Writing 0000D bytes -q

Cu ajutorul editorului NOTEPAD deschidem fişierul HELLO.TXT din folderul Mm.

Page 18: Microprocesoare Si Microcontrolere

Utilitarul DEBUG. Familia de Microprocesoare 80X86

18

Page 19: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

19

2. Programe Simple în Limbaj de Asamblare

Dacă ataşăm fiecărei instrucţiuni un mnemonic (anexa A, pentru microprocesoarele 80X86), obţinem o reprezentare simbolică a instrucţiunilor unui microprocesor numită limbaj de asamblare. Translatarea programului scris în limbaj de asamblare în program cod-maşină se face cu un program special numit asamblor. Productivitatea scrierii programelor în limbajele de nivel înalt (C++, de exemplu) a detronat în timp limbajul de asamblare, cu excepţia programării mixte (asm … ) în care performanţele impuse de o anumită aplicaţie nu pot fi atinse altfel (situaţii frecvent întâlnite atât în domenile experimentale cât şi în domenii legate de simularea unor procese, fenomene cu ajutorul calculatorului). Deoarece fiecare mnemonic din programul scris (cod ASCII) în limbaj de asamblare este translatat într-o singură instrucţiune în program cod-maşină, avem o imagine clară a ceea ce execută microprocesorul în fiecare etapă a programului. Acesta este marele merit al limbajului de asamblare.

Utilitarul DEBUG are integrat un asamblor interactiv cu ajutorul căruia vom ilustra câteva aspecte de bază ale programării în limbaj de asamblare. Lansăm în execuţie utilitarul DEBUG şi tastăm comanda,

-a 1371:0100

după care asamblorul aşteaptă introducerea mnemonicelor.

1371:0100 mov ax,CAFE 1371:0103 mov bx,ax 1371:0105 mov cx,bx 1371:0107 mov dx,cx 1371:0109 -

La prompterul utilitarului DEBUG se ajunge printr-un ([CR],Enter) suplimentar. Dacă asamblorul ne semnalează o eroare reintroducem toată linia, deoarece adresa offset nu se modifică (să nu ne enervăm se poate scrie un întreg capitol despre greşelile tipice din această etapă).

Translatarea din programul cod-maşină în limbajul de asamblare se poate face cu un program desasamblor. Acesta este de asemenea integrat în utilitarul DEBUG. Pentru a vedea rezultatul procesului anterior de asamblare tastăm următoarea comandă:

-u100

Page 20: Microprocesoare Si Microcontrolere

20 Programe Simple în Limbaj de Asamblare

1371:0100 B8FECA MOV AX,CAFE 1371:0103 89C3 MOV BX,AX 1371:0105 89D9 MOV CX,BX 1371:0107 89CA MOV DX,CX 1371:0109 C3 RET 1371:010A A169D7 MOV AX,[D769] 1371:010D 8B366BD7 MOV SI,[D76B] 1371:0111 C606A7D800 MOV BYTE PTR [D8A7],00 1371:0116 C606A3D800 MOV BYTE PTR [D8A3],00 1371:011B 8B34 MOV SI,[SI] 1371:011D 006013 ADD [BX+SI+13],AH -

Pentru adresele cu offset-ul mai mare sau egal cu 109h pe ecranul unui alt calculator vor fi desigur alte informaţii (memoria este ştearsă prin înscriere). Prin comanda precedentă putem vedea atât modul de translatare a mnemonicelor cât şi opcod-urile generate. Pentru a înţelege acest mecanism şi implicaţiile lui tastăm următoarea comandă.

-u101 1371:0101 FECA DEC DL 1371:0103 89C3 MOV BX,AX 1371:0105 89D9 MOV CX,BX 1371:0107 89CA MOV DX,CX 1371:0109 C3 RET 1371:010A A169D7 MOV AX,[D769] 1371:010D 8B366BD7 MOV SI,[D76B] 1371:0111 C606A7D800 MOV BYTE PTR [D8A7],00 1371:0116 C606A3D800 MOV BYTE PTR [D8A3],00 1371:011B 8B34 MOV SI,[SI] 1371:011D 006013 ADD [BX+SI+13],AH 1371:0120 0E PUSH CS -

Secvenţa de mnemonice a fost asamblată începând cu adresa offset 100h. Desasamblăm începând cu adresa 101h şi constatăm că microprocesorul ar executa o altă instrucţiune fără a semnala vreo eroare (probabil aşa ceva se întâmplă atunci când din senin sistemul se blochează). Multe comentarii nu putem face în această etapă "a hoinărelii noastre prin oraşul de numere", aşa că tastăm în continuare "cuprinşi de disperarea unei posibile rătăciri" următoarele comenzi:

-r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0100 NV UP EI PL NZ NA PO NC 1371:0100 B8FECA MOV AX,CAFE -t AX=CAFE BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0103 NV UP EI PL NZ NA PO NC

Page 21: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

21

1371:0103 89C3 MOV BX,AX -t AX=CAFE BX=CAFE CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0105 NV UP EI PL NZ NA PO NC 1371:0105 89D9 MOV CX,BX -t AX=CAFE BX=CAFE CX=CAFE DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0107 NV UP EI PL NZ NA PO NC 1371:0107 89CA MOV DX,CX -t AX=CAFE BX=CAFE CX=CAFE DX=CAFE SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0109 NV UP EI PL NZ NA PO NC 1371:0109 C3 RET -

Comanda r ne asigură că regiştrii şi flag-urile sunt neschimbate, iar cu ajutorul comenzii t rulăm programul pas cu pas. Executarea instrucţiunii de la adresa offset 100h a avut ca efect mutarea (move) numărului CAFEh în registrul AX, iar registrul IP a fost incrementat şi conţine adresa offset 103h a instrucţiunii următoare.

În cod-maşină mnemonica MOV AX,CAFE a fost translatată sub forma B8FECA. Este uşor de înţeles că opcod-ul B8 este asociat cu MOV AX, iar FECA este numărul pe care dorim să îl mutăm în registrul AX, scris cu octeţi inversati. Adică, octetul mai puţin semnificativ este la cea mai mică adresă (little-endian systems). Această convenţie este o particularitate a microprocesoarelor Intel ce poate fi semnalată în acest moment. Alte microprocesoare din familia Motorola 68000, de exemplu, utilizează convenţia opusă, octetul cel mai semnificativ la cea mai mică adresă (big-endian systems). Putem urmări în continuare opcod-ul (pe doi octeţi, adică un cuvânt în cazul unor microprocesoare de 16 biţi) celorlalte mnemonice şi efectele generate de executarea lor. Modul de stabilire a opcod-urilor este o problemă prea complicată pentru un viitor novice. O regulă specifică mnemonicelor microprocesoarelor Intel este dată de modul de exprimare, de la dreapta la stînga, a acţiunii dintr-o mnemonică (numărul CAFEh trece în registrul AX, sau conţinutul registrului AX trece în registrul BX).

Tastăm q şi părăsim utilitarul DEBUG. Acest lucru este necesar pentru a evita o catastrofă, blocarea sistemului. Prin rularea pas cu pas a secvenţei anterioare de instrucţiuni, unele informaţii importante pentru programul DEBUG au fost distruse. Utilitarul DEBUG ne crează impresia că microprocesorul este numai la dizpoziţia noastră. Este desigur numai o impresie. Dacă totuşi blocăm sistemul, putem merge până la apăsarea pe butonul RESET. Dacă nu am reuşit să blocăm

Page 22: Microprocesoare Si Microcontrolere

22 Programe Simple în Limbaj de Asamblare

sistemul, vom lansa utilitarul DEBUG pentru o nouă aventură. Tastăm în continuare comanda

-a 100

şi următoarele mnemonice:

1371:0100 mov ax,CAFE 1371:0103 mov bx,ax 1371:0105 mov cx,ax 1371:0107 mov dx,ax 1371:0109 push ax 1371:010A push bx 1371:010B push cx 1371:010C push dx 1371:010D mov dx,BADA 1371:0110 mov cx,dx 1371:0112 mov bx,cx 1371:0114 mov ax,bx 1371:0116 pop dx 1371:0117 pop cx 1371:0118 pop bx 1371:0119 pop ax 1371:011A -

după care, pentru a vedea ce se întâmplă, vom rula pas cu pas secvenţa de instrucţiuni care a fost asamblată începând cu adresa offset 100h.

-r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0100 NV UP EI PL NZ NA PO NC 1371:0100 B8FECA MOV AX,CAFE -t AX=CAFE BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0103 NV UP EI PL NZ NA PO NC 1371:0103 89C3 MOV BX,AX -t AX=CAFE BX=CAFE CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0105 NV UP EI PL NZ NA PO NC 1371:0105 89C1 MOV CX,AX -t AX=CAFE BX=CAFE CX=CAFE DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0107 NV UP EI PL NZ NA PO NC 1371:0107 89C2 MOV DX,AX -t AX=CAFE BX=CAFE CX=CAFE DX=CAFE SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0109 NV UP EI PL NZ NA PO NC 1371:0109 50 PUSH AX -t AX=CAFE BX=CAFE CX=CAFE DX=CAFE SP=FFEC BP=0000 SI=0000 DI=0000

Page 23: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

23

DS=1371 ES=1371 SS=1371 CS=1371 IP=010A NV UP EI PL NZ NA PO NC 1371:010A 53 PUSH BX -t AX=CAFE BX=CAFE CX=CAFE DX=CAFE SP=FFEA BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=010B NV UP EI PL NZ NA PO NC 1371:010B 51 PUSH CX -t AX=CAFE BX=CAFE CX=CAFE DX=CAFE SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=010C NV UP EI PL NZ NA PO NC 1371:010C 52 PUSH DX -t AX=CAFE BX=CAFE CX=CAFE DX=CAFE SP=FFE6 BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=010D NV UP EI PL NZ NA PO NC 1371:010D BADABA MOV DX,BADA -t AX=CAFE BX=CAFE CX=CAFE DX=BADA SP=FFE6 BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0110 NV UP EI PL NZ NA PO NC 1371:0110 89D1 MOV CX,DX -t AX=CAFE BX=CAFE CX=BADA DX=BADA SP=FFE6 BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0112 NV UP EI PL NZ NA PO NC 1371:0112 89CB MOV BX,CX -t AX=CAFE BX=BADA CX=BADA DX=BADA SP=FFE6 BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0114 NV UP EI PL NZ NA PO NC 1371:0114 89D8 MOV AX,BX -t AX=BADA BX=BADA CX=BADA DX=BADA SP=FFE6 BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0116 NV UP EI PL NZ NA PO NC 1371:0116 5A POP DX -t AX=BADA BX=BADA CX=BADA DX=CAFE SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0117 NV UP EI PL NZ NA PO NC 1371:0117 59 POP CX -t AX=BADA BX=BADA CX=CAFE DX=CAFE SP=FFEA BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0118 NV UP EI PL NZ NA PO NC 1371:0118 5B POP BX -t AX=BADA BX=CAFE CX=CAFE DX=CAFE SP=FFEC BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0119 NV UP EI PL NZ NA PO NC 1371:0119 58 POP AX -t AX=CAFE BX=CAFE CX=CAFE DX=CAFE SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=011A NV UP EI PL NZ NA PO NC 1371:011A 008B3400 ADD [BP+DI+0034],CL SS:0034=18 -

Prin comanda r ne asigurăm că regiştrii şi flag-urile sunt neschimbate. Observăm în continuare efectul identic de încărcare a regiştrilor generali prin utilizarea altor instrucţiuni. Regulă: dacă nu este o restricţie impusă de producătorul

Page 24: Microprocesoare Si Microcontrolere

24 Programe Simple în Limbaj de Asamblare

microprocesorului tot ce pare logic este posibil. De altfel, asamblorul din utilitarul DEBUG ştie ce nu se poate. Să avem pentru început încredere în semnalizările lui (Error). La adresa de offset 109h din program avem o instrucţiune de tip PUSH a cărei efect este extrem de important deoarece activează un mecanism întâlnit la toate microprocesoarele, stiva.

Tot aşa cum regiştrii CS:IP asigură împreună rularea programului din segmentul de cod, regiştrii SS:SP sunt utilizaţi împreună pentru a adresa stiva. Stiva este un segment de memorie (SS) utilizat ca o zonă de stocare a informaţiei după regula ultimul intrat primul ieşit (last-in first-out, LIFO). Registrul BP este de asemenea asociat cu registrul SS şi este utilizat pentru a adresa o anumită locaţie de memorie din stivă.

Segmentul de stivă poate să se suprapună sau să coincidă cu orice alt segment inclusiv cu segmentul de cod (atenţie, IP pe timpul rulării programului pleacă de la adrese mici spre adrese mari). Conţinutul registrului SP se modifică de la adrese mari spre adrese mici (decrementare) cu fiecare octet sau cuvânt copiat pe stivă. Dacă programăm în limbaj de asamblare trebuie să fim atenţi la o eventuală coliziune dintre stivă si codul programului (sau dintre stivă si blocul de date), în cazul în care segmentele de memorie se suprapun sau coincid (.COM).

Înainte de a comenta secvenţa de instrucţiuni anterioară să înţelegem, de ce este important mecanismul de stivă. După cum se poate vedea, numărul regiştrilor unui microprocesor este relativ mic (despre microprocesorul de faţă se poate spune că are foarte mulţi regiştrii), iar la un moment dat, pentru a continua programul trebuie să sacrificăm conţinutul unui registru. Dar conţinutul lui este important intr-o etapă imediat următoare a programului. Într-o asemenea situaţie (dar nu numai) apelăm la mecanismul de stivă. Pe de altă parte opcod-ul instrucţiunilor de tip PUSH este de numai un octet, asigurând astfel o bună optimizare a programului-cod.

Executarea instrucţiuni PUSH AX a determinat copierea în stivă a cuvântului conţinut în registrul AX. Efectul vizibil prin informaţia afişată de utilitarul DEBUG ne arată o decrementare cu doi (au fost copiaţi doi octeţi) a numărului conţinut în registrului SP. Cuvântul din registrul SP point-ează pe prima adresă liberă din vârful stivei. Adresa din registrul SP este obţinută printr-un proces automat de decrementare/incrementare. Acesta este un alt avantaj al mecanismului de stivă în raport cu operaţiile de salvare (prin copiere pe stivă) a unor date care sunt intens utilizate de program.

După copierea conţinutului celor patru regiştrii generali în stivă le modificăm conţinutul prin mutarea cuvântului BADAh în fiecare din aceştia (am

Page 25: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

25

folosit alte forme pentru MOV, trebuie puţin curaj, dacă nu e bine ne informează asamblorul interactiv din utilitarul DEBUG).

La adresa offset 116h întâlnim instrucţiunea POP. Dacă urmărim cum se modifică conţinutul regiştrilor generali prin executarea acestei secvenţe, înţelegem rolul acestei instrucţiuni: refacerea conţinutului iniţial al regiştrilor generali. Spunem că stiva a fost descărcată deoarece pe măsură ce instrucţiunile POP sunt executate, conţinutul lui SP se încrementează cu doi pentru a ajunge în final (după refacerea tuturor regiştrilor generali) la valoarea iniţială. Pentru a nu altera conţinutul registrilor în raport cu conţinutul lor iniţial şi cunoscând mecanismul de stivă (LIFO), trebuie ca restaurarea să o facem în ordine inversă. Sunt situaţii în care algoritmul impune un alt mod de restaurare a conţinutului regiştrilor prin mecanismul de stivă (totul este posibil în măsura în care este util scopului final, rezolvarea problemei). O altă regulă este ca, la ieşirea dintr-un program (sau o subrutină), conţinutul stivei să fie acelaşi cu cel din momentul apelării. Dacă problema o cere şi această regulă se poate încălca; acesta este oraşul de numere (faci ce vrei, dar şti ce faci ?). Din exemplele anterioare constatăm o mixare ciudată de exactitate (vezi efectele desasamblării începănd cu adresa offset 101h) şi libertate. Aceasta din urmă este dusă uneori până la estravaganţă, adică un fel de "libertate în lanţuri" (”Nu cred ca acest curs o sa-mi influenteze modul de a gindi.”). Tastaţi comanda q urmată de exit, şi să ne pregătim sufleteşte pentru întâlnirea cu vectorii de întrerupere.

Vectorii de întrerupere sunt marea "găselniţă" prezentă în orice calculator modern. Aceştia au o zonă de memorie rezervată, numită tabela vectorilor de întrerupere. Dacă din utilitarul DEBUG tastăm comanda

-d0:0 0000:0000 9E 0F C9 00 65 04 70 00-16 00 87 08 65 04 70 00 ....e.p.....e.p. 0000:0010 65 04 70 00 54 FF 00 F0-88 80 00 F0 6F EF 00 F0 e.p.T.......o... 0000:0020 00 00 00 C8 28 00 87 08-6F EF 00 F0 6F EF 00 F0 ....(...o...o... 0000:0030 6F EF 00 F0 6F EF 00 F0-9A 00 87 08 65 04 70 00 o...o.......e.p. 0000:0040 07 00 70 C8 4D F8 00 F0-41 F8 00 F0 7F 25 A7 FD ..p.M...A....%.. 0000:0050 39 E7 00 F0 40 02 0B 02-2D 04 70 00 28 0A 51 02 [email protected].(.Q. 0000:0060 A4 E7 00 F0 2F 00 48 09-6E FE 00 F0 04 06 51 02 ..../.H.n.....Q. 0000:0070 1D 00 00 C8 A4 F0 00 F0-22 05 00 00 93 49 00 C0 ........"....I.. -d 0000:0080 A8 0F C9 00 2F 04 5F 09-4F 03 F6 0C 8A 03 F6 0C ..../._.O....... 0000:0090 17 03 F6 0C BC 0F C9 00-C6 0F C9 00 D0 0F C9 00 ................ 0000:00A0 6C 10 C9 00 66 04 70 00-B4 05 51 02 6C 10 C9 00 l...f.p...Q.l... 0000:00B0 6C 10 C9 00 6C 10 C9 00-62 01 13 0B CC 01 14 0B l...l...b....... 0000:00C0 EA E4 0F C9 00 EF 00 F0-6C 10 C9 00 01 00 3F 0A ........l.....?. 0000:00D0 6C 10 C9 00 6C 10 C9 00-6C 10 C9 00 6C 10 C9 00 l...l...l...l... 0000:00E0 6C 10 C9 00 6C 10 C9 00-6C 10 C9 00 6C 10 C9 00 l...l...l...l... 0000:00F0 6C 10 C9 00 6C 10 C9 00-6C 10 C9 00 6C 10 C9 00 l...l...l...l... -

Page 26: Microprocesoare Si Microcontrolere

26 Programe Simple în Limbaj de Asamblare

putem vedea o parte din conţinutul acestei zone (adresa maximă a zonei este 3FFh, 1 Kbyte). Fiecare va vedea altceva, tocmai de aceea calculatoarele noastre sunt compatibile între ele.

Iniţial, întreruperile au fost introduse pentru a putea cere atenţia unităţii centrale în clipa când anumite evenimente imprevizibile au loc (întreruperi hard, le lăsam pe mai târziu). Pe lângă întreruperile hard microprocesoarele 80X86 mai au încă două tipuri de întreruperi: întreruperi excepţionale (apariţia unor situaţii cu totul deosebite, împărţire cu zero, …) şi întreruperile soft (INT). Asamblăm următoarea secvenţă de instrucţiuni:

-a 1371:0100 mov cx,0 1371:0103 mov dh,18 1371:0105 mov dl,4f 1371:0107 mov bh,70 1371:0109 mov ax,600 1371:010C int 10 1371:010E nop 1371:010F -

şi o rulăm pas cu pas să vedem ce se întâmplă.

-r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0100 NV UP EI PL NZ NA PO NC 1371:0100 B90000 MOV CX,0000 -t AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0103 NV UP EI PL NZ NA PO NC 1371:0103 B618 MOV DH,18 -t AX=0000 BX=0000 CX=0000 DX=1800 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0105 NV UP EI PL NZ NA PO NC 1371:0105 B24F MOV DL,4F -t AX=0000 BX=0000 CX=0000 DX=184F SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0107 NV UP EI PL NZ NA PO NC 1371:0107 B770 MOV BH,70 -t AX=0000 BX=7000 CX=0000 DX=184F SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0109 NV UP EI PL NZ NA PO NC 1371:0109 B80006 MOV AX,0600 -t

Page 27: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

27

AX=0600 BX=7000 CX=0000 DX=184F SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=010C NV UP EI PL NZ NA PO NC 1371:010C CD10 INT 10 -t AX=0600 BX=7000 CX=0000 DX=184F SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=C870 IP=0007 NV UP DI PL NZ NA PO NC C870:0007 FB STI -t AX=0600 BX=7000 CX=0000 DX=184F SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=C870 IP=0008 NV UP EI PL NZ NA PO NC C870:0008 84E4 TEST AH,AH -

Până la adresa offset 10Ch nimic nou, aici urmează să fie executată instrucţiunea INT 10, care are opcod-ul CD urmat de 10, numărul invocat de INT.

Execuţia acestei instrucţiuni are efecte neaşteptate. Observăm că s-a modificat conţinutul regiştrilor CS:IP, dovadă că suntem în alt segment de memorie şi la o altă adresă offset. De asemenea, a fost decrementat registrul SP, care de fapt ne informează că au fost copiaţi pe stivă şase octeţi. De asemenea flag-ul interrupt, EI (întreruperile erau activate) a trecut în DI (întreruperile sunt dezactivate), pentru ca mai apoi să fie repus în starea EI de către instrucţiunea STI (opcod, FB). De ce această instrucţiune a determinat aceste schimbări profunde şi de unde a fost luat noul conţinut al regiştrilor CS:IP? Să privim în tabela vectorilor de întrerupere în dreptul adresei offset 40h (0000:0040 07 00 70 C8). Dacă ne aducem aminte de convenţia specifică microprocesoarelor Intel (little-endian systems), atunci răspunsul cu privire la noul conţinut al regiştrilor CS:IP este următorul: noul conţinut al regiştrilor CS:IP a fost copiat din tabela vectorilor de întrerupere.

Mai mult, în regiştrii CS:IP au fost copiaţi patru octeţi (4*10h = 40h), de unde putem deduce regula după care este organizată tabela vectorilor de întrerupere. Aşa că, numărul de după o instrucţiune de tip INT este de fapt numărul unei intrări din tabela vectorilor de întrerupere. Pentru microprocesoarele din familia 80X86 avem 256 de întreruperi posibile (INT 0, INT 1, …, INT FF). De asemenea, nu putem să nu remarcăm cât de puternic este acest mecanism prin care invocăm sistemului de operare un serviciu. Pentru aceasta este suficient să invocăm întreruperea aferentă serviciului respectiv, indiferent unde este localizat (în memoria fizică) programul care deseverşte acest serviciu. O comparaţie cu telefonia celulară nu este lipsită de temei. Noi apelăm un număr de telefon, iar abonatul poate fi oriunde. Mai mult, abonatul ne poate informa că este în alt loc decât cel real. În acest caz, abonatul este un posibil virus.

Page 28: Microprocesoare Si Microcontrolere

28 Programe Simple în Limbaj de Asamblare

Mai trebuie să înţelegem câteva amănunte deloc lipsite de importanţă. Executarea instrucţiunii de întrerupere a dezactivat automat întreruperile. Aşa că, nu vom fi deranjaţi de o eventuală altă întrerupere. În cazul serviciului invocat programatorul nu a dorit acest lucru şi întreruperile au fost reactivate prin instrucţiunea STI. Probabil că întreruperea invocată nu execută ceva foarte important. O altă problemă ce trebuie lămurită este legată de copierea pe stivă a celor şase octeţi. Este uşor de bănuit că patru dintre aceşti octeţi sunt de fapt vechiul conţinut al regiştrilor CS:IP. După ce serviciul invocat va fi executat, cu siguranţă trebuie să revenim la programul iniţial (deci IP va pointa pe instrucţiunea următoare lui INT, înainte de a fi copiat pe stivă) pentru a continua cu instrucţiunea următoare.

Ce altceva ar mai putea fi, cu siguranţă, distrus de serviciul invocat ? Flag-urile. Tocmai de aceea, flag-urile sunt copiate automat în stivă (flag-urile formează un registru de 16 biţi, utilitarul DEBUG ne afişează doar starea a opt flag-uri) la executarea unei instrucţiuni INT. Tastăm comanda q şi relansăm utilitarul DEBUG. Asamblăm aceeaşi secvenţă de instrucţiuni şi tastăm comanda g10E. Aceasta va asigura execuţia tuturor instrucţiunilor până la adresa 10Eh .

-a 1371:0100 mov cx,0 1371:0103 mov dh,18 1371:0105 mov dl,4f 1371:0107 mov bh,70 1371:0109 mov ax,600 1371:010C int 10 1371:010E nop 1371:010F -g10e AX=0600 BX=7000 CX=0000 DX=184F SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=010E NV UP EI PL NZ NA PO NC 1371:010E 90 NOP -

Presupunerile făcute asupra modului de acţiune al intrucţiuni INT s-au adeverit. Registrul SP a fost incrementat până la valoarea avută iniţial. Ceilalţi regiştri au, de asemenea, conţinutul neschimbat în raport cu situaţia precedentă invocării întreruperii. Flag-urile sunt, de asemenea, neschimbate în raport cu situaţia iniţială. Am spune că nu s-a întâmplat nimic. Numai că modul de lucru al ecranului a fost revers-at şi tot ce era afişat a fost şters. Această secvenţă de instrucţiuni face ceva, aşa că, este în sfârşit un program. Acesta şterge tot ce este afişat pe ecran şi face revers. Tastăm comanda q urmată de exit. Cu ajutorul utilitarului DEBUG rescriem programul. Se putea şi altfel, dar să nu ne grăbim.

Page 29: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

29

-a 1371:0100 mov cx,0 1371:0103 mov dh,18 1371:0105 mov dl,4f 1371:0107 mov bh,70 1371:0109 mov ax,600 1371:010C int 10 1371:010E mov ax,4c00 1371:0111 int 21 1371:0113 -rcx CX 0000 :13 -nclrscr.com -w Writing 00013 bytes -q

Cu ajutorul comenzii DIR putem constata existenţa primului nostru program scris în limbaj de asamblare. Acum îl putem apela simplu de la linia de comandă

C:\Mm>clrscr

urmat evident de C:\Mm>exit

pentru a reface starea iniţială a ecranului. Câteva precizări sunt necesare înainte de o nouă "hoinăreală". Invocarea diverselor servicii ale sistemului de operare prin mecanismul întreruperilor simplifică mult lucrurile. Nu trebuie să ştim decât numărul întreruperii. Acesta este folosit de microprocesor pentru aflarea adresei fizice din tabela vectorilor de întrerupere. Adresa se poate schimba de la un fabricant la altul sau de la o versiune la alta a sistemului de operare. Pentru a asigura compatibilitatea nu trebuie decât respectată cu stricteţe ordinea vectorilor în tabelă. Acest mecanism asigură portabilitatea programelor între toate calculatoarele IBM PC (o veste bună pentru viitorii hacker-i, orice vector din aceasta tabelă poate fi schimbat cu uşurinţă).

Momentan trebuie să reţinem că sistemul de operare al calculatoarelor IBM PC înglobează componenta BIOS (această componentă răspunde în principal de gestionarea echipamentelor de intrare/ieşire). Aceasta este o colecţie de servicii conţinute într-o memorie nevolatilă de pe placa de bază a calculatorului. Deci în BIOS vom găsi gata scrise şi puse la punct, o serie întreagă de subrutine legate de echipamentele de intrare/ieşire. Ce bine că le putem folosi, fără a ne mai bate capul

Page 30: Microprocesoare Si Microcontrolere

30 Programe Simple în Limbaj de Asamblare

cu scrierea lor de fiecare dată, când dezvoltăm o aplicaţie. Apelarea acestor subrutine se face, bineînţeles, prin întreruperi. Pentru lucrul cu fiecare echipament periferic a fost alocată o întrerupere soft. Aceste întreruperi nu trebuie încurcate cu întreruperile hard, care lucrează cu echipamentele de intrare/ieşire, într-un mod pe care momentan îl considerăm transparent pentru noi. Principalele întreruperi BIOS sunt rezumate mai jos: INT 10h ; Servicii de ecran INT 13h ; Servicii de disc INT 14h ; Servicii de comunicaţii seriale INT 16h ; Servicii de tastatură INT 17h ; Servicii de imprimantă INT 5h ; Copiere ecran la imprimantă INT 19h ; Activare bootstrap (reîncărcare sistem de operare, de regulă MS-DOS) INT 1Ah ; Servicii de timp şi data. INT 20h ; Terminare program

In cadrul fiecărei întreruperi se pot face mai multe "chestii", acestea sunt serviciile. Selecţia serviciului dorit se face prin încărcarea, înainte de invocarea întreruperii, a registrului AH, cu numărul serviciului. Parametrii de apel ai serviciului se încarcă la fel, în anumiţi regiştrii, după caz. Atenţie mare, unele servicii distrug conţinutul unor regiştrii. Dacă avem în regiştrii ce urmează să fie distruşi date utile, conţinutul acestora trebuie copiat pe stivă, înainte de apelarea întreruperii.

Vom numi servicii DOS (servicii ale sistemului de operare), întregul set de operaţii pe care sistemul de operare le pune la dispoziţie. Aceste servicii se împart în întreruperi DOS şi funcţii DOS. Întreruperile DOS sunt invocate prin instrucţiunea INT cu tipul rezervat pentru fiecare întrerupere în parte. Pe de altă parte funcţiile DOS, cam la fel ca serviciile BIOS, sunt invocate printr-o singură întrerupere, numită “întrerupere umbrelă”. Aceasta este INT 21 (4*21h = 84h,

0000:0080 A8 0F C9 00 2F 04 5F 09-4F 03 F6 0C 8A 03 F6 0C) iar parametrul din registrul AH fixează serviciul solicitat. Întreruperile şi funcţiile DOS vor fi studiate individual. Există multă documentaţie şi programe tutoriale legate de modul de invocare al acestora, respectiv serviciile oferite (funcţie de conţinutul regiştrilor în momentul invocării). O parte din serviciile oferite de componenta BIOS sunt dublate de componenta DOS. De regulă, este preferată invocarea variantei DOS a seviciului cu scopul asigurării unei portabilităţi mai bune a programului.

Programatorul este un om şi ca orice om uită. Tocmai de aceea, este bine să comentăm programul pe măsură ce îl scriem. Obţinem odată cu programul şi documentaţia acestuia. Partea de comentariu care va însoţi fiecare instrucţiune nu trebuie introdusă în cazul asamblorului interactiv din utilitarul DEBUG. Dar dacă utilizăm un editor şi un asamblor extern (MASM sau TASM, de exemplu) este bine

Page 31: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

31

să o facem. La fel în cadrul programării mixte, la scrierea unor funcţii în limbaj de asamblare, este indicat ca fiecare instrucţiune să fie urmată de un comentariu (asm … , acest stil de programare este de altfel scopul acestei cărţi). Pentru a înţelege modul de utilizare concretă a serviciilor BIOS şi DOS, asamblăm şi salvăm următorul program.

-a 1371:0100 mov cx,0 ; linia / coloana colţul stânga sus 1371:0103 mov dx,184f ; linia / coloana colţul dreapta jos 1371:0106 mov bh,70 ; atributul liniilor blank 1371:0108 mov ax,600 ; fixăm serviciul, scroll page up 1371:010B int 10 ; invocare întrerupere BIOS 1371:010D mov dx,119 ; adresa offset a primului caracter al

; şirului de tipărit 1371:0110 mov ah,09 ; fixăm serviciul, tipăreşte şir de

; caractere până la caracterul “$” ; (end of string, EOS)

1371:0112 int 21 ; invocare întrerupere DOS 1371:0114 mov ax,4c00 ; fixăm serviciul, exit 1371:0117 int 21 ; invocare întrerupere DOS 1371:0119 db "Hello World !" ; db, pseudo-instrucţiune, şirul de tipărit ; 1371:0126 db 0a,0d,0a,0d,"$" ; caractere de control, LF (line feed),

; CR (carriage return), …, EOS 1371:012B -rcx CX 0000 :2b -nhello.com -w Writing 0002B bytes

Tastăm în continuare următoarea comandă: -g112 AX=0900 BX=7000 CX=0000 DX=0119 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=1371 IP=0112 NV UP EI PL NZ NA PO NC 1371:0112 CD21 INT 21 -t AX=0900 BX=7000 CX=0000 DX=0119 SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1371 ES=1371 SS=1371 CS=095F IP=042F NV UP DI PL NZ NA PO NC 095F:042F EAA0045102 JMP 0251:04A0 -

şi analizăm conţinutul regiştrilor CS:IP şi SP. Constatăm respectarea tuturor anticipaţiilor făcute pentru serviciile DOS legate de INT 21h şi de această dată flag-ul interrupt s-a modificat (adică, întreruperile au fost dezactivate).

Page 32: Microprocesoare Si Microcontrolere

32 Programe Simple în Limbaj de Asamblare

De fiecare dată asamblarea s-a făcut automat începând cu adresa offset 100h. Pentru a vedea ce este până la această adresă tastăm comanda q urmată de exit şi apoi lansăm utilitarul DEBUG. Tastăm în continuare următoarele comenzi:

-nhello.com -l -d0 1393:0000 CD 20 00 A0 00 9A F0 FE-1D F0 4F 03 F6 0C 8A 03 . ........O..... 1393:0010 F6 0C 17 03 F6 0C E5 0C-01 01 01 00 02 FF FF FF ................ 1393:0020 FF FF FF FF FF FF FF FF-FF FF FF FF 82 13 5E 3E ..............^> 1393:0030 F6 0C 14 00 18 00 93 13-FF FF FF FF 00 00 00 00 ................ 1393:0040 07 0A 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 48 45 4C .!...........HEL 1393:0060 4C 4F 20 20 20 43 4F 4D-00 00 00 00 00 20 20 20 LO COM..... 1393:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00 ........ -d 1393:0080 09 48 45 4C 4C 4F 2E 43-4F 4D 0D 00 00 00 00 00 .HELLO.COM...... 1393:0090 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00B0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00C0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00D0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ -d 1393:0100 B9 00 00 BA 4F 18 B7 70-B8 00 06 CD 10 BA 19 01 ....O..p........ 1393:0110 B4 09 CD 21 B8 00 4C CD-21 48 65 6C 6C 6F 20 57 ...!..L.!Hello W 1393:0120 6F 72 6C 64 20 21 0A 0D-0A 0D 24 01 06 5B E2 C3 orld !....$..[.. 1393:0130 53 8B 1E 5F E2 80 BF 64-E3 5C 74 12 80 BF 64 E3 S.._...d.\t...d. 1393:0140 3A 74 0B C6 87 65 E3 5C-43 83 06 5F E2 01 C7 06 :t...e.\C.._.... 1393:0150 59 E2 65 E3 01 1E 59 E2-80 3E 5D E2 00 75 0D C7 Y.e...Y..>]..u.. 1393:0160 87 65 E3 2A 2E 43 43 83-06 5F E2 02 C7 87 65 E3 .e.*.CC.._....e. 1393:0170 2A 00 83 06 5F E2 01 5B-C3 57 8B 3E 5B E2 AC AA *..._..[.W.>[... -

şi putem admira conţinutul memoriei în zona de adrese offset 0h - 17Fh. Blocul de memorie cuprins între adresele offset 00h şi FFh se numeşte PSP (Program Status Prefix). Acest bloc este construit de sistemul de operare la încărcarea programului şi conţine informaţii vitale despre programul ce urmează a fi rulat. Totodată, acest bloc oferă puntea de legătură între program şi resursele soft oferite de sistemul de operare. Linia de comandă (de la prompterul DOS) care lansează programul în execuţie este împărţită în nume, parametrii şi opţiuni.

Tot ce urmează numelui, până la terminator ([CR]), va fi copiat şi în PSP începănd cu poziţia 81h, în forma ASCII. Lungimea acestor informaţii este încărcată în octetul de pe poziţia 80h. De aici programul va copia aceste informaţii şi le va folosi în cadrul task-urilor programului. Începând cu adresa offset 100h putem vedea forma cod-maşină a programului. Pentru a vedea legătura dintre

Page 33: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

33

program şi sistemul de operare făcută prin PSP, modificăm programul astfel (este şi un prim exerciţiu de reverse-engineering, nu vom plăti daune nici unei firme deoarece programul HELLO.COM este produsul nostru):

-u100 1393:0100 B90000 MOV CX,0000 1393:0103 BA4F18 MOV DX,184F 1393:0106 B770 MOV BH,70 1393:0108 B80006 MOV AX,0600 1393:010B CD10 INT 10 1393:010D BA1901 MOV DX,0119 1393:0110 B409 MOV AH,09 1393:0112 CD21 INT 21 1393:0114 B8004C MOV AX,4C00 1393:0117 CD21 INT 21 1393:0119 48 DEC AX 1393:011A 65 DB 65 1393:011B 6C DB 6C 1393:011C 6C DB 6C 1393:011D 6F DB 6F 1393:011E 20576F AND [BX+6F],DL

Pentru început să ne convingem că programul nu a suferit modificări. Începând cu adresa 119h este şirul ce urmează să fie tipărit pe ecranul calculatorului. Dar acest lucru nu-l ştie desasamblorul şi cu atât mai puţin microprocesorul. Aceste maşini stupide sunt gata să interpreteze şi să execute orice număr găsit în segmentul de cod. Aşa că, pentru ele orice număr este un posibil opcode sau pseudo-instrucţiune. Începând cu adresa offset 114h a programului ne pregătim de ieşire (cu pace să ieşim …) şi realizăm efectiv acest lucru prin invocarea unui serviciu DOS. Modificăm această zonă a programului astfel:

-a114 1393:0114 ret 1393:0115 -u100 1393:0100 B90000 MOV CX,0000 1393:0103 BA4F18 MOV DX,184F 1393:0106 B770 MOV BH,70 1393:0108 B80006 MOV AX,0600 1393:010B CD10 INT 10 1393:010D BA1901 MOV DX,0119 1393:0110 B409 MOV AH,09 1393:0112 CD21 INT 21 1393:0114 C3 RET 1393:0115 004CCD ADD [SI-33],CL 1393:0118 214865 AND [BX+SI+65],CX 1393:011B 6C DB 6C 1393:011C 6C DB 6C 1393:011D 6F DB 6F

Page 34: Microprocesoare Si Microcontrolere

34 Programe Simple în Limbaj de Asamblare

1393:011E 20576F AND [BX+6F],DL

şi observăm modul în care a fost translatată această nouă instrucţiune (RET, RETurn). Opcod-ul său este numai de un octet aşa că zona de patru octeţi cuprinsă între adresele de offset 115h şi 118h va rămâne practic izolată.

Este uşor de bănuit că se va întoarce undeva, pentru a afla unde tastăm comanda

-g114 Hello World ! AX=0924 BX=7000 CX=0000 DX=0119 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0114 NV UP EI PL NZ NA PO NC 1393:0114 C3 RET -t AX=0924 BX=7000 CX=0000 DX=0119 SP=0000 BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0000 NV UP EI PL NZ NA PO NC 1393:0000 CD20 INT 20 -t AX=0924 BX=7000 CX=0000 DX=0119 SP=FFFA BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=00C9 IP=0FA8 NV UP DI PL NZ NA PO NC 00C9:0FA8 90 NOP -g Program terminated normally -

şi ne îndreptăm ca de obicei atenţia spre regiştrii şi flag-urile microprocesorului (adică, spre tot ce are). Constatăm o surprinzătoare modificare a registrului IP astfel încât pointează la adresa 0h, adică la începutul PSP-ului. Aici microprocesorul a descoperit opcod-ul instrucţiunii INT 20 (terminare program). Cu ajutorul comenzii g trecem peste această procedură. Descoperiţi singuri în tabela vectorilor de întrerupere, valoarea din regiştrii CS:IP, cu scopul de a determina adresa fizică a rutinei ce asigură acest serviciu. În concluzie, putem spune că la începutul PSP-ului, pe primi doi octeţi sistemul de operare pune opcod-ul instrucţiuni INT 20. Este bine să ştim că pe următorii doi octeţi este specificată lungimea programului exprimată în multiplii de 16 octeţi. Deşi funcţionează corect, pentru compatibilitate este preferată versiunea iniţială a programului. De altfel, din motive de siguranţă vom utiliza pe cât este posibil întreruperile şi funcţiile DOS.

Pentru a încheia ziua de muncă, tastăm comanda q urmată de exit, apoi de la promterul MS-DOS lansăm în execuţie programul zilei.

Page 35: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

35

C:\Mm>hello

Page 36: Microprocesoare Si Microcontrolere

36 Programe Simple în Limbaj de Asamblare

Page 37: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

37

3. Circuite Specializate Programabile

Un embedded system fără periferice de intrare/ieşire este ca o casă fără uşi şi ferestre. Nu putem să ne lipsim de uşi şi ferestre pentru că locuinţa ar deveni inutilă. Similar, un embedded system (un calculator IBM PC, în acest caz) nu are sens fără o periferie de intrare/ieşire. De altfel, încă de la început, odată cu microprocesoarele au fost concepute şi unele circuite specializate pentru periferie. Aşa că, fiecare firmă a realizat o serie de circuite specializate (pentru un domeniu specific de aplicaţii) programabile pentru o familie dată de microprocesoare.

Deoarece transferul câte unui byte s-a considerat acceptabil pentru perifericele uzuale, familia de microprocesoare 80X86 (de la Intel) a moştenit practic nemodificate circuitele specializate programabile ale microprocesorului 8080 (primul microprocesor "adevărat" de 8 biţi). Este probabil greu de înţeles legătura dintre conceptul de circuit specializat şi cel de circuit programabil. Să ne imaginăm un membru al unui partid politic, el este specializat în măsura în care promovează politica partidului şi programabil atunci când trebuie să voteze.

Să încercăm să ne dezmorţim puţin şi să lansăm în execuţie utilitarul DEBUG. Tastăm următoarele comenzi şi secvenţe de instrucţiuni: -a 1371:0100 mov ah,02 ; fixăm serviciul, scrie caracter la consolă 1371:0102 mov dl,07 ; codul ASCII al caracterului BEL 1371:0104 int 21 ; invocăm întrerupere DOS 1371:0106 mov ax,4c00 ; fixăm serviciul, exit 1371:0109 int 21 ; invocăm întrerupere DOS 1371:010B -nbeep1.com -rcx CX 0000 :b -w Writing 0000B bytes -q

De la prompterul MS-DOS lansăm în execuţie programul realizat (beep1.com). Dacă calculatorul pe care lucrăm are placă de sunet, să nu uităm să conectăm boxele. După cum era uşor de bănuit, caracterul ASCII 7h numit BEL nu este tipărit, el produce un sunet în difuzor. Noi am auzit efectul rulării programului beep1.com datorită faptului că există un periferic specializat în producerea de sunete.

Page 38: Microprocesoare Si Microcontrolere

38 Circuite Specializate Programabile

Mai înainte de a vedea dacă acest periferic este şi programabil să ne mai antrenăm puţin în scrierea de programe în limbaj de asamblare. Lansăm în execuţie utilitarul DEBUG şi realizăm programul beep2.com. -a 1371:0100 jmp 119 ; salt necondiţionat la add. offset 119h 1371:0102 mov ah,02 ; fixăm serviciul, - subrutina - scrie BEL 1371:0104 mov dl,07 ; codul ASCII al caracterului BEL 1371:0106 int 21 ; invocăm întrerupere DOS 1371:0108 ret ; return, subrutina scrie BEL 1371:0109 mov bx,01ff ; subrutina delay, în BX număr repetări loop 1371:010C mov cx,ffff ; în CX număr de repetări în loop 1371:010F nop ; nu face nimic, consumăm timp 1371:0110 loopnz 10f ; dacă CX > 0, repetă de la adresa offset 10Fh 1371:0112 dec bx ; decrementăm DX 1371:0113 cmp bx,0000 ; este BX = 0h 1371:0116 jnz 10c ; dacă este diferit de 0h salt la 10Ch 1371:0118 ret ; return, subrutina delay 1371:0119 call 102 ; aici sare jmp, apelăm subrutina - scrie BEL 1371:011C call 109 ; apelăm subrutina delay 1371:011F call 102 ; apelăm subrutina - scrie BEL 1371:0122 mov ax,4c00 ; fixăm seviciul, exit 1371:0125 int 21 ; invocăm întrerupere DOS 1371:0127 -nbeep2.com -rcx CX 0000 :27 -w Writing 00027 bytes -q

De la prompterul MS-DOS lansăm programul beep2.com în execuţie şi ascultăm cu atenţie. Dar dacă auzim trebuie să şi înţelegem instrucţiunile din precedentul program.

Prin subrutină se înţelege o secvenţă de instrucţiuni, scrisă separat, care poate fi apelată din diferite puncte ale unui program. Subrutinele grupează unele secvenţe de instrucţiuni care sunt frecvent apelate, eventual cu parametri diferiţi. Parametrii pot fi transferaţi prin regiştri sau prin stivă. Mecanismul de implementare a subrutinelor este realizat cu ajutorul instrucţiunilor CALL şi RET. Subrutinele se pot găsi în acelaşi segment cu programul apelant (apelare intrasegment - near) sau în segmente diferite (apelare intersegment – far). Pentru cele două cazuri, avem mnemonice diferite, aşa că vor fi generate opcod-uri diferite. Când se face un CALL, adresa unde urmează să se facă întoarcerea (adresa următoarei instrucţiuni) este copiată pe stivă. Când se face întoarcerea prin RET, acea adresă este scoasă din stivă reîncărcând registrul IP.

Page 39: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

39

Mai mult, subrutinele pot fi imbricate, adică o subrutină poate apela o altă subrutină. Folosirea stivei permite acest lucru. Astfel, primul RET va fi pereche cu ultimul CALL. Reţinem, apelurile intrasegment salvează doar offset-ul adresei de revenire. La RET această valoare se reîncarcă în registrul IP. Apelurile intersegment salvează atât conţinutul registrului segment CS, cât şi offset-ul din registrul IP; la RETF ambele sunt reactualizate. În cazul în care, subrutina alterează (foloseşte) regiştrii a căror conţinut este necesar în programul apelant, aceşti regiştrii sunt salvaţi şi ei pe stivă, cu PUSH. După revenire, valorile lor sunt refăcute cu POP, de regulă în ordinea inversă salvării. Dacă utilizăm asamblorul din utilitarul DEBUG este bine să scriem prima dată subrutinele, pentru a şti ulterior care este adresa de offset a acestora. Pentru a trece peste această parte a programului folosim o intrucţiune de salt necondiţionat.

Implementarea buclelor (ciclurilor) într-un program se face cu instrucţiuni LOOP. Registrul CX este iniţializat cu numărul de repetări şi la fiecare executare a unei instrucţiuni LOOP este decrementat cu o unitate. Condiţia de ieşire din buclă este de regulă dată de evaluarea automată a conţinutului registrului CX.

Subrutinele de întârziere (delay) sunt esenţiale pentru realizarea unor temporizări într-o aplicaţie dată. De asemenea, ele sunt importante în etapa de punere la punct a unui program care lucrează cu un periferic. Acest lucru se datorează vitezei mari de execuţie a intrucţiunilor. La o rulare normală este posibil să nu putem observa nimic prin intermediul simţurilor noastre. După cum uşor se poate constata., explicaţiile devin din ce în ce mai generale (să nu uităm de anexa A). Acest lucru se datorează experienţei pe care o avem în exploatarea utilitarului DEBUG. Toate aceste programe pot fi rulate pas cu pas (trace) urmărind cu atenţie ce se întâmplă. Scopul este să învăţăm, lucrând tot timpul la calculator. Un exemplu de utilizare inteligentă a comenziilor utilitarului DEBUG va fi prezentată în continuare. Noi ştim ce va face programul pe măsură ce fiecare instrucţiune este scrisă, aşa că trebuie doar să ne convingem că microprocesorul ajunge în fiecare etapă la starea anticipată de noi. C:\Mm>debug -nbeep2.com -l -u 1393:0100 EB17 JMP 0119 1393:0102 B402 MOV AH,02 1393:0104 B207 MOV DL,07 1393:0106 CD21 INT 21 1393:0108 C3 RET 1393:0109 BBFF01 MOV BX,01FF 1393:010C B9FFFF MOV CX,FFFF 1393:010F 90 NOP

Page 40: Microprocesoare Si Microcontrolere

40 Circuite Specializate Programabile

1393:0110 E0FD LOOPNZ 010F 1393:0112 4B DEC BX 1393:0113 83FB00 CMP BX,+00 1393:0116 75F4 JNZ 010C 1393:0118 C3 RET 1393:0119 E8E6FF CALL 0102 1393:011C E8EAFF CALL 0109 1393:011F E8E0FF CALL 0102 -u 1393:0122 B8004C MOV AX,4C00 1393:0125 CD21 INT 21 1393:0127 010659E2 ADD [E259],AX 1393:012B 01065BE2 ADD [E25B],AX 1393:012F C3 RET 1393:0130 53 PUSH BX 1393:0131 8B1E5FE2 MOV BX,[E25F] 1393:0135 80BF64E35C CMP BYTE PTR [BX+E364],5C 1393:013A 7412 JZ 014E 1393:013C 80BF64E33A CMP BYTE PTR [BX+E364],3A 1393:0141 740B JZ 014E -r AX=0000 BX=0000 CX=0027 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0100 NV UP EI PL NZ NA PO NC 1393:0100 EB17 JMP 0119 -t AX=0000 BX=0000 CX=0027 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0119 NV UP EI PL NZ NA PO NC 1393:0119 E8E6FF CALL 0102 -t AX=0000 BX=0000 CX=0027 DX=0000 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0102 NV UP EI PL NZ NA PO NC 1393:0102 B402 MOV AH,02 -t AX=0200 BX=0000 CX=0027 DX=0000 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0104 NV UP EI PL NZ NA PO NC 1393:0104 B207 MOV DL,07 -t AX=0200 BX=0000 CX=0027 DX=0007 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0106 NV UP EI PL NZ NA PO NC 1393:0106 CD21 INT 21 -t=108 AX=0200 BX=0000 CX=0027 DX=0007 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=011C NV UP EI PL NZ NA PO NC 1393:011C E8EAFF CALL 0109 -t AX=0200 BX=0000 CX=0027 DX=0007 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0109 NV UP EI PL NZ NA PO NC

Page 41: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

41

1393:0109 BBFF01 MOV BX,01FF -t AX=0200 BX=01FF CX=0027 DX=0007 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=010C NV UP EI PL NZ NA PO NC 1393:010C B9FFFF MOV CX,FFFF -t AX=0200 BX=01FF CX=FFFF DX=0007 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=010F NV UP EI PL NZ NA PO NC 1393:010F 90 NOP -t AX=0200 BX=01FF CX=FFFF DX=0007 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0110 NV UP EI PL NZ NA PO NC 1393:0110 E0FD LOOPNZ 010F -t AX=0200 BX=01FF CX=FFFE DX=0007 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=010F NV UP EI PL NZ NA PO NC 1393:010F 90 NOP -t AX=0200 BX=01FF CX=FFFE DX=0007 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0110 NV UP EI PL NZ NA PO NC 1393:0110 E0FD LOOPNZ 010F -t=118 AX=0200 BX=01FF CX=FFFE DX=0007 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=011F NV UP EI PL NZ NA PO NC 1393:011F E8E0FF CALL 0102 -t=122 AX=4C00 BX=01FF CX=FFFE DX=0007 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0125 NV UP EI PL NZ NA PO NC 1393:0125 CD21 INT 21 -g Program terminated normally -

Dacă pe aceste programe facem experienţe, trebuie să lucrăm cu atenţie. Numai astfel, nu vom bloca calculatorul (oricum nu se va strica fizic). Sfat: numai şi numai dacă nu reuşim prin CTRL-ALT-DEL urmat de [End-Task] vom apăsa butonul RESET.

De exemplu, funcţie de calculatorul pe care lucrăm va trebui să fixăm parametrul din registrul BX. Prin acest parametru stabilim numărul de repetări pentru bucla pricipală (de la adresa offset 109h) a subrutinei de întîrziere din programul precedent. Această valoare depinde de performanţele reale ale calculatorului (frecvenţa de tact, clock, ceas) pe care lucrăm. Dacă nu ne convine

Page 42: Microprocesoare Si Microcontrolere

42 Circuite Specializate Programabile

parametrul actual nu vom rescrie tot programul. Pentru aceasta putem proceda în felul următor: C:\Mm>debug -nbeep2.com -l -a109 1393:0109 mov bx,17f 1393:010C -w Writing 00027 bytes -q C:\Mm>beep2

Toate programele realizate până în acest moment nu conţin o condiţie explicită de ieşire (exit). Aşa că după ce toate celelalte sarcini ale progamului au fost realizate, ieşirea din program este de fapt ultimul serviciu pe care programul îl cere sistemului de operare. Ieşirea din program poate fi însă legată de o condiţie externă, cum ar fi de exemplu apăsarea unei taste. Un astfel de program continuă să execute într-o buclă diverse sarcini până la îndeplinirea unei condiţii. Programul beep3.com prezentat în continuare este o buclă cu ieşirea condiţionată de apăsarea unei taste (serviciul BIOS, INT 16h, AH = 01h). In cadrul acestei bucle după scrierea la consolă a caracterului BEL (07h) urmează o secvenţă de întârziere. La ieşirea din buclă se află secvenţa de ieşire prin care este invocată funcţia exit din DOS. -a 1371:0100 mov ah,02 1371:0102 mov dl,07 1371:0104 int 21 1371:0106 mov bx,00ff 1371:0109 mov cx,ffff 1371:010C nop 1371:010D loopnz 10c 1371:010F dec bx 1371:0110 cmp bx,0000 1371:0113 jnz 109 1371:0115 mov ah,01 ;fixăm serviciul solicitat, stare tastatură 1371:0117 int 16 ;invocăm întrerupere BIOS, poziţionează fanion 1371:0119 jz 100 ;dacă nu este apasată tastă salt la 100h 1371:011B mov ax,4c00 ;altfel, fixăm exit 1371:011E int 21 ;invocăm întrerupere DOS 1371:0120 -nbeep3.com -rcx CX 0000 :20

Page 43: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

43

-w Writing 00020 bytes -

Prin rularea acestui program putem observa că timpul dintre două sunete nu este întotdeauna acelaşi. Din analiza programului nu putem oferi o explicaţie acestui fenomen. Explicaţia este, fără îndoială, legată de mecanismul de întreruperi externe. Microprocesorul nu se ocupă numai de rularea programului nostru, el mai rezolvă între timp (adică furând din timpul programului nostru) o serie de alte task-uri/evenimente care ţin de funcţionarea calculatorului. O comportare asemănătoare poate fi observată şi în alte programe care folosesc secvenţe de întârziere realizate prin software. O primă etapă a antrenamentului de scriere a unor programe în limbaj de asamblare este în acest moment încheiată. Acum avem suficiente cunoştiinţe de programare în limbaj de asamblare pentru a aborda unul din cele mai vechi circuite specializate programabile 8255 (PPI, Programmable Peripheral Interface). Acest circuit se afla fizic pe placa de bază a primelor calculatoare IBM PC. Pentru compatibilitate, funcţiile acestui circuit au fost preluate de circuitele moderne care tind să integreze toate circuitele clasice într-un singur chip. Orice circuit de periferie are un număr de port-uri, prin intermediul cărora acesta schimbă informaţie cu exteriorul (operaţii de intrare/ieşire, I/O). Port-urile sunt un alt fel de locaţii de memorie la care are acces atât microprocesorul cât şi periferia de intrare/ieşire. Port-urile sunt pentru microprocesor într-un spaţiu de adrese, separat de adresele de memorie. Accesul la acest spaţiu de memorie şi implicit la port-uri se face prin instrucţiuni specifice de lucru cu acestea. De altfel, la familiile de microprocesoare dezvoltate de firma Motorola nu se face această distincţie, aşa că port-urile sunt accesate prin aceleaşi instrucţiuni care sunt utilizate pentru operaţiile cu memoria.

In cazul circuitului 8255 port-urile au câte 8 biţi fiecare şi din exterior sunt văzute ca fiind port-urile A, B şi respectiv C. Port-urile A, B şi C ale circuitului 8255 aflat pe Mother Board-ul unui calculator IBM PC sunt accesate prin următoarele adrese de port: 60h, 61h, 62h. Modul de lucru al fiecărui port (intrare, ieşire sau alte funcţii specifice unui protocol de transfer) este stabilit prin intermediul Registrului de Control de la adresa 63h. Circuitul 8255 este frecvent utilizat în aplicaţiile de achiziţie de date şi control implementate cu ajutorul calculatoarelor IBM PC. Acest lucru se datorează atât simplităţii sale cât şi compatibilităţii cu familia 80X86 de microprocesoare. Trebuie subliniat faptul că longevitatea circuitului se datorează în mare parte carierei sale didactice. De altfel, există o serie de alte circuite (produse de Motorola, Zilog, Mostek) care asigură

Page 44: Microprocesoare Si Microcontrolere

44 Circuite Specializate Programabile

mult mai multe funcţii decât acest circuit. Nu de puţine ori în acest domeniu s-a întâmplat ca cel mai utilizat circuit să nu fie neapărat şi cel mai performant. 8255 este un circuit programabil de interfaţă paralelă. El are trei părţi care trebuie bine cunoscute pentru o apreciere şi o utilizare corectă: interfaţa spre procesor, interfaţa spre periferie şi circuitele interne (registrele). Toate aceste componente sunt puse în evidenţă în figura 3.1. Transferul datelor la şi de la circuit se face pe o magistrala de date organizată pe 8 biţi.

Figura 3.1. 8255 - PPI diagrama bloc. Protocolul transferului este asigurat de semnalele de pe magistrala de comandă (CS - Chip Select , RD - ReaD, WR - WRite) respectiv magistrala de adresă (A0,A1). Nu este greu să ne imaginăm că numai îndeplinirea simultană a condiţiilor implicate de semnalele precedente asigură activarea circuitului 8255.

În acest fel, prin intermediul unor decodificatoare (hardware) pot fi accesate pe aceeaşi magistrală de date (un număr de linii cu aceeaşi funcţie) circuite diferite

PB7

D0

D1PA0

D3

D4

D5

D6

D7

/RD

D2

PA7

A1

A0

RESET

/CS

/WR

PB7

PC7

PC0

Registrul de Control

8255 - PPI

PB0

Page 45: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

45

aflate la adrese diferite. Interfaţa cu periferia conţine 24 de linii I/O. Caracteristicile şi rolul liniilor de interfaţă sunt funcţie de modul de operare care se selectează sub controlul programului. Toate acestea sunt sumar prezentate în tabelul 3.1. Modul 0. În modul 0, oricare din port-uri poate fi folosit fie ca registru de ieşire, fie ca un registru de intrare. Modul 1. Modul intrare-ieşire strobată. În acest mod, port-ul A şi B utilizează liniile port-ului C pentru semnalele de control ale transferului (handshaking signals). Aceste semnale sunt: STB, IBF (Input Buffer Full) şi INTR (Interrupt Request) pentru controlul intrărilor şi OBF (Output Buffer Full), ACK (Acknowledge), INTR pentru controlul ieşirilor.

Tabelul 3.1

PIN MODUL 0 MODUL 1 MODUL 2 IN OUT IN OUT IN-OUT

PA0 - PA7 * * * * * PB0 -PB7 * * * * Neutilizat

PC0 * * INTRB INTRB I/O PC1 * * IBFB OBFB I/O PC2 * * STBB ACKB I/O PC3 * * INTRA INTRA INTRA PC4 * * STBA * STBA PC5 * * IFBA * IBFA PC6 * * * ACKA ACKA PC7 * * * OBFA OBFA

Pentru cazul în care datele vin de la periferic împreună cu semnalul de strob

(STB), acestea sunt înscrise (de STB) în registrul tampon intern semnalizând aceasta prin semnalul IBF şi INTR. Semnalul IBF poate fi folosit pentru a confirma perifericului că data a fost preluată. Tot IBF ca stare a registrului intern poate fi testată citind portul C (PC5 - IBFA, PC1 - IBFB) în vederea unui transfer programat. Semnalul INTR poate fi folosit ca o cerere de întrerupere adresată microprocesorului pentru ca acesta să preia din 8255 data depusă de periferic. După ce microprocesorul depune în registrele port-ului A sau B o dată destinată unui periferic, el lasă protocolul de transfer pe seama lui 8255. Prezenţa datei în port este semnalizată perifericului prin semnalul OBF care poate fi folosit şi ca strob al datelor. Prin semnalul ACK, perifericul confirmă circuitului 8255 preluarea datei care dezactivează semnalul OBF şi activează semnalul INTR. Transferul poate fi complet sub controlul programului, prin transferarea byte cu byte în urma testării interne a portului C (PC7 - OBFA, PC1 - OBFB) sau folosind semnalul INTR pentru a întrerupe microprocesorul când perifericul este gata de a

Page 46: Microprocesoare Si Microcontrolere

46 Circuite Specializate Programabile

primi un nou byte. Pentru achitarea acestei cereri de întrerupere, microprocesorul sare la subrutina care asigură depunerea unui nou byte în registrul tampon corespunzător. Modul 2. Acest mod se referă numai la grupul de linii PA7-0, linii bidirecţionale (port A) şi 5 linii din port-ul C. Semnalele de control ale transferului, OBF, ACK, STB, IBF şi INTR sunt cele din modul 1 intrare-ieşire. Acestea asigură fluenţa transferului bidirecţional. În modul 2 port-ul A are afectate două registre care asigură simultan o operaţie de intrare şi una de ieşire. După depunerea datei în 8255 de către microprocesor, aceasta nu va afecta ieşirile portului A. Data depusă activează ieşirile portului A numai dacă perifericul doreşte preluarea ei (aică activează semnalul ACK). Perifericul poate să nu facă preluarea ci dimpotrivă, să depună o altă dată pentru microprocesor. Nici această dată nu va ajunge direct pe magistrala de date a microprocesorului, ci va fi zăvorâtă în registru, de unde va putea fi citită ulterior de către microprocesor. Modul de adresare şi tipurile de operaţii ale circuitului sunt prezentate în tabelul 3.2.

Tabelul 3.2

CS A1 A0 RD WR OPERAŢIA 0 0 0 0 1 Citeşte port-ul A 0 0 1 0 1 Citeşte port-ul B 0 1 0 0 1 Citeşte port-ul C 0 1 1 0 1 Operaţiune ilegală 0 0 0 1 0 Scrie în port-ul A 0 0 1 1 0 Scrie în port-ul B 0 1 0 1 0 Scrie în portul C 0 1 1 1 0 Scrie în Registrul de

Control 1 X X X X Magistrala de date trece în

impedanţă ridicată

Programarea modului de operare se face simplu printr-un singur byte de control, cu structura prezentată în tabelul 3.3. Citirea stării port-ului C în modul 1 şi 2 este utilă în cazul unui transfer de date dintre microprocesor şi periferic sub controlul programului. Formatul byte-ului de stare este dat în tabelul 3.4. Acest mod de transfer este mai lent şi de regulă se utilizează pentru un volum relativ mic de date. Singurul avantaj al acestui mod este de natură hardware; circuitul 8255 nu este particularizat pentru o anumită aplicaţie, ci este utilizat în acest caz, ca un circuit de interfaţă de uz general.

Page 47: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

47

Tabelul 3.3

D7 D6 D5 D4 D3 D2 D1 D0 1

Def. Mod

Grup A, 00-MOD 0 01 - MOD 1, 1X - MOD2

PA7-0 1/0-I/O

PC7-4 1/0-I/O

Grup B 1/0-I/O

PB7-0 1/0-I/O

PC3-0 1/0-I/O

În urma citirii conţinutului port-ului C, noi putem cunoaşte starea fiecărui transfer luând în program deciziile corespunzătoare.

Tabelul 3.4

D7 D6 D5 D4 D3 D2 D1 D0 MOD 1 IN I/O I/O IBFA INTEA INTRA INTEB IBFB INTRB MOD 1 OUT OBFA INTEA I/O I/O INTRA INTEB OBFB INTRB MOD 2 OBFA INTE1 IBFA INTE2 INTRA I/O I/O I/O

Circuitul 8255 asigură o serie de servicii (de exemplu, tastatură) la nivelul unui calculator IBM PC, printre acestea şi activarea/dezactivarea (PB1) ieşirii de sunet, după cum se poate vedea în figura 3.2. Deoarece acest proces de activare/dezactivare modifică starea logică de la ieşirea porţii spre difuzor (o poartă AND sau NAND), noi vom putea genera un semnal dreptunghiular.

Figura 3.2. Schema bloc pentru Speaker IBM PC.

Pentru ca acest semnal să fie în domeniul audio vom apela la o subrutină de întârziere. Utilizând comenzile utilitarului DEBUG vom scrie programul următor care se constituie într-un prim exemplu de utilizare a circuitului programabil 8255. Deoarece, în acest caz circuitul 8255 deserveşte mai multe periferice, intervenţiile

Speaker

&

PB1 - 8255

OUT2 - 8254, "1" logic

Page 48: Microprocesoare Si Microcontrolere

48 Circuite Specializate Programabile

noastre asupra conţinutului regiştrilor interni trebuie să fie minime. Acest lucru a fost realizat prin grupul de instrucţiuni de la adresa offset 109h - 10Dh, respectiv 112h - 116h. -a 1371:0100 jmp 109 ;jump la adresa de start, 109h 1371:0102 mov cx,8fff ;subrutina de întârziere 1371:0105 nop ; 1371:0106 loopnz 105 ; 1371:0108 ret ; 1371:0109 in al,61 ;citim valoare din port-ul B 1371:010B or al,02 ;modificăm numai PB1 - "1" logic 1371:010D out 61,al ;scriem noua valoare în port 1371:010F call 102 ;apelăm subrutina de întârziere 1371:0112 in al,61 ;citim valoare din port-ul B 1371:0114 and al,fd ;modificăm numai PB1 - "0" logic 1371:0116 out 61,al ;scriem noua valoare în port 1371:0118 call 102 ;apelăm subrutina de întârziere 1371:011B mov ah,01 ;fixăm serviciul solicitat, stare tastatură 1371:011D int 16 ;invocăm întrerupere BIOS, poziţionează fanion 1371:011F jz 109 ;dacă nu este apasată tastă salt la start 1371:0121 mov ax,4c00 ;altfel, fixăm exit 1371:0124 int 21 ;invocăm întrerupere DOS 1371:0126 -nppi.com -rcx CX 0000 :26 -w Writing 00026 bytes -

Desigur, modificarea parametrilor din subrutina de întârziere va determina frecvenţa semnalului dreptunghiular generat prin această metodă. Frecvenţa semnalului generat depinde de performanţele calculatorului utilizat şi desigur va fi modulată de intervenţia altor servicii pe care microprocesorul le va executa în acelaşi timp. O asemenea situaţie poate fi neplacută în diverse aplicaţii şi pe de altă parte, acest procedeu de generare a unui semnal audio este un bun exemplu de irosire a puterii microprocesorului. Pentru astfel de sarcini prezenţa unui circuit programabil specializat ar fi cea mai bună soluţie. Acest circuit există pe Mother Board-ul unui calculator IBM PC şi se numeşte 8254 (PIC, Programmable Interval Counter). Acest circuit este specializat pentru generarea şi contorizarea de impulsuri. Schema bloc a circuitului 8254 (compatibil cu versiunea iniţială 8253, această versiune are performanţe electrice modeste) este prezentată în figura 3.3. De altfel, circuitul 8254 este mai puţin versatil decât alte circuite similar

Page 49: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

49

specializate produse de alte firme. De asemenea, ca şi 8255 are merite didactice şi norocul de a fi utilizat în calculatoarele IBM PC.

Figura 3.1. 8254 - PIC diagrama bloc. Circuitul 8254 are 3 numărătoare (CouNTer) de 16 biţi (word)

independente; fiecare din ele poate fi înscris sau citit şi i se poate stabili un mod de funcţionare propriu. Cele 3 numărătoare (CNT0, CNT1, CNT2) se decrementează la fiecare impuls extern, evitându-se astfel decodificatoarele de coincidenţă. Modul de numărare poate fi în sistemul binar sau în sistemul ZCB, după modul stabilit prin byte-ul de control. Interfaţa spre microprocesor este identică cu a circuitului 8255, mai puţin semnalul de RESET. Prin magistrala de date este transferat în circuit byte-ul de control, respectiv valoarea de numărat. Acest transfer are loc sub controlul liniilor din magistrala de comandă şi adresă (CS, RD, WR, A0, A1). Adresa celor 3 numărătoare în cazul particular al unui calculator IBM PC este 40h, 41h, 42h, iar registrul de control se află la adresa 43h.

/RD

A1

A0

/CS

/WR

PB7

OUT2

CLK2

GATE2

D0

D1CLK0

D3

D4

D5

D6

D7

D2OUT0

CLK1

Registrul deControl

8254 - PIC GATE1

OUT1

GATE0

Page 50: Microprocesoare Si Microcontrolere

50 Circuite Specializate Programabile

Interfaţa cu periferia conţine câte o linie de tact CLK, o linie GATE şi o linie OUT pentru fiecare numărător (CLK0, CLK1, CLK2, GATE0, GATE1, GATE2, OUT0, OUT1, OUT2). Dacă linia de GATE este în "1" logic, atunci numărătorul respectiv este activat. Pentru fiecare numărător, ieşirea OUT indică momentul în care numărătorul a atins valoarea 0. Semnalul de ieşire este specific modului în care numărătorul a fost programat să funcţioneze. Fiecare numărător are nevoie de un singur byte de control pentru a i se stabili modul de funcţionare şi baza de numeraţie (binară sau ZCB). Deoarece adresarea este unică pentru oricare din cele trei numărătoare la care s-ar referi byte-ul de control, specificarea numărătorului (Counter) la care se referă este conţinută în chiar structura byte-ului (D7, D6). Pentru programator este importantă structura byte-ului de control, aceasta este prezentată în tabelul 3.5. Modul 0. Ieşirea numărătorului se pune pe "0" logic imediat după înscrierea byte-ului de control, iar numărătoarea inversă începe imediat după înscrierea valorii în numărător. Pe fiecare impuls de tact numărătorul se decrementează; la atingerea valorii 0 acesta îşi trece ieşirea în starea "1" logic. Intrarea GATE inhibă numărătoarea când este ţinută în "0" logic.

Tabelul 3.5

D7 D6 D5 D4 D3 D2 D1 D0 SC1 SC0 RL1 RL0 M2 M1 M0 BCD

00 - CNT0 01 - CNT1 10 - CNT2

00 - Load word 01 - Read low byte 10 - Read high byte 11 - Read word

000 - MOD0 001 - MOD1 010 - MOD2 011 - MOD3 100 - MOD4 101 - MOD5

0 - BIN 1 - ZCB

Modul 1 (monostabil declanşabil). Ieşirea OUT devine "0" pe primul clock după frontul pozitiv al intrării GATE şi rămâne în această stare până la terminarea numărătorii. Intrarea GATE poate fi folosită pentru redeclanşarea monostabilului. Fiecare front pozitiv aplicat intrării GATE va declanşa decrementarea valorii iniţiale din numărător. Dacă se înscrie o nouă valoare în timpul ciclului de numărare inversă, această valoare nu va afecta ciclul în desfăşurare. Modul 2 (multivibrator). În acest mod, ieşirea se pune la "0" pe durata unui impuls de tact (CLK) la sfârşitul fiecărei secvenţe de numărare, atâta timp cât semnalul de intrare GATE rămâne în "1" logic. Dacă o nouă valoare se înscrie în numărător în timpul desfăşurării modului 2, secvenţa curentă de decrementare se încheie fără nici

Page 51: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

51

o schimbare, iar secvenţa următoare va începe decrermentarea de la noua valoare depusă în numărător. Modul 3 (multivibrator cu factor de umplere 1/2). Acest mod este asemănător cu cel descris anterior, deosebirea constând în factorul de umplere. Dacă valoarea iniţială înscrisă în numărător este pară, ieşirea va sta jumătate de perioadă în starea "1" logic şi cealaltă jumătate în "0" logic, iar dacă este impară va sta (N+1)/2 perioade de tact în "1" logic şi (N-1)/2 perioade de tact în "0" logic. Modul 4. În acest mod, după înscrierea valorii în numărător începe decrementarea, şi numai la atingerea valorii 0, ieşirea trece în "0" logic pe durata unui impuls de tact. Intrarea GATE în "0" logic inhibă funcţionarea. Modul 5. Este asemănător cu cel descris anterior, cu observaţia că un front pozitiv pe intrarea GATE va declanşa numărătoarea. Valoarea "0" logic pe intrarea GATE nu inhibă o secvenţă deja declanşată.

Cu ajutorul utilitarului DEBUG să scriem un program care să genereze un semnal dreptunghiular în domeniul frecvenţelor audibile apelând la seviciul circuitului 8254. După cum se poate vedea în programul următor, pentru acest lucru vom utiliza numărătorul de la adresa 42h. Celelalte două numărătoare sunt utilizate pentru alte servicii de mare importanţă pentru funcţionarea întregului sistem (refreşarea memoriei DRAM, respectiv Ceasul de sistem). De asemenea, trebuie remarcat faptul că ieşirea PB0 a circuitului 8255 controlează intrarea GATE2 a circuitului 8254. Aşa că, pentru a produce un sunet în difuzor trebuie îndeplinite simultan două condiţii: poarta spre difuzor să fie deschisă (PB1 în "1" logic) şi intrarea GATE2 a circuitului 8254 să fie de asemenea în stare "1" logic (PB0 în "1" logic, adică numărătorul CNT2 nu este inhibat). -a 1371:0100 mov al,b6 ;fixăm byte-ul de control pentru 8254 1371:0102 out 43,al ;scriem byte-ul de control în reg. control 1371:0104 mov al,ff ;fixăm şi scriem în CNT2 numărul 0fffh 1371:0106 out 42,al 1371:0108 mov al,0f 1371:010A out 42,al 1371:010C in al,61 ;citim valoarea port-ului B, 8255 1371:010E or al,03 ;modificăm bit0,1 la "1" logic 1371:0110 out 61,al ;scriem noua valoare în port B 8255, sună! 1371:0112 mov ah,01 ;verificăm cond. exit 1371:0114 int 16 1371:0116 jz 112 ;dacă nu exit, salt la verifică cond. exit 1371:0118 in al,61 ;altfel, citim valoarea port-ului B, 8255 1371:011A and al,fc ;modificăm bit0,1 la "0" logic 1371:011C out 61,al ;scriem noua valoare în port B 8255, tace! 1371:011E mov ax,4c00 ;apel DOS exit 1371:0121 int 21 1371:0123

Page 52: Microprocesoare Si Microcontrolere

52 Circuite Specializate Programabile

-nctc1.com -rcx CX 001D :23 -w Writing 00023 bytes -

Rulăm pas cu pas (trace) programul precedent pentru a înţelege interacţiunea dintre microprocesor şi circuitele programabile 8254 şi 8255. Pentru a evita blocarea calculatorului este recomandabilă următoarea secvenţă de comenzi, care implică relansarea utilitarului DEBUG. C:\Mm>debug -nctc1.com -l -r AX=0000 BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0100 NV UP EI PL NZ NA PO NC 1393:0100 B0B6 MOV AL,B6 -t AX=00B6 BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0102 NV UP EI PL NZ NA PO NC 1393:0102 E643 OUT 43,AL -t AX=00FF BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0106 NV UP EI PL NZ NA PO NC 1393:0106 E642 OUT 42,AL -t AX=00FF BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0108 NV UP EI PL NZ NA PO NC 1393:0108 B00F MOV AL,0F -t AX=000F BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=010A NV UP EI PL NZ NA PO NC 1393:010A E642 OUT 42,AL -t AX=000F BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=010C NV UP EI PL NZ NA PO NC 1393:010C E461 IN AL,61 -t AX=003F BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0110 NV UP EI PL NZ NA PE NC 1393:0110 E661 OUT 61,AL -t

Page 53: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

53

În acest moment trebuie să auzim un sunet în difuzor. Cu această ocazie putem constata calitatea semnalului generat (stabilitatea frecvenţei, tonul) şi constatăm că, deşi pentru moment programul nu mai rulează (suntem în mod trace), semnalul este generat în continuare. Deoarece, de generarea semnalului cu parametri fixaţi (secvenţa de instrucţiuni de la adresa offset 104h - 10Ah) se ocupă circuitul 8254, singura preocupare a microprocesorului este de a verifica condiţia de ieşire (exit) din program; apăsarea unei taste (secvenţa de instrucţiuni de la adresa offset 112h - 116h). Cu următoarea comandă sărim peste subrutina serviciului BIOS, INT 16 AX=013F BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0114 NV UP EI PL NZ NA PE NC 1393:0114 CD16 INT 16 -t=116

şi rulăm în continuare pas cu pas să vedem ce se întâmplă. În modul rulare pas cu pas lucrul cu tastatura asigură automat condiţia de ieşire pentru program. AX=013F BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0118 NV UP EI PL NZ NA PE NC 1393:0118 E461 IN AL,61 -t AX=012C BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=011C NV UP EI PL NZ NA PO NC 1393:011C E661 OUT 61,AL -t

În acest moment nu mai auzim sunet în difuzor, ieşirea spre acesta a fost dezactivată, iar pe intrarea GATE2 a circuitului 8254 avem în acest moment "0" logic. Spunem că numărătorul a fost inhibat. Cu următoarea comandă trecem şi peste serviciul DOS invocat de INT 21. AX=4C00 BX=0000 CX=0023 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0121 NV UP EI PL NZ NA PO NC 1393:0121 CD21 INT 21 -g Program terminated normally -

Pentru a putea atinge stadiul de novice în domeniul embedded system să exersăm programarea în limbaj de asamblare, prin scrierea a două programe care produc efecte sonore de bază. Cu puţină imaginaţie, putem genera un sweep tip "dinte de fierăstrău" (semnal cu frecvenţa variabilă în timp). Un asemenea semnal ar putea fi, de exemplu, util în măsurarea benzii de trecere a unui amplificator audio

Page 54: Microprocesoare Si Microcontrolere

54 Circuite Specializate Programabile

sau incintă acustică. Cu ajutorul utilitarului DEBUG scriem, salvăm şi rulăm următorul program: -a 1371:0100 jmp 116 ;salt necondiţionat la start, 116h 1371:0102 mov al,b6 ;subrutină de initializare 8254 cu număr 1371:0104 out 43,al 1371:0106 mov ax,bx 1371:0108 out 42,al 1371:010A mov al,ah 1371:010C out 42,al 1371:010E ret ; 1371:010F mov cx,01ff ;subrutină de întârziere scurtă 1371:0112 nop 1371:0113 loopnz 112 1371:0115 ret ; 1371:0116 in al,61 ;start, citesc valoare port B 1371:0118 or al,03 1371:011A out 61,al ;activez ieşire difuzor, fixăm GATE2 - "1" 1371:011C mov bx,03ff ;fixăm valoare max. număr în reg. BX 1371:011F mov cx,02ff ;fixăm de câte ori să fie decrementat reg. BX 1371:0122 dec bx ;decrementăm BX 1371:0123 call 102 ;apelăm subrutină init. 8254 1371:0126 push cx ;salvăm valoarea din CX pe stivă 1371:0127 pushf ;idem fanioane, le distruge subrutina de întârziere 1371:0128 call 10f ;apelăm subrutina de întârziere 1371:012B popf ;refac fanione 1371:012C pop cx ;refac valoarea initială din CX 1371:012D loopnz 122 ;dacă valoarea din reg. CX nu este zero

;salt la 122h 1371:012F mov ah,01 ;verific condiţia de exit 1371:0131 int 16 1371:0133 jz 11c ;dacă nu exit atunci salt la offset 11Ch 1371:0135 in al,61 ;altfel dezactivăm, inhibăm 1371:0137 and al,fc 1371:0139 out 61,al 1371:013B mov ax,4c00 ;ieşire DOS 1371:013E int 21 1371:0140 -nctc2.com -rcx CX 0000 :40 -w Writing 00040 bytes -

Dacă modificăm puţin programul anterior, putem obţine un sweep "triunghiular". Din păcate orice modificare implică modificarea adreselor de offset. Utilitarul DEBUG a fost conceput pentru realizarea de aplicaţii simple, aplicaţiile

Page 55: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

55

scrise pentru un asamblor adevărat (MASM, TASM) sunt mult mai uşor de întreţinut şi/sau modificat. Pentru a nu mai complica lucrurile, vom scrie următorul program cu ajutorul comenzilor utilitarului DEBUG. Cu toate acestea este bine să aruncăm o privire asupra diferenţelor dintre cele două programe. -a 1371:0100 jmp 116 ;salt necondiţionat la start, 116h 1371:0102 mov al,b6 ;subrutină de initializare 8254 cu număr 1371:0104 out 43,al 1371:0106 mov ax,bx 1371:0108 out 42,al 1371:010A mov al,ah 1371:010C out 42,al 1371:010E ret ; 1371:010F mov cx,ffff ;subrutină de întârziere scurtă 1371:0112 nop 1371:0113 loopnz 112 1371:0115 ret ; 1371:0116 in al,61 ;start, citesc valoare port B 1371:0118 or al,03 1371:011A out 61,al ;activez ieşire difuzor, fixăm GATE2 - "1" 1371:011C mov bx,03ff ;idem secvenţa din cazul precedent 1371:011F mov cx,02ff 1371:0122 dec bx ;decrementez reg. BX 1371:0123 call 102 1371:0126 pushf 1371:0127 push cx 1371:0128 call 10f 1371:012B pop cx 1371:012C popf 1371:012D loopnz 122 1371:012F mov cx,02ff ;refac valoarea din reg. CX 1371:0132 inc bx ;incrementez reg. BX 1371:0133 call 102 1371:0136 push cx 1371:0137 pushf 1371:0138 call 10f 1371:013B popf 1371:013C pop cx 1371:013D loopnz 132 1371:013F mov ah,01 ;idem secvenţa din cazul precedent 1371:0141 int 16 1371:0143 jz 11c 1371:0145 in al,61 1371:0147 and al,fc 1371:0149 out 61,al 1371:014B mov ax,4c00 1371:014E int 21 1371:0150 -nctc3.com -rcx CX 0000

Page 56: Microprocesoare Si Microcontrolere

56 Circuite Specializate Programabile

:50 -w Writing 00050 bytes -

Probabil aceste două programe ne ridică câteva probleme pentru moment. În această etapă a cărţi, urmărind comentariile prezente în sursa programelor, ar trebui să înţelegem modul de funcţionare al acestora. După ce am înţeles programele (aplicaţiile) precedente putem să încercăm alte valori de start pentru numărătorul CNT2, sau numărul de decrementări şi/sau încrementări ale valorii de start (se poate apela la rularea pas cu pas a programelor, pentru aceasta vom utiliza cu inteligenţă comenzile utilitarului DEBUG). Aceste modificări nu implică rescrierea programului. Desigur, valorile posibile sunt în intervalul 0000h - FFFFh, dar nu pentru toate aceste valori vom obţine frecvenţe audibile ale semnalului generat. O altă modificare posibilă este valoarea iniţială a registrului CX din subrutina de întârziere şi de această dată jucându-ne cu aceste programe se pot învăţa multe.

În final, să aruncăm o privire în folder-ul (director-ul) Mm, pentru a dovedi că am lucrat ceva. C:\Mm>dir Volume in drive C is SYSTEM Volume Serial Number is 3871-17FF Directory of C:\Mm . <DIR> 02-06-00 11:36a . .. <DIR> 02-06-00 11:36a .. ASCII TXT 94 02-06-00 2:50p ascii.txt HELLO TXT 13 02-06-00 8:45p HELLO.TXT CLRSCR COM 19 02-07-00 10:00p CLRSCR.COM HELLO COM 43 02-07-00 10:21p HELLO.COM BEEP1 COM 11 02-12-00 4:53p BEEP1.COM BEEP2 COM 39 02-12-00 7:00p BEEP2.COM BEEP3 COM 23 02-14-00 7:46p BEEP3.COM CTC1 COM 35 02-15-00 7:10p CTC1.COM CTC2 COM 64 02-15-00 8:12p CTC2.COM CTC3 COM 80 02-15-00 8:11p CTC3.COM PPI COM 38 02-15-00 6:53p ppi.com 11 file(s) 459 bytes 2 dir(s) 1,987,710,976 bytes free C:\Mm>

Cu această ocazie, putem vedea cât de lungi sunt programele noastre. Cel mai lung program are 80 de bytes. Dacă scriem aceleaşi programe în limbajul C, vom înţelege de ce se spune că limbajul de asamblare foloseşte cel mai eficient resursele

Page 57: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

57

unui calculator. Desigur, avantajele sunt legate atât de spaţiul de memorie utilizat de program, cât şi de viteza de rulare a acestuia.

Scrierea unor aplicaţii complexe în limbaj de asamblare nu este productivă, dar nu de puţine ori, anumite părţi din program trebuie scrise în acest limbaj. După cum am mai spus, marele merit al limbajului de asamblare este faptul că ştim în fiecare moment ce face microprocesorul. Cu inteligenţă şi imaginaţie, nu de puţine ori, reuşim să realizăm aplicaţii care par incredibile pentru un programator care lucrează numai cu limbaje de nivel înalt.

Page 58: Microprocesoare Si Microcontrolere

58 Circuite Specializate Programabile

Page 59: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

59

4. Portul Paralel. Aplicaţii Simple Portul paralel este marele aliat al începătorului în domeniul achiziţiei de date şi control. Un mare număr de astfel de "specialişti" cred cu convingere că orice aplicaţie de achiziţie de date şi control se poate aborda prin intermediul portului paralel. Evident, acest lucru este adevărat ori de câte ori complexitatea problemei sau fluxul de date ce trebuie transferat nu depăşeşte posibilităţile reale ale acestuia. Oricum, o asemenea abordare a unei probleme de achiziţie de date şi control se vrea întodeauna o demonstraţie de ingeniozitate. Din păcate, suferă profesia pentru fericirea "specialistului". Reuşita nu face decât să demonstreze încă o dată cât de flexibilă şi adaptabilă este această tehnologie şi nu neapărat cât de mare este "specialistul". Trebuie recunoscut că acest atât de blamat port (până în anul 1994) are reale calităţi didactice, aşa că vom folosi şi noi portul paralel în primul rând pentru instruire. Nu de puţine ori o abordare ingenioasă, prin intermediul portului paralel, a unor probleme relativ complicate de achiziţie de date şi control a condus la aplicaţii incitante (cu portul paralel în mod EPP sau ECP ). În concluzie, nu trebuie să avem complexe că, în acest moment, suntem novici în domeniul embedded system. Important este să nu rămânem la acest nivel. Iar experienţele pe care le vom face pe portul paralel vor deveni în timp o amintire plăcută a copilăriei noastre în acest domeniu. Portul paralel este compus din 4 linii de control (Control Register), 5 linii de stare (Status Register), şi 8 linii de date (Data Register). Toate aceste linii sunt prezente de regulă pe partea din spate a carcasei PC-ului într-un conector de tip D25 (cu pin female, LPTx). Conectorul D25 cu pin male conţine liniile portului serial RS-232 care este organizat cu totul diferit faţă de portul paralel. Până în anul 1994 portul paralel nu a fost standardizat, deşi a oferit suport hardware pentru diverse periferice printer, scanner, drivere CD-ROM, cameră video, etc. Lipsa de standardizare a dus în timp la multe versiuni, de implementare a portului paralel, încât este greu de spus care este comportamentul real al portului paralel pentru un calculator no-name. De asemenea tehnologia utilizată la realizarea circuitelor driver pentru portul paralel a evoluat în timp de la TTL la CMOS. De toate acestea se poate face răspunzătoare firma IBM care pentru prima versiune a calculatorului IBM PC a limitat (nu cred că în mod intenţionat) utilizarea portului paralel la controlul unei imprimante (Centronics). Dacă portul paralel ar fi fost proiectat de la început pentru uz general (eventual cu transfer DMA (ECP) şi facilităţi de alimentare pentru hardware extern), alta ar fi fost istoria multor aplicaţii.

Page 60: Microprocesoare Si Microcontrolere

60 Portul Paralel. Aplicaţii Simple

Orice nouă versiune a portului paralel asigură compatibilitatea cu versiunea iniţială SPP (Standard Parallel Port) sau "Centronics Mode". În acest mod, datele sunt transferate într-o singură direcţie, de la calculator la periferic, cu o viteză de 50 bytes/secundă dar poate fi şi mai mare (depinde de periferic), până la 150 bytes/secundă. Pentru a citi date de la periferic avem în versiunea SPP la dispoziţie, cu siguranţă, modul Nibble. La unele versiuni este prezent şi modul Byte, dar nu putem conta pe această facilitate decât la calculatoarele produse relativ recent. În anul 1994 prin standardul IEEE 1284-1994 au fost definite 5 moduri de operare. Acestea sunt: • Centronics Mode. • Nibble Mode. • Byte Mode. • EPP Mode (Enhanced Parallel Port). • ECP Mode (Extended Capabilities Printer port). Tabelul 4.1

Pin Signal In/Out Register Inverted 1 Strobe Out Control # 2 Data 0 Out Data 3 Data 1 Out Data 4 Data 2 Out Data 5 Data 3 Out Data 6 Data 4 Out Data 7 Data 5 Out Data 8 Data 6 Out Data 9 Data 7 Out Data 10 Ack In Status 11 Busy In Status # 12 Paper Out / End In Status 13 Select In Status 14 Auto Linefeed In/Out Control # 15 Error /Fault In Status 16 Initialize In/Out Control 17 Select Printer In/Out Control # 18-25 Ground Gnd

Page 61: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

61

Modul de lucru pentru portul paralel este set-at în BIOS şi poate fi modificat în timpul secvenţei de initializare (boot). Pentru modurile EPP şi ECP transferurile sunt realizate fără intervenţia unor instrucţiuni de I/O din partea microprocesorului (viteza de transfer este de câţiva Mbytes/secundă). Un hardware specializat asigură în acest caz protocolul de transfer, este păstrată compatibitatea cu modul SPP. Pentru a nu avea surprize neplăcute (specifice calculatoarelor no-name) este bine să mizăm numai pe versiunea SPP a portului paralel. Semnificaţia pin-ilor portului paralel în mod SPP pentru un conector tip D25 female este prezentată în tabelul 4.1.

Unele dintre liniile din registrul Status şi Control sunt inversate la ieşirea/intrarea din registri portului paralel. De acest lucru trebuie ţinut cont fie la proiectarea hardware-ului extern, sau mai simplu (fără consum de componente), la scrierea programului. Liniile din Registrul de Control ar trebui să fie de tip Open Collector (Open Drain pentru CMOS), configuraţie ce permite transferul bidirecţional pe aceste patru linii; cu excepţia unor situaţii cu totul particulare această regulă nu este încălcată de producătorii de hardware. La unele caculatoare, portul paralel este suficient de evoluat (nu se poate miza pe acest lucru) pentru a putea folosi liniile din Registrul de Date pentru transfer bidirecţional. Dacă acest mod este disponibil Registrul de Control trebuie set-at cu valoarea 0010xxxx pentru a putea putea efectua operaţii de citire prin registrul de date.

Pentru a înţelege această ultimă informaţie trebuie să fim atenţi la semnificaţia biţilor din cele trei registre ale portului paralel. Tabelul 4.2 detaliază semnificaţia fiecărui bit din aceşti regiştri, pentru portul paralel utilizat în modul SPP. Pentru toate programele prezentate în continuare, noi vom face abstracţie de destinaţia iniţială a unor linii, aşa că vom privi portul paralel ca un port de uz general cu 8 linii de ieşire (Data Port) şi patru linii de intrare (Status Port).

Portul de Date sau Registrul de Date poate fi utilizat pentru a scoate date pe liniile portului paralel (Pin 2-9). În mod normal, acesta este un port numai pentru output. În această situaţie, dacă vom face o operaţie de citire noi vom primi valoarea ultimului byte încris (util în a testa hard-ul, byte-ul înscris trebuie să coincidă cu cel citit, utilizăm 00h şi ffh pentru a testa toate liniile portului). Dacă acest port este bi-direcţional atunci dacă scriem în port 00h şi facem enable bi-dir. (0010xxxx), fără a conecta nimic în port, trebuie să citim ffh. În cazul în care citim tot 00h, portul de date este unidirecţional. Portul Status sau Registrul Status este un port care poate numai citi date, sunt disponibile 5 linii de intrare (Pin 10-13, 15). Portul de Control sau registrul de Control a fost proiectat cu intenţia de a fi port de ieşire. Avem disponibile patru linii de control pentru imprimantă. De regulă,

Page 62: Microprocesoare Si Microcontrolere

62 Portul Paralel. Aplicaţii Simple

acest port este realizat fizic cu drivere Open Collector/Drain. Din acest motiv, el poate fi utilizat şi ca port de intrare respectând regula unei magistrale ŞI cablat (vom scrie mai întâi în port valoarea 00001111, adică 0fh pentru a nu falsifica datele de la intrarea portului).

Tabelul 4.2

Offset Name Read/Write Bit Number Properties Base + 0 Data Port Write or R/W if Bit 7 Data 7 Port is bi-dir. Bit 6 Data 6 Bit 5 Data 5 Bit 4 Data 4 Bit 3 Data 3 Bit 2 Data 2 Bit 1 Data 1 Bit 0 Data 0 Base + 1 Status

Port Read Only Bit 7 Busy

Bit 6 Ack Bit 5 Paper Out Bit 4 Select In Bit 3 Error Bit 2 IRQ (Not) Bit 1 Reserved Bit 0 Reserved Base + 2 Control

Port Read/Write Bit 7 Unused

Bit 6 Unused Bit 5 Enable bi-dir. Bit 4 Enable IRQ via

Ack Line Bit 3 Select Printer Bit 2 Reset Bit 1 Auto Linefeed Bit 0 Strobe

Pentru a face primele noastre experienţe legate de modul în care un embedded system interacţionează cu mediul înconjurător, vom realiza o extensie

Page 63: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

63

hardware care completează portul paralel cu elemente de execuţie (semnalizare, Led-uri), respectiv posibilitatea de a introduce diverse date din exterior. Schema acestei extensii este prezentată în figura 4.1. Capabilitatea de curent a portului paralel este scăzută, de aceea se înseriază cu LED-urile resistoare cu valoarea de 470 ohmi.

Figura 4.1. Schema extensiei pentru Portul Paralel.

Pentru a nu folosi o sursă externă de energie, nivelul de "1" logic la swich-urile de la Portul Status este asigurat de ieşirea Data 7 via resistoarele de 3,3 kohmi (Pin 9) cu rol de separare swich-uri (raportul 470/3300 nu afectează prea mult valoarea potenţialului din punctul comun de legătură). Aşa că vom set-a bitul 7 din Portul de Date pe "1" pentru a activa partea de input a extensiei.

Page 64: Microprocesoare Si Microcontrolere

64 Portul Paralel. Aplicaţii Simple

Pentru a vedea ce porturi paralele (pot fi două, numite LPT1 şi LPT2) avem instalate în calculatorul nostru şi care este adresa lor de bază apelăm la utilitarul DEBUG. -d0000:0400 0000:0400 F8 03 F8 02 00 00 00 00-78 03 00 00 00 00 00 00 ........x....... 0000:0410 23 C4 00 80 02 80 00 20-00 00 2A 00 2A 00 34 05 #...... ..*.*.4. 0000:0420 30 0B 30 0B 30 0B 08 0E-0D 1C 0D 1C 0D 1C E0 48 0.0.0..........H 0000:0430 64 20 30 0B 30 0B 30 0B-30 0B 3A 27 30 0B 00 00 d 0.0.0.0.:'0... 0000:0440 00 00 C0 00 00 00 00 00-00 03 50 00 00 10 00 00 ..........P..... 0000:0450 00 18 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0000:0460 0E 0D 00 D4 03 29 30 A4-17 7D 85 04 D4 4B 13 00 .....)0.....K.. 0000:0470 00 00 00 00 00 01 00 00-14 14 14 3C 01 01 01 01 ...........<.... -d 0000:0480 1E 00 3E 00 18 10 00 60-89 51 0B C9 58 01 00 01 ..>....`.Q..X... 0000:0490 07 07 00 00 00 00 10 02-00 00 00 00 00 00 00 00 ................ 0000:04A0 00 00 00 CE 00 00 C0 00-32 00 00 C0 10 10 00 00 ........2....... 0000:04B0 00 00 00 01 9B 00 44 00-00 00 05 00 00 00 00 00 ......D......... 0000:04C0 00 00 00 00 00 00 0A 00-00 00 00 00 00 00 00 00 ................ 0000:04D0 00 00 00 00 00 00 00 00-DC 04 00 00 00 00 00 00 ................ 0000:04E0 00 00 00 00 00 00 00 80-07 00 08 00 00 00 00 00 ................ 0000:04F0 AA 00 00 00 00 00 00 00-2A 00 A8 00 00 00 00 00 ........*....... -

Aceasta este o parte din zona de lucru a BIOS-ului, rezervată automat la iniţializarea sistemului. Multe din locaţiile acestei zone sunt iniţializate în acest moment. Prima zonă de date a BIOS-ului începe la adresa 0000:0400h. Datorită modului de generare a adresei fizice, această adresă poate fi specificată sub mai multe forme, două sunt cele mai utilizate: 0000:0400h şi 0040:0000h. Această zonă conţine date şi variabile utilizate de către BIOS, iar locaţiile la care se află acestea sunt fixate pentru a păstra compatibilitatea cu versiunile viitoare de BIOS. O parte din aceste locaţii nu au conţinutul specificat, ele sunt rezervate pentru viitoare evoluţii ale BIOS-ului. Fără a face o descriere completă a acestei zone (poate fi cel puţin subiectul unui capitol separat) reţinem câteva semnificaţii: 0000:0400 Adresa primului port serial RS - 232, COM1. 0000:0402 COM2 0000:0404 COM3 0000:0406 COM4 0000:0408 Adresa primului port paralel, LPT1 0000:040A LPT2 0000:040C LPT3 0000:040E LPT4 0000:0410 Lista echipamentelor instalatate .

.

.

Page 65: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

65

După cum se poate vedea în cazul acestui calculator avem două port-uri seriale (COM1, COM 2) cu adresele de bază 03F8h, 02F8 şi un singur port paralel cu adresa de bază 0378h. Nu este greu să deducem adresa pentru fiecare registru al portului paralel (Tabelul 4.2). Registrul de Date va avea adresa 0378h. Conţinutul Registrului Status va putea fi aflat dacă citim valoarea din portul de adresă 0379h, iar pentru Registrul de Control vom utiliza adresa 037Ah.

Figura 4.2. Realizarea practică a extensiei pentru Portul Paralel.

Înainte de a scrie câteva programe pentru portul paralel cu extensia din figura 4.1 reţinem că pentru porturile cu adresa mai mare de FFh nu mai este posibilă adresarea directă (exemplu; in al,61 toate porturile de pe Mother Board au adresa mai mică sau cel mult egală cu FFh). O altă ciudăţenie a microprocesoarelor Intel 80x86, care a fost moştenită din ani '70. Aşa că, pentru adresarea porturilor cu adresa mai mare de FFh se foloseşte adresarea indirectă prin intermediul registrului DX. Secvenţa de scriere în port-ul de adresă 0378h este: mov dx,378 mov al, data_byte

Page 66: Microprocesoare Si Microcontrolere

66 Portul Paralel. Aplicaţii Simple

out dx,al iar pentru citire din portul 0379h vom utiliza secvenţa de instrucţiuni:

mov dx,379 in al, dx. După ce conectăm în portul paralel (LPT1) extensia hardware prezentată în figura 4.2, lansăm în execuţie utilitarul DEBUG pentru a scrie următorul program. Atenţie, putem distruge portul paralel dacă placa de extensie are scurtcircuite între liniile Portului de Date (ieşirea acestuia este Totem pole). -a 1371:0100 jmp 117 1371:0102 mov bx,007f 1371:0105 mov cx,ffff 1371:0108 nop 1371:0109 loopnz 108 1371:010B dec bx 1371:010C cmp bx,0000 1371:010F jnz 105 1371:0111 ret 1371:0112 mov dx,378 1371:0115 out dx,al 1371:0116 ret 1371:0117 mov al,01 1371:0119 push ax 1371:011A pop ax 1371:011B call 112 1371:011E rol al,1 1371:0120 call 102 1371:0123 push ax 1371:0124 mov ah,01 1371:0126 int 16 1371:0128 jz 11a 1371:012A pop ax 1371:012B mov al,00 1371:012D call 112 1371:0130 mov ax,4c00 1371:0133 int 21 1371:0135 -npprl.com -rcx CX 0000 :35 -w Writing 00035 bytes -

Rulăm programul de la consolă şi trebuie să obţinem o lumină dinanică pe şirul de Led-uri (Jumper 1-2). Dacă sunt aspecte ale programului pe care nu le înţelegem, e simplu, rulăm programul pas cu pas (trace). În rest, nimic nou sub

Page 67: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

67

soare. Pentru a schimba sensul de rotaţie a luminii dimanice lansăm în execuţie utilitarul DEBUG şi scriem următoarele comenzi: C:\Mm>debug -npprl.com -l -u 1393:0100 EB15 JMP 0117 1393:0102 BB7F00 MOV BX,007F 1393:0105 B9FFFF MOV CX,FFFF 1393:0108 90 NOP 1393:0109 E0FD LOOPNZ 0108 1393:010B 4B DEC BX 1393:010C 83FB00 CMP BX,+00 1393:010F 75F4 JNZ 0105 1393:0111 C3 RET 1393:0112 BA7803 MOV DX,0378 1393:0115 EE OUT DX,AL 1393:0116 C3 RET 1393:0117 B001 MOV AL,01 1393:0119 50 PUSH AX 1393:011A 58 POP AX 1393:011B E8F4FF CALL 0112 1393:011E D0C0 ROL AL,1 -a11e 1393:011E ror al,1 1393:0120 -npprr.com -w Writing 00035 bytes -

Obţinem în final două programe, câte unul pentru fiecare sens de rotaţie. Dacă viteza de baleiere a şirului de LED-uri este nepotrivită, modificăm valoarea de start din rutina delay (1393:0102). De asemenea, un bun exerciţiu de virtuozitate este comentarea programelor precedente. În acest moment, suntem cât de cât familiarizaţi cu modul în care pot fi comandate (controlate) elementele de execuţie externe (LED-uri, dar poate fi la fel de bine şi altceva, de exemplu poate fi controlată simultan starea a opt ghilotine). Un singur pas mai avem de făcut pentru a putea să ne imaginăm aplicaţii complexe în care embedded system-ul preia informaţii din exterior, le prelucrează şi le returnează pentru atingerea unor obiective. Acest pas constă în citirea datelor de la un periferic extern. Pe placa de extensie a portului paralel (figura 4.1) se află 4 swich-uri cu ajutorul cărora putem controla starea celor 4 linii de intrare din Portul Status. După cum se poate observa în figura 4.1, valoarea "1" logic este preluată din Portul de Date (Data 7, Pin 9), aşa că, vom avea grijă ca mai întâi să set-ăm în "1" logic linia Data 7. Această relativă complicare a hardware-ului extern a făcut

Page 68: Microprocesoare Si Microcontrolere

68 Portul Paralel. Aplicaţii Simple

posibilă o mare simplificare: nu este nevoie de o sursă externă de alimentare. Din tabelul 4.2 rezultă că liniile de intrare le găsim în zona Bit 7 - Bit 4 a Portului Status. Aşa că, pentru a nu perturba linia Data 7 din Portul de Date înainte de a returna datele citite, acestea sunt rotite la dreapta cu patru poziţii. De asemenea, ne asigurăm tot timpul că linia Data 7 este set-tată în "1" logic.

Figura 4.3. Schema modificarii extensiei pentru Portul Status simulată prin program.

Lasăm în execuţie utilitarul DEBUG şi scriem programul următor. -a 1393:0100 mov dx,378 ;fixăm portul de output 1393:0103 mov al,80 ;bit-ul 7 set-at în "1" logic 1393:0105 out dx,al ;înscriu data din reg. AL în port 1393:0106 mov dx,379 ;fixăm portul de input 1393:0109 in al,dx ;citim data din Portul Status 1393:010A and al,f0 ;mask, reţinem numai 4 biţi superiori 1393:010C ror al,1 ;rotim biţi în zona inferioară 1393:010E ror al,1 1393:0110 ror al,1 1393:0112 ror al,1 1393:0114 or al,80 ;set-ăm bitul 7 pe "1" logic, sursă pt. swich 1393:0116 mov dx,378 ;pregătim portul de output 1393:0119 out dx,al ;noua valoare în port 1393:011A mov ah,01 1393:011C int 16 1393:011E jz 106

Page 69: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

69

1393:0120 mov al,00 1393:0122 out dx,al 1393:0123 mov ax,4c00 1393:0126 int 21 1393:0128 -nppdr.com -rcx CX 0000 :28 -w Writing 00028 bytes -

Lansăm în execuţie programul precedent şi după cum rezultă dintr-un studiu atent al schemei din figura 4.1 în paralel cu informaţiile din tabelele 4.1 şi 4.2, biţii 6 şi 7 sunt inversaţi între ei, iar bit-ul 7 este negat intern. Dacă am fi realizat o schemă externă după indicaţiile din figura 4.3 aceste complicaţii nu ar fi apărut, numai că ar fi fost necesar un circuit inversor şi o complicare inutilă a cablajului. Reţinem că, orice încercare de soluţionare prin hardware a unor astfel de probleme nu face decât să complice inutil lucrurile. Următorul program reface toate problemele legate de citirea datelor prin Portul de Status. -a 1371:0100 mov dx,378 ;fixăm portul de output 1371:0103 mov al,80 ;bit-ul 7 set-at în "1" logic 1371:0105 out dx,al ;înscriu data din reg. AL în port 1371:0106 mov dx,379 ;fixăm portul de input 1371:0109 in al,dx ;citim data din Portul Status 1371:010A push ax ;copiem pe stivă 1371:010B push ax ;copiem pe stivă 1371:010C not al ;negăm conţinutul reg. AL 1371:010E ror al,1 ;rotim spre dreapta 1371:0110 and al,40 ;mask, reţinem numai bit-ul 6 1371:0112 mov bl,al ;mutăm momentan valoarea în reg. BL 1371:0114 pop ax ;refacem conţinutul iniţial 1371:0115 rol al,1 ;rotim la stinga 1371:0117 and al,80 ;mask, reţinem numai bit-ul 7 1371:0119 or al,bl ;informaţia a fost corectată pentru biţii 7, 6 1371:011B mov bl,al ;mutăm momentan valoarea în reg. BL 1371:011D pop ax ;refacem conţinutul iniţial 1371:011E and al,30 ;mask, reţinem numai biţii 5, 4 1371:0120 or al,bl ;informaţia a fost corectată 1371:0122 ror al,1 ;rotim biţi în zona inferioară 1371:0124 ror al,1 1371:0126 ror al,1 1371:0128 ror al,1 1371:012A or al,80 ;set-ăm bitul 7 pe "1" logic, sursă pt. swich 1371:012C mov dx,378 ;pregătim portul de output 1371:012F out dx,al ;noua valoare în port 1371:0130 mov ah,01

Page 70: Microprocesoare Si Microcontrolere

70 Portul Paralel. Aplicaţii Simple

1371:0132 int 16 1371:0134 jz 106 1371:0136 mov al,00 1371:0138 out dx,al 1371:0139 mov ax,4c00 1371:013C int 21 1371:013E -nppok.com -rcx CX 0000 :3e -w Writing 0003E bytes -

Dacă lansăm în execuţie programul precedent, vom constata că lucrurile au revenit la o situaţie cu o logică mai uşor de reţinut (la robinetul de apă caldă curge apă caldă). Câteva instrucţiuni în cod maşină au rezolvat o problemă hardware. De regulă, aplicaţia nu are de suferit din astfel de cauze deoarece timpul în care o asemenea secvenţă de instrucţiuni este executată de un calculator modern este de ordinul zecilor de nanosecunde. Deoarece putem avea unele probleme în înţelegerea unor secvenţe din programul precedent, vom rula programul pas cu pas pentru situaţia când toate intrările sunt în "1" logic. C:\Mm>debug -nppok.com -l -r AX=0000 BX=0000 CX=003E DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0100 NV UP EI PL NZ NA PO NC 1393:0100 BA7803 MOV DX,0378 -t AX=0000 BX=0000 CX=003E DX=0378 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0103 NV UP EI PL NZ NA PO NC 1393:0103 B080 MOV AL,80 -t AX=0080 BX=0000 CX=003E DX=0378 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0105 NV UP EI PL NZ NA PO NC 1393:0105 EE OUT DX,AL -t AX=0080 BX=0000 CX=003E DX=0378 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0106 NV UP EI PL NZ NA PO NC 1393:0106 BA7903 MOV DX,0379 -t AX=0080 BX=0000 CX=003E DX=0379 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0109 NV UP EI PL NZ NA PO NC

Page 71: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

71

1393:0109 EC IN AL,DX -t AX=0078 BX=0000 CX=003E DX=0379 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=010A NV UP EI PL NZ NA PO NC 1393:010A 50 PUSH AX -t AX=0078 BX=0000 CX=003E DX=0379 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=010B NV UP EI PL NZ NA PO NC 1393:010B 50 PUSH AX -t AX=0078 BX=0000 CX=003E DX=0379 SP=FFFA BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=010C NV UP EI PL NZ NA PO NC 1393:010C F6D0 NOT AL -t AX=0087 BX=0000 CX=003E DX=0379 SP=FFFA BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=010E NV UP EI PL NZ NA PO NC 1393:010E D0C8 ROR AL,1 -t AX=00C3 BX=0000 CX=003E DX=0379 SP=FFFA BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0110 NV UP EI PL NZ NA PO CY 1393:0110 2440 AND AL,40 -t AX=0040 BX=0000 CX=003E DX=0379 SP=FFFA BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0112 NV UP EI PL NZ NA PO NC 1393:0112 88C3 MOV BL,AL -t AX=0040 BX=0040 CX=003E DX=0379 SP=FFFA BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0114 NV UP EI PL NZ NA PO NC 1393:0114 58 POP AX -t AX=0078 BX=0040 CX=003E DX=0379 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0115 NV UP EI PL NZ NA PO NC 1393:0115 D0C0 ROL AL,1 -t AX=00F0 BX=0040 CX=003E DX=0379 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0117 OV UP EI PL NZ NA PO NC 1393:0117 2480 AND AL,80 -t AX=0080 BX=0040 CX=003E DX=0379 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0119 NV UP EI NG NZ NA PO NC 1393:0119 08D8 OR AL,BL -t

Page 72: Microprocesoare Si Microcontrolere

72 Portul Paralel. Aplicaţii Simple

AX=00C0 BX=0040 CX=003E DX=0379 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=011B NV UP EI NG NZ NA PE NC 1393:011B 88C3 MOV BL,AL -t AX=00C0 BX=00C0 CX=003E DX=0379 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=011D NV UP EI NG NZ NA PE NC 1393:011D 58 POP AX -t AX=0078 BX=00C0 CX=003E DX=0379 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=011E NV UP EI NG NZ NA PE NC 1393:011E 2430 AND AL,30 -t AX=0030 BX=00C0 CX=003E DX=0379 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0120 NV UP EI PL NZ NA PE NC 1393:0120 08D8 OR AL,BL -t AX=00F0 BX=00C0 CX=003E DX=0379 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0122 NV UP EI NG NZ NA PE NC 1393:0122 D0C8 ROR AL,1 -t AX=0078 BX=00C0 CX=003E DX=0379 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0124 OV UP EI NG NZ NA PE NC 1393:0124 D0C8 ROR AL,1 -t AX=003C BX=00C0 CX=003E DX=0379 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0126 NV UP EI NG NZ NA PE NC 1393:0126 D0C8 ROR AL,1 -t AX=001E BX=00C0 CX=003E DX=0379 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0128 NV UP EI NG NZ NA PE NC 1393:0128 D0C8 ROR AL,1 -t AX=000F BX=00C0 CX=003E DX=0379 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=012A NV UP EI NG NZ NA PE NC 1393:012A 0C80 OR AL,80 -t AX=008F BX=00C0 CX=003E DX=0379 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=012C NV UP EI NG NZ NA PO NC 1393:012C BA7803 MOV DX,0378 -t AX=008F BX=00C0 CX=003E DX=0378 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=012F NV UP EI NG NZ NA PO NC 1393:012F EE OUT DX,AL

Page 73: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

73

-t AX=008F BX=00C0 CX=003E DX=0378 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=0130 NV UP EI NG NZ NA PO NC 1393:0130 B401 MOV AH,01 -g Program terminated normally -

Pentru o mai bună înţelegere a modului de lucru a programului precedent complicăm puţin programul pentru a ne asigura o mai bună interacivitate cu Portul Status. Datele citite şi corectate vor fi nu numai returnate în Portul de Date, ci vor fi şi tipărite pe ecran în format binar. Lansăm în execuţie utilitarul DEBUG şi realizăm următorul program: -a 1371:0100 jmp 110 1371:0102 mov ah,02 ;subrutina, tipăreşte caracter 1371:0104 int 21 1371:0106 ret 1371:0107 mov dl,30 ;subrutină, fixăm cod ASCII pentru "0/1" logic 1371:0109 shl al,1 1371:010B jnc 10f 1371:010D inc dl 1371:010F ret 1371:0110 mov dx,378 ;start program, identic cu programul precedent 1371:0113 mov al,80 1371:0115 out dx,al 1371:0116 mov dx,379 1371:0119 in al,dx 1371:011A push ax 1371:011B push ax 1371:011C not al 1371:011E ror al,1 1371:0120 and al,40 1371:0122 mov bl,al 1371:0124 pop ax 1371:0125 rol al,1 1371:0127 and al,80 1371:0129 or al,bl 1371:012B mov bl,al 1371:012D pop ax 1371:012E and al,30 1371:0130 or al,bl 1371:0132 push ax ;copiem pe stivă, urmează să fie tipărit 1371:0133 ror al,1 ;pregătim data din reg. AL pentru port output 1371:0135 ror al,1 1371:0137 ror al,1 1371:0139 ror al,1 1371:013B or al,80

Page 74: Microprocesoare Si Microcontrolere

74 Portul Paralel. Aplicaţii Simple

1371:013D mov dx,378 1371:0140 out dx,al ;data este în port 1371:0141 mov cx,0004 ;contor număr caractere 1371:0144 mov dl,20 ;în reg. DL caracterul de tipărit, blank 1371:0146 call 102 ;tipărim blank 1371:0149 pop ax ;refac data citită din Port Status 1371:014A pushf ;copiem flag-urile pe stivă, vor fi distruse 1371:014B call 107 ;stabilim cod ASCII 1371:014E popf ;refac flag-urile 1371:014F push ax ;copiem pe stivă, data din Port Status 1371:0150 call 102 ;tipărim 1371:0153 loopnz 144 ;repetăm până mai sunt caractere 1371:0155 pop ax ;refac stare stivă 1371:0156 mov dl,0d ;fac return cursor fără new line 1371:0158 call 102 1371:015B mov ah,01 ;secventă tipică, test keyboard 1371:015D int 16 1371:015F jz 110 1371:0161 mov al,00 ;dezactivez tot din Port Data 1371:0163 mov dx,378 1371:0166 out dx,al 1371:0167 mov ax,4c00 ;invocăm ieşire în DOS 1371:016A int 21 1371:016C -nppdrv.com -rcx CX 0000 :6c -w Writing 0006C bytes -

Părţile mai dificile, cu elemente de noutate sunt comentate în sursa programului. Aşa că, urmărind cu atenţie comentariile, nu avem probleme dificile legate de înţelegerea modului de afişare pe ecran. Este bine să privim cunoştiinţele acumulate în acest domeniu ca un continuum (tocmai de aceea nu sunt tot felul de paragrafe), deoarece toate componentele din sistem sunt în interacţiune sau pot fi puse în interacţiune. Pentru a demonstra acest lucru, vom scrie un program care generează un sunet cu ajutorul circuitului programabil 8254. Sunetul produs de acest circuit va fi auzit în difuzor numai dacă Push Button-ul de pe placa de extensie este apăsat (adică avem "0" logic pe linia ACK din Portul Status). Apelând la procedurile cunoscute de acum vom realiza, următorul program: -a 1371:0100 mov al,b6 1371:0102 out 43,al 1371:0104 mov al,ff 1371:0106 out 42,al

Page 75: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

75

1371:0108 mov al,0f 1371:010A out 42,al 1371:010C mov dx,378 1371:010F mov al,80 1371:0111 out dx,al 1371:0112 mov dx,379 1371:0115 in al,dx 1371:0116 and al,40 1371:0118 jz 122 1371:011A in al,61 1371:011C and al,fc 1371:011E out 61,al 1371:0120 jmp 128 1371:0122 in al,61 1371:0124 or al,03 1371:0126 out 61,al 1371:0128 mov ah,01 1371:012A int 16 1371:012C jz 112 1371:012E in al,61 1371:0130 and al,fc 1371:0132 out 61,al 1371:0134 mov dx,378 1371:0137 mov al,00 1371:0139 out dx,al 1371:013A mov ax,4c00 1371:013D int 21 1371:013F -nppdrs.com -rcx CX 0000 :3f -w Writing 0003F bytes -

Rulăm programul, eventual şi pas cu pas, pentru a elimina problemele legate de înţelegerea procedurilor care decid starea circuitului 8254 şi a porţii spre difuzor. Pentru a demonstra abilitatea soft-ului de a prelua unele task-uri specifice hardware, pe placa de extensie se află şi un afişaj clasic cu 7 segmente. Unul din exemplele tipice de circuit logic utilizat la translatarea de cod este decodificatorul BCD - 7 Segmente. În tabelul 4.3 este prezentată relaţia dintre codul HEX (include şi BCD) al numărului şi codul ce trebuie înscris în Portul de Date (Pini 2-9) pentru a desena imaginea numărului. Activarea părţii de input este asigurată de Data 7 în "1" logic. Lansăm în execuţie utilitarul DEBUG şi realizăm programul următor. -a 1371:0100 mov dx,378 1371:0103 mov al,80 1371:0105 out dx,al

Page 76: Microprocesoare Si Microcontrolere

76 Portul Paralel. Aplicaţii Simple

1371:0106 mov dx,379 1371:0109 in al,dx 1371:010A push ax 1371:010B push ax 1371:010C not al 1371:010E ror al,1 1371:0110 and al,40 1371:0112 mov bl,al 1371:0114 pop ax 1371:0115 rol al,1 1371:0117 and al,80 1371:0119 or al,bl 1371:011B mov bl,al 1371:011D pop ax 1371:011E and al,30 1371:0120 or al,bl 1371:0122 ror al,1 1371:0124 ror al,1 1371:0126 ror al,1 1371:0128 ror al,1 1371:012A mov bx,148 ;fixăm începutul tabelei de translatare 1371:012D and ax,000f ;ne asigurăm că nu avem munere mai mari de Fh 1371:0130 add bx,ax ;stabilim adresa offset în tab. translatare 1371:0132 mov al, [bx] ;citim valoarea de la adresa din reg. BX 1371:0134 mov dx,378 1371:0137 or al,80 ;ne asigurăm că switch-urile sunt alimentate 1371:0139 out dx, al 1371:013A mov ah,01 1371:013C int 16 1371:013E jz 106 1371:0140 mov al,00 1371:0142 out dx,al 1371:0143 mov ax,4c00 1371:0146 int 21 ;tabelul de translatare 1371:0148 db bf,86, db,cf,ee,ed,fd,87,ff,ef,f7,fc,b9,de,f9,f1 1371:0158 -npp7seg.com -rcx CX 0000 :58 -w Writing 00058 bytes -

Înainte de a lansa programul în execuţie, mutăm Jumper-ul în poziţia 2-3. În această situaţie, orice "1" logic prezent pe liniile Data 0 - Data 6 va determina aprinderea segmentului (LED) corespunzător.

După cum se poate observa, transalatarea codului se face pe baza unui tabel (xxxx:0148). Orice număr reprezentabil pe un nibble (4 biţi) este convertit în codul

Page 77: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

77

de la o adresă formată din suma dintre adresa de bază (din registrul BX) şi valoarea numărului. Nimic nou, după cum ştim deja un circuit combinaţional poate fi uşor implementat cu ajutorul unei memorii care are un număr de linii de adresă cel puţin egal cu numărul variabilelor funcţiei date. Acum este uşor de înţeles de ce logica cablată a rămas o ciudată realitate tehnologică a anilor '60. Nu trebuie însă să ignorăm importanţa didactică a problemelor de logică cablată, de regulă, este cel mai comod mod de a ne familiariza cu câteva elemente de logică elementară.

Tabelul 4.3

HEX COD Data 7

on/off D6 g

D5 f

D 4 e

D3 d

D2 c

D1 b

D0 a

0 BF 1 0 1 1 1 1 1 1 1 86 1 0 0 0 0 1 1 0 2 DB 1 1 0 1 1 0 1 1 3 CF 1 1 0 0 1 1 1 1 4 EE 1 1 1 0 1 1 1 0 5 ED 1 1 1 0 1 1 0 1 6 FD 1 1 1 1 1 1 0 1 7 87 1 0 0 0 0 1 1 1 8 FF 1 1 1 1 1 1 1 1 9 EF 1 1 1 0 1 1 1 1 A F7 1 1 1 1 0 1 1 1 B FC 1 1 1 1 1 1 0 0 C B9 1 0 1 1 1 0 0 1 D DE 1 1 0 1 1 1 1 0 E F9 1 1 1 1 1 0 0 1 F F1 1 1 1 1 0 0 0 1

În acest moment, alfabetizarea o putem considera practic încheiată (doar în

patru capitole). O mică finisare a cunoştiintelor anterioare în paralel cu abordarea unor aplicaţii complexe ne va asigura o cultură minimă în acest domeniu. Să nu uităm de limbajul C, numai pentru o mai bună instruire eventual situaţii limită în unele aplicaţii complexe vom apela la limbajul de asamblare. Toate exerciţiile din acest curs legate de familia de microprocesoare 80x86 pot fi scrise şi în limbajul C. Atenţie, acestea vor fi rulate în mod consolă (un bun mediu de lucru, gratuit pe Internet, este LCC). Un astfel de program destinat depanării şi/sau testării unor

Page 78: Microprocesoare Si Microcontrolere

78 Portul Paralel. Aplicaţii Simple

aplicaţii cu circuite FPGA (Field Programmable Gate Array) este prezentat la sfârşitul acestui capitol.

Programul AXSPORT.EXE este destinat unui sistem de dezvoltare (XS40), care conţine un circuit FPGA şi un microcontroler din familia 8051 Intel, produs de firma Xess Ltd. Programul este o extensie interactivă a programului XSPORT.EXE al firmei Xess Ltd. şi reţine o istorie recentă a evenimentelor de la pinii de intrare a circuitului FPGA. De asemenea, este păstrată compatibilitatea 100% cu programul XSPORT.EXE al firmei Xess Ltd. Versiunea compilată a programului poate fi testată cu ajutorul extensiei din figura 4.1. Liniile Data 0 şi Data 1 sunt conectate prin intermediul unor inversoare la circuitul FPGA din sistemul de dezvoltare XS40 al firmei Xess Ltd. Aşa că, ceea ce vedem pe ecran nu este valoarea înscrisă în Portul de Date, ci este valoarea de la pini de intrare ai circuitului FPGA. Dacă scriem aplicaţii pentru Windows xxxx (Visual C, Visual Basic) să nu uităm că utilizarea portului paralel ca port de uz general este posibilă numai prin încărcarea unui driver software destinat acestui scop. Vom găsi câteva gata scrise pe Internet, cele mai puţin performante chiar în versiune freeware. Deoarece unele versiuni ale sistemului de operare Windows xxxx permit trecerea microprocesorului în situaţii excepţionale în mod Real (compatibilitate 100% cu MS-DOS) vom găsi multe aplicaţii în care portul paralel este utilizat ca un port de uz general.

Lucrul direct cu porturile sub sistemul de operare Windows NT sau Linux se supune unor reguli mai stricte. Deoarece, micropocesorul nu lucrează în mod Real, pentru aceste sisteme de operare este indicat, pe cât posibil, să ocolim astfel de situaţii în care porturile standard de comunicaţie (paralel, serial) sunt utilizate ca porturi de uz general.

Page 79: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

79

/******************************* ** Advanced XSPORT ** Version: 1.0 ** Date: May 05, 2000 ** Copyright 2000 by Ioan Burda ** Revision: 0 *******************************/ #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <ctype.h> #include <string.h> #include <math.h> /* variable */ unsigned short lpt_port; unsigned int data_port; unsigned int val_port; unsigned int h5_val; unsigned int h4_val; unsigned int h3_val; unsigned int h2_val; unsigned int h1_val; unsigned int s_out; /* stamp */ void d_text(void) printf("\n AXSPORT Ver. 1.0\n"); printf(" Advanced XSPORT for XS40 and XS95 Boards\n"); printf(" (c) 2000 by Ioan Burda\n\n"); printf(" Usage: axsport [-a] [-p 2] [b7...b0]\n\n"); printf(" BIT : 7 6 5 4 - 3 2 1 0\n\n\n\n\n\n\n\n\n\n"); /* dec printf bin */ void bin_p (void) char lpt; unsigned int hbin; unsigned int i; unsigned int j; unsigned int val_bin; gotoxy(wherex(),wherey() - 9); lpt = '1'; if (lpt_port == 0x278) lpt='2'; for (j=1; j<7; j++) switch(j) case 1: if (h5_val == 0x1ff) printf (" x x x x - x x x x"); textcolor(2); if (s_out == 2) textcolor(10);

Page 80: Microprocesoare Si Microcontrolere

80 Portul Paralel. Aplicaţii Simple

if (s_out == 0) textcolor(12); printf(" [S]trobe\n"); textcolor(7); continue; else textcolor(7); val_bin = h5_val; printf(" # -5: "); textcolor(3); break; case 2: if (h4_val == 0x1ff) printf (" x x x x - x x x x\n"); continue; else textcolor(7); val_bin = h4_val; printf(" # -4: "); textcolor(2); break; case 3: if (h3_val == 0x1ff) printf (" x x x x - x x x x"); textcolor(2); if (s_out == 3) textcolor(10); printf(" [A]lways\n"); textcolor(7); continue; else textcolor(7); val_bin = h3_val; printf(" # -3: "); textcolor(3); break; case 4: if (h2_val == 0x1ff) printf (" x x x x - x x x x\n"); continue; else

Page 81: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

81

textcolor(7); printf(" # -2: "); val_bin = h2_val; textcolor(2); break; case 5: if (h1_val == 0x1ff) printf (" x x x x - x x x x"); printf(" [C]ounter_up -> [D]own\n"); continue; else textcolor(7); val_bin = h1_val; printf(" # -1: "); textcolor(3); break; case 6: textcolor(7); val_bin = val_port; printf(" XS95: P80 P81 P52 P51 - P50 P48 P47 P46\n"); printf(" XS40: P34 P32 P49 P48 - P47 P46 P45 P44\n"); printf(" # 0: "); textcolor(10); if(s_out == 2) textcolor(12); break; hbin = 128; for (i=1; i<9; i++) if (val_bin/hbin >= 1) printf(" 1 "); val_bin = val_bin - hbin; else printf(" 0 "); hbin = hbin/2; if (i == 4) printf("- "); if(j == 4) printf("\n"); if(j == 2) printf("\n"); if(j == 1) textcolor(2); if (s_out == 2) textcolor(10); if (s_out == 0) textcolor(12);

Page 82: Microprocesoare Si Microcontrolere

82 Portul Paralel. Aplicaţii Simple

printf(" [S]trobe\n"); textcolor(3); if(j == 3) textcolor(2); if (s_out == 3) textcolor(10); printf(" [A]lways\n"); textcolor(3); if(j == 5) textcolor(7); printf(" [C]ounter_up -> [D]own\n"); if (j == 6) textcolor(7); printf(" HEX: "); textcolor(10); if (s_out == 2) textcolor(12); printf("%02X ",val_port); textcolor (7); printf(" LPT: %c \n",lpt); printf(" KEYS: [E] [R] [T] [Y] - [U] [I] [O] [P] [W] - Reverse [Q]uit\n"); textcolor(7); /* advanced xsport*/ void a_choice(void) char ch; val_port = _inp(lpt_port)^0x03; do if (data_port == val_port && s_out == 2) s_out = 0; if (data_port != val_port && s_out == 0) s_out = 2; if(data_port != val_port && s_out != 0 && s_out != 2) h5_val=h4_val; h4_val=h3_val; h3_val=h2_val; h2_val=h1_val; h1_val=data_port; data_port = val_port; _outp(lpt_port,data_port^0x03); val_port = data_port; if (s_out == 1) s_out = 0; bin_p(); ch = getch(); ch = toupper(ch);

Page 83: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

83

switch(ch) case 'E': val_port = val_port^0x80; break; case 'R': val_port = val_port^0x40; break; case 'T': val_port = val_port^0x20; break; case 'Y': val_port = val_port^0x10; break; case 'U': val_port = val_port^0x08; break; case 'I': val_port = val_port^0x04; break; case 'O': val_port = val_port^0x02; break; case 'P': val_port = val_port^0x01; break; case 'C': val_port = val_port + 1; if (val_port == 256) val_port = 0; break; case 'D': if (val_port == 0) val_port = 255; val_port = val_port - 1; break; case 'S': if (s_out == 3) s_out = 0; if (s_out == 2) s_out = 1; break; case 'A': s_out = 3; break; case 'W': val_port = val_port^0xff; break; case 'Q': exit(0); while (1); /* xsport option */ void x_choice (char *s_bits)

Page 84: Microprocesoare Si Microcontrolere

84 Portul Paralel. Aplicaţii Simple

int i; int s_len; data_port = 0; s_len = strlen(s_bits); for (i= 0; i < s_len;i++) if(s_bits[s_len - 1 - i] == '1') data_port = data_port + pow(2,i); if(s_bits[s_len - 1 - i] != '1' && s_bits[s_len - 1 - i] != '0') exit(0); _outp(lpt_port,data_port^0x03); data_port = 0x1ff; /* main */ void main (int argc, char *argv[]) h5_val = 0x1ff; h4_val = 0x1ff; h3_val = 0x1ff; h2_val = 0x1ff; h1_val = 0x1ff; data_port = 0x1ff; s_out = 1; if(argc == 1) lpt_port = 0x378; d_text(); a_choice(); if(argc == 2) if(!strcmp(argv[1],"-a")) lpt_port = 0x378; d_text(); a_choice(); lpt_port = 0x378; x_choice(argv[1]); if(argc == 3) if(!strcmp(argv[1],"-p") && !strcmp(argv[2],"2")) lpt_port = 0x278; d_text(); a_choice(); if(!strcmp(argv[1],"-a")) lpt_port = 0x378; d_text(); x_choice(argv[2]);

Page 85: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

85

a_choice(); if(argc == 4) if(!strcmp(argv[1],"-p") && !strcmp(argv[2],"2")) lpt_port = 0x278; x_choice(argv[3]); if(!strcmp(argv[1],"-a") && !strcmp(argv[2],"-p") && !strcmp(argv[1],"2")) lpt_port = 0x278; d_text(); a_choice(); if(argc == 5) if(!strcmp(argv[1],"-a") && !strcmp(argv[2],"-p") && !strcmp(argv[3],"2")) lpt_port = 0x278; d_text(); x_choice(argv[4]); a_choice();

Page 86: Microprocesoare Si Microcontrolere

86 Portul Paralel. Aplicaţii Simple

Page 87: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

87

5. Programe Rezidente în Memorie Evoluţia sistemelor de operare din ultimul timp în particular evoluţia sistemului de operare Windows xxxx a determinat ca anumite stiluri clasice de programare să fie, în prezent, mai puţin utilizate. Trebuie reţinut încă de la început faptul că manevrarea unei întreruperi externe rămâne o procedură standart în domeniul achiziţiei de date şi al controlului. Atingerea nivelului de novice în domeniul embedded system implică o practică minimă legată de întreruperile hardware respectiv rezidenţa programelor în memorie. Deoarece, de regulă, prin astfel de programe (aplicaţii) sistemele de operare Microsoft cad pradă unor programe virus şi dat fiind caracterul didactic al acestui capitol, vom evita pe cât posibil acele exemple care nu fac cinste "breslei". Aşa că noi vom reruta întreruperile (prin intermediul tabelei vectorilor de întrerupere) cu cele mai nobile intenţii, pentru a învăţa prin descoperire. Înainte de a ne lansa în câteva aventuri tipice acestui domeniu (atenţie sunt foarte mari şanse de a bloca sistemul, vom face un fel de operaţie pe creier), să vedem care sunt informaţiile de care are nevoie sistemul de operare pentru putea lansa în execuţie un program.

Programele pe care în mod general le acceptăm ca fiind programe executabile sunt cele cele de tip ".COM" şi ".EXE". Din cauza spaţiului de memorie segmentat al microprocesoarelor 80X86 şi a faptului că instrucţiunile JMP şi CALL (de salt respectiv apel de procedură) lucrează cu adrese relative, oricare tip de program poate fi încărcat şi executat în memorie la orice adresă de segment. Astfel, un program poate fi făcut resident în memorie şi în continuarea lui poate fi încărcat un alt program pentru a fi executat. Programele nu sunt niciodată scrise în ideea de a fi încărcate la o anumită adresă (cu excepţia unor programe care se autoîncarcă). Formatul ".COM" al unui fişier este imaginea binară a datelor şi a codului unui program. Fişierul trebuie să fie mai mic de 64 Kbyte şi nu vor fi făcute relocări ale adreselor de segment. Formatul ".EXE" al unui fişier conţine un antet cu informaţii folosite de încărcătorul sistem pentru a executa ajustările la referinţele de segmente (relocări) în momentul încărcării. Pentru a putea înţelege ceva din filosofia sistemului de operare MS-DOS legată de modul de încărcare şi execuţie a programelor, vom analiza pentru început formatul *.COM care ne aşteptăm să fie mai simplu. Formatul ".COM" defineşte un singur segment (sau cel puţin nu face referinţe explicite la un alt segment). Programul de tip ".COM" este încărcat în memorie începând cu adresa PSP (Program Segment Prefix):0100h. Un program de tip ".COM" poate utiliza mai multe segmente, dar trebuie să calculeze adresele pentru celelalte segmente, luând

Page 88: Microprocesoare Si Microcontrolere

88 Programe Rezidente în Memorie

ca referintă PSP-ul de bază. Programele de tip ".COM" ocupă mai puţin spaţiu pe disc, se încarcă mai rapid în memorie şi au o structură mult mai simplă decît cele de tip ".EXE". După cum este uşor de bănuit, această simplitate le face de multe ori mult mai vulnerabile la un atac din exterior asupra sistemului (virus). Încărcarea în memorie a unui program de tip ".COM" este urmată de set-area regiştrilor CS, ES, DS, SS cu valoarea adresei PSP-ului de bază. Registrul SP este set-at cu o valoare corespunzătoare sfârşitului segmentului PSP (FFFFh). Toată memoria sistem (640 Kbyte) de după segmentul programului este alocată programului. Un cuvânt 0000h este încărcat pe stivă, iar registrul IP este set-at cu valoarea 0100h. PSP este construit începând de la adresa offset 0000h până la 0100h (adică primii 256 de bytes), iar de la adresa offset 0100h începe programul. PSP-ul are următoarea structură:

• 0000h Instrucţiune pentru INT 20.

• 0002h Memoria totală în segmente.

• 0004h Rezervat.

• 0005h Opcod-uri pentru FAR CALL la DOS.

• 000Ah Adresa rutinei de exit (IP, CS), pentru refacerea vectorului INT 22h la terminarea programului.

• 000Eh Adresa CTRL/Break (IP, CS), pentru refacerea vectorului INT 23h la terminarea programului.

• 0012h Adresa rutinei de eroare critică (IP, CS), pentru refacerea vectorului INT 24h la terminarea programului.

• 0016h Rezervaţi (22 de bytes).

• 002Ch Adresa de segment a mediului DOS.

• 002Eh Rezervaţi (46 de bytes).

• 005Ch Primul FCB (File Control Block) după cum rezultă din primul parametru al liniei de comandă.

• 006Ch Al doilea FCB (File Control Block) după cum rezultă din al doilea parametru al liniei de comandă.

• 0080h Lungime linie de comandă (bytes).

• 0081h Linia de comandă (parametrii).

Prin parametru se înţelege orice şir de caractere din linia de comandă (separatorul fiind spaţiul), cu excepţia comenzii propriu-zise. Blocurile care încep la 005Ch şi 006Ch sunt construite pe baza primilor doi parametri tastaţi după comandă. Deoarece toate programele scrise de noi până acum sunt de tip ".COM", cu ajutorul utilitarului DEBUG putem vedea zona PSP a unui astfel de program. C:\Mm>debug -npp7seg.com -l -d0 1393:0000 CD 20 00 A0 00 9A F0 FE-1D F0 4F 03 F6 0C 8A 03 . ........O..... 1393:0010 F6 0C 17 03 F6 0C E5 0C-01 01 01 00 02 FF FF FF ................

Page 89: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

89

1393:0020 FF FF FF FF FF FF FF FF-FF FF FF FF 82 13 5E 3E ..............^> 1393:0030 F6 0C 14 00 18 00 93 13-FF FF FF FF 00 00 00 00 ................ 1393:0040 07 0A 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 50 50 37 .!...........PP7 1393:0060 53 45 47 20 20 43 4F 4D-00 00 00 00 00 20 20 20 SEG COM..... 1393:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00 ........ -d 1393:0080 0A 50 50 37 53 45 47 2E-43 4F 4D 0D 00 00 00 00 .PP7SEG.COM..... 1393:0090 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00B0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00C0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00D0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1393:00F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ -d 1393:0100 BA 78 03 B0 80 EE BA 79-03 EC 50 50 F6 D0 D0 C8 .x.....y..PP.... 1393:0110 24 40 88 C3 58 D0 C0 24-80 08 D8 88 C3 58 24 30 [email protected]..$.....X$0 1393:0120 08 D8 D0 C8 D0 C8 D0 C8-D0 C8 BB 48 01 25 0F 00 ...........H.%.. 1393:0130 01 C3 8A 07 BA 78 03 0C-80 EE B4 01 CD 16 74 C6 .....x........t. 1393:0140 B0 00 EE B8 00 4C CD 21-BF 86 DB CF EE ED FD 87 .....L.!........ 1393:0150 FF EF F7 FC B9 DE F9 F1-80 3E 5D E2 00 75 0D C7 .........>]..u.. 1393:0160 87 65 E3 2A 2E 43 43 83-06 5F E2 02 C7 87 65 E3 .e.*.CC.._....e. 1393:0170 2A 00 83 06 5F E2 01 5B-C3 57 8B 3E 5B E2 AC AA *..._..[.W.>[... -

Dacă structura PSP-ului pentru un format de tip ".COM" este cât se poate de simplă, după cum vom vedea în continuare nu acelaşi lucru se poate spune şi despre antetul unui fişier de tip ".EXE". Formatul de tip ".EXE" al programelor permite utilizarea mai multor segmente de program, incluzând segmentele de cod, date şi stivă. Fişierul de tip ".EXE" este încărcat în memorie începând cu adresa PSP:0100h. Pe măsură ce este încărcat, sunt preluate unele informaţii din antetul fişierului pentru a se realiza relocarea. Pentru a vedea conţinutul fisierului axsport.exe vom face o copie de lucru a acestuia pe care o vom redenumi axsport.txt (rename axsport.exe axsport.txt). Putem încerca să deschidem fişierul axsport.txt cu ajutorul editorului NOTEPAD, dar mult mai utilă este informaţia pe care o putem obţine cu ajutorul utilitarului DEBUG:

C:\Mm>debug -naxsport.txt -l -d 1371:0100 4D 5A 90 00 03 00 00 00-04 00 00 00 FF FF 00 00 MZ.............. 1371:0110 B8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00 ........@....... 1371:0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 1371:0130 00 00 00 00 00 00 00 00-00 00 00 00 80 00 00 00 ................ 1371:0140 0E 1F BA 0E 00 B4 09 CD-21 B8 01 4C CD 21 54 68 ........!..L.!Th 1371:0150 69 73 20 70 72 6F 67 72-61 6D 20 63 61 6E 6E 6F is program canno 1371:0160 74 20 62 65 20 72 75 6E-20 69 6E 20 44 4F 53 20 t be run in DOS

Page 90: Microprocesoare Si Microcontrolere

90 Programe Rezidente în Memorie

1371:0170 6D 6F 64 65 2E 0D 0D 0A-24 00 00 00 00 00 00 00 mode....$....... -d 1371:0180 50 45 00 00 4C 01 05 00-9D 76 18 39 6C 31 00 00 PE..L....v.9l1.. 1371:0190 60 02 00 00 E0 00 02 01-0B 01 01 03 00 1C 00 00 `............... 1371:01A0 00 0C 00 00 00 02 00 00-CB 11 00 00 00 10 00 00 ................ 1371:01B0 00 30 00 00 00 00 40 00-00 10 00 00 00 02 00 00 .0....@......... 1371:01C0 01 00 00 00 00 00 00 00-04 00 00 00 00 00 00 00 ................ 1371:01D0 00 70 00 00 00 04 00 00-00 00 00 00 03 00 00 00 .p.............. 1371:01E0 00 00 10 00 00 10 00 00-00 00 10 00 00 10 00 00 ................ 1371:01F0 00 00 00 00 10 00 00 00-00 00 00 00 00 00 00 00 ................ -

Dacă pentru noi conţinutul acestui fişier pare lipsită de sens, nu acelaşi lucru îl putem spune pentru sistemul de operare. Aşa că, să vedem în continuare care este semnificaţia conţinutului unui antet de fişier de tip ".EXE":

• 0h (offset-ul se referă la fişierul de tip *.EXE şi nu la program) Semnătura programelor *.EXE (MZ).

• 2h Lungimea paginii parţiale de la sfârşit (PARTPAG).

• 4h Lungimea în pagini de 512 bytes, inclusiv antetul (PAGECNT.

• 6h Numărul înregistrărilor din tabela de relocare (RELOCNT).

• 8h Dimensiunea antetului în paragrafe (de 16 bytes, HDRSIZE).

• 0Ah Minimul de memorie necesar pentru program (în paragrafe, MINMEM).

• 0Ch Maximul de memorie necesar după program (în paragrafe, MAXMEM).

• 0Eh Deplasamentul pentru segmentul de stivă (RELOSS).

• 10h Valoarea pentru registrul SP la lansare (EXESP).

• 12h Suma de control a fişierului (suma negativă a tuturor cuvintelor fişierului, CHKSUM).

• 14h Valoarea registrului IP la lansarea în execuţie (EXEIP).

• 16h Deplasamentul pentru segmentul de cod (RELOCS).

• 18h Deplasamentul primei înregistrări de relocare (TBLEOFF).

• 1Ah Numărul de suprapuneri (OVERLAY).

• 1Ch Dimensiunea porţiunii formatate a antetului *.EXE (4 bytes).

Lansarea în execuţie a unui program implică crearea unui PSP cu ajutorul funcţiei MS-DOS 26h, urmată de citirea a 1Ch bytes din fişierul de tip ".EXE" într-o zonă de memorie locală. Etapa de iniţializare şi relocare implică determinarea modulului de încărcat (stabilit de relaţia = ((PAGECNT*512) - (HDRSIZE*16)) - PARTPAG), urmată de stabilirea deplasamentului modulului de încărcat (dimantet*16). Alegerea unei adrese de segment START_SEG pentru încărcare (uzual, PSP + 10h) este urmată de citirea modulului de încărcat în memorie la adresa START_SEG:0000h. Urmează poziţionarea pointerului fişierului la începutul tabelei de relocare, iar pentru fiecare înregistrare de relocare sistemul de operare va efectua următoarele operaţii:

Page 91: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

91

se citeşte înregistrarea ca două cuvinte (words) de 16 biţi (I_OFF, I_SEG);

se adună RELO_SEG = (START_SEG + I_SEG); se determină astfel adresa de relocare;

se citeşte cuvântul de la adresa RELO_SEG:I_OFF; se adună START_SEG la acest cuvânt (fixarea segmentului); se încarcă suma obţinută înapoi la adresa originală (RELO_SEG:I_OFF).

Înainte de a lansa programul în execuţie se alocă memorie pentru program în concordanţă cu MINMEM şi MAXMEM, se iniţializează regiştrii şi se execută programul după parcurgerea următorilor paşi: ES = DS = adresa PSP; se încarcă AX pentru a indica validitatea identificatorului unităţii din

linia de comandă; SS = START_SEG +RELOSS, SP = EXESP; CS = ETART_SEG +RELOCS, IP = EXEIP.

Pentru a suplini în parte faptul că sistemul de operare MS-DOS este mono-tasking (ceea ce înseamnă că un singur program poate rula la un moment dat), acesta permite ca un program la terminare să rămână rezident în memoria internă. Pentru acest program se alocă o zonă de memorie, de regulă mult mai mică decât memoria disponibilă (altfel rezidenţa nu ar mai avea nici un sens). Accesul la resursele soft rămase rezidente se poate face prin mecanismul întreruperilor de orice fel. Rezidenţa unui program în memorie se poate face în mai multe moduri. Cel mai performant mod constă în invocarea funcţiei DOS 31h prin întreruperea umbrelă INT 21h. Aceasta primeşte ca argument în registrul DX numărul de paragrafe (16 bytes) ce urmează să rămână rezidente, faţă de începutul programului, restul eliberându-se în vederea încărcării altor aplicaţii. O altă posibilitate pe care, de altfel, o vom utiliza şi noi, este să apelăm la o metodă tradiţională INT 27h (în registrul DX se specifică ultima adresă a porţiunii care se alocă +1). În general, un program rezident este format din două părţi: o parte de iniţializare, care, de regulă, nu rămâne rezidentă şi de aceea este plasată la sfîrşitul programului, şi o parte ce rămâne rezidentă în memorie. O subrutină rămasă rezidentă în vederea tratării unei întreruperi o vom numi handle-r.

Canalul 0 al circuitului programabil 8254 (prezentat în capitolul 3) este ceas de timp real în calculatorul IBM PC. Acest canal este programat să genereze o întrerupere hard la fiecare 54 de ms (de 18.2 ori pe secundă), iar subrutina de tratare a acestei întreruperi este parte a sistemului de operare MS-DOS. Reţinem pentru moment că sistemul lucrează cu unitatea de timp de 54 ms numită "tick", care este convertită în unităţi uzuale (secunde, minute, ore) doar pentru confortul nostru. Pentru acest lucru este implementat un contor în memorie la adresa 0000:0046C pe

Page 92: Microprocesoare Si Microcontrolere

92 Programe Rezidente în Memorie

o lungime de patru bytes. Pentru a vedea la lucru acest serviciu al sistemului de operare MS-DOS în utilitarul DEBUG tastăm următoarele comenzi:

-d0000:046c 0000:0460 21 53 06 00 !S.. 0000:0470 00 00 00 00 00 01 00 00-14 14 14 3C 01 01 01 01 ...........<.... 0000:0480 1E 00 3E 00 18 10 00 60-89 51 0B 89 58 01 00 01 ..>....`.Q..X... 0000:0490 07 07 00 00 00 00 10 02-00 00 00 00 00 00 00 00 ................ 0000:04A0 00 00 00 CE 00 00 C0 00-32 00 00 C0 10 10 00 00 ........2....... 0000:04B0 00 00 00 01 9B 00 44 00-00 00 05 00 00 00 00 00 ......D......... 0000:04C0 00 00 00 00 00 00 0A 00-00 00 00 00 00 00 00 00 ................ 0000:04D0 00 00 00 00 00 00 00 00-DC 04 00 00 00 00 00 00 ................ 0000:04E0 00 00 00 00 00 00 00 80-07 09 08 00 ............ -d0000:046c 0000:0460 88 54 06 00 .T.. 0000:0470 00 00 00 00 00 01 00 00-14 14 14 3C 01 01 01 01 ...........<.... 0000:0480 1E 00 3E 00 18 10 00 60-89 51 0B 89 58 01 00 01 ..>....`.Q..X... 0000:0490 07 07 00 00 00 00 10 02-00 00 00 00 00 00 00 00 ................ 0000:04A0 00 00 00 CE 00 00 C0 00-32 00 00 C0 10 10 00 00 ........2....... 0000:04B0 00 00 00 01 9B 00 44 00-00 00 05 00 00 00 00 00 ......D......... 0000:04C0 00 00 00 00 00 00 0A 00-00 00 00 00 00 00 00 00 ................ 0000:04D0 00 00 00 00 00 00 00 00-DC 04 00 00 00 00 00 00 ................ 0000:04E0 00 00 00 00 00 00 00 80-07 09 08 00 ............ -

Desigur vor fi alte valori, important este însă că ele se modifică în permanenţă. În plus faţă de incrementarea contorului de timp, rutina de gestiune a acestei întreruperi mai are câteva funcţii. Astfel, prin intermediul acestui serviciu vor fi oprite motoarele unităţii de dischetă, dacă aceasta nu a mai fost accesată o perioadă de timp, sau mult mai important pentru noi este apelul unei subrutine utilizator cu vectorul de întrerupere 1Ch (INT 1Ch) care de regulă conţine numai instrucţiunea IRET (întoarcere din întrerupere). Această facilitate de înseriere a unei subrutine utilizator cu vectorul la adresa 1Ch va fi exploatată în continuare. Pentru început, să ne convingem că nu avem deja instalată o astfel de subrutină (alta decât aceea care conţine numai instrucţiunea IRET). Lansăm utilitarul DEBUG şi afişăm pe ecran zona cu vectorii de întrerupere. -d0000:0000 0000:0000 9E 0F C9 00 65 04 70 00-16 00 66 08 65 04 70 00 ....e.p...f.e.p. 0000:0010 65 04 70 00 54 FF 00 F0-88 80 00 F0 6F EF 00 F0 e.p.T.......o... 0000:0020 00 00 00 C8 28 00 66 08-6F EF 00 F0 6F EF 00 F0 ....(.f.o...o... 0000:0030 6F EF 00 F0 6F EF 00 F0-9A 00 66 08 65 04 70 00 o...o.....f.e.p. 0000:0040 07 00 70 C8 4D F8 00 F0-41 F8 00 F0 7F 25 A7 FD ..p.M...A....%.. 0000:0050 39 E7 00 F0 40 02 0B 02-2D 04 70 00 28 0A 51 02 [email protected].(.Q. 0000:0060 A4 E7 00 F0 2F 00 27 09-6E FE 00 F0 04 06 51 02 ..../.'.n.....Q. 0000:0070 1D 00 00 C8 A4 F0 00 F0-22 05 00 00 93 49 00 C0 ........"....I.. -

Page 93: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

93

Nu este greu să citim de aici adresa subrutinei cu vectorul de la adresa 4*1Ch = 70h (C800:001D), dar este mult mai simplu cu următoarea comandă: -d0:70 L 4 0000:0070 1D 00 00 C8 .... -

Dezasamblăm în continuare de la adresa rutinei de tratare a întreruperii 1Ch şi obţinem: -uc800:001d C800:001D EA53FF00F0 JMP F000:FF53 C800:0022 090D OR [DI],CX C800:0024 150101 ADC AX,0101 C800:0027 050709 ADD AX,0907 C800:002A 0B25 OR SP,[DI] C800:002C 27 DAA C800:002D 292B SUB [BP+DI],BP C800:002F 7F7F JG 00B0 C800:0031 7F7F JG 00B2 C800:0033 7F7F JG 00B4 C800:0035 7F7F JG 00B6 C800:0037 7F7F JG 00B8 C800:0039 7F7F JG 00BA C800:003B 7F7F JG 00BC -

urmând indicaţiile din program facem şi noi un salt la adresa F000:FF53 cu ajutorul următoarei comenzi: -uf000:ff53 F000:FF53 CF IRET F000:FF54 60 DB 60 F000:FF55 1E PUSH DS F000:FF56 B84000 MOV AX,0040 F000:FF59 50 PUSH AX F000:FF5A 1F POP DS F000:FF5B B001 MOV AL,01 F000:FF5D 86060001 XCHG AL,[0100] F000:FF61 3C01 CMP AL,01 F000:FF63 746F JZ FFD4 F000:FF65 FB STI F000:FF66 B3FF MOV BL,FF F000:FF68 B402 MOV AH,02 F000:FF6A 33D2 XOR DX,DX F000:FF6C CD17 INT 17 F000:FF6E 80E4A0 AND AH,A0 F000:FF71 795C JNS FFCF -

Page 94: Microprocesoare Si Microcontrolere

94 Programe Rezidente în Memorie

unde se poate observa instrucţiunea IRET. Pe un alt calculator această aventură cu siguranţă va fi diferită, acesta fiind "blestemul" compatibilităţii. În concluzie, nu avem o subrutină utilizator care să fi schimbat rutarea normală a acestei întreruperi din sistemul MS-DOS (instrucţiunea JMP F000:FF53 este un pseudo-vector de întrerupere, nu comentăm această situaţie). Pentru a vedea la lucru cunoştiinţele acumulate până în prezent, să scriem un program cu ajutorul utilitarului DEBUG care sa rămână rezident. Acest program rezident (handler) va fi activat de "tick" (INT 1Ch) şi va verifica dacă este apăsat push-button-ul de pe placa de extensie din portul paralel. Dacă acest push-button va fi apăsat, va genera un semnal sonor până la eliberarea acestuia. Deoarece programul este rezident, el va crea impresia funcţionării în paralel cu alte programe, dar din păcate este numai o impresie. -a 1371:0100 jmp 125 ;salt la adresa de start 1371:0102 push ax ;început handler,salvez starea reg. 1371:0103 push dx ;care vor fi utilizaţi 1371:0104 mov dx,378 ;fixăm linia D7 în "1" logic, sursă 1371:0107 mov al,80 1371:0109 out dx,al 1371:010A mov dx,379 ;secvenţa test push-button 1371:010D in al,dx 1371:010E and al,40 1371:0110 jz 11a ;salt la 11Ah dacă este apăsat 1371:0112 in al,61 ;altfel, închid poarta spre difuzor 1371:0114 and al,fc 1371:0116 out 61,al 1371:0118 jmp 122 ;salt la 122h, pentru exit hamdler 1371:011A in al,61 ;deschid poarta spre difuzor 1371:011C or al,03 1371:011E out 61,al 1371:0120 jmp 104 ;salt la 104h, test pentru push-button 1371:0122 pop dx ;refac starea reg. utilizaţi 1371:0123 pop ax 1371:0124 iret ;return din întrerupere 1371:0125 mov ax,0000 ;aici începe efectiv programul 1371:0128 mov es,ax ;ES < 0000h, prima pagină de memorie 1371:012A mov ax,cs ;pagina curentă în AX 1371:012C mov ds,ax ;pagina curentă în DS 1371:012E pushf ;pe stivă starea curentă a fanion-elor 1371:012F cli ;dezactivăm întreruperile 1371:0130 es: 1371:0131 mov [0072],ax ;valoarea reg. AX la adresa 0000:0072 1371:0134 mov ax,0102 ;AX adresa de început handler 1371:0137 es: 1371:0138 mov [0070],ax ;valoarea reg. AX la adresa 0000:0070 1371:013B popf ;refac starea fanion-elor 1371:013C mov al,b6 ;pregătesc 8254 pentru generare sunet 1371:013E out 43,al

Page 95: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

95

1371:0140 mov al,ff 1371:0142 out 42,al 1371:0144 mov al,0f 1371:0146 out 42,al 1371:0148 mov dx,0125 ;reg. DX offset sfîrşit handler 1371:014B int 27 ;să rămână resident 1371:014D mov ax,4c00 ;invocăm ieşire în DOS 1371:0150 int 21 1371:0152 -nticks.com -rcx CX 0000 :52 -w Writing 00052 bytes -

Ne putem convinge de buna funcţionare a programului anterior, dacă îl lansăm în execuţie de la prompterul MS-DOS. Aparent nu se întâmplă nimic, numai că, dacă apăsăm pe push-button-ul de pe extensia portului paralel, vom constata că programul nostru este rezident în memorie şi verifică (de 18.2 ori pe secundă) starea liniei ACK din portul paralel. Pentru a vedea unde s-a instalat în memorie acest program, vom apela la utilitarul DEBUG, aşa că vom tasta următoarele comenzi: C:\Mm>debug -d0:70 l4 0000:0070 02 01 E4 0C .... -u0ce4:0102 0CE4:0102 50 PUSH AX 0CE4:0103 52 PUSH DX 0CE4:0104 BA7803 MOV DX,0378 0CE4:0107 B080 MOV AL,80 0CE4:0109 EE OUT DX,AL 0CE4:010A BA7903 MOV DX,0379 0CE4:010D EC IN AL,DX 0CE4:010E 2440 AND AL,40 0CE4:0110 7408 JZ 011A 0CE4:0112 E461 IN AL,61 0CE4:0114 24FC AND AL,FC 0CE4:0116 E661 OUT 61,AL 0CE4:0118 EB08 JMP 0122 0CE4:011A E461 IN AL,61 0CE4:011C 0C03 OR AL,03 0CE4:011E E661 OUT 61,AL 0CE4:0120 EBE2 JMP 0104 -u 0CE4:0122 5A POP DX 0CE4:0123 58 POP AX 0CE4:0124 CF IRET 0CE4:0125 B80000 MOV AX,0000 0CE4:0128 8EC0 MOV ES,AX

Page 96: Microprocesoare Si Microcontrolere

96 Programe Rezidente în Memorie

0CE4:012A 8CC8 MOV AX,CS 0CE4:012C 8ED8 MOV DS,AX 0CE4:012E 9C PUSHF 0CE4:012F FA CLI 0CE4:0130 4D DEC BP 0CE4:0131 0A0D OR CL,[DI] 0CE4:0133 1100 ADC [BX+SI],AX 0CE4:0135 0201 ADD AL,[BX+DI] 0CE4:0137 26 ES: 0CE4:0138 A37000 MOV [0070],AX 0CE4:013B 9D POPF 0CE4:013C B0B6 MOV AL,B6 0CE4:013E E643 OUT 43,AL 0CE4:0140 54 PUSH SP 0CE4:0141 4D DEC BP -

Programul anterior nu face apel la funcţii ale sistemului de operare pentru procedurile de rerutare a vectorului de întrerupere sau pentru a asigura rezidenţa programului. Au fost preferate aceste metode pentru că sunt mult mai didactice, lăsând celui care programează libertatea de a controla în fiecare moment ce instrucţiuni execută efectiv microporcesorul. După cum se poate vedea, vectorul pentru întreruperea 1Ch a fost modificat, iar la noua adresă găsim în memorie handler-ul scris de noi. Câte glume de prost gust se pot face exploatând aceast stil de programare… Am putea scrie un handler care să conţină o secvenţă delay, aşa că de 18.2 ori pe secundă caculatorul ar pierde ceva timp de fiecare dată şi utilizatorul va observa că în mod inexplicabil calculatorul rulează mai încet. Dar mai bine să ne imaginăm lucruri utile care cu siguranţă vor fi mult mai multe decât putem crede la prima vedere.

La fiecare apăsare a unei taste, acţiunea este semnalizată BIOS-ului prin intermediul unei întreruperi de tip 09h (INT 9h). Această întrerupere este frecvent redirectată cu scopuri mai puţin nobile. Se pot face multe glume de prost gust cum ar fi: dezactivarea unor taste, modificarea semnificaţiei normale a acestora sau scrierea automată a unui text "enervant" la tastarea unei combinaţii prestabilite. Cu ajutorul comenziilor din utilitarul DEBUG noi vom realiza un program care va redirecta întreruperea 09h pentru a genera un "beep" la apăsarea unei taste. Subrutina originală este apelată din acest nou handler prin intermediul unui instrucţiuni CALL FAR la o adresă salvată în corpul handler-ului la adresa offset 104h - 106h. Înainte de lansarea în execuţie la această adresă offset a handler-ului este o adresă fictivă (cafe:bece) care are doar scopul de a trasmite spre asamblorul din utilitarul DEBUG o instrucţiune corectă. Comentariile din cadrul programului următor sunt suficiente pentru a înţelege modul de lucru a unui astfel de handler. -a

Page 97: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

97

1396:0100 jmp 12a ;salt la start program, peste handler 1396:0102 pushf ;handler, salvez stare fanions (IRET). 1396:0103 call cafe:bece ;call handler original 1396:0108 sti ;activăm întreruperile 1396:0109 push ax ;salvez starea reg. utilizaţi 1396:010A push bx 1396:010B push cx 1396:010C in al,61 ;deschid poarta spre difuzor 1396:010E or al,03 1396:0110 out 61,al 1396:0112 mov bx,001f ;secvenţa delay, cât durează sunetul 1396:0115 mov cx,ffff 1396:0118 loopnz 118 1396:0119 dec bx 1396:011B cmp bx,0000 1396:011E jnz 115 1396:0120 in al,61 ;închid poarta spre difuzor 1396:0122 and al,fd 1396:0124 out 61,al 1396:0126 pop cx ;refac starea reg. distruşi 1396:0127 pop bx 1396:0128 pop ax 1396:0129 iret ;return din întrerupere 1396:012A mov ax,0000 ;aici începe programul, secvenţa de 1396:012D mov es,ax ;iniţializare reg. ES, DS 1396:012F mov ax,cs 1396:0131 mov ds,ax 1396:0133 pushf ;pe stivă starea curentă a fanion-elor 1396:0134 cli ;dezactivăm întreruperile 1396:0135 es: 1396:0136 mov ax,[0024] ;în AX adresa handler original INT 09h 1396:0139 mov [0104],ax ;adresa call ,,, la adresa originală 1396:013C es: 1396:013D mov ax,[0026] 1396:0140 mov [0106],ax 1396:0143 mov ax,cs ;voloarea din CS în AX 1396:0145 es: ;adresa noului handler în tabela 1396:0146 mov [0026],ax ;vectorilor de întrerupere 1396:0149 mov ax,0102 1396:014C es: 1396:014D mov [0024],ax 1396:0150 popf ;refac starea fanion-elor 1396:0151 mov al,b6 ;pregătesc 8254 pentru generare sunet 1396:0153 out 43,al 1396:0155 mov al,ff 1396:0157 out 42,al 1396:0159 mov al,0f 1396:015B out 42,al 1396:015D mov dx,012a ;reg. DX offset sfîrşit handler 1396:0160 int 27 ;să rămână resident 1396:0162 mov ax,4c00 ;invocăm ieşire în DOS 1396:0165 int 21 1396:0167

Page 98: Microprocesoare Si Microcontrolere

98 Programe Rezidente în Memorie

-nkeys.com -rcx CX 0000 :67 -w Writing 00067 bytes -

Pentru a putea vedea ce se întâmplă la lansarea în execuţie a programului precedent scriem în continuare următoarea secvenţă de comenzi în cadrul utilitarului DEBUG. C:\Mm>debug -nkeys.com -l -d0:24 l4 0000:0020 28 00 66 08 (.f. -u 1393:0100 EB28 JMP 012A 1393:0102 9C PUSHF 1393:0103 9A28006608 CALL cafe:bece 1393:0108 FB STI 1393:0109 50 PUSH AX 1393:010A 53 PUSH BX 1393:010B 51 PUSH CX 1393:010C E461 IN AL,61 1393:010E 0C03 OR AL,03 1393:0110 E661 OUT 61,AL 1393:0112 BB1F00 MOV BX,001F 1393:0115 B9FFFF MOV CX,FFFF 1393:0118 E0FE LOOPNZ 0118 1393:011A 4B DEC BX 1393:011B 83FB00 CMP BX,+00 1393:011E 75F5 JNZ 0115 -t AX=0000 BX=0000 CX=0067 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=012A NV UP EI PL NZ NA PO NC 1393:012A B80000 MOV AX,0000 -t AX=0000 BX=0000 CX=0067 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=1393 SS=1393 CS=1393 IP=012D NV UP EI PL NZ NA PO NC 1393:012D 8EC0 MOV ES,AX -t AX=0000 BX=0000 CX=0067 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=0000 SS=1393 CS=1393 IP=012F NV UP EI PL NZ NA PO NC 1393:012F 8CC8 MOV AX,CS -t AX=1393 BX=0000 CX=0067 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000

Page 99: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

99

DS=1393 ES=0000 SS=1393 CS=1393 IP=0131 NV UP EI PL NZ NA PO NC 1393:0131 8ED8 MOV DS,AX -t AX=1393 BX=0000 CX=0067 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 DS=1393 ES=0000 SS=1393 CS=1393 IP=0133 NV UP EI PL NZ NA PO NC 1393:0133 9C PUSHF -t AX=1393 BX=0000 CX=0067 DX=0000 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=0000 SS=1393 CS=1393 IP=0134 NV UP EI PL NZ NA PO NC 1393:0134 FA CLI -t AX=1393 BX=0000 CX=0067 DX=0000 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=0000 SS=1393 CS=1393 IP=0135 NV UP DI PL NZ NA PO NC 1393:0135 26 ES: 1393:0136 A12400 MOV AX,[0024] ES:0024=0028 -t AX=0028 BX=0000 CX=0067 DX=0000 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=0000 SS=1393 CS=1393 IP=0139 NV UP DI PL NZ NA PO NC 1393:0139 A30401 MOV [0104],AX DS:0104=0028 -t AX=0028 BX=0000 CX=0067 DX=0000 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=0000 SS=1393 CS=1393 IP=013C NV UP DI PL NZ NA PO NC 1393:013C 26 ES: 1393:013D A12600 MOV AX,[0026] ES:0026=0866 -t AX=0866 BX=0000 CX=0067 DX=0000 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=0000 SS=1393 CS=1393 IP=0140 NV UP DI PL NZ NA PO NC 1393:0140 A30601 MOV [0106],AX DS:0106=0866 -t AX=0866 BX=0000 CX=0067 DX=0000 SP=FFFC BP=0000 SI=0000 DI=0000 DS=1393 ES=0000 SS=1393 CS=1393 IP=0143 NV UP DI PL NZ NA PO NC 1393:0143 8CC8 MOV AX,CS -u100 1393:0100 EB28 JMP 012A 1393:0102 9C PUSHF 1393:0103 9A28006608 CALL 0866:0028 1393:0108 FB STI 1393:0109 50 PUSH AX 1393:010A 53 PUSH BX 1393:010B 51 PUSH CX 1393:010C E461 IN AL,61 1393:010E 0C03 OR AL,03

Page 100: Microprocesoare Si Microcontrolere

100 Programe Rezidente în Memorie

1393:0110 E661 OUT 61,AL 1393:0112 BB1F00 MOV BX,001F 1393:0115 B9FFFF MOV CX,FFFF 1393:0118 E0FE LOOPNZ 0118 1393:011A 4B DEC BX 1393:011B 83FB00 CMP BX,+00 1393:011E 75F5 JNZ 0115 -g Program terminated normally -d0:24 l4 0000:0020 02 01 93 13 .... -q

Orice comemntariu este de prisos în acest moment. O serie de transformări pot fi observate atât în corpul programului cât şi în tabela vectorilor de întrerupere.

Figura 5.1. Diagrama bloc a circuitului 8259.

De asemenea, o atenţie deosebită trebuie să acordăm fanionul-ui de întrerupere. Orice redirectare din tabela vectorilor de întrerupere este precedată de dezactivarea tuturor întreruperilor, pe perioada necesară redirectării. Despre utilitatea portului paralel în aplicaţii simple de achiziţie de date şi control cred că acum suntem

D0

D1 INTA

D3

D4

D5

D6

D7

/RD

D2

IR6

A0

/CS

/WR

CAS0

CAS2

IR0

8259

CAS1

IR2

IR7

INT

IR1

SP

IR3

IR4

IR5

Page 101: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

101

convinşi. Aria aplicaţiilor şi implicit calitatea acestora ar creşte dacă ar fi posibilă lansarea unei întreruperi hard prin intermediul portului paralel. Calculatorul ar rula diverse programe şi la apariţia unui eveniment extern (generat de un fenomen fizic de exemplu) se va genera o întrerupere care va activa handler-ul specific unei aplicaţii date. Microprocesorul va fi astfel implicat în procesul de achiziţie de date şi control numai atunci când prezenţa lui este necesară. Dacă nu ar exista această posibilitate microprocesorul ar trebui să ruleze într-o buclă infinită în corpul cărei-a tot timpul va testa îndeplinirea unei condiţii (ar fi un mod ineficient de utilizare a microprocesorului).

Lansarea unei întreruperi hard din portul paralel este posibilă. Înţelegerea unui asemenea handler implică studierea mecanismului (hard-ului) prin care un semnal extern (nivel logic) devine semnal de întrerupere (INT) pentru microprocesor. Deoarece microprocesoarele au, o singură linie de întrerupere supervizarea mai multor posibile surse de intrerupere, respectiv ierarhizarea lor în raport cu un criteriu de prioritate este lăsată în sarcina unui circuit specializat, controler-ul de întreruperi programabil, 8259.

Circuitul 8259 (figura 5.1) este un controler de întreruperi programabil. Un singur circuit poate trata până la 8 cereri de întrerupere, rezolvând şi problemele de prioritate aferente. Legând în cascadă (CAS0, …, CAS2) mai multe astfel de circuite se pot trata până la 64 cereri de întrerupere. Într-un calculator compatibil IBM PC sunt două astfel de circuite. Cererile de întrerupere se pot masca în mod individual. În figura 5.1 sunt prezentate conexiunile exterioare ale circuitului sub forma unei diagrame bloc. Programarea circuitului constă în trimiterea spre acesta a unor cuvinte de comandă. Pregătirea circuitului pentru operare se face cu ajutorul unor cuvinte de iniţializare (ICW). Caracteristicile funcţionale ale circuitului se stabilesc prin intermediul unor cuvinte de comandă (OCW). Tot prin intermediul acestora poate fi citită şi starea circuitului. În tabelul 5.1 se prezintă în rezumat programarea circuitului, respectiv citirea stării sale. De asemenea, să reţinem secvenţa obligatorie, EOI (End Of Intereupt); mov al,20 out 20,al prin care circuitul este înştiinţat că întreruperea a fost procesată de către handler. După secvenţa EOI circuitul este gata să solicite atenţia microprocesorului pentru o altă întrerupere. Noua întrerupere transmisă microprocesorului va fi selectată funcţie de prioritatea întreruperii (dată de modul de cablarea a circuitului 8259) respectiv conţinutul registrului de mascare a întreruperilor.

Page 102: Microprocesoare Si Microcontrolere

102 Programe Rezidente în Memorie

Tabelul 5.1 A0 D4 D3 RD WR CS Operaţii 0 0 1 0 Citeşte registrele IRR, ISR 1 0 1 0 Citeşte registrul de mascare 0 1 X 1 0 0 Depune ICW1 0 0 1 0 0 0 Depune OCW2 0 0 1 1 0 0 Depune OCW3 1 X X 1 0 0 Depune OCW1, ICW2 sau ICW3 X X X 1 1 0 D0-D7 sunt trecute în SIR X X X X X 1 D0-D7 sunt trecute în SIR

Aceste informaţii sunt suficiente pentru a realiza un program care să

activeze linia ACK din portul paralel pentru întreruperea IRQ7. Utilizând comenziile utilitarului DEBUG realizăm următorul program care va rămâne rezident şi va fi activat prin internediul liniei ACK - IRQ7 din portul paralel (capitolul 4, tabelul 4.2). -a 1371:0100 jmp 135 ;salt la start program, peste handler 1371:0102 cli ;aici începe handler, rămâne resident 1371:0103 pushf 1371:0104 push ax 1371:0105 push bx 1371:0106 push cx 1371:0107 push dx 1371:0108 mov dx,0378 1371:010B mov al,ff 1371:010D out dx,al 1371:010E mov dx,379 1371:0111 mov bx,00ff ;întârziere pentru a elimina zgomotele 1371:0114 mov cx,ffff ;electrice generate de push-button 1371:0117 loopnz 117 1371:0119 dec bx 1371:011A cmp bx,0000 1371:011D jnz 114 1371:011F in al,dx 1371:0120 cmp al,38 1371:0122 jz 0111 1371:0124 mov dx,378 1371:0127 mov al,00 1371:0129 out dx,al 1371:012A mov al,20 ;secvenţa EOI 1371:012C out 20,al 1371:012E pop dx 1371:012F pop cx

Page 103: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

103

1371:0130 pop bx 1371:0131 pop ax 1371:0132 popf 1371:0133 sti 1371:0134 iret 1371:0135 mov ax,0000 ;secvenţa redirectare IRQ7 1371:0138 mov es,ax 1371:013A mov ax,cs 1371:013C mov ds,ax 1371:013E pushf 1371:013F cli 1371:0140 es: 1371:0141 mov [003e],ax 1371:0144 mov ax,0102 1371:0147 es: 1371:0148 mov [003c],ax 1371:014B popf 1371:014C mov dx,16e ;secvenţa mesaj display 1371:014F mov ah,09 1371:0151 int 21 1371:0153 mov dx,37a ;secvenţa activare IRQ7 1371:0156 in al,dx 1371:0157 or al,10 1371:0159 out dx,al 1371:015A in al,21 ;secvenţa de mask-are întreruperi 1371:015C and al,7f 1371:015E out 21,al 1371:0160 mov al,20 ;secvenţa EOI 1371:0162 out 20,al 1371:0164 mov dx,0135 ;secvenţa resident 1371:0167 int 27 1371:0169 mov ax,4c00 ;secvenţa exit DOS 1371:016C int 21 1371:016E db 0a,0d,"verme la lucru",0a,0d,0a,0d,"$" 1371:0183 -nverme.com -rcx CX 0000 :83 -w Writing 00083 bytes -

Comentariile din corpul programului asigură înţelegerea modului de lucru a acestui handler. Pe timpul cât acest hadler este activ, activitatea sistemului este oprită, deoarece toate întreruperile sunt dezactivate (CLI). Este un bun exemplu de programare agresivă a sistemului, practic pe timpul rulării handlerului sistemul "este la mâna noastră". Pentru o bună însuşire a acestor tehnici agresive de programare pot fi imaginate de fiecare dintre noi programe interesante. Să le vedem la lucru.

Page 104: Microprocesoare Si Microcontrolere

104 Programe Rezidente în Memorie

Page 105: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

105

6. Perioada şi Frecvenţa unui Semnal Extern

Realizarea unor programe prin intermediul cărora să potă fi determinaţi parametrii fizici (perioadă, frecvenţă) ai unui semnal extern este un bun antrenament pentru o situaţie reală din domeniul achiziţiei de date şi control. Deoarece sistemul de operare Windows xxxx este de tip multitasking, pentru o bună funcţionare a programelor din acest capitol, calculatorul trebuie să fie restartat în modul MS-DOS. Această trecere în modul MS-DOS simplifică procedurile de tratare a întreruperilor, ceea ce duce la posibilitatea realizării programelor din aceast capitol, apelând numai la elementele sistemului de operare. Într-un mediu de programare evoluat, se pot scrie programe identice funcţional care să poată rula sub un sistem de operare performant, numai că, noi vom apela şi de această dată la serviciile oferite de utilitarul DEBUG, care desigur sunt minimale. Este bine să reţinem că scopul tuturor programelor este numai acela de a învăţa cîteva proceduri standard, într-un mod interactiv, cu utilizarea minimală a facilităţilor sistemului de operare. Desigur că, programele sunt dezvoltate, de regulă, cu ajutorul unui mediu specializat şi dedicat fiecărui limbaj de programare de nivel înalt. Programarea orientată pe obiecte şi mediile "Visual" au adus unelte noi, extrem de eficiente, cu ajutorul cărora programatorul poate realiza relativ uşor aplicaţii aparent sofisticate.

Cu toate acestea, orice mediu de programare permite scrierea unei părţi din program (sau cel puţin permite inserarea unor subrutine, inline) în limbaj de asamblare. Acest lucru este necesar ori de câte ori nu se poate altfel, adică, atunci când performanţele impuse de aplicaţie nu pot fi atinse prin programarea în limbaj de nivel înalt. Trebuie reţinut că marele merit al limbajului de asamblare este acela că programatorul ştie exact ce instrucţiune va executa microprocesorul în fiecare moment şi de cât timp va fi nevoie pentru a executa instrucţiunea respectivă. Desigur, acest stil de programare nu este frecvent întâlnit şi este legat de instrumentaţia virtuală, de supervizarea în timp real a unor procese externe şi/sau prelucrarea în timp real a informaţiei. Acestea sunt tocmai acele aplicaţii specifice domeniilor experimentale din fizică. Aşa că, această carte nu are alt scop decât acela de a specializa pe cei familiarizaţi cu cel puţin un limbaj de nivel înalt (preferabil C), cu stilul de programare şi câteva proceduri specifice domeniului embedded system.

Nivelul de specializare pe care-l putem atinge prin aceste programe este, din păcate, cel de novice deoarece tehnologiile digitale sunt atât de dezvoltate în prezent (şi în plină dezvoltare), încât este nevoie de un efort considerabil pentru a învăţa la nivel de avansat, chiar şi numai tehnologiile specifice unui subdomeniu. Acest lucru

Page 106: Microprocesoare Si Microcontrolere

106 Perioada şi Frecvenţa unui Semnal Extern

se datorează, pe de o parte, complexităţii şi specializării componentelor hardware şi pe de altă parte, evoluţiei şi specializării mediilor de lucru şi limbajelor de programare generate de noile tehnologii.

Pentru început, va trebui să realizăm un dispozitiv extern (hardware) care să genereze un semnal ai cărui parametrii fizici îi vom determina cu ajutorul unor programe scrise în limbaj de asamblare. Plecând de la experienţa pe care o avem cu portul paralel, vom completa modulul de extensie a portului paralel prezentat în capitolul patru cu un generator de semnal dreptunghiular (figura 6.1).

Figura 6.1. Schema generatorului de semnal dreptunghiular.

Deoarece pentru modulul de extensie din portul paralel nu este utilizată o

sursă externă de alimentare şi această facilitate vrem să o pastrăm şi în continuare, vom utiliza un circuit integrat realizat în tehnologie CMOS (CD4011, patru porţi NAND cu două intrări). Aceste circuite au un consum redus de energie, aşa că, vom putea utiliza şi de această dată un semnal de ieşire al portului paralel (Data 7) drept sursă de energie. De asemenea, pentru a putea adapta acest modul la orice situaţie particulară de implementare (sau obţinută în urma operaţiilor de setare-iniţializare) a portului paralel, vom utiliza la ieşirea generatorului de semnal dreptunghiular o

DATA 7 PIN 14

10uF 0.1uF

PIN 14

ACK

82k

39k

22nF

5K6100K

3k3

68k

10k 10k

BC547

CD4011

Page 107: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

107

configuraţie de tip open-collector (colectorul în gol). Frecvenţa (perioada) semnalului poate fi modificată (din potenţiometrul de 100k) în limite rezonabile (numai în domeniul audio), astfel încât, după ce vom cunoaşte parametri fizici ai semnalului extern, să putem face şi o evaluare a performanţelor calculatorului pe care rulăm programele din această carte.

După cum se poate vedea în figura 6.1, noul modul de extensie prin intermediul unui jumper asigură o facilă adaptare a extensiei hardware la tipul de program ce urmează a fi implementat. Realizarea practică a acestei noi părţi a modulului de extensie este prezentată în figura 6.2, aceasta a fost interconectată cu modulul de extensie iniţial, formând astfel o unitate hardware externă care acoperă o mare parte din programele prezentate în primele şase capitole din această carte.

Figura 6.2. Realizarea practica a generatorului de semnal dreptunghiular.

Pentru a putea acoperi o arie largă de aplicaţii, altele decât cele prezentate

în această carte, semnalul dreptunghiular este aplicat pe linia ACK a portului paralel. Deoarece parametrii externi (RC) ai generatorului de semnal dreptunghiular (realizat cu circuitul integrat CD4011) fixează domeniul frecvenţelor generate la

Page 108: Microprocesoare Si Microcontrolere

108 Perioada şi Frecvenţa unui Semnal Extern

spectrul audio, ne punem problema dacă semnalul extern produs de generatorul de semnal dreptunghiular nu poate fi auzit în difuzorul calculatorului. La o primă evaluare, acest lucru pare imposibil, deoarece nu putem realiza o legătură fizică între ieşirea generatorului de semnal dreptunghiular (conectat la portul paralel) şi difuzor, fără a interveni distructiv în cablarea iniţială a calculatorului IBM PC. După cum deja ştim, difuzorul este conectat fizic la circuitul 8254 prin intermediul unei porţi controlate (PB1) cu ajutorul circuitului 8255. În unul din primele noastre programe de producere a unui sunet în difuzorul calculatorului am generat sunetul din difuzor prin controlul stării porţii de la ieşirea OUT2 a circuitului 8254. Tot prin intermediul circuitului 8255 (PB0) numărătorul (CNT2) era blocat prin fixarea stării pentru intrarea GATE2 în "0" logic. Dacă vom reuşi să controlăm poarta spre difuzor, sincron cu starea semnalului extern produs de generatorul de semnal dreptunghiular, atunci vom reproduce în difuzor chiar acest semnal. Realizarea unui program care să captureze starea liniei ACK din portul paralel (379h pentru LPT1) şi să o transfere pe linia PB1 (61h) a circuitului PPI 8255 nu este o sarcină dificilă la nivelul actual de competenţă. Nu trebuie să uităm nici un moment că generatorul de semnal dreptunghiular este alimentat cu energie din linia de ieşire Data 7 a portului paralel (378h pentru LPT1). Aşa că, apelând la comenzile utilitarului DEBUG vom realiza şi rula următorul program: -a 1371:0100 mov dx,378 ;alimentăm generatorul de semnal 1371:0103 mov al,80 1371:0105 out dx,al 1371:0106 mov dx,379 ;citim starea curentă a liniei ACK 1371:0109 in al,dx 1371:010A and al,40 ;reţinem numai această informaţie 1371:010C ror al,1 ;o aducem în pozitia PB1, 8255 1371:010E ror al,1 1371:0110 ror al,1 1371:0112 ror al,1 1371:0114 ror al,1 1371:0116 push ax 1371:0117 in al,61 ;reţimen starea curentă a portului 61h 1371:0119 pop bx 1371:011A and al,fd ;preparăm noul conţinit pentru port 61h 1371:011C or al,bl 1371:011E out 61,al ;starea liniei ACK copită în portul 61h 1371:0120 mov ah,01 ;verificăm keyboard 1371:0122 int 16 1371:0124 jz 100 ;dacă nu este tasta apasată reluăm 1371:0126 in al,61 ;altfel facem pregătirile pt. exit 1371:0128 and al,fd 1371:012A out 61,al 1393:012C mov dx,378 1393:012F mov al,00

Page 109: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

109

1393:0131 out dx,al 1393:0132 mov ax,4c00 1393:0135 int 21 1393:0137 -nppados.com -rcx CX 0000 :37 -w Writing 00037 bytes -

Modificând frecvenţa semnalului generat (din potenţiometrul de 100k) ne vom convinge atât de buna fucţionare a programului, cât şi de eficienţa metodei utilizate. Dacă în locul semnalului produs de generatorul de semnal dreptunghiular vom conecta un semnal provenit de la un montaj, ce conţine un microfon urmat de un amplificator-limitator, în difuzor vom auzi sunetele produse în faţa microfonului. Metoda utilizată, de eşantionare pe un bit, este suficient de puternică pentru a reda vocea umană inteligibil. Chiar şi o analiză sumară a acestui program pune în dificultate experienţa noastră legată de materialitatea unui semnal fizic (exprimat sub forma: u = U(t) sau i = I(t)). Cunoştinţele noastre clasice de electricitate şi/sau electronică, în care totul era măsurabil şi palpabil, sunt incapabile să explice prin relaţii fizice uzuale acest transfer de semnal. Nu avem un suport material clasic, în sensul proprietăţii unor materiale de a fi bune conductoare de curent electric, pentru acest transfer. În programul precedent, prin eşantionarea semnalului dreptunghiular din portul de intrare, reţinem o informaţie referitoare la starea semnalului în acel moment ("0" sau "1" logic ). Ulterior, prin transferul acestei informaţii într-un port de ieşire, semnalul este refăcut în forma iniţială. Faptul că un semnal fizic poate exista pentru un moment (practic oricât de lung) sub formă de informaţie despre semnalul fizic este principiul de bază al procesării digitale a semnalelor. Acest salt de la realitatea materială, palpabilă şi primitivă, la un univers în care avem doar informaţii despre această realitate materială este, din păcate imposibil pentru prea mulţi dintre noi.

Aşa cum universul real poate fi reprezentat sub forma unor informaţii digitale şi produsul imaginaţiei noastre poate fi reprezentat, la fel de bine, sub această formă. Coexistenţa în forma aceleaşi reprezentări a realului şi a imaginarului este fără indoială suportul universului virtual. Acest nou univers, generat de saltul tehnologic de la sfârşitul secolului XX este în plină expansiune şi probabil mulţi dintre noi se vor muta aici cât de curând. În universul real, dacă frecvenţa unui semnal este audibilă, atunci el poate fi doar auzit, dar nu poate fi văzut atâta timp cât creierul nostru nu suferă de o afecţiune ce ţine de domeniul parapsihologiei. Pentru a fi văzut, el trebuie să fie într-un domeniu de frecvenţe numit spectru

Page 110: Microprocesoare Si Microcontrolere

110 Perioada şi Frecvenţa unui Semnal Extern

vizibil. Aşa că, pentru a vedea ceea ce ar trebui doar să auzim, vom apela la suportul tehnologic oferit de calculatorul personal. Nu trebuie să uităm nici un moment că suntem într-un univers virtual, iar aici, în sfârşit, nu mai avem nici o graniţă între realitate şi imaginaţie. Pentru a putea scrie programul prin care să vedem sunetul, trebuie mai întâi să învăţăm câte ceva despre capabilităţiile grafice ale calculatorului personal IBM PC.

Dacă în programele de pîna acum am utilizat numai modul text al ecranului reţinem că pentru a putea desena pe ecran acesta va trebui controlat la nivel de pixel (punct pe ecran). Modurile grafice spre deosebire de modurile text ne permit să desenăm puncte pe ecran, şi astfel să construim pe ecran imagini oricât de complexe. Numărul de pixeli pe care-i putem controla, pe ecran, depinde de modul de lucru ales. Pentru a putea alege un mod din ce în ce mai performant, avem nevoie de o placa video şi un monitor din ce în ce mai performante. Cu alte cuvinte, cu cât modul grafic ales are o rezoluţie mai mare (număr de pixeli raportat la numărul de culori pe pixel) cu atât avem nevoie de mai multă memorie diponibilă pe placa video (numită memorie video nu numai din motive legate de destinaţie cât mai ales pentru a justifica performanţele electrice ale acesteia). Deoarece placa video din calculatoarele personale compatibile IBM PC a avut fără îndoială cea mai tumultoasă istorie şi este încă o componentă în plină evoluţie, nu vom insista asupra modurilor de lucru ale ecranului aşa-zis "istorice". Sistemele moderne de operare utilizează numai modul grafic de înaltă rezoluţie al plăcilor video. La rândul lor, acestea (placile video) încorporează procesoare specializate în prelucrarea avansată a imaginilor. Scopul programelor din acest capitol este numai acela de a ilustra capabilităţiile grafice ale calculatoarelor şi relaţia dintre imaginea vizualizată pe ecran şi parametri fizici ai unui semnal extern. Fiecare pixel de pe ecran are o coordonată de rând şi una de coloană. Dacă apelăm la seviciile BIOS, lucrul în mod grafic nu ridică mari dificultăţi. Astfel, vom invoca serviciile de ecran din componenta BIOS (INT 10) pentru stabilirea modului de lucru a ecranului respectiv pentru a desena un punct pe ecran. Dacă cu ajutorul programului precedent am auzit semnalul extern produs de generatorul de semnal dreptunghiular în continuare apelând la facilităţiile utilitarului DEBUG vom realiza un program prin intermediul caruia să vizualizăm pe ecran acest semnal. -a100 1371:0100 jmp 126 ;salt la adresa de start a programului 1371:0102 mov dx,bx ;desenează un punct pe ecran, mod grafic 1371:0104 mov bx,0000 1371:0107 mov ah,0c 1371:0109 int 10 1371:010B cmp cx,027f ;număr maxim de coloane 1371:010F jz 114

Page 111: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

111

1371:0111 inc cx 1371:0112 jmp 123 1371:0114 mov cx,0000 1371:0117 cmp dx,01df ;număr maxim de linii 1371:011B jz 120 1371:011D inc dx 1371:011E jmp 123 1371:0120 mov dx,0000 1371:0123 mov bx,dx 1371:0125 ret 1371:0126 mov dx,378 ;alimentăm generatorul de semnal 1371:0129 mov al,80 1371:012B out dx,al 1371:012C mov bx,0000 ;fixăm poziţia iniţială ecran mod grafic 1371:012F mov cx,0000 1371:0132 mov al,12 ;fixăm mod grafic - 12h 1371:0134 mov ah,00 1371:0136 int 10 1371:0138 mov dx,379 ;citim stare semnal extern, ACK 1371:013B in al,dx 1371:013C and al,40 ;reţinem numai informaţia utilă 1371:013E ror al,1 ;o poziţionăm pentru serviciul video 1371:0140 ror al,1 1371:0142 ror al,1 1371:0144 ror al,1 1371:0146 ror al,1 1371:0148 ror al,1 1371:014A call 0102 ;desenează un punct pe ecran 1371:014D mov ah,01 ;testăm keyboard 1371:014F int 16 1371:0151 jz 0138 ;daca nu este tasta apasată 1371:0153 mov ah,00 ;altfel, trecem în mod text 1371:0155 mov al,02 1371:0157 int 10 1393:0159 mov dx,378 ;oprim generatorul de semnal 1393:015C mov al,00 1393:015E out dx,al 1393:015F mov ax,4c00 ;invocăm ieşire în DOS 1393:0162 int 21 1393:0164 -nppvdos.com -rcx CX 0000 :64 -w Writing 00064 bytes -

Rularea programului precedent va determina comutarea ecranului în modul grafic prin invocarea INT 10 urmată de desenarea pe ecran a unor imagini a căror formă este greu de interpretat. Forma acestor imagini este puternic influenţată de frecvenţa semnalului dreptunghiular (potenţiometrul de 100k). Pentru unele

Page 112: Microprocesoare Si Microcontrolere

112 Perioada şi Frecvenţa unui Semnal Extern

frecvenţe se pot obţine imagini relativ stabile de forma celor prezentate în figura 6.3. Dacă facem o paralelă cu imaginile TV am putea spune că avem imagini nesincronizate. Lucrul acesta este pe deplin adevărat deoarece nu am stabilit în programul precedent nici o condiţie/relaţie între semnalul extern şi imaginea desenată pe ecran. Un alt neajuns al programului ar fi pierderea informaţiei iniţiale, sunetul. Aşa că, se prefigurează două direcţii de acţiune: pe de o parte recuperarea informaţiei audio şi pe de altă parte obţinerea unor imagini stabile pe ecran, indiferent de frecvenţa semnalului dreptunghiular generat de modulul de extensie. Chiar cu neajunsurile menţionate anterior programele precedente sunt un mare pas înainte spre stadiul de novice în domeniul embedded system. Acum suntem convinşi că un semnal extern poate ajunge sub formă de "informaţie despre el" în calculator, iar pe baza acestei informaţii acesta poate fi recreat (sub formă de sunet) sau poate fi creată o imagine cu o formă dependentă de parametrii unui semnal extern.

Figura 6.3. Exemplu de imaginea obţinută pe ecran prin rularea programului ppvdos.com.

Dacă nu cumva suntem "academicieni ocupaţi cu pontajul oamenilor de

ştiinţă", putem realiza un program care să execute simultan cele două task-uri (sunet

Page 113: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

113

şi imagine) din programele precedente. Aşa că, apelând la utilitarul DEBUG vom putea realiza următorul program: -a100 1371:0100 jmp 126 1371:0102 mov dx,bx 1371:0104 mov bx,0000 1371:0107 mov ah,0c 1371:0109 int 10 1371:010B cmp cx,027f 1371:010F jz 114 1371:0111 inc cx 1371:0112 jmp 123 1371:0114 mov cx,0000 1371:0117 cmp dx,01df 1371:011B jz 120 1371:011D inc dx 1371:011E jmp 123 1371:0120 mov dx,0000 1371:0123 mov bx,dx 1371:0125 ret 1371:0126 mov dx,378 1371:0129 mov al,80 1371:012B out dx,al 1371:012C mov bx,0000 1371:012F mov cx,0000 1371:0132 mov al,12 1371:0134 mov ah,00 1371:0136 int 10 1371:0138 mov dx,379 1371:013B in al,dx 1371:013C and al,40 1371:013E ror al,1 1371:0140 ror al,1 1371:0142 ror al,1 1371:0144 ror al,1 1371:0146 ror al,1 1371:0148 push bx 1393:0149 push ax 1393:014A push ax 1393:014B in al,61 1393:014D pop bx 1393:014E and al,fd 1393:0150 or al,bl 1393:0152 out 61,al 1393:0154 pop ax 1393:0155 pop bx 1393:0156 ror al,1 1393:0158 call 0102 1393:015B mov ah,01 1393:015D int 16 1393:015F jz 0138 1393:0161 mov ah,00

Page 114: Microprocesoare Si Microcontrolere

114 Perioada şi Frecvenţa unui Semnal Extern

1393:0163 mov al,02 1393:0165 int 10 1393:0167 mov dx,0378 1393:016A mov al,00 1393:016C out dx,al 1393:016D mov ax,4c00 1393:0170 int 21 1393:0172 -nppavdos.com -rcx CX 0000 :72 -w Writing 00072 bytes -

Dacă ne bazăm pe experienţa noastră în acest domeniu, acumulată până în prezent, şi comentariile ce însoţesc programele precedente, înţelegerea acestora nu ar trebui să fie în acest stadiu o problemă pentru noi. Acum suntem mai aproape ca niciodată de stadiul de novice în domeniul embedded system. A fost uşor să scriem un program care să producă simultan sunet şi imagine, numai că imaginea în continuare depinde în mod aleatoriu de frecvenţa semnalului extern. Pentru a elimina acest neajuns este necesară realizarea unui program care să producă pe ecran o imagine sincronă. Două informaţii sunt bine localizate temporal în evoluţia semnalului dreptunghiular. Acestea sunt tranziţia din "0" logic în "1" logic a semnalului respectiv tranziţia din "1" logic în "0" logic. Deoarece în cazul tranziţiei din "0" logic în "1" logic avem de-a face la ieşirea generatorului de semnal dreptungiular cu o trecere de la o tensiune mică la una mare vom spune în continuare că această trecere este frontul pozitiv al semnalului dreptunghiular. Prin analogie pentru tranziţia inversă avem frontul negativ al semnalului dreptunghiular. Aşa că, imaginea de pe ecran poate fi sincronă cu frontul pozitiv sau negativ al semnalului extern. În acest moment ideea prinde contur şi se poate spune că desenarea fiecărei linii pe ecran trebuie începută simultan (sincron) cu un front al semnalului extern. Acest lucru implică existenţa în corpul programului a unei proceduri de testare a uneia din condiţiile menţionate. Aceasta procedură o vom numi în continuare procedură de sincronizare. Desenarea fiecărei linii din imagine este precedată de invocarea procedurii de sincronizare. În continuare vom apela la serviciile utilitarului DEBUG pentru a realiza următorul program:

-a 1393:0100 jmp 126 1393:0102 mov dx,bx 1393:0104 mov bx,0000 1393:0107 mov ah,0c 1393:0109 int 10

Page 115: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

115

1393:010B cmp cx,027f 1393:010F jz 114 1393:0111 inc cx 1393:0112 jmp 123 1393:0114 mov cx,0000 1393:0117 cmp dx,01df 1393:011B jz 120 1393:011D inc dx 1393:011E jmp 123 1393:0120 mov dx,0000 1393:0123 mov bx,dx 1393:0125 ret 1393:0126 mov dx,378 1393:0129 mov al,80 1393:012B out dx,al 1393:012C mov bx,0000 1393:012F mov cx,0000 1393:0132 mov al,12 1393:0134 mov ah,00 1393:0136 int 10 1393:0138 mov dx,379 ;procedura de sincronizare 1393:013B in al,dx 1393:013C and al,40 1393:013E mov ah,al 1393:0140 in al,dx 1393:0141 and al,40 1393:0143 cmp al,ah 1393:0145 jz 13b ;dacă nu este al diferit de ah > salt 1393:0147 cmp al,00 1393:0149 jz 13b ;dacă este al = 0 > salt 1393:014B mov dx,379 1393:014E in al,dx 1393:014F and al,40 1393:0151 ror al,1 1393:0153 ror al,1 1393:0155 ror al,1 1393:0157 ror al,1 1393:0159 ror al,1 1393:015B ror al,1 1393:015D call 102 1393:0160 cmp cx,027f 1393:0164 jnz 14b 1393:0166 mov ah,01 1393:0168 int 16 1393:016A jz 138 1393:016C mov ax,0002 1393:016F int 10 1393:0171 mov dx,378 1393:0174 mov al,00 1393:0176 out dx,al 1393:0177 mov ax,4c00 1393:017A int 21 1393:017C

Page 116: Microprocesoare Si Microcontrolere

116 Perioada şi Frecvenţa unui Semnal Extern

-nppvsn.com -rcx CX 0000 :7c -w Writing 0007C bytes -

De la linia de comandă lansăm în execuţie programul precedent. Ecranul trece în mod grafic, iar pe ecran trebuie să obţinem o imagine sincronă indiferent de frecvenţa semnalului extern. O astfel de imagine este prezentată în figura 6.4 şi după cum uşor se poate constata, fiecare linie din imaginea de pe ecran începe imediat după frontul negativ.

Figura 6.4. Exemplu de imaginea obţinută pe ecran prin rularea programului ppvsn.com.

Lansăm utilitarul DEBUG şi încărcăm programul recent realizat. Fără a rescrie programul, cu ajutorul următoarelor comenzi realizăm o nouă versiune a programului precedent care va sincroniza imaginea de pe ecran pe frontul pozitiv al semnalului extern.

Page 117: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

117

-a149 1393:0149 jnz 13b ;dacă nu este al = 0 > salt 1393:014B -nppvsp.com -rcx CX 0000 :7c -w Writing 0007C bytes -

Dacă lansăm în execuţie acest nou program, vom obţine pe ecran o imagine asemănătoare cu ceea din figura 6.5. Desigur forma imaginii depinde de frecvenţa semnalului extern, dar pentru orice frecvenţă imaginea obţinută va fi sincronă cu frontul pozitiv al acestuia.

Figura 6.5. Exemplu de imaginea obţinută pe ecran prin rularea programului ppvsp.com.

Cu ajutorul serviciilor utilitarului DEBUG realizăm în continuare un nou

program în care imaginea obţinută va fi sincronă pentru un număr de linii cu frontul pozitiv al semnalului extern şi pentru un număr de linii cu frontul negativ. Printr-o

Page 118: Microprocesoare Si Microcontrolere

118 Perioada şi Frecvenţa unui Semnal Extern

bună gestionare a ecranului se poate obţine o imagine gen "tablă de şah" (la o frecvenţă dată a semnalului extern) de forma celei din figura 6.6. -a 1393:0100 JMP 014E 1393:0102 MOV DX,BX 1393:0104 MOV BX,0000 1393:0107 MOV AH,0C 1393:0109 INT 10 1393:010B CMP CX,027F 1393:010F JZ 0114 1393:0111 INC CX 1393:0112 JMP 0123 1393:0114 MOV CX,0000 1393:0117 CMP DX,01DF 1393:011B JZ 0120 1393:011D INC DX 1393:011E JMP 0123 1393:0120 MOV DX,0000 1393:0123 MOV BX,DX 1393:0125 RET 1393:0126 MOV DX,0379 1393:0129 IN AL,DX 1393:012A AND AL,40 1393:012C MOV AH,AL 1393:012E IN AL,DX 1393:012F AND AL,40 1393:0131 CMP AL,AH 1393:0133 JZ 0129 1393:0135 CMP AL,00 1393:0137 JNZ 0129 1393:0139 RET 1393:013A MOV DX,0379 1393:013D IN AL,DX 1393:013E AND AL,40 1393:0140 MOV AH,AL 1393:0142 IN AL,DX 1393:0143 AND AL,40 1393:0145 CMP AL,AH 1393:0147 JZ 013D 1393:0149 CMP AL,00 1393:014B JZ 013D 1393:014D RET 1393:014E MOV BX,0000 1393:0151 MOV CX,0000 1393:0154 MOV AL,12 1393:0156 MOV AH,00 1393:0158 INT 10 1393:015A MOV DX,0378 1393:015D MOV AL,80 1393:015F OUT DX,AL 1393:0160 MOV DX,0379 1393:0163 IN AL,DX

Page 119: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

119

1393:0164 AND AL,40 1393:0166 ROR AL,1 1393:0168 ROR AL,1 1393:016A ROR AL,1 1393:016C ROR AL,1 1393:016E ROR AL,1 1393:0170 ROR AL,1 1393:0172 CALL 0102 1393:0175 CMP CX,027F 1393:0179 JNZ 0160 1393:017B MOV AH,01 1393:017D INT 16 1393:017F JZ 0183 1393:0181 JMP 01DB 1393:0183 CMP DX,003C 1393:0186 JGE 018D 1393:0188 CALL 0126 1393:018B JMP 0160 1393:018D CMP DX,0078 1393:0190 JGE 0197 1393:0192 CALL 013A 1393:0195 JMP 0160 1393:0197 CMP DX,00B4 1393:019B JGE 01A2 1393:019D CALL 0126 1393:01A0 JMP 0160 1393:01A2 CMP DX,00F0 1393:01A6 JGE 01AD 1393:01A8 CALL 013A 1393:01AB JMP 0160 1393:01AD CMP DX,012C 1393:01B1 JGE 01B8 1393:01B3 CALL 0126 1393:01B6 JMP 0160 1393:01B8 CMP DX,0168 1393:01BC JGE 01C3 1393:01BE CALL 013A 1393:01C1 JMP 0160 1393:01C3 CMP DX,01A4 1393:01C7 JGE 01CE 1393:01C9 CALL 0126 1393:01CC JMP 0160 1393:01CE CMP DX,01DF 1393:01D2 JGE 01D9 1393:01D4 CALL 013A 1393:01D7 JMP 0160 1393:01D9 JMP 0188 1393:01DB MOV AX,0002 1393:01DE INT 10 1393:01E0 MOV DX,0378 1393:01E3 MOV AL,00 1393:01E5 OUT DX,AL 1393:01E6 MOV AX,4C00

Page 120: Microprocesoare Si Microcontrolere

120 Perioada şi Frecvenţa unui Semnal Extern

1393:01E9 INT 21 1393:01EB -nppvspn.com -rcx CX 0000 :eb -w Writing 000EB bytes -

Programul precedent deşi nu este comentat este uşor de înţeles deoarece practic nu are elemente noi în raport cu celelalte programe prezentate până acum în aceast capitol. Privind cu atenţie imaginea din figura 6.6 constatăm că generatorul de semnal dreptunghiular este departe de a fi ideal. Factorul de umplere nu este de 50% adică timpul cât semnalul are nivel logic "0" este mai lung decăt timpul cât semnalul are nivel "1" logic. Aceasta este o particularitate a generatorului de semnal dreptunghiular şi se datorează faptului că a fost proiectat în ideea de a fi cât mai simplu şi fără alimentare externă.

Figura 6.6. Exemplu de imaginea obţinută pe ecran prin rularea programului ppvspn.com

Page 121: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

121

Un bun exemplu de antrenament ar fi realizarea unui program care să elimine prin software acest neajuns al generatorului de semnal dreptunghiular. Adică, ar trebui ca funcţie de frecvenţa semnalului extern programul să facă o corecţie în timp real al factorului de umplere al semnalului (se poate şi mai simplu), dar care este frecvenţa semnalului extern şi cum o putem afla? Cu ajutorul unui algoritm clasic de măsurare a frecvenţei (numărul de perioade contorizate într-o fereastră de timp egală cu 1 secundă) putem afla frecvenţa semnalului aplicat la intrarea D6 (ACK) a portului de adresă 0379h. În acest moment suntem în faţa celei mai grele sarcini din cadrul acestui capitol. Trebuie să ne imaginăm un program care trebuie să facă simultan două lucruri. Programul trebuie să incrementeze o valoare, iniţial egală cu zero, la fiecare front negativ al semnalului (între două fronturi de acelaşi tip avem o perioadă a semnalului extern) şi în acelaşi timp să contorizeze trecerea timpului pentru a implementa o fereastră de numărare a perioadelor semnalului extern egală cu o secundă. Singura posibilitate constă în realizarea a două task-uri care să ruleze simultan şi să facă schimb de informaţii între ele. Task-ul care contorizează trecerea timpului va fi activat la fiecare 54 ms de întreruperea de ceas (tick), aşa că vom contoriza 18 astfel de întreruperi pentru o secundă (0.972 s, adică o eroare acceptabilă pentru măsurarea frecvenţei de 2,8%). Vom spune că acest task rulează în background activat de întreruperea de ceas a calculatorului. Spre deosebire de acesta, un alt task va rula în foreground şi va contoriza numărul de perioade al semnalului extern evaluând totodată şi informaţia rezultată prin rularea task-ului din background. Cu cât task-ul din background va fi rulat într-o fereastră de timp mai mică, cu atât performanţele electrice ale frecvenţmetrului implementat prin software vor fi mai bune (frecvenţa maximă ce poate fi măsurată va fi mai mare). Aşa că, este nevoie ca task-ul de contorizare a timpului să fie cât mai scurt posibil iar transferul de informaţie (informaţia legată de trecerea timpului) să fie cât mai simplu şi să nu consume inutil din resursele de timp ale microprocesorului. Pentru a realiza acest deziderat vom sacrifica un registru al microprocesorului numai pentru acest scop. De asemenea, pentru a nu complica inutil programul, frecvenţa semnalului va fi afişată în hexazecimal. Plecând de la informaţiile precedente, cu ajutorul utilitarului DEBUG vom realiza următorul program. -a 1371:0100 jmp 13d ;salt la adresa de start 1371:0102 push ax ;noul serviciu de ceas, ~ 1s 1371:0103 dec bl ;decrementăm timp 1371:0105 mov al,20 ;secvenţa EOI 1371:0107 out 20,al 1371:0109 pop ax 1371:010A iret ;return din intrerupere

Page 122: Microprocesoare Si Microcontrolere

122 Perioada şi Frecvenţa unui Semnal Extern

1371:010B add dl,30 ;subrutine de conversie, tipărire 1371:010E cmp dl,3a 1371:0111 jl 116 1371:0113 add dl,07 1371:0116 mov ah,02 1371:0118 int 21 1371:011A ret 1371:011B shl dx,1 1393:011D shl dx,1 1393:011F shl dx,1 1393:0121 shl dx,1 1393:0123 push dx 1393:0124 and dx,f000 1393:0128 mov dl,dh 1393:012A shr dx,1 1393:012C shr dx,1 1371:012E shr dx,1 1371:0130 shr dx,1 1371:0132 and dx,000f 1371:0136 call 10b 1371:0139 pop dx 1371:013A loopnz 11b 1371:013C ret 1371:013D mov dx,378 ;alimentăm generatorul de semnal 1371:0140 mov al,80 1371:0142 out dx,al 1371:0143 in al,21 ;capturăm stare controler, 8259 1371:0145 push ax 1371:0146 mov ax,0000 ;reţimen vector de ceas vechi 1371:0149 mov es,ax 1371:014B es: 1371:014C mov ax,[0020] 1371:014F push ax 1371:0150 es: 1371:0151 mov ax,[0022] 1371:0154 push ax 1371:0155 mov ax,cs 1371:0157 cli 1371:0158 es: 1371:0159 mov [0022],ax ;modificăm vector de ceas 1371:015C mov ax,0102 1371:015F es: 1371:0160 mov [0020],ax 1371:0163 mov al,fe ;lăsăm activă numai întreruperea de ceas 1371:0165 out 21,al 1371:0167 mov bx,0012 ;fixăm lungimea ferestrei de timp 1371:016A mov ah,40 1371:016C mov cx,0000 ;iniţializăm contor perioade 1371:016F mov dx,379 1371:0172 sti ;sicronizare cu intrerupere ceas 1371:0173 hlt 1371:0174 in al,dx 1371:0175 cmp bl,bh ;test dacă a trecut timpul

Page 123: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

123

1371:0177 jz 189 1371:0179 test al,ah ;test front 1371:017B jnz 174 1371:017D in al,dx 1371:017E cmp bl,bh ;test dacă a trecut timpul 1371:0180 jz 189 1371:0182 test al,ah ;test front 1371:0184 jz 17d 1371:0186 inc cx ;incrmentăm contor perioade semnal 1371:0187 jmp 174 ;dacă nu a trecut timpul reluăm 1371:0189 cli ;refacem stare iniţiala vector ceas 1371:018A pop ax 1371:018B es: 1371:018C mov [0022],ax 1371:018F pop ax 1371:0190 es: 1371:0191 mov [0020],ax 1371:0194 pop ax 1371:0195 out 21,al ;refacem stare iniţială controler, 8259 1371:0197 sti ;întreruperi active 1371:0198 push cx ;tipărim rezultatul 1371:0199 mov dl,20 1371:019B call 116 1371:019E mov cx,0004 1371:01A1 pop dx 1371:01A2 call 123 1371:01A5 mov dl,0d 1371:01A7 call 116 1371:01AA mov ah,01 ;testăm keyboard 1371:01AC int 16 1371:01AE jz 1bb 1371:01B0 mov dx,378 ;oprim generatorul de semnal 1371:01B3 mov al,00 1371:01B5 out dx,al 1371:01B6 mov ax,4c00 ;invocăm ieşire DOS 1371:01B9 int 21 1371:01BB jmp 13d 1371:01BD -nppfdos.com -rcx CX 0000 :bd -w Writing 000BD bytes -

Structura programului precedent o putem considera clasică. Începem cu o instrucţiune de salt (JMP) peste subrutine la adresa de start a programului. Buna funcţionare a programului este asigurată de redirectarea întreruperii de ceas, în acest exemplu la adresa 1371:0102, unde se află noul serviciu al întreruperii de ceas (până la instrucţiunea IRET). Deoarece odată cu redirectarea acestei întreruperi toate

Page 124: Microprocesoare Si Microcontrolere

124 Perioada şi Frecvenţa unui Semnal Extern

celelalte întreruperi au fost mascate prin programarea corespunzătoare a circuitului 8259 (a fost prezentat pe larg în capitolul 5), singura întrerupere activă pe parcursul unei secvenţe de măsurare este întreruperea de ceas. După cum se poate constata, noua subrutină care deserveşte întreruperea de ceas nu face altceva decât să decrementeze registrul partajat (sacrificat) BL şi să comunice circuitului 8259 că întreruperea a fost deservită (EOI, End Of Intereupt). Desigur, pe perioada măsurării frecvenţei semnalului extern, ceasul de sistem nu contorizează trecerea timpului, aşa că, odată cu fiecare măsurătoare ceasul de sistem al calculatorului rămâne în urmă cu aproximativ o secundă. În secvenţa de contorizare a perioadelor semnalului extern din task-ul care rulează în foreground este verificată şi trecerea timpului prin evaluarea valorii curente din registrul partajat BL. În acest fel, cele două task-uri comunică între ele printr-un protocol simplu şi extrem de eficient din prisma performanţelor electrice ale instrumentului implementat prin software (instrument virtual). Afişarea frecvenţei se face în hexazecimal, pentru a nu complica inutil programul. Pentru un novice în domeniul embedded system acest lucru nu mai trebuie să fie un impediment. În continuare, pentru a evalua performanţele calculatorului pe care ne antrenăm, lansăm în execuţie aplicaţia precedentă şi fixăm din potenţiometrul de 100k frecvenţa semnalului extern egală cu 1000 Hz, adică 3E8h în hexazecimal. Cu ajutorul programelor din acest capitol putem să auzim, respectiv vedem, semnalul extern. Vom lansa în final în execuţie unul din programele de vizualizare a semnalului cu sincronizare pe frontul pozitiv sau negativ şi vom stabili numărul de perioade ale semnalului extern vizibile pe ecran atunci când frecvenţa acestuia este de 1000 Hz. Ştiind că pe orizontală imaginea are 640 de pixeli este uşor să calculăm de câte ori pe secundă sistemul, prin rularea programului, poate să citească o informaţie din portul paralel şi să o afişeze în mod grafic pe ecran. Informaţia pe care o obţinem prin algoritmul prezentat anterior ne va da o imagine clară despre ce ar putea face un calculator personal de tip IBM PC, numai prin proceduri software, în domeniul achiziţiei, respectiv prelucrării de semnal. În funcţie de aplicaţia concretă pe care o avem în vedere, în urma constatărilor anterioare vom fi entuziasmaţi sau dezamăgiţi. Asta este, în practică niciodată un calculator nu va fi atât de rapid încât să putem rezolva prin software orice aplicaţie. Această constatare a determinat găsirea altor soluţii hardware/software care au transformat în timp domeniul embedded system într-o junglă, în care, după cum putem constata, cu greu se poate pătrunde. Au apărut microprocesoare cu arhitecturi noi, circuite programabile extrem de complexe şi specializate şi nu în ultimul rând, sisteme de operare pentru aplicaţiile în timp real. Acest lucru a generat în timp subdomenii specializate ale domeniului embedded

Page 125: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

125

system. De altfel, pe un asemenea subdomeniu (calculatoarele personale IBM PC) noi am atins stadiul de novice. În următoarele trei capitole vom atinge stadiul de "novice bine informat" în domeniul embedded system. Dacă programele de până acum sunt clare, să trecem mai departe, partea frumoasă abia de acum se arată. Dar dacă nu am rămas cu mare lucru din munca de până acum, ar fi mai bine, să ne gândim serios la o altă meserie. Fiecare om nu va putea face performanţă decât într-un domeniu dat, acesta însă, din păcate, nu de puţine ori trebuie căutat toată viaţa. Preocuparea de bază în domeniul embedded system este aceea de a îngloba "inteligenţa microprocesoarelor" în tot ce a fost realizat tehnologic până în prezent şi în tot ce se va realiza în viitor. Acest adaos "de astfel de inteligenţă" aduce mari beneficii în performanţele aplicaţiilor în preţul şi fiabilitatea acestora, cât şi facilităţii legate de uşurinţa folosirii acestor aplicaţii. Toate acestea vor marca profund viaţa de zi cu zi a oamenilor cel puţin în primul secol al mileniului trei. În raport cu noile tehnologii fiecare dintre noi poate fi cu uşurinţă spectator, utilizator, sau creator. Este cu adevărat o piatră de încercare să devenim din utilizatori creatori de noi tehnologii sau cel puţin creatori de noi aplicaţii ale tehnologiilor actuale. Nu vom ştii niciodată cu siguranţă dacă suntem creatori veritabili în acest domeniu, dar avem un indiciu că suntem pe drumul cel bun, statul de plată. Este greu de înţeles cum se pot obţine foloase materiale în spaţiul real în urma unor activităţi prestate în spaţiul virtual. Probabil viitoarele realizări din domeniul ingineriei genetice (adică orice nou născut va ştii totul despre domeniul embedded system tot aşa cum ştie acum să respire) vor pune în pericol această afacere a zilelor noastre. Unul din subdomeniile embedded system-ului, aflat în plină maturitate şi pe deopotrivă ascensiune, este cel al sistemelor cu microcontroler. Acestea nu sunt nimic altceva decât nişte calculatoare mai mult sau mai puţin specializate, realizate într-un singur chip (on-chip computer). Să le vedem la lucru.

Page 126: Microprocesoare Si Microcontrolere

126 Perioada şi Frecvenţa unui Semnal Extern

Page 127: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

127

7. Microcontrolerul 68HC11. PcBug Nu pentru orice aplicaţie se justifică utilizarea unui microprocesor puternic de tipul celor studiate până în prezent. Pe de altă, parte apelarea la un calculator personal în orice aplicaţie ridică nejustficat preţul de cost al acesteia sau face chiar imposibilă (datorită costului) utilizarea tehnologiei calculatoarelor personale IBM PC. Nevoia firească de a ridica performanţele produselor prin aportul adus de tehnologia microprocesoarelor a determinat apariţia şi dezvoltarea aproape simultană a unor calculatoare "on-chip" (microprocesorul, memoria şi periferia pe o singură pastilă de siliciu). Acestea s-au constituit într-o clasă aparte cunoscută sub denumirea de microcontrolere. Desigur, acestea (microcontrolerele) sunt de regulă suportul fizic al aplicaţiilor în domeniul embedded system. Chiar dacă aşa stau lucrurile, în realitate noi nu am început cu acestea, din două motive. Un prim motiv este nevoia unei culturi minime în domeniul microprocesoarelor şi respectiv a calculatorului personal IBM PC pentru a putea aborda miezul tare al domeniului embedded system cu succes. Timpul în care pot fi învăţate unele elemente de bază ale domeniului prin intermediul calculatorului personal IBM PC poate fi extrem de scurt. Aşa că un al doilea scop este de ordin didactic. Desigur, în acelaşi timp am reuşit să clarificăm unele probleme legate de arhitectura şi programarea calculatorului personal IBM PC. Pe baza cunoştiinţelor acumulate până acum se pot realiza multe aplicaţii de achiziţie de date şi control. Modul de abordare al problemelor de achiziţie de date şi control prezentat până acum în această carte era caracteristic anilor '80 eventual '90. Nevoia de creştere a performanţelor acestor aplicaţii la un preţ de cost din ce în ce mai mic a fost posibilă prin apariţia unor microprocesoare, respectiv microcontrolere, specializate. Astfel, pentru fiecare clasă de aplicaţii, la ora actuală o serie de firme oferă suport software bazat pe un hardware specializat. Aşa că, de cele mai multe ori este lipsită de argument ştiinţific şi/sau economic particularizarea unui calclulator personal IBM PC numai pentru o anumită aplicaţie. De altfel, evoluţia sistemelor de operare, după cum am putut constata, a dus la o situaţie din ce în ce mai restrictivă cu abordarea clasică a problemelor de achiziţie de date şi control. Capacitatea unui hardware-software specializat de a prelucra local task-urile aplicaţiei dublată de capacitatea acestuia de a comunica prin intermediul unui canal standard degrevează calculatorul personal IBM PC de interacţia cu o periferie primitivă care, de regulă, tinde să monopolizeze timpul microprocesorului în favoarea ei. În această situaţie calculatorul personal IBM PC poate superviza mai

Page 128: Microprocesoare Si Microcontrolere

128 Microcontrolerul 68HC11. PcBug

multe aplicaţii în acelaşi timp, iar task-urile acestora vor fi rezolvate simultan şi/sau în timp real de către mai multe centre de prelucrare-decizie. Într-o asemenea concepţie de procesare distribuită a datelor este uşor să ne imaginăm, de exemplu, aplicaţii de achiziţie de date şi control conduse prin Internet. Fără a intra în disputa dintre firmele producătoare şi fanii acestora, microcontrolerul 68HC11 de la firma Motorola s-a dovedit la data apariţiei un produs extrem de flexibil şi puternic la nivelul microcontrolelelor de 8/16 biţi. Combinarea în acelaşi chip a unei unităţi centrale, bazate pe tradiţionalul microprocesor M6800 de la firma Motorola, a unor circuite de memorie performante (EEPROM), cât şi a unei periferii extrem de diversificate şi flexibile a dus fără îndoială la succesul acestui proiect. Pentru început, vom încerca să ne facem o imagine generală despre acest microcontroler. Studiul lui va trebui însă aprofundat în particular pentru a putea pune în operă aplicaţii reale cu o altă utilitate decât cea didactică, demonstrativă.

Figura 7.1. Diagrama pinilor la microcontrolerul 68HC11 (PLCC).

Page 129: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

129

Microcontrolerul 68HC11 (figura 7.1) este realizat în tehnologia HCMOS (high-density complementary metal-oxide semiconductor) şi conţine în acelaşi chip o unitate avansată de procesare pe 8-biţi, cel puţin două tipuri de memorie precum şi o sofisticată periferie, toate acestea la o viteză nominală de bus de 2 Mhz. Microcontrolerul este static aşa că el poate opera la frecvenţe joase practic pâna la DC. Astfel, într-o aplicaţie dată se pot face reduceri însemnate de energie consumată de la sursa de alimentare. Principalele subsisteme ale microcontrolerului şi modul de conectare al acestora la pini sunt prezentate în figura 7.2.

Figura 7.2. Diagrama bloc a microcontrolerului 68HC11.

După cum se poate constata din figura 7.2 în jurul unităţii centrale de

procesare (CPU - Central Processing Unit) microcontrolerul 68HC11 în versiunea 68HC11A8 are trei tipuri de memorie: EEPROM, RAM şi ROM. O altă versiune a microcontrolerului 68HC811E2 are aceeaşi configuraţie dar cu 2 Kbytes de memorie EEPROM şi fără memorie ROM. În versiunea 68HC11A1 microcontrolerul nu are memorie ROM, iar în versiunea 68HC11A0 nu are memorie ROM şi EEPROM. Acestea sunt cele mai uzuale versiuni ale acestui microcontroler, versiuni pe care de altfel le vom utiliza în continuare. Pe lîngă memoria internă microcontrolerul posedă o puternică periferie specializată în

Page 130: Microprocesoare Si Microcontrolere

130 Microcontrolerul 68HC11. PcBug

comunicaţie (SCI, SPI), timer, watchdog, convertor A/D, un subsistem pentru gestionarea întreruperilor şi porturi I/O de uz general (PORT B, PORT C). Dacă pentru o aplicaţie dată resursele microcontrolerului în mod "Single Chip" nu sunt suficiente (avem nevoie de mai multă memorie pentru program şi/sau date ori mai multe porturi I/O) atunci porturile de uz general (PORT B, PORT C) pot fi transformate într-o magistrală de adrese-date multiplexată prin trecerea microcontrolerului în mod "Expanded". După cum se poate vedea în figura 7.1 alegerea modului de lucru se face prin intermediul subsistemului "Mode Select". Modul de lucru al microcontrolerului este funcţie de starea logică a doi pini (MODA, MODB) a căror semnificaţie este prezentată în tabelul 7.1.

Tabelul 7.1.

După cum rezultă din acest tabel microcontrolerul 68HC11 are două moduri

normale şi două moduri speciale. Pentru "Single Chip" avem un mod special (Special Bootstrap) care activează o memorie internă ROM ce conţine un program pentru secvenţa de autoboot. După cum vom vedea, această facilitate extrem de importantă şi unică în lumea microcontrolerelor face posibilă dezvoltarea de aplicaţii fară a fi nevoie de un programator extern. Dintr-un mod special, se poate trece prin software la un mod normal. Pentru aceasta este nevoie să cunoaştem semnificaţia biţilor registrului HPRIO (de la adresa $103C, prefixul "$" este o notaţie tipică firmei Motorola pentru numere hexazecimale). Funcţie de valorile biţilor din registrul HPRIO prezentat în tabelul 7.2 microcontrolerul poate fi adaptat la o aplicaţie dată. Tabelul 7.2.

HPRIO: SMOD - Special Mode

Poate fi scris cu zero dar nu poate fi readus în unu din program

Page 131: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

131

1 - Special mode 0 - Normal mode MDA - Mode A Select Poate fi scris numai dacă SMOD este egal cu unu 1 - Normal Expanded sau Special test mode 0 - Normal Single Chip sau Special bootstrap mode

Acesta nu este singurul registru care asigură flexibilitate microcontrolerului 68HC11. O serie de alţi regiştri concură la această calitate unică a microcontrolerului. Prezentarea sumară a microcontrolerului urmată de câteva programe simple nu va putea scoate în evidenţă toate calităţile acestei familii de microcontrolere. Utilizarea eficientă a acestui microcontroler extrem de complex nu poate fi făcută fără un studiu al manualului de firmă (Pink Book). Pentru început este nevoie să proiectăm şi realizăm practic un sistem cu microcontrolerul 68HC11. Am optat pentru versiunea 68HC11A1 a microcontrolerului şi o implementare în mod "Single-Chip". Această implementare conţine pe lângă 68HC11 şi circuitul MAX232, care asigură compatibilitatea electrică între interfaţa serială RS232 şi microcontroler. Realizarea practică a unei astfel de aplicaţii este prezentată în figura 7.3.

Figura 7.3. Realizarea practică a sistemului cu 68HC11 mod "Single-Chip".

Page 132: Microprocesoare Si Microcontrolere

132 Microcontrolerul 68HC11. PcBug

Fără a insista asupra părţii de hardware, să vedem dacă istoria din capitolele 1 - 6 se repetă. Adică, să vedem dacă cunoştiinţele acumulate până acum ne ajută la abordarea acestei familii de microcontrolere. De data aceasta utilitarul minune se numeşte PCBUG şi vom vedea în continuare în ce măsură se aseamănă sau nu cu utilitarul DEBUG.

Desigur lucrurile nu stau chiar aşa de simplu, în primul rând utilitarul PCBUG nu mai este un program al sistemului de operare. Aşa că, va trebui să-l încărcăm de pe un suport extern. Odată cu PCBUG va trebui să avem şi alte programe (de exemplu un asamblor) toate disponibile într-o trusă de scule (folder) pe care va trebui să-l creem şi întreţinem singuri. O mare parte din programele de care avem nevoie le vom gasi gratuit pe Internet, unele dintre ele chiar pe unul din site-urile firmei Motorola. Lansarea în execuţie a programului PCBUG trebuie precedată de realizarea unei conexiuni între sistemul cu 68HC11 şi calculatorul gazdă (IBM PC) precum şi alimentarea respectiv resetrea acestuia. Pentru început, programul PCBUG va lansa un dialog de forma celui prezentat în continuare prin care informăm programul despre particularităţile sistemului extern. PCbug11 Ver 3.42 - M68HC11 Monitor for PC Hosts (c) Motorola Ltd 1994 PCbug11 Command Line Compiler - press <Esc> to terminate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~ Is the talker installed on your board? (Y/N) : N Do you wish to use the XIRQ interrupt? (Y/N) : N MCU boot talkers available ~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 68HC11A0/1/7/8 2 68HC11D0/3 3 68HC11E0/1/8/9 4 68HC811E2 5 68HC11F1 6 68HC11G0/5/7 7 68HC11J0/6 8 68HC11K0/4 9 68HC11L0/6 10 68HC11ED0 11 68HC711E9 12 68HC11E20 13 68HC711E20 14 68HC11EA9 15 68HC711EA9 16 68HC711G5 17 68HC711L6 18 68HC711K4 19 68HC11KA4 20 68HC711KA4 21 68HC11M2 22 68HC711M2 23 68HC11P2 24 68HC711P2 Which device are you using? : 1 Do you wish to load a macro automatically? (Y/N) : N PC communications port : 1. COM1 2. COM2 Which communications port are you using? : port=2 Assume an 8MHz crystal in use (Y/N) : Y Command Line : PCBUG11 -A port=2 Press <Esc> to quit or any other key to run PCBUG11

Page 133: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

133

Prin apăsarea oricărei taste cu excepţia tastei "ESC" se va lansa în execuţie programul. Dacă parametrii fixaţi anterior sunt corecţi şi conexiunea dintre sisteme este bine realizată nu vor apărea nici un fel de probleme şi vom ajunge în situaţia prezentată în figura 7.4.

Figura 7.4. Utilitarul PCBUG lansat în execuţie.

La fel ca şi în cazul utilitarului DEBUG, prin comanda "help" putem obţine toate comenzile acestui utilitar. Dată fiind complexitatea acestui sistem, atât în ce priveşte organizarea memoriei interne, şi mai ales datorită periferiei pe care o are microcontrolerul 68HC11, utilitarul PCBUG are o lista mare de comenzi astfel încât să fie uşor de adaptat la orice situaţie concretă. +-----------------------------------------------------------------------------+ ¦MENU ¦ ¦Use the host-computer keyboard to edit the PCbug11 command line. A recall ¦ ¦buffer holds the last 16 commands entered. The following table lists the ¦ ¦edit keys. ¦ ¦ ¦ ¦left arrow - Moves cursor back one character ¦ ¦right arrow - Moves cursor forward one character ¦ ¦Home - Moves cursor to first character ¦ ¦End - Moves cursor to last character ¦ ¦delete left - Deletes to the left of the cursor ¦ ¦Del - Deletes at the cursor position ¦ ¦<CTRL> End - Deletes from cursor position to the end of line ¦ ¦Ins - Inserts at cursor position (cursor changes to blocked ¦

Page 134: Microprocesoare Si Microcontrolere

134 Microcontrolerul 68HC11. PcBug

¦ cursor) ¦ +--- Viewing MENU ----- Line : 1 ---------------------------------------------+ +-----------------------------------------------------------------------------+ ¦ cursor) ¦ ¦up arrow - Recalls previous commands, in reverse order ¦ ¦down arrow - Recalls last command in recall buffer ¦ ¦Esc - Clears command line or terminates most commands in progress ¦ ¦ ¦ ¦The four lines above the command line serve as a trace of the last four ¦ ¦commands. The fifth line above the command line shows breakpoints and ¦ ¦error codes. ¦ ¦ ¦ ¦Possible error codes are: ¦ ¦ 0 : No error ¦ ¦ 1 : VERF error ¦ ¦ 2 : MS or BF error ¦ ¦ 3 : Talker communication failure. ¦ +--- Viewing MENU ----- Line : 14 --------------------------------------------+ +-----------------------------------------------------------------------------+ ¦ 3 : Talker communication failure. ¦ ¦ ¦ ¦For MS-DOS batch files, an error code can be checked via ERRORLEVEL after ¦ ¦PCbug11 terminates. ¦ ¦ ¦ ¦ ¦ ¦Monitor Commands ¦ ¦ ¦ ¦The following is a summary of PCbug11 commands. ¦ ¦ ¦ ¦---------------------------------------------------------------------------- ¦ ¦ COMMAND DESCRIPTION ¦ ¦---------------------------------------------------------------------------- ¦ ¦ ASM addr [mne dir] Call symbolic macro line assembler, with ¦ +--- Viewing MENU ----- Line : 27 --------------------------------------------+ +-----------------------------------------------------------------------------+ ¦ ASM addr [mne dir] Call symbolic macro line assembler, with ¦ ¦ option to auto insert mnemonic or directive ¦ ¦---------------------------------------------------------------------------- ¦ ¦ BAUD [rate] Display or set serial baud rate ¦ ¦ BF addr1 [addr2] byte word Block fill memory with byte or word ¦ ¦ BL Display breakpoints ¦ ¦ BR [addr [macroname]] Display/Set break point ¦ ¦ [with optional macro execution] ¦ ¦---------------------------------------------------------------------------- ¦ ¦ CALL addr Execute the subroutine at addr ¦ ¦ CLRM Clear all command macros ¦ ¦ CLS Clear main window ¦ ¦ CONTROL Display or set CONTROL parameters ¦ ¦ CONTROL BASE BIN HEX DEC Change default number base ¦ +--- Viewing MENU ----- Line : 40 --------------------------------------------+ +-----------------------------------------------------------------------------+ ¦ CONTROL BASE BIN HEX DEC Change default number base ¦ ¦ CONTROL BIOS Access serial COM port through BIOS calls ¦ ¦ CONTROL COLOR Set PCbug11 display colors ¦ ¦ CONTROL COLOUR Set PCbug11 display colours ¦ ¦ CONTROL COM1 Use COM1 port ¦ ¦ CONTROL COM2 Use COM2 port ¦

Page 135: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

135

¦ CONTROL EPROG address Change the EPROM register address ¦ ¦ CONTROL ERRMSG option Enable or disable display of error messages ¦ ¦ CONTROL HARDWARE Access COM port directly through hardware ¦ ¦ CONTROL LAST Toggle the last error message window on/off ¦ ¦ CONTROL LOG CLOSE Close the open command log file ¦ ¦ CONTROL LOG OFF Suspend logging to command log file ¦ ¦ CONTROL LOG ON Enable logging to the command log file ¦ ¦ CONTROL LOG OPEN Open the command log file ¦ +--- Viewing MENU ----- Line : 53 --------------------------------------------+ +-----------------------------------------------------------------------------+ ¦ CONTROL LOG OPEN Open the command log file ¦ ¦ CONTROL PPROG address Change the EEPROM register address ¦ ¦ CONTROL PROTECT Use the RTS to provide memory protection ¦ ¦ CONTROL RTS Control the RTS line directly ¦ ¦ CONTROL RTS ON OFF Set RTS line high or low ¦ ¦ CONTROL TIMEOUT [value] Display or set the value of serial ¦ ¦ COM timeout during input ¦ ¦---------------------------------------------------------------------------- ¦ ¦ DASM addr1 [addr2] Disassemble from addr1 [to addr2] ¦ ¦ DB startaddr [endaddr] Display MCU Memory ¦ ¦ DEBUG Reserved word ¦ ¦ DEFINE symbol value address Define a symbol ¦ ¦ DEFM macrnam TRACE AUTOSTART Define a command, trace or autostart macro ¦ ¦ DELM macrnam TRACE AUTOSTART Delete a command, trace or autostart macro ¦ +--- Viewing MENU ----- Line : 66 --------------------------------------------+ +-----------------------------------------------------------------------------+ ¦ DELM macrnam TRACE AUTOSTART Delete a command, trace or autostart macro ¦ ¦ DIR [mask] Display disk directory ¦ ¦ DOS [command] Shell to DOS or execute DOS command ¦ ¦---------------------------------------------------------------------------- ¦ ¦ EDITM macrnam Edit a macro ¦ ¦ EEPROM [startaddr [endaddr]] Display, clear, set EEPROM address range(s) ¦ ¦ EEPROM DELAY option Set EEPROM erase or write programming time ¦ ¦ EEPROM ERASE [option] Display or change EEPROM erase-before-write ¦ ¦ ENV Define Environment save options ¦ ¦ EPROM [startaddr [endaddr]] Display, clear, set EPROM address range(s) ¦ ¦ EPROM DELAY option Set EPROM erase or write programming time ¦ ¦---------------------------------------------------------------------------- ¦ ¦ FIND byte word addr1 addr2 Find all occurrences of byte or word ¦ ¦ between addr1 & addr2 ¦ +--- Viewing MENU ----- Line : 79 --------------------------------------------+ +-----------------------------------------------------------------------------+ ¦ between addr1 & addr2 ¦ ¦ FIND mnemonic addr1 addr2 Find all occurrences of mnemonic ¦ ¦ between addr1 & addr2 ¦ ¦---------------------------------------------------------------------------- ¦ ¦ G [addr] Start user code execution ¦ ¦---------------------------------------------------------------------------- ¦ ¦ HELP [command] Display help information ¦ ¦ HELP MCU [topic] Display help on specific MCU topic ¦ ¦---------------------------------------------------------------------------- ¦ ¦ KLE Kill last error message ¦ ¦---------------------------------------------------------------------------- ¦ ¦ LOADM [filename] [macroname] Load macro definitions from default or user ¦ ¦ file ¦ ¦ LOADS filename [loadaddr] Load S-record file into MCU memory ¦ +--- Viewing MENU ----- Line : 92 --------------------------------------------+

Page 136: Microprocesoare Si Microcontrolere

136 Microcontrolerul 68HC11. PcBug

+-----------------------------------------------------------------------------+ ¦ LOADS filename [loadaddr] Load S-record file into MCU memory ¦ ¦ LS symbol Display symbols ¦ ¦ LSTM [mname TRACE AUTOSTART] Display macro names or definitions ¦ ¦---------------------------------------------------------------------------- ¦ ¦ MD startaddr [endaddr] Display MCU memory ¦ ¦ MM addr Modify memory from addr ¦ ¦ MOVE addr1 addr2 addr3 Move MCU memory between addr1 & addr2 to ¦ ¦ addr3 ¦ ¦ MS addr byte word [byte word] Set MCU memory byte(s) or word(s) ¦ ¦ MSG [string] Display message in main window ¦ ¦---------------------------------------------------------------------------- ¦ ¦ NOBR [address] Remove all or specified breakpoints ¦ ¦---------------------------------------------------------------------------- ¦ ¦ PAUSE [ms] Wait for any key press or delay time ¦ +--- Viewing MENU ----- Line : 105 -------------------------------------------+ +-----------------------------------------------------------------------------+ ¦ PAUSE [ms] Wait for any key press or delay time ¦ ¦ PRINT Display PCbug11 version number ¦ ¦ PROTECT [startaddr [endaddr]] Display, clear or set write-protected ¦ ¦ address range(s) ¦ ¦---------------------------------------------------------------------------- ¦ ¦ QUIT [Y] Terminate PCbug11 session ¦ ¦ [without confirming] ¦ ¦---------------------------------------------------------------------------- ¦ ¦ RD [T] Display ot trace MCU registers ¦ ¦ RESET [addr] MCU Hardware Reset with Existing or new ¦ ¦ reset vector. ¦ ¦ RESTART [option] Restart PCbug11 with same or new option. ¦ ¦ RM Modify MCU registers in window ¦ ¦ RS register value Set value of MCU register ¦ +--- Viewing MENU ----- Line : 118 -------------------------------------------+ +-----------------------------------------------------------------------------+ ¦ RS register value Set value of MCU register ¦ ¦---------------------------------------------------------------------------- ¦ ¦ S Stop user code execution ¦ ¦ SHELL ["command" ;P] Shell to DOS or execute DOS command ¦ ¦ SAVEM [filename] Save macro definitions in default or user ¦ ¦ file ¦ ¦---------------------------------------------------------------------------- ¦ ¦ T [addr] Trace user code ¦ ¦ TERM [X1 Y1 X2 Y2] Simple windowed terminal emulator ¦ ¦ TYPE filename Display disk file in main window ¦ ¦---------------------------------------------------------------------------- ¦ ¦ UNDEF symbol Undefine a symbol ¦ ¦---------------------------------------------------------------------------- ¦ ¦ VER Display version number ¦ +--- Viewing MENU ----- Line : 131 -------------------------------------------+ +-----------------------------------------------------------------------------+ ¦ VER Display version number ¦ ¦ VERF ERASE addr1 [addr2] Verify that memory contains $FF ¦ ¦ VERF SET addr1 addr2 value Verify that memory contains the value ¦ ¦ VERF filename [memaddr] Verify S-record disk file against memory ¦ ¦---------------------------------------------------------------------------- ¦ ¦ WAIT [ms] Wait for ms ¦ ¦---------------------------------------------------------------------------- ¦ ¦ ¦

Page 137: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

137

¦Special Key operations: ¦ ¦---------------------------------------------------------------------------- ¦ ¦ <CTRL> B Send break on COM channel ¦ ¦ <CTRL> P Toggle MCU memory write protect/RTS line ¦ ¦ <CTRL> R Attempt to re-synchronise talker ¦ ¦---------------------------------------------------------------------------- ¦ +--- Viewing MENU ----- Line : 144 -------------------------------------------+ +-----------------------------------------------------------------------------+ ¦---------------------------------------------------------------------------- ¦ ¦ ¦ ¦EVS Compatible commands ¦ ¦ ¦ ¦These commands operate in a similar manner to the command of the same ¦ ¦name on the Motorola 68HC11 EVS systems. ¦ ¦ ¦ ¦ASM, BF, BR, G, HELP, MD, MM, NOBR, RD, RM ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ +--- Viewing MENU ----- Line : 157 -------------------------------------------+

Nici de această dată nu vom încerca să le învăţăm pe de rost, acum ştim cum le putem afla. Stadiul de novice în domeniul embedded system a fost atins în primele şase capitole din această carte, aşa că de acum vom schiţa un eventual parcurs spre stadiul de "novice bine informat". Pentru a avea o mai mare productivitate este bine în acest stadiu să utilizăm un asamblor exterm pe care trebuie să-l avem în cutia cu scule. Acesta (asamblorul) este gratuit. Aşa că, noi vom utiliza în continuare pentru realizarea de programe un editor ASCII si asamblorul "asm11.exe". Cu ajutorul asamblorului vom obţine fişierele în format hexazecimal de tip ".S19" care apoi cu ajutorul utilitarului PCBUG le vom încărca în memoria EEPROM a microcontrolerului 68HC11 pentru a fi rulate de acesta. Pentru versiunea 68HC11A1 memoria EEPROM este paginată începând cu adresa $B600 şi are o lungime de 512 bytes. Aşa că, în continuare, pentru a testa buna funcţionare a sistemului cu 68HC11 (anexa B) vom realiza un fisier ASCII cu următorul conţinut: * test program for EEPROM, PD * Program "LEDPD3.ASM" * portd equ $08 ddrd equ $09 * org $b600 ; org of EEprom start lds #$ff ldx #$1000 bset ddrd,x$08

Page 138: Microprocesoare Si Microcontrolere

138 Microcontrolerul 68HC11. PcBug

led ldaa portd,x eora #$08 staa portd,x ldd #$8000 delay subd #1 bne delai bra led org $fffe fdb start ; after Reset * end

Programul anterior nu face altceva decât să producă un semnal dreptunghiular de joasă frecvenţă la ieşirea PD3 a microcontrolerului. Odată creat acest fişier îl vom salva cu denumirea "LedPD3.asm" în acelaşi folder cu asamblorul (asm11.exe). Cu ajutorul asamblorului vom obţine fişierul "LedPD3.s19" cu următorul conţinut: S11CB6008E00FFCE10001C0908A6088808A708CC800083000126FB20F0A7 S105FFFEB60047 S9030000FC

Pentru a ne convinge de buna funcţionare a sistemului vom încărca acest fişier în memoria EEPROM a lui 68HC11 şi-l vom lansa în execuţie.

Figura 7.5. Încărcarea unui program în memoria EEPROM.

Page 139: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

139

Comenzile ce trebuie date în utilitarul PCBUG, respectiv răspunsul acestuia la aceste comenzi este prezentat în figura 7.5. Deoarece frecvenţa generată este foarte joasă, funcţionarea corectă a programului anterior poate fi pusă în evidenţă cu un simplu LED înseriat cu o resistenţă de 220 Ω. În această etapă, folosirea unui asamblor extern ne permite să realizăm sursa în format ASCII a programelor. Aşa că, de această dată programele noastre trebuie să fie comentate în aşa fel încât odată cu programul să producem şi documentaţia aferentă acestuia. Pentru a asigura o mai mare portabilitate a documentaţiei aferente este bine încă de la început să facem toate comentariile în limba engleză folosind pe cât se poate formulări consacrate.

Figura 7.5. Realizarea practică a modului LCD alfanumeric.

Chiar dacă experienţa precedentă nu este deloc spectaculoasă, la sfârşitul ei vom şti o mulţime de comenzi utile şi nu în ultimul rând ne vom convinge de buna funcţionare a sistemului. Este bine să reţinem că, de fiecare dată, pe orice sistem, mult este până reuşim să aprindem un LED cum şi când vrem noi. De aici încolo, totul este muncă de rutină. Pentru a ne convinge de acest lucru vom realiza în

Page 140: Microprocesoare Si Microcontrolere

140 Microcontrolerul 68HC11. PcBug

continuare un modul de afişare LCD (Liquid Cristal Display) de tip alfanumeric. Realizarea practică a acestui modul se poate vedea în figura 7.6.

Modulul LCD prezentat anterior face parte din aceeaşi clasă tehnologică cu 68HC11 şi la rândul lui conţine un microcontroler specializat HD44780. Acest microcontroler specializat comunică cu un alt sistem prin intermediul unor porturi paralele. Comunicarea se realizează printr-o magistrală de date de 8/4 biţi iar protocolul de comunicaţie este asigurat printr-o magistrală de control (E, R/W, RS, - Enable control line, Read/Write control line, Register-Select control line). Pentru o bună înţelegere a următorului program, va trebui să consultăm fişa tehnică (uşor de găsit pe Internet) a modului LCD. Programul va trebui să ţină cont de tipul de transfer pe 8 sau 4 biţi şi de modul de organizare a ecranului LCD (numărul de rânduri respectiv numărul de caractere pe fiecare rând). Pe de altă parte, modulul LCD are stocate în memoria internă de tip ROM mai multe pagini de caractere (acoperă inclusiv aria asiatică) aşa că, va trebui să selectăm pagina de caractere care intenţionăm să le afişăm. De asemenea, putem defini, de regulă, 8 caractere cu o grafică la alegere controlată la nivel de pixel. Programul prezentat în continuare este particularizat pentru situaţia hardware prezentată în figura 7.6. Şi anume, sunt folosite numai cele 8 linii ale portului "PC". Astfel, sunt utilizate numai şapte linii de I/O ale lui 68HC11 pentru a realiza un trasfer de informaţie pe o magistrală de date de numai 4 biţi respectiv pentru a implementa protocolul de transfer prin magistrala de comenzi aferentă (E, R/W, RS).

Dacă prin programul precedent am facut să pâlpâie un LED, acum în acord cu primele noastre experienţe în domeniul embedded sytem vom realiza un program care scrie pe ecranul modulului LCD " Hello World !...". ************************************* * PROGRAM "LCDHWE.ASM" * * * * * ************************************* ETX: EQU $04 REGS: EQU $1000 DDRC: EQU $07 PC: EQU $03 ORG $B600 LDS #$FF JSR LCD4BIT JSR LCDINIT LDX #TEXTHW JSR LCDTXT LOOPHW: JMP LOOPHW

Page 141: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

141

TEXTHW: FCC 'Hello World !...' FCB ETX ************************************* * ROUTINE FOR NORMAL DIPLAY * * * * X-> pointer to strigt * * end of string $04, * * line control $0A * * if present change the line * * * * Reg aff: X,CCR * ************************************* LCDTXT: PSHA LCDTXT2: LDAA ,X * load pointer to X INX * increment pointer CMPA #$0A * verify if - line change BEQ LCDTXT5 * if yes, change the line CMPA #$04 * if end of strig BEQ LCDTXT4 * yes, end print JSR LCDTEST * test LCD JSR LCDWDATA * write to LCD BRA LCDTXT2 * next chr. LCDTXT4: PULA * end routine RTS LCDTXT5: LDAA #$C0 * Point to case #1 of the line #2 JSR LCDTEST * test LCD JSR LCDWCTL * send new address BRA LCDTXT2 * write in the line #2 ************************************* * LCDTEST * * * * Test if LCD is not busy * * * * Reg Aff:CC * ************************************* LCDTEST: PSHA LCDTEST1: JSR LCDRCTL * read the controle register BMI LCDTEST1 * if busy, test again PULA * end routine RTS ************************************* * LCDRDATA * * * * Data read RS = 1 * * return in A * * * * Reg Aff: A,CC *

Page 142: Microprocesoare Si Microcontrolere

142 Microcontrolerul 68HC11. PcBug

************************************* * LCDRCTL * * * * Control read RS = 0 * * return in A * * * * Reg Aff: A,CC * ************************************* LCDRDATA: PSHB LDAB #%00000110 BRA LCDR LCDRCTL: PSHB LDAB #%00000100 LCDR: PSHX LDX #REGS LDAA DDRC,X * load the PC state I or O ANDA #%00001111 * set I and O line of the PC ORAA #%00001110 * not bit 0 STAA DDRC,X LDAA PC,X * read PC value ANDA #%00000001 * mask ABA * TAB STAB PC,X BSET PC,X %00001000 * set E, delay NOP LDAA PC,X * read data, 4 bit BCLR PC,X %00001000 * set E, delay PSHA STAB PC,X BSET PC,X %00001000 * set E to 1 + Delay NOP LDAA PC,X * read data, 4 bit BCLR PC,X %00001000 * set E to 0 + Delay LSRA LSRA LSRA LSRA PULB ANDB #%11110000 ABA PULX PULB RTS ************************************* * LCDWDATA * * * * Write 8 bit from A * * and set RS = 1 * * *

Page 143: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

143

* Reg Aff: CC * ************************************* * LCDWCTL * * * * Write 8 bit from A * * and set RS = 0 * * * * Reg Aff: CC * ************************************* LCDWDATA: PSHB LDAB #%00000010 BRA LCDW LCDWCTL: PSHB LDAB #%00000000 LCDW: PSHX PSHA PSHA LDX #REGS PSHA LDAA DDRC,X * read the PC state ORAA #%11111110 * set the PC in write mode STAA DDRC,X * store DDRC LDAA PC,X * read the PC value ANDA #%00000001 * not change the Bit 0 ABA TAB PULA ANDA #%11110000 * set E to 0 and write data (4 bit) ABA STAA PC,X BSET PC,X %00001000 * set E to 1 + Delay BCLR PC,X %00001000 * set E to 0 + Delay PULA * pulA for second part ASLA * Shift second prat ASLA * data + Delay ASLA ASLA ABA STAA PC,X BSET PC,X %00001000 * set E to 1 + Delay BCLR PC,X %00001000 * set E to 0 + Delay PULA * pulA for end PULX * pulX for end PULB RTS * end routine ************************************* * LCD4BIT * * * * The LCD in 4 bit mode * * *

Page 144: Microprocesoare Si Microcontrolere

144 Microcontrolerul 68HC11. PcBug

* Reg Aff: CC * ************************************* LCD4BIT: PSHX LDAA #%00110000 BSR LCD4B2 * delay 16.4 ms BSR LCD4B2 BSR LCD4B2 BSR LCD4B2 BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms LDAA #%00100000 BSR LCD4B1 * set 4 Bit PULX RTS LCD4B1: PSHA PSHX PSHB LDX #REGS LDAB #%11111111 * set the DATA in write STAB DDRC,X * store DDRC PULB ANDA #%11110000 STAA PC,X BCLR PC,X #%00001110 * set E & R/W & RS to 0 BSET PC,X #%00001000 * set E a 1 BCLR PC,X #%00001000 * set E a 0 PULX PULA RTS LCD4B2: LDX #$0384 * delay 4.5 ms LCD4B21: DEX CPX #$0000 BNE LCD4B21 RTS ************************************* * LCDINIT * * * * Set the LCD in mode * * 4 bit 2 line * * Display ON Cursor OFF Blinking OFF* * Clear Display * * Cursor INC, Shift OFF * * * * Reg Aff: A,CC * *************************************

Page 145: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

145

LCDINIT: JSR LCDTEST LDAA #%00101000 * 4 Bit 2 line JSR LCDWCTL JSR LCDTEST LDAA #%00001100 * display ON cursor OFF blink OFF JSR LCDWCTL JSR LCDTEST LDAA #%00000001 * clear display JSR LCDWCTL JSR LCDTEST LDAA #%00000110 * cursor INC shift OFF JSR LCDWCTL RTS

Fişierul sursă realizat va trece prin toate etapele de acum cunoscute spre forma obiect ".S19", astfel încât să poată fi încărcat în memoria EEPROM a microcontrolerului 68HC11. Pentru a vedea programul la lucru vom conecta printr-un cablu panglică cele două module între ele. Dacă până acum doar am bănuit că prin interfaţa de comunicaţii RS232 se face un transfer de informaţie între calculatorul personal IBM PC (calculator gazdă, host) şi embedded systemul realizat cu microcontrolerul 68HC11A1 (sistem ţintă, target), în continuare vom realiza un program care să pună în evidenţă transferul de informaţie între sistemele prezentate până acum. Din modul terminal al utilitarului PCBUG (atenţie la setarea parametrului de viteză pentru interfaţa serială, BAUD) vom trimite diferite mesaje către sistemul ţintă pe care acesta le va afişa on-line pe LCD. Practic, programul următor nu este altceva decât o extensie a programului precedent cu un task orientat spre interfaţa serială, adică după cum spuneam, muncă de rutină. ************************************** * PROGRAM "LCDSCI.ASM" * * * * * ************************************** ETX: EQU $04 REGS: EQU $1000 DDRC: EQU $07 PC: EQU $03 BAUD: EQU $2B SCCR1: EQU $2C SCCR2: EQU $2D SCSR: EQU $2E SCDR: EQU $2F * start here ORG $B600

Page 146: Microprocesoare Si Microcontrolere

146 Microcontrolerul 68HC11. PcBug

LDS #$00FF JSR LCD4BIT JSR LCDINIT LDX #TEXTSCI JSR LCDTXT JSR INISCI RETURLIN: LDAA #$C0 JSR LCDTEST * test LCD JSR LCDWCTL * send new address LDAA #$0A JSR OUTCAR LDAA #$0D JSR OUTCAR LDAB #$00 LOOPSCI: JSR INCAR INCB JSR LCDTEST * test LCD JSR LCDWDATA * write data to LCD JSR OUTCAR CMPB #$10 BEQ RETURLIN JMP LOOPSCI TEXTSCI: FCC 'MODE SCI: LINE 2' FCB ETX ************************************** * Set SCI * * 9600 bps, 8 bit, no parity, * * 1 bit sstop * * * * Reg aff: A,CCR * ************************************** INISCI: LDX #REGS LDAA #$30 * 9600 BPS STAA BAUD,X LDAA #$00 * 8 BIT, NO WAKE UP, 1 STOP BIT STAA SCCR1,X LDAA #$0C * NO INTERRUPT, TX ENABLE, RX ENABLE STAA SCCR2,X RTS ************************************* * Send data from A to SCI * * * * * * Reg aff:CCR * *************************************

Page 147: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

147

OUTCAR: PSHB PSHX LDX #REGS OUTCAR2: LDAB SCSR,X BITB #%10000000 BEQ OUTCAR2 STAA SCDR,X PULX PULB RTS ************************************* * LOOKCAR * * * * Look the SCI for car. * * * * Z=1, without car. * * Z=0, car. In A register * * * * Reg Aff: A,CCR * ************************************* LOOKCAR: PSHB PSHX LDX #REGS LDAB SCSR,X BITB #%00100000 BEQ LOOKCAR1 LDAA SCDR,X PSHA TPA ANDA #%11111011 TAP PULA LOOKCAR1: PULX PULB RTS ************************************* * INCAR * * * * Read the SCI * * * * Reg Aff: A,CCR * ************************************* INCAR: JSR LOOKCAR BEQ INCAR RTS ************************************* * ROUTINE FOR NORMAL DIPLAY * * *

Page 148: Microprocesoare Si Microcontrolere

148 Microcontrolerul 68HC11. PcBug

* X-> pointer to strigt * * end of string $04, * * line control $0A * * if present change the line * * * * Reg aff: X,CCR * ************************************* LCDTXT: PSHA LCDTXT2: LDAA ,X * load pointer to X INX * increment pointer CMPA #$0A * verify if - line change BEQ LCDTXT5 * if yes, change the line CMPA #$04 * if end of strig BEQ LCDTXT4 * yes, end print JSR LCDTEST * test LCD JSR LCDWDATA * write to LCD BRA LCDTXT2 * next chr. LCDTXT4: PULA * end routine RTS LCDTXT5: LDAA #$C0 * Point to case #1 of the line #2 JSR LCDTEST * test LCD JSR LCDWCTL * send new address BRA LCDTXT2 * write in the line #2 ************************************* * LCDTEST * * * * Test if LCD is not busy * * * * Reg Aff:CC * ************************************* LCDTEST: PSHA LCDTEST1: JSR LCDRCTL * read the controle register BMI LCDTEST1 * if busy, test again PULA * end routine RTS ************************************* * LCDRDATA * * * * Data read RS = 1 * * return in A * * * * Reg Aff: A,CC * ************************************* * LCDRCTL * * * * Control read RS = 0 * * return in A * * *

Page 149: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

149

* Reg Aff: A,CC * ************************************* LCDRDATA: PSHB LDAB #%00000110 BRA LCDR LCDRCTL: PSHB LDAB #%00000100 LCDR: PSHX LDX #REGS LDAA DDRC,X * load the PC state I or O ANDA #%00001111 * set I and O line of the PC ORAA #%00001110 * not bit 0 STAA DDRC,X LDAA PC,X * read PC value ANDA #%00000001 * mask ABA * TAB STAB PC,X BSET PC,X %00001000 * set E, delay NOP LDAA PC,X * read data, 4 bit BCLR PC,X %00001000 * set E, delay PSHA STAB PC,X BSET PC,X %00001000 * set E to 1 + Delay NOP LDAA PC,X * read data, 4 bit BCLR PC,X %00001000 * set E to 0 + Delay LSRA LSRA LSRA LSRA PULB ANDB #%11110000 ABA PULX PULB RTS ************************************* * LCDWDATA * * * * Write 8 bit from A * * and set RS = 1 * * * * Reg Aff: CC * ************************************* * LCDWCTL * * * * Write 8 bit from A * * and set RS = 0 *

Page 150: Microprocesoare Si Microcontrolere

150 Microcontrolerul 68HC11. PcBug

* * * Reg Aff: CC * ************************************* LCDWDATA: PSHB LDAB #%00000010 BRA LCDW LCDWCTL: PSHB LDAB #%00000000 LCDW: PSHX PSHA PSHA LDX #REGS PSHA LDAA DDRC,X * read the PC state ORAA #%11111110 * set the PC in write mode STAA DDRC,X * store DDRC LDAA PC,X * read the PC value ANDA #%00000001 * not change the Bit 0 ABA TAB PULA ANDA #%11110000 * set E to 0 and write data (4 bit) ABA STAA PC,X BSET PC,X %00001000 * set E to 1 + Delay BCLR PC,X %00001000 * set E to 0 + Delay PULA * pulA for second part ASLA * Shift second prat ASLA * data + Delay ASLA ASLA ABA STAA PC,X BSET PC,X %00001000 * set E to 1 + Delay BCLR PC,X %00001000 * set E to 0 + Delay PULA * pulA for end PULX * pulX for end PULB RTS * end routine ************************************* * LCD4BIT * * * * The LCD in 4 bit mode * * * * Reg Aff: CC * ************************************* LCD4BIT: PSHX LDAA #%00110000 BSR LCD4B2 * delay 16.4 ms

Page 151: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

151

BSR LCD4B2 BSR LCD4B2 BSR LCD4B2 BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms LDAA #%00100000 BSR LCD4B1 * set 4 Bit PULX RTS LCD4B1: PSHA PSHX PSHB LDX #REGS LDAB #%11111111 * set the DATA in write STAB DDRC,X * store DDRC PULB ANDA #%11110000 STAA PC,X BCLR PC,X #%00001110 * set E & R/W & RS to 0 BSET PC,X #%00001000 * set E a 1 BCLR PC,X #%00001000 * set E a 0 PULX PULA RTS LCD4B2: LDX #$0384 * delay 4.5 ms LCD4B21: DEX CPX #$0000 BNE LCD4B21 RTS ************************************* * LCDINIT * * * * Set the LCD in mode * * 4 bit 2 line * * Display ON Cursor OFF Blinking OFF* * Clear Display * * Cursor INC, Shift OFF * * * * Reg Aff: A,CC * ************************************* LCDINIT: JSR LCDTEST LDAA #%00101000 * 4 Bit 2 line JSR LCDWCTL JSR LCDTEST LDAA #%00001100 * display ON cursor OFF blink OFF

Page 152: Microprocesoare Si Microcontrolere

152 Microcontrolerul 68HC11. PcBug

JSR LCDWCTL JSR LCDTEST LDAA #%00000001 * clear display JSR LCDWCTL JSR LCDTEST LDAA #%00000110 * cursor INC shift OFF JSR LCDWCTL RTS

Pentru o mai bună familiarizare cu stilul de programare şi instrucţiunile microcontrolerului 68HC11, în continuare vom realiza o aplicaţie independentă de calculatorul gazdă. După ce programul următor va fi transferat în sistemul cu 68HC11A1, acesta va funcţiona independent şi nu va fi nimic altceva decât un ceas. Pentru a nu complica inutil programul s-a apelat la un task de întârziere (delay) chiar dacă sistemul dispune de sisteme avansate de temporizare, întrerupere. Oricum programul următor este unic în sistem, aşa că, el nu va fi deranjat de alte programe pentru simplul motiv că acestea nu există. În acest fel, precizia de măsurare a timpului nu depinde de eleganţa metodei utilizate şi astfel este posibil să obţinem un o aplicaţie funcţional corectă fără prea mari complicaţii software. Afişarea timpului la nivel de zecimi de ms cred că sugerează cam ce poate un asemenea sistem chiar şi în această versiune minimală. ************************************** * PROGRAM "CLKLCD.ASM" * * * * * ************************************** ETX: EQU $04 REGS: EQU $1000 DDRC: EQU $07 PC: EQU $03 BAUD: EQU $2B SCCR1: EQU $2C SCCR2: EQU $2D SCSR: EQU $2E SCDR: EQU $2F OPT: EQU $39 ADCTL: EQU $30 ADR1: EQU $31 * define variables ORG $0000 HREG: RMB 1 * HH:, 0 to 23 MREG: RMB 1 * MM:, 0 to 59 SREG: RMB 1 * SS:, 0 to 59 MSREG: RMB 1 * MS, 0 to 99 * start here

Page 153: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

153

ORG $B600 LDS #$00FF JSR LCD4BIT JSR LCDINIT LDX #TEXTAD JSR LCDTXT LOOPCK: CLR HREG CLR MREG CLR SREG CLR MSREG TICCK: LDX #8 JSR LDELAY LDAA MSREG ADDA #1 DAA PSHA STAA MSREG LDAA #$C0 JSR LCDTEST * test LCD JSR LCDWCTL * send new address JSR TIPTIC PULA CMPA #$99 BNE TICCK CLR MSREG LDAA SREG ADDA #1 DAA STAA SREG CMPA #$60 BNE TICCK CLR SREG LDAA MREG ADDA #1 DAA STAA MREG CMPA #$60 BNE TICCK CLR MREG LDAA HREG ADDA #1 DAA STAA HREG CMPA #$24 BNE TICCK JMP LOOPCK *************************************** * Routine qui WRITE la valeur de * A au LCD sous la forme BCD ASCII. * * Reg aff:CCR

Page 154: Microprocesoare Si Microcontrolere

154 Microcontrolerul 68HC11. PcBug

*************************************** LCD2HA: PSHA PSHA LSRA LSRA LSRA LSRA ORA #$30 JSR LCDTEST JSR LCDWDATA PULA ANDA #$0F ORA #$30 JSR LCDTEST JSR LCDWDATA PULA RTS * tiptic TIPTIC: LDX #TEXTTM JSR LCDTXT LDAA HREG JSR LCD2HA LDAA #$3A JSR LCDTEST JSR LCDWDATA LDAA MREG JSR LCD2HA LDAA #$3A JSR LCDTEST JSR LCDWDATA LDAA SREG JSR LCD2HA LDAA #$3A JSR LCDTEST JSR LCDWDATA LDAA MSREG JSR LCD2HA RTS TEXTAD: FCC 'Clock Tick 10 ms' FCB ETX TEXTTM: FCC 'Time:' FCB ETX * LBINBCD: **************************************

Page 155: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

155

* LOOP DELAY * * on entry, X = delay in ms * * 286 x 7 x .0005 = 1 ms * ************************************** LDELAY: LDY #287 LOOPDY: DEY BNE LOOPDY DEX BNE LDELAY RTS ************************************* * ROUTINE FOR NORMAL DIPLAY * * * * X-> pointer to strigt * * end of string $04, * * line control $0A * * if present change the line * * * * Reg aff: X,CCR * ************************************* LCDTXT: PSHA LCDTXT2: LDAA ,X * load pointer to X INX * increment pointer CMPA #$0A * verify if - line change BEQ LCDTXT5 * if yes, change the line CMPA #$04 * if end of strig BEQ LCDTXT4 * yes, end print JSR LCDTEST * test LCD JSR LCDWDATA * write to LCD BRA LCDTXT2 * next chr. LCDTXT4: PULA * end routine RTS LCDTXT5: LDAA #$C0 * Point to case #1 of the line #2 JSR LCDTEST * test LCD JSR LCDWCTL * send new address BRA LCDTXT2 * write in the line #2 ************************************* * LCDTEST * * * * Test if LCD is not busy * * * * Reg Aff:CC * ************************************* LCDTEST: PSHA LCDTEST1: JSR LCDRCTL * read the controle register BMI LCDTEST1 * if busy, test again PULA * end routine

Page 156: Microprocesoare Si Microcontrolere

156 Microcontrolerul 68HC11. PcBug

RTS ************************************* * LCDRDATA * * * * Data read RS = 1 * * return in A * * * * Reg Aff: A,CC * ************************************* * LCDRCTL * * * * Control read RS = 0 * * return in A * * * * Reg Aff: A,CC * ************************************* LCDRDATA: PSHB LDAB #%00000110 BRA LCDR LCDRCTL: PSHB LDAB #%00000100 LCDR: PSHX LDX #REGS LDAA DDRC,X * load the PC state I or O ANDA #%00001111 * set I and O line of the PC ORAA #%00001110 * not bit 0 STAA DDRC,X LDAA PC,X * read PC value ANDA #%00000001 * mask ABA * TAB STAB PC,X BSET PC,X %00001000 * set E, delay NOP LDAA PC,X * read data, 4 bit BCLR PC,X %00001000 * set E, delay PSHA STAB PC,X BSET PC,X %00001000 * set E to 1 + Delay NOP LDAA PC,X * read data, 4 bit BCLR PC,X %00001000 * set E to 0 + Delay LSRA LSRA LSRA LSRA PULB ANDB #%11110000 ABA PULX

Page 157: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

157

PULB RTS ************************************* * LCDWDATA * * * * Write 8 bit from A * * and set RS = 1 * * * * Reg Aff: CC * ************************************* * LCDWCTL * * * * Write 8 bit from A * * and set RS = 0 * * * * Reg Aff: CC * ************************************* LCDWDATA: PSHB LDAB #%00000010 BRA LCDW LCDWCTL: PSHB LDAB #%00000000 LCDW: PSHX PSHA PSHA LDX #REGS PSHA LDAA DDRC,X * read the PC state ORAA #%11111110 * set the PC in write mode STAA DDRC,X * store DDRC LDAA PC,X * read the PC value ANDA #%00000001 * not change the Bit 0 ABA TAB PULA ANDA #%11110000 * set E to 0 and write data (4 bit) ABA STAA PC,X BSET PC,X %00001000 * set E to 1 + Delay BCLR PC,X %00001000 * set E to 0 + Delay PULA * pulA for second part ASLA * Shift second prat ASLA * data + Delay ASLA ASLA ABA STAA PC,X BSET PC,X %00001000 * set E to 1 + Delay BCLR PC,X %00001000 * set E to 0 + Delay PULA * pulA for end

Page 158: Microprocesoare Si Microcontrolere

158 Microcontrolerul 68HC11. PcBug

PULX * pulX for end PULB RTS * end routine ************************************* * LCD4BIT * * * * The LCD in 4 bit mode * * * * Reg Aff: CC * ************************************* LCD4BIT: PSHX LDAA #%00110000 BSR LCD4B2 * delay 16.4 ms BSR LCD4B2 BSR LCD4B2 BSR LCD4B2 BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms LDAA #%00100000 BSR LCD4B1 * set 4 Bit PULX RTS LCD4B1: PSHA PSHX PSHB LDX #REGS LDAB #%11111111 * set the DATA in write STAB DDRC,X * store DDRC PULB ANDA #%11110000 STAA PC,X BCLR PC,X #%00001110 * set E & R/W & RS to 0 BSET PC,X #%00001000 * set E a 1 BCLR PC,X #%00001000 * set E a 0 PULX PULA RTS LCD4B2: LDX #$0384 * delay 4.5 ms LCD4B21: DEX CPX #$0000 BNE LCD4B21 RTS ************************************* * LCDINIT *

Page 159: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

159

* * * Set the LCD in mode * * 4 bit 2 line * * Display ON Cursor OFF Blinking OFF* * Clear Display * * Cursor INC, Shift OFF * * * * Reg Aff: A,CC * ************************************* LCDINIT: JSR LCDTEST LDAA #%00101000 * 4 Bit 2 line JSR LCDWCTL JSR LCDTEST LDAA #%00001100 * display ON cursor OFF blink OFF JSR LCDWCTL JSR LCDTEST LDAA #%00000001 * clear display JSR LCDWCTL JSR LCDTEST LDAA #%00000110 * cursor INC shift OFF JSR LCDWCTL RTS

Abordarea într-un sigur capitol a unor tehnologii extrem de moderne şi sofisticate este desigur mai puţin productivă. Trebuie să avem încredere în ceea ştim deja din primele şase capitole şi să nu uităm că numai acest microcontroler, dacă vom putea să-l învăţăm, cât de cât, în aproximativ o jumătate de an, este o mare realizare. În acest capitol sunt schiţate câteva lucruri, un posibil drum de urmat, este nevoie însă de multă voinţă pentru a ajunge aici. Acum avem la îndemână o tehnologie modernă de abordare a aplicaţiilor de achiziţie de date şi control. Deja se conturează un nou mod de abordare al aplicaţiilor total diferit de ceea ce am învătat în capitolul 4 (pentru portul paralel nu face pământul să fie rotund aşa cum cred tot felul de pseudo-specialişti). Am putut vedea în acest capitol sisteme interconectate între ele, fiecare sistem cu propria lui inteligenţă locală respectiv cu propria lui specializare. Aşa că, prin prisma tehnologiilor actuale abordarea fiecărei părţi a unei aplicaţii se face prin intermediul unui hardware-software specializat în care toate componentele concură la obţinerea rezultatului final. Achiziţia de date, controlul şi procesarea distribuită a informaţiei a permis realizarea unor aplicaţii care până acum câtiva ani păreau de domeniul SF. Astăzi ele sunt realitate şi pentru multe alte aplicaţii această tehnologie, în plină dezvoltare, are resurse sau va avea resurse. Tocmai de aceea efortul de a învăţa merită, este singura posibilitate de a ne oferi o şansa să facem ceva în acest domeniu fără de care, lumea de azi nu s-ar fi deosebit, prea mult, de cea de la începutul secolului XX.

Page 160: Microprocesoare Si Microcontrolere

160 Microcontrolerul 68HC11. PcBug

Page 161: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

161

8. Voltmetru Digital cu Microcontrolerul 68HC11

Nu au fost lipsite de interes aplicaţiile din capitolul precedent dacă abordăm lucrurile din punctul de vedere al unui antrenament cu această nouă tehnologie. După cum am putut constata microcontrolerul 68HC11 are o periferie puternică şi dintre toate facilităţile oferite de această periferie, fără îndoială, cea mai atractivă dintre acestea este convertorul Analog-Digital (A/D).

68HC11 a fost primul microcontroler care a avut înglobată o asemenea periferie. Convertorul A/D utilizează o tehnică de conversie oarecum inedită pentru tehnologia clasică, redistribuirea capacitivă de sarcină. Sunt astfel diponibile 8 canale de conversie fiecare cu o rezoluţie de 8 biţi, rezultatul conversiei fiind obţinut prin aproximări succesive cu o acurateţe de ± 1/2 LSB (Least Significant Bit). Pe de altă parte, folosirea unei tehnici de redistribuire capacitivă a sarcinii pentru conversie face inutilă utilizarea în aplicaţii a unui circuit "sample-hold" extern.

Fără a insista asupra caracteristicilor electrice şi asupra modului de implementare a tehnicii de conversie amintite în continuare ne vom îndrepta atenţia asupra informaţiilor necesare pentru utilizarea acestei periferii în aplicaţiile de achiziţie de date. Pentru a putea realiza conversia A/D a semnalului analogic extern într-un domeniu larg (până la tensiunea de alimentare a microcontrolerului, 5V) pe lângă convertorul A/D în 68HC11 mai sunt şi două pompe de sarcină cu ajutorul căreia pot fi obţinute intern tensiuni de circa 7 - 8 V. Aceste pompe de sarcină trebuie să fie active în două situaţii: atunci când este programată memoria EEPROM (fiecare situaţie cu pompa de sarcină corespunzătoare) şi atunci când vrem să utilizăm covertorul A/D. Pentru a înţelege acest mecanism în tabelul 8.1 este prezentată semnificaţia biţilor din registrul OPTION ($1039).

Tabelul 8.1

După cum se poate vedea, ambele pompe sunt selectate cu acelaşi bit CSEL prin care se asigură semnal de ceas pentru ele. Pompa care furnizează tensiune mare pentru comparatoarele convertorului A/D este activată prin intermediul bitului de control ADPU. Pe lângă registrul OPTION mai trebuie să ştim şi să înţelegem şi semnificaţia biţilor din registrul ADCTL prezentat în tabelul 8.2. Toţi biţii din acest

Page 162: Microprocesoare Si Microcontrolere

162 Voltmetru Digital cu Microcontrolerul 68HC11

registru pot fi citiţi sau scrişi cu excepţia bitului 7 (CCF) care nu poate fi decât citit şi a bitului şase care este tot timpul zero. Semnificaţia şi rolul fiecărui bit este prezentată succint în continuare: Tabelul 8.2

• CCF (Conversion complete Flag) - este setat atunci când regiştri de rezultat conţin o valoare validă obţinută în urma conversiei.

• SCAN (Continuous Scan Control) - dacă acest bit este egal cu zero atunci conversia cerută este realizată iar rezultatul este diponibil în regiştri destinaţi acestui scop (ADR1 - ADR4), când bitul este egal cu unu atunci convertorul funcţionează în regim "round-robin" adică depune tot timpul rezultate în regiştri ADR1 - ADR4 pe măsură ce acestea devin disponibile.

Tabelul 8.3

Page 163: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

163

• MULT (Multiple-Channel/Single-Channel Control) - dacă acest bit este egal cu zero atunci convertorul este configurat pentru a realiza patru conversii succesive a unui singur canal selectat de biţi CD - CA ai registrului ADCTL, când bitul este egal cu unu atunci convertorul este configurat pentru a realiza conversia pe fiecare canal dintr-un grup de patru canale specificat de biţi CD - CC. În acest mod (multiple-channel mode) fiecare canal este asociat cu un registru de canal specific.

• CD, CC, CB, CA (Channel Selects) - aceşti patru biţi sunt utilizaţi pentru a specifica canalul/canalele pe care lucrează convertorul A/D. Semnificaţia lor este prezentată în tabelul 8.3.

Regiştrii de rezultat (ADR1 - ADR4) sunt utilizaţi numai pentru stocarea rezultatelor conversiei A/D, aşa că ei sunt de tipul "read-only". Ori de câte ori bitul CCF este egal cu unu, aceşti regiştri vor conţine un rezultat valid care poate fi citit şi utilizat prin program. Considerând acestă prezentare a convertorului A/D suficientă, să realizăm în continuare un program prin care să transformăm embedded system-ul cu 68HC11 conectat cu modulul LCD într-un voltmetru digital pe 8 canale. Folosind utilitarele şi comenzile prezentate în capitolul anterior vom obţine din fişierul sursă prezentat în continuare un fişier obiect tip ".S19" pe care-l vom încărca în memoria EEPROM a lui 68HC11. ************************************** * PROGRAM "ADLCD.ASM" * * * * * ************************************** ETX: EQU $04 REGS: EQU $1000 DDRC: EQU $07 PC: EQU $03 BAUD: EQU $2B SCCR1: EQU $2C SCCR2: EQU $2D SCSR: EQU $2E SCDR: EQU $2F OPT: EQU $39 ADCTL: EQU $30 ADR1: EQU $31 * define variables ORG $0000 AREG: RMB 1 * tmp storage BCDBUF: RMB 3 * $xxxx - dddddd * start here ORG $B600 LDS #$00FF

Page 164: Microprocesoare Si Microcontrolere

164 Voltmetru Digital cu Microcontrolerul 68HC11

JSR LCD4BIT JSR LCDINIT LDX #TEXTAD JSR LCDTXT JSR INIAD NEWAD: LDAB #$00 LOOPAD: LDAA #$C0 JSR LCDTEST * test LCD JSR LCDWCTL * send new address PSHB TBA PSHA ADDA #$30 * ASCII conversion JSR LCDTEST * test LCD JSR LCDWDATA * write to LCD LDX #TEXTDP JSR LCDTXT PULA JSR ADREAD TAB CLRA ASLB * value = value x 2, ~5V full scale BCC NOCARRY LDAA #$01 NOCARRY: JSR BINBCD LDAA BCDBUF+1 * load ms digit ANDA #$0F ORA #$30 JSR LCDTEST * test LCD JSR LCDWDATA * write to LCD LDAA #$2E JSR LCDTEST * test LCD JSR LCDWDATA * write to LCD LDAA BCDBUF+2 LSRA LSRA LSRA LSRA ORA #$30 JSR LCDTEST * test LCD JSR LCDWDATA * write to LCD LDAA BCDBUF+2 ANDA #$0F ORA #$30 JSR LCDTEST * test LCD JSR LCDWDATA * write to LCD LDX #TEXTV JSR LCDTXT LDX #2000 JSR LDELAY PULB INCB CMPB #$08

Page 165: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

165

BEQ NEWADS JMP LOOPAD NEWADS: JMP NEWAD TEXTAD: FCC '8 Channels ADC :' FCB ETX TEXTDP: FCC ' : ' FCB ETX TEXTV: FCC ' Volts' FCB ETX ************************************** * LOOP DELAY * * on entry, X = delay in ms * * 286 x 7 x .0005 = 1 ms * ************************************** LDELAY: LDY #287 LOOPDY: DEY BNE LOOPDY DEX BNE LDELAY RTS ************************************** * BINBCD - BIN to BCD conversion * * Input value in D, * * Conversion value in BCDBUF, ... * ************************************** BINBCD: CLR BCDBUF CLR BCDBUF+1 CLR BCDBUF+2 STAA AREG TSTD: LDAA AREG SUBD #0 BEQ XBINBCD SUBD #1 STAA AREG LDAA BCDBUF+2 ADDA #1 DAA STAA BCDBUF+2 BCC TSTD LDAA BCDBUF+1 ADDA #1 DAA STAA BCDBUF+1 BCC TSTD LDAA BCDBUF ADDA #1 DAA STAA BCDBUF

Page 166: Microprocesoare Si Microcontrolere

166 Voltmetru Digital cu Microcontrolerul 68HC11

BCC TSTD XBINBCD: RTS ************************************** * Routine for A/D convertor * * * * * ************************************** ************************************** * INIAD * * * * Routine to init * * charge pompe for A/D * * * * * * Reg Aff: A,CCR * ************************************** INIAD: LDX #REGS BSET OPT,X %10000000 BCLR OPT,X %01000000 RTS ************************************** * ADREAD * * * * Routine for read value * * conversion from PEx * * * * * * Reg Aff: A,CCR * ************************************** ADREAD: PSHX LDX #REGS ANDA #%00001111 STAA ADCTL,X ADREAD1: LDAA ADCTL,X BMI ADREAD1 LDAA ADR1,X PULX RTS ************************************* * ROUTINE FOR NORMAL DIPLAY * * * * X-> pointer to strigt * * end of string $04, * * line control $0A * * if present change the line * * * * Reg aff: X,CCR *

Page 167: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

167

************************************* LCDTXT: PSHA LCDTXT2: LDAA ,X * load pointer to X INX * increment pointer CMPA #$0A * verify if - line change BEQ LCDTXT5 * if yes, change the line CMPA #$04 * if end of strig BEQ LCDTXT4 * yes, end print JSR LCDTEST * test LCD JSR LCDWDATA * write to LCD BRA LCDTXT2 * next chr. LCDTXT4: PULA * end routine RTS LCDTXT5: LDAA #$C0 * Point to case #1 of the line #2 JSR LCDTEST * test LCD JSR LCDWCTL * send new address BRA LCDTXT2 * write in the line #2 ************************************* * LCDTEST * * * * Test if LCD is not busy * * * * Reg Aff:CC * ************************************* LCDTEST: PSHA LCDTEST1: JSR LCDRCTL * read the controle register BMI LCDTEST1 * if busy, test again PULA * end routine RTS ************************************* * LCDRDATA * * * * Data read RS = 1 * * return in A * * * * Reg Aff: A,CC * ************************************* * LCDRCTL * * * * Control read RS = 0 * * return in A * * * * Reg Aff: A,CC * ************************************* LCDRDATA: PSHB LDAB #%00000110 BRA LCDR

Page 168: Microprocesoare Si Microcontrolere

168 Voltmetru Digital cu Microcontrolerul 68HC11

LCDRCTL: PSHB LDAB #%00000100 LCDR: PSHX LDX #REGS LDAA DDRC,X * load the PC state I or O ANDA #%00001111 * set I and O line of the PC ORAA #%00001110 * not bit 0 STAA DDRC,X LDAA PC,X * read PC value ANDA #%00000001 * mask ABA * TAB STAB PC,X BSET PC,X %00001000 * set E, delay NOP LDAA PC,X * read data, 4 bit BCLR PC,X %00001000 * set E, delay PSHA STAB PC,X BSET PC,X %00001000 * set E to 1 + Delay NOP LDAA PC,X * read data, 4 bit BCLR PC,X %00001000 * set E to 0 + Delay LSRA LSRA LSRA LSRA PULB ANDB #%11110000 ABA PULX PULB RTS ************************************* * LCDWDATA * * * * Write 8 bit from A * * and set RS = 1 * * * * Reg Aff: CC * ************************************* * LCDWCTL * * * * Write 8 bit from A * * and set RS = 0 * * * * Reg Aff: CC * ************************************* LCDWDATA: PSHB LDAB #%00000010

Page 169: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

169

BRA LCDW LCDWCTL: PSHB LDAB #%00000000 LCDW: PSHX PSHA PSHA LDX #REGS PSHA LDAA DDRC,X * read the PC state ORAA #%11111110 * set the PC in write mode STAA DDRC,X * store DDRC LDAA PC,X * read the PC value ANDA #%00000001 * not change the Bit 0 ABA TAB PULA ANDA #%11110000 * set E to 0 and write data (4 bit) ABA STAA PC,X BSET PC,X %00001000 * set E to 1 + Delay BCLR PC,X %00001000 * set E to 0 + Delay PULA * pulA for second part ASLA * Shift second prat ASLA * data + Delay ASLA ASLA ABA STAA PC,X BSET PC,X %00001000 * set E to 1 + Delay BCLR PC,X %00001000 * set E to 0 + Delay PULA * pulA for end PULX * pulX for end PULB RTS * end routine ************************************* * LCD4BIT * * * * The LCD in 4 bit mode * * * * Reg Aff: CC * ************************************* LCD4BIT: PSHX LDAA #%00110000 BSR LCD4B2 * delay 16.4 ms BSR LCD4B2 BSR LCD4B2 BSR LCD4B2 BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms BSR LCD4B1 * set 8 bit

Page 170: Microprocesoare Si Microcontrolere

170 Voltmetru Digital cu Microcontrolerul 68HC11

BSR LCD4B2 * Delay 4.1 ms BSR LCD4B1 * set 8 bit BSR LCD4B2 * Delay 4.1 ms LDAA #%00100000 BSR LCD4B1 * set 4 Bit PULX RTS LCD4B1: PSHA PSHX PSHB LDX #REGS LDAB #%11111111 * set the DATA in write STAB DDRC,X * store DDRC PULB ANDA #%11110000 STAA PC,X BCLR PC,X #%00001110 * set E & R/W & RS to 0 BSET PC,X #%00001000 * set E a 1 BCLR PC,X #%00001000 * set E a 0 PULX PULA RTS LCD4B2: LDX #$0384 * delay 4.5 ms LCD4B21: DEX CPX #$0000 BNE LCD4B21 RTS ************************************* * LCDINIT * * * * Set the LCD in mode * * 4 bit 2 line * * Display ON Cursor OFF Blinking OFF* * Clear Display * * Cursor INC, Shift OFF * * * * Reg Aff: A,CC * ************************************* LCDINIT: JSR LCDTEST LDAA #%00101000 * 4 Bit 2 line JSR LCDWCTL JSR LCDTEST LDAA #%00001100 * display ON cursor OFF blink OFF JSR LCDWCTL JSR LCDTEST LDAA #%00000001 * clear display JSR LCDWCTL JSR LCDTEST LDAA #%00000110 * cursor INC shift OFF

Page 171: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

171

JSR LCDWCTL RTS

Chiar şi în această implementare minimală a unui embedded system cu microcontrolerul 68HC11 se poate uşor implementa un sistem distribuit de achiziţie de date. Utilizând cu pricepere comanda "copy - paste" a editorului nu a fost greu să realizăm programele anterioare. Programele pentru microcontrolerul 68HC11 prezentate până acum au multe subrutine comune care pur şi simplu au fost copiate dintr-un program în altul, acesta este marele avantaj a utilizării unui asamblor extern. Utilizând cu pricepere această facilitate, în scurt timp putem obţine fişierul sursă prezentat în continuare: ************************************** * PROGRAM "ADSCI.ASM" * * * * * ************************************** ETX: EQU $04 REGS: EQU $1000 DDRC: EQU $07 PC: EQU $03 BAUD: EQU $2B SCCR1: EQU $2C SCCR2: EQU $2D SCSR: EQU $2E SCDR: EQU $2F OPT: EQU $39 ADCTL: EQU $30 ADR1: EQU $31 * define variables ORG $0000 AREG: RMB 1 * tmp storage BCDBUF: RMB 3 * $xxxx - dddddd * start here ORG $B600 LDS #$00FF JSR INISCI JSR INIAD LOOPAD: JSR INCAR PSHA PSHA LDAA #$0A JSR OUTCAR LDAA #$0D JSR OUTCAR PULA

Page 172: Microprocesoare Si Microcontrolere

172 Voltmetru Digital cu Microcontrolerul 68HC11

JSR OUTCAR LDAA #$3A JSR OUTCAR PULA SUBA #$30 * channel 0 to 7 JSR ADREAD TAB CLRA ASLB * value = value x 2, ~5V full scale BCC NOCARRY LDAA #$01 NOCARRY: JSR BINBCD LDAA BCDBUF+1 * load ms digit ANDA #$0F ORA #$30 JSR OUTCAR LDAA #$2E JSR OUTCAR LDAA BCDBUF+2 LSRA LSRA LSRA LSRA ORA #$30 JSR OUTCAR LDAA BCDBUF+2 ANDA #$0F ORA #$30 JSR OUTCAR JMP LOOPAD ************************************** * BINBCD - BIN to BCD conversion * * Input value in D, * * Conversion value in BCDBUF, ... * ************************************** BINBCD: CLR BCDBUF CLR BCDBUF+1 CLR BCDBUF+2 STAA AREG TSTD: LDAA AREG SUBD #0 BEQ XBINBCD SUBD #1 STAA AREG LDAA BCDBUF+2 ADDA #1 DAA STAA BCDBUF+2 BCC TSTD LDAA BCDBUF+1 ADDA #1

Page 173: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

173

DAA STAA BCDBUF+1 BCC TSTD LDAA BCDBUF ADDA #1 DAA STAA BCDBUF BCC TSTD XBINBCD: RTS ************************************** * Routines for A/D converter * * * * * ************************************** ************************************** * INIAD * * * * Routine for A/D init * * * * charge pompe on * * * * Reg Aff: A,CCR * ************************************** INIAD: LDX #REGS BSET OPT,X %10000000 BCLR OPT,X %01000000 RTS ************************************** * ADREAD * * * * Routine for read A/D value * * from PEx channel * * * * * * * * Reg Aff: A,CCR * ************************************** ADREAD: PSHX LDX #REGS ANDA #%00001111 STAA ADCTL,X ADREAD1: LDAA ADCTL,X BMI ADREAD1 LDAA ADR1,X PULX RTS **************************************

Page 174: Microprocesoare Si Microcontrolere

174 Voltmetru Digital cu Microcontrolerul 68HC11

* Init SCI * * * * 9600 bps, 8 bit, no parity, * * 1 stop bit * * * * Reg aff: A,CCR * ************************************** INISCI: LDX #REGS LDAA #$30 * 9600 BPS STAA BAUD,X LDAA #$00 * 8 BIT, NO WAKE UP, 1 STOP BIT STAA SCCR1,X LDAA #$0C * NO INTERRUPT, TX ENABLE, RX ENABLE STAA SCCR2,X RTS ************************************* * Send value from A to SCI * * * * * * Reg aff:CCR * ************************************* OUTCAR: PSHB PSHX LDX #REGS OUTCAR2: LDAB SCSR,X BITB #%10000000 BEQ OUTCAR2 STAA SCDR,X PULX PULB RTS ************************************* * LOOKCAR * * * * test char * * if available * * * * Z=1, not car. * * Z=0, car. into A * * * * Reg Aff: A,CCR * ************************************* LOOKCAR: PSHB PSHX LDX #REGS LDAB SCSR,X

Page 175: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

175

BITB #%00100000 BEQ LOOKCAR1 LDAA SCDR,X PSHA TPA ANDA #%11111011 TAP PULA LOOKCAR1: PULX PULB RTS ************************************* * INCAR * * * * Read char. From SCI * * * * * * Reg Aff: A,CCR * ************************************* INCAR: JSR LOOKCAR BEQ INCAR RTS

De această dată, prin rularea programului anterior pe embedded system-ul cu microcontrolerul 68HC11 realizăm o interacţiune puternică între sistemul gazdă şi sistemul ţintă. Astfel, sistemul gazdă trimite prin interfaţa serială o cerere de conversie pe unul din cele 8 canale ale convertorului A/D, iar sistemul ţintă răspude prin acelaşi canal de comunicaţie cu valoarea tensiuni, de pe acel canal, exprimată în volţi şi convertită în zecimal. Această situaţie poate fi pusă în evidenţă prin intermediul utilitarului PCBUG în modul terminal. La fel de bine se poate scrie un program pentru calculatorul gazdă care să implementeze acest protocol de comunicaţie şi astfel să obţinem un sistem distribuit de achiziţie de date.

Desigur în acest moment se pot imagina multe aplicaţii concrete pe baza acestei tehnologii. Dar nu orice se poate face cu acest embedded system minimal, el este foarte bun pentru rezolvarea unor situaţii relativ simple şi este foarte bun pentru a ne instrui în acest domeniu. Pentru aplicaţii mai pretenţioase este necesară mai multă memorie şi/sau mai multe porturi de I/O. După cum am menţionat în capitolul anterior, microcontrolerul 68HC11 poate lucra şi în mod "Expanded". O asemenea configuraţie hardware care păstrează în continuare avantajele "autoboot" ale microcontrolerului este prezenată în figura 8.1. În această versiune dispunem de o memorie SRAM de 32Kbyte suficientă pentru programe complexe respectiv pentru manipularea unui volum relativ mare de date. De asemenea, se asigură o structură

Page 176: Microprocesoare Si Microcontrolere

176 Voltmetru Digital cu Microcontrolerul 68HC11

de dezvoltare de tip "open aplication" suficient de flexibilă atăt la nivel hardware cât mai ales la nivel software.

Figura 8.1.Realizarea practică a versiunii "Expanded" a microcontrolerului 68HC11.

Este bine să menţionăm că pentru acest hardware au fost adaptate o serie de interpretoare pentru limbaje de nivel înalt cum ar fi C, Basic, Forth. A fost testat, de asemenea cu succes, o versiune adaptată a celebrului monitor BUFALO utilizat de firma Motorola pentru propriile sisteme de dezvoltare. Acesta nu este altceva decât un utilitar gen PCBUG numai că de această dată sunt utilizate resursele embedded system-ului pentru realizarea tuturor comenzilor calculatorul gazdă find un simplu terminal. Posibilitatea de a lucra direct în limbaje de nivel înalt prin intermediul unor interpretoare conţinute în sistem duce la creşterea productivităţii atunci când avem aplicaţii nu prea pretenţioase în raport cu viteza de execuţie mică a unui program interpretat. Desigur, sunt disponibile şi compilatoare pentru limbajele de nivel înalt menţionate anterior cu ajutorul cărora se poate obţine uşor versiunea cod maşină (.S19) urmată de o creştere semnificativă a performanţelor. Dacă nici aşa nu putem să satisfacem foamea de viteză a unei aplicaţii nu trebuie să uităm că în aceste două capitole am facut deja un contact dur cu limbajul de asamblare al microcontrolerului 68HC11. Microcontrolerul 68HC11 a fost şi este un proiect foarte reuşit al firmei Motorola şi în acelaşi timp, unul dintre cele mai reuşite microcontrolere de uz general produse până în prezent în gama de 8 biţi. Nu în orice aplicaţie avem însă

Page 177: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

177

nevoie de o periferie atât de bine reprezentată şi atât de flexibilă. După cum vom vedea în capitolul următor, se poate şi altfel. Astăzi există pe piaţă o ofertă extrem de bogată de microcontrolere, fiecare familie având zeci de versiuni. De altfel fiecare firmă dezvoltă simultan câteva familii (de regulă până în zece) şi de asemenea pot fi considerate active cel putin zece mari firme în acest domeniu. De multe ori este greu să alegi cea mai bună soluţie pentru o aplicaţie dată. Pe de altă parte, sunt prezente pe piaţă microcontrolere de 4, 8, 16, şi 32 de biţi într-o mare varietate şi un domeniu extrem de larg în ceea ce priveşte performanţele. Astfel sunt disponibile microcontrolere care cu greu pot controla un LED sau microcontrolere atât de evoluate şi specializate încât cu nu de puţine ori eşti tentat să crezi că în faţa ta un monstru sacru se dă în spectacol. După cum am constatat din aplicaţiile de până acum, lumea Motorola este substanţial diferită de lumea Intel. Care este mai frumoasă ? Care este mai bună ? Greu de spus.

Page 178: Microprocesoare Si Microcontrolere

178 Voltmetru Digital cu Microcontrolerul 68HC11

Page 179: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

179

9. Microcontrolerul PIC16F84 Microcontrolerul PIC16F84 face parte din grupul PIC16FXX al familiei PIC16CXX şi este un produs al firmei MicroChip. Această familie de microcontrolere respectiv microcontrolerul PIC16F84 a devenit în timp extrem de populară în aria aplicaţiilor cu un buget redus. Succesul microcontrolerului PIC16F84 (figura 9.1) se datorează atât preţului extrem de scăzut, cât şi arhitecturii avansate de tip RISC (Reduced Set Instruction Computer, numai 35 de instrucţiuni) fiind realizat într-o tehnologie CMOS. Microcontrolerul PIC16F84 este de tip static încât permite funcţionarea de la DC până la frecvenţe ale ceasului de maxim 20 MHz. Spre deosebire de microcontrolerul 68HC11 prezentat în capitolul 7 (care are drept sursă de inspiraţie familia clasică de microprocesoare de 8 biţi de la firma Motorola) care este de tip CISC (Complex Set Instruction Computer) cu o arhitectură clasică (von Neumman), PIC16F84 are o arhitectură Harvard cu o magistrală de instrucţiuni de 14 biţi (instrucţiunile sunt organizate pe cuvinte de 14 biţi) şi o magistrală separată de date de 8 biţi. Cu excepţia instrucţiunilor de salt toate celelalte instrucţiuni sunt executate într-un singur ciclu graţie unui "pipiline" în două etape. Toate acestea fac ca PIC16F84 să fie cel mai rapid microcontroler din clasa sa.

Figura 9.1. Diverse variante ale microcontrolerului PIC16F84.

Page 180: Microprocesoare Si Microcontrolere

180 Microcontrolerul PIC16F84

Microcontrolerul PIC16F84 a fost proiectat cu scopul obţinerii unui raport maxim simplitate/performanţă. Astfel, el are o o stivă internă pe 8 nivele şi multiple surse de întrerupere atât interne cât şi externe. De asemenea, dispune pe lîngă memoria program FLASH de 1Kword (un word este de 14 biţi) de o memorie de date (organizată pe 8 biţi) compusă dintr-un RAM de 64 bytes şi un EEPROM de 64 bytes. PIC16F84 este uşor de confundat cu un banal circuit integrat, deoarece fizic este o capsulă cu doar 18 pini, figura 9.2.

Figura 9.2. Diagrama pinilor pentru microcontrolerul PIC16F84.

Dintre aceştia doar 13 pini pot fi utilizaţi pentru operaţii de I/O, aşa că

microcontrolerul nu permite o prea mare varietate de configuraţii (adică are numai mod Single-Chip) şi din acest punct de vedere a fost realizat cu scopul utilizării unui minim de componente într-o aplicaţie dată. Aşa se explică cele patru opţiuni pentru oscilatorul de ceas intern. Microcontrolerul PIC16F84 poate folosi în aplicaţiile ieftine o configuraţie externă RC a oscilatorului conectată la un singur pin sau se poate opta pentru o configuraţie LP (Low Power consumption) a acestuia. Aplicaţiile pretenţioase în modul XT pot utiliza pe post de rezonator un cristal standard sau un cristal de mare viteză pentru modul HS.

O altă soluţie elegant rezolvată la acest microcontroler este circuitul intern "Watchdog" care beneficiază de un oscilator RC separat conţinut şi acesta în structura sa internă, prin această structură se poate preîntâmpina situaţiile de blocare

Page 181: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

181

software ale microcontrolerului. Posibilitatea de a fi programat în circuit prin intermediul a numai doi pini simplifică depanarea programelor sau operaţiile de upgrade pentru programe - aplicaţii. Cu toate acestea, este nevoie de un programator extern (dispozitiv hardware specializat) care trebuie să fie de asemenea diponibil în cutia noastră de scule. De asemenea, prezenţa şi a unei memorii interne de tip EEPROM pentru date permite o uşoară implementare a operaţiilor de calibrare, respectiv o uşoară modificare a acestor date pe parcursul dezvoltării unei aplicaţii.

Figura 9.3. Arhitectura internă a microcontrolerului PIC16F84.

Înainte de a folosi acest microcontroler, trebuie să citim cu atenţie

documentaţia oferită de firma MicroChip. Acest capitol nu face altceva decât să ne clarifice unele aspecte de ordin general şi să ne traseze un posibil drum în aborarea microcntrolerelor de tip RISC. Arhitectura internă a microcontrolerului PIC16F84 este prezentată în figura 9.3.

Page 182: Microprocesoare Si Microcontrolere

182 Microcontrolerul PIC16F84

Această arhitectură (Harvard) este specifică oricărui microcontroler de tip RISC şi se distinge prin accesarea programului şi a datelor din memorii diferite. Această separare a memoriilor şi evident a magistralelor aferente a permis realizarea unor microcontrolere cu cuvinte de mărime diferită pentru instrucţiuni şi respectiv pentru date. Toate acestea sunt completate de un set de instrucţiuni orthogonal (simetric), adică, un set de instrucţiuni (anexa C) care permite folosirea cu orice registru a oricărui mod de adresare. Această simetrie a setului de instrucţiuni permite atât o programare eficientă a microcontrolerului PIC16F84 cât şi posibilitatea realizării unor compilatoare atât de eficiente, pentru limbajele de nivel înalt (de regulă pentru C), încât practic nu mai face necesară programarea în limbaj de asamblare decât în unele situaţii cu totul excepţionale. Din punctul de vedere al programatorului este importantă cunoaşterea modului de organizare a memoriei şi a regiştrilor (figura 9.4) în cazul microcontrolerului PIC16F84.

Figura 9.4. Modul de organizare a memoriei şi a regiştrilor microcontrelerului PIC16F84

Page 183: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

183

De asemenea este importantă cunoaşterea set-ărilor şi funcţiilor ce pot fi activate prin intermediul acestora. Tabelul 9.1 preluat din documentaţia originală prezintă într-o formă condensată regiştri de bază ai microcontrolerului PIC16F84. Tabelul 9.1

Pentru efectuarea unor experienţe cu acest microcontroler, mai întâi trebuie să realizăm o implementare hardware, fie şi minimală, a acestuia. O asemenea implementare pentru microcontrolerul PIC16F84 cu facilităţi de programare în circuit este prezentată în figura 9.5. Cel mai folosit programator pentru proiecte mici care folosesc microcontrolerul PIC16F84 este cunoscut sub numele de JDM (sau LUPIDO), iar despre acest programator pot fi găsite pe Internet suficiente informaţii încât să poată fi realizat. De asemenea, sunt disponibile gratuit pe Internet o serie de programe care lucrează cu acest tip de programator sau care pot fi uşor set-ate pentru utilizarea cu JDM. Acest programator lucrează pe interfaţa serială RS232 şi nu are nevoie de o sursă externă de energie. Dacă preocupările noastre se reduc la folosirea acestui tip de microcontroler (PIC16F84) programatorul JDM poate fi o soluţie acceptabilă. De

Page 184: Microprocesoare Si Microcontrolere

184 Microcontrolerul PIC16F84

asemenea, pe Internet sunt disponibile informaţii despre programatoare mult mai sofisticate care pot programa o arie mai mare de astfel de circuite. Nu în ultimul rând, trebuie menţionate programatoarele produse de firma MicroChip care se adresează unui public avizat.

Figura 9.5. Realizarea practică a sistemului cu microcontrolerul PIC16F84.

După cum am menţionat anterior, pentru programarea acestei clase de microcontrolere (cu simetrie ridicată pentru setul de instrucţiuni) se poate folosi cu foarte bune performanţe limbajul C. Desigur, compilatorul (precum şi mediul de programare) este adaptat la caracteristicile acestor microcontrolere şi ca atare, un prim contact cu această implementare a limbajului C poate părea neconformă cu versiunea clasică. În continuare, discuţia va face referinţă la mediul de programare C2C destinat microcontrolerelor produse de firma MicroChip. Astfel, sunt acceptate următoarele facilităţi ale standardului C:

• if, else, while, for, return, break, continue, extern, switch, case, default;

• goto and labels;

• char, short, int, long, void;

• ~, ++, --, +, -, <, <=, >, >=, ==, !=, =, !, &, |, ^, &=, |=, ^=, &&, ||, *, /, %, <<, >>, <<=, >>=;

• one-dimensional arrays;

• const char pointers;

• const variables and arrays;

Page 185: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

185

• functions with no/one/many parameters and void/char return type;

• built-in assembler;

• #include

• #define, #undef

• #ifdef, #ifndef, #else, #endif

De asemenea, compilatorul recunoaşte următoarele variabile, fără a fi explicit declarate:

• INDF ind f register( 0x00 )

• TMR0 8-bit real-time clock/counter( 0x01 )

• PCL low order 8 bits program counter( 0x02, 0x82 )

• STATUS status register( 0x03, 0x83 )

• FSR indirect data memory address pointer( 0x04, 0x84 )

• PORTA port A( 0x05 )

• PORTB port B( 0x06 )

• EEDATA EEPROM data register( 0x08 )

• EEADRE EPROM address register( 0x09 )

• PCLATH high order 5 bits program counter( 0x0A, 0x8A )

• INTCON intcon register( 0x0b, 0x8b )

• OPTION_REG option register( 0x81 )

• TRISA port A data direction register( 0x85 )

• TRISB port B data direction register( 0x86 )

• EECON1 EEPROM control register( 0x88 )

• EECON2 EEPROM control register( 0x89 )

Suportă variabile de 8 şi 16 biţi, care pot fi definite ca variabile locale sau ca variabile globale. Variabilele locale vor utiliza acelaşi spaţiu de memorie aşa că utilizarea acestora este încurajată. De asemenea, sunt acceptate următoarele tipuri de date: Data Type Syntax Example Decimal XXXXX 1563 Octal 0XXXX 0234 Hexadecimal 0xXXXX 0xFFA8 Binary XXXXXb 10000001b ASCII 'X' 'S'

După cum ştim, limbajul C este orientat spre conceptul de funcţie, aşa că, este bine să reţinem câteva facilităţi ale versiunii C2C în raport cu acest aspect. Avem următoarele funcţii speciale:

• main

• interrupt

Page 186: Microprocesoare Si Microcontrolere

186 Microcontrolerul PIC16F84

precum şi funcţii predefinite care uşurează mult programarea acestei clase de microcontrolere:

• clear_wdt

• enable_interrupt

• disable_interrupt

• set_mode

• set_option

• set_tris_a

• set_tris_b

• set_tris_c

• output_port_a

• output_port_b

• output_port_c

• output_high_port_a

• output_high_port_b

• output_high_port_c

• output_low_port_a

• output_low_port_b

• output_low_port_c

• input_port_a

• input_port_b

• input_port_c

• input_pin_port_a

• input_pin_port_b

• input_pin_port_c

• sleep

• nop

• set_bit

• clear_bit

• putchar

• getchar

• delay_s

• delay_ms

• delay_us

• char_to_bcd

• bcd_to_char

Mult mai multe informaţii pot fi obţinute din help-ul on-line care este parte a mediului de programare C2C. Vom lansa în execuţie mediul C2C pentru a realiza un program în limbajul C care va face sâ pâlpâie LED-ul de pe linia RB7 (figura 9.5). Cu ajutorul editorului din mediul de programare C2C vom deschide fişierul Flashtst.c din folderul Samples:

//This test program for the PIC 16F84 target shows how to use //flash and uses 'write_flash' and 'write_flash' calls

Page 187: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

187

//provided in the 'flash.c' file //The flash from 0 to FLASH_SIZE is filled and tested //by numbers. By the end the blinkind of the LED //connected to B7 indicates success and blinking //of all LEDs connected to B0-B7 indicates failure #include "flash.c" #define FLASH_SIZE 64 #pragma CLOCK_FREQ 4000000 main() char i, a, err = 0; disable_interrupt( GIE ); set_bit( STATUS, RP0 ); set_tris_b( 0 ); clear_bit( STATUS, RP0 ); output_port_b( 0 ); for( i = 0; i < FLASH_SIZE; i++ ) write_flash( i, i*2 ); a = read_flash( i ); if( a != i*2 ) err = 1; break; while( 1 ) if( err ) output_port_b( 0 ); delay_ms( 250 ); output_port_b( 255 ); else output_high_port_b( 7 ); delay_ms( 250 ); output_low_port_b( 7 ); delay_ms( 250 );

Page 188: Microprocesoare Si Microcontrolere

188 Microcontrolerul PIC16F84

Deoarece programul anterior va include în timpul compilării şi fişierul flash.c, pentru o mai bună înţelegere a modului de programare în limbaj C a acestei clase de microcontrolere îl vom deschide şi pe acesta (îl vom găsi în acelaşi folder). //the memory bank 0 should be selected void write_flash( char addr, char data ) //Write flash EEADR = addr; EEDATA = data; set_bit( STATUS, RP0 ); set_bit( EECON1, WREN ); EECON2 = 0x55; EECON2 = 0xAA; set_bit( EECON1, WR ); while(EECON1&2); clear_bit( EECON1, WREN ); clear_bit( STATUS, RP0 ); char read_flash( char addr ) //Read flash EEADR = addr; set_bit( STATUS, RP0 ); set_bit( EECON1, RD ); clear_bit( STATUS, RP0 ); asm movf EEDATA, W /* EOF ********************/

După compilarea programului, vom obţine versiunea în limbaj de asamblare a programului scris în limbajul C. Pentru a ne familiariza cât de cât cu limbajul de asamblare a acestui microcontroler este prezentată în continuare această formă a programului. ; This file was generated by C2C-plus compiler version 4.00.7e include "p16F876.inc" ;Variables ***************************************** _code_tmp_0000 equ 0x70 _code_tmp_0001 equ 0x71 _code_tmp_0002 equ 0x72 param00_delay_ms equ 0x73 param00_write_flash equ 0x75 param01_write_flash equ 0x76

Page 189: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

189

param00_read_flash equ 0x77 _i_main equ 0x78 _a_main equ 0x79 _err_main equ 0x7a ORG 0 clrf PCLATH goto start__code ORG 4 _interrupt bcf INTCON, T0IF ;clear interrupt flag retfie _write_flash goto _write_flash__code _read_flash goto _read_flash__code _delay_ms goto _delay_ms__code start__code _main__code clrf _err_main bcf INTCON, GIE bsf STATUS, RP0 bsf STATUS, RP0 bcf STATUS, RP1 clrf TRISB bcf STATUS, RP0 bcf STATUS, RP0 clrf PORTB clrf _i_main label_0002 movlw D'64' subwf _i_main, W movlw 1 btfsc STATUS, C clrw sublw 0 btfsc STATUS, Z goto label_0003 movf _i_main, W movwf param00_write_flash clrf _code_tmp_0000 movlw D'9' movwf _code_tmp_0002 movf _i_main, W movwf _code_tmp_0001 movlw D'2' bcf STATUS, C label_0004 rrf _code_tmp_0000 , F rrf _code_tmp_0001 , F btfsc STATUS, C

Page 190: Microprocesoare Si Microcontrolere

190 Microcontrolerul PIC16F84

addwf _code_tmp_0000 , F decfsz _code_tmp_0002 , F goto label_0004 movf _code_tmp_0001 , W movwf param01_write_flash call _write_flash bcf PCLATH, 3 bcf PCLATH, 4 movf _i_main, W movwf param00_read_flash call _read_flash bcf PCLATH, 3 bcf PCLATH, 4 movwf _a_main clrf _code_tmp_0000 movlw D'9' movwf _code_tmp_0002 movf _i_main, W movwf _code_tmp_0001 movlw D'2' bcf STATUS, C label_0006 rrf _code_tmp_0000 , F rrf _code_tmp_0001 , F btfsc STATUS, C addwf _code_tmp_0000 , F decfsz _code_tmp_0002 , F goto label_0006 movf _code_tmp_0001 , W subwf _a_main, W btfsc STATUS, Z goto label_0007 movlw 1 goto label_0008 label_0007 movf _code_tmp_0000 , W sublw 0 movlw 1 btfsc STATUS, Z clrw label_0008 sublw 0 btfsc STATUS, Z goto label_0005 movlw D'1' movwf _err_main goto label_0003 label_0005 incf _i_main, F goto label_0002 label_0003 label_0009 movf _err_main, W

Page 191: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

191

btfsc STATUS, Z goto label_0011 bcf STATUS, RP0 bcf STATUS, RP1 clrf PORTB movlw D'250' movwf param00_delay_ms call _delay_ms bcf PCLATH, 3 bcf PCLATH, 4 movlw D'255' bcf STATUS, RP0 bcf STATUS, RP1 movwf PORTB goto label_0014 label_0011 bcf STATUS, RP0 bcf STATUS, RP1 bsf PORTB, 7 movlw D'250' movwf param00_delay_ms call _delay_ms bcf PCLATH, 3 bcf PCLATH, 4 bcf STATUS, RP0 bcf STATUS, RP1 bcf PORTB, 7 label_0014 movlw D'250' movwf param00_delay_ms call _delay_ms bcf PCLATH, 3 bcf PCLATH, 4 goto label_0009 label_0010 _main__end _write_flash__code movf param00_write_flash, W bcf STATUS, RP0 bcf STATUS, RP1 movwf EEADR movf param01_write_flash, W movwf EEDATA bsf STATUS, RP0 bsf STATUS, RP0 bsf EECON1, WREN movlw D'85' movwf EECON2 movlw D'170' movwf EECON2 bsf EECON1, WR label_0000 bsf STATUS, RP0

Page 192: Microprocesoare Si Microcontrolere

192 Microcontrolerul PIC16F84

bcf STATUS, RP1 btfss EECON1, 1 goto label_0001 goto label_0000 label_0001 bsf STATUS, RP0 bcf STATUS, RP1 bcf EECON1, WREN bcf STATUS, RP0 return _write_flash__end _read_flash__code movf param00_read_flash, W bcf STATUS, RP0 bcf STATUS, RP1 movwf EEADR bsf STATUS, RP0 bsf STATUS, RP0 bsf EECON1, RD bcf STATUS, RP0 bcf STATUS, RP0 movf EEDATA, W return _read_flash__end _delay_ms__code label_0012 movlw D'142' movwf param00_delay_ms+1 nop nop label_0013 nop nop nop nop decfsz param00_delay_ms+1, 1 goto label_0013 nop decfsz param00_delay_ms, 1 goto label_0012 nop return _delay_ms__end END

Următoarea operaţie este apelarea asamblorului care plecând de la forma în limbaj de asamblare a programului va genera codul ce trebuie încărcat în memoria microcontrolerului PIC16F84. În figura 9.6 este prezentat mediul de lucru C2C după parcurgerea tuturor etapelor menţionate anterior. Atenţie asamblorul (MPASM) nu este inclus în mediul de programare, el poate fi găsit pe site-ul firmei MicroChip ca parte a mediului de programare MPLAB.

Page 193: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

193

Figura 9.6. Mediul de programare C2C.

În acest moment avem fişierul (Flashtst.hex) cu codul ce trebuie încarcat în memoria microcontrolerului PIC16F84, cu ajutorul unui programator extern, în format HEX. Conţinutul acestui fişier este următorul: :040000008A01092840 :080008000B11090076288E2877 :100010009928FA018B138316831603138601831222 :1000200083128601F8014030780201300318030181 :10003000003C031955287808F500F0010930F2005A :100040007808F10002300310F00CF10C0318F007EF :10005000F20B24287108F60006208A110A1278088B :10006000F70007208A110A12F900F0010930F200A6 :100070007808F10002300310F00CF10C0318F007BF :10008000F20B3C28710879020319482801304D28E9 :100090007008003C013003190301003C0319532888 :1000A0000130FA005528F80A13287A080319652840 :1000B000831203138601FA30F30008208A110A1212 :1000C000FF308312031386007028831203138617F0 :1000D000FA30F30008208A110A12831203138613E0 :1000E000FA30F30008208A110A1255287508831285 :1000F00003138D0076088C00831683160C1555307B :100100008D00AA308D008C14831603138C1C892853

Page 194: Microprocesoare Si Microcontrolere

194 Microcontrolerul PIC16F84

:100110008428831603130C118312080077088312B6 :1001200003138D00831683160C14831283120C089C :1001300008008E30F4000000000000000000000005 :100140000000F40B9D280000F30B99280000080024 :00000001FF

Ultima etapă constă în programarea microcontrolerului PIC16F84 cu ajutorul unui programator extern. Pentru aceasta vom lansa în execuţie unul din programele care poate interacţiona cu programatorul extern pe care-l avem. Acesta este conectat pe interfaţa serială RS232 sau la Portul Paralel al calculatorului IBM PC. Totul depinde de tipul şi performanţele programatorului de care dispunem. Pentru a ne face o idee despre programarea microcontrolerului PIC16F84 în figura 9.7 este prezentat un caz particular pentru această etapă.

Figura 9.7. Programarea microcontrolerului PIC16F84.

Pentru a ne convinge de buna funcţionare a programului şi/sau a sistemului, microcontrolerul programat va fi mutat după programare pe placa sistemului de dezvoltare din figura 9.5 sau a oricărui alt sistem de dezvoltare pentru PIC16F84. Alimentăm montajul şi LED-ul trebuie să pâlpâie. Toate aceste etape va trebui să le

Page 195: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

195

parcurgem de foarte multe ori, mai ales la începuturile meseriei, deoarece vom face multe greşeli şi vom uita tot felul de amănunte. Nu de puţine ori produsul experienţelor noastre în acest domeniu nu va fi nimic altceva decât un fum negru, greu şi înecăcios. Mult este până putem să controlăm un simplu LED.

Page 196: Microprocesoare Si Microcontrolere

196 Microcontrolerul PIC16F84

Page 197: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

197

A. Setul de Instrucţiuni al Familiei de Microprocesoare 80X86 În această anexă va fi prezentat şi analizat succint setul de instrucţiuni al microprocesoarelor Intel începând cu versiunea 8086 şi teminând cu versiunea Pentium. O prezentare în detaliu şi completă a setului de instrucţiuni a microprocesorelor Intel 80X86 în evoluţia lor necesită cu siguranţă un spaţiu de cel puţin zece ori mai mare decât cel oferit de această carte în întregul ei. Scopul întregii cărţi este atingerea stadiului de novice în domeniul embedded system, aşa că amănuntele legate de setul de instrucţiuni a microprocesoarelor Intel 80X86 cu toate ciudăţenile lor, impuse de compatibilitatea de sus în jos, nu fac obiectul acestui material. De altfel după cum se poate constata din aplicaţiile prezentate în această carte pentru scrierea unei proceduri software avem cel puţin teoretic o infinitate de variante, aşa că practica a dovedit că fiecare programator scrie programele apelând la un set restrâns de instrucţiuni.

Plecând şi de la această realitate compilatoarele limbajelor de nivel înalt au evoluat spre maşina standard, şi desigur aceste tendinţe au dus la inovaţii importante în hardware încât astăzi, practic, competiţia a fost tranşată în favoarea microprocesoarelor cu set restrâns de instrucţiuni (RISC, Reduced Instruction Set Computer). Această reorientare a permis microprocesoarelor Intel 80X86 o creştere spectaculoasă a performanţelor, limitată desigur în primul rând de blestemul compatibilităţii cu primele versiuni CISC (Complex Instruction Set Computer).

Instrucţiunile limbajului de asamblare (mnemonice) sunt alcătuite cu scopul de a descrie fiecare operaţie pe care o poate executa microprocesorul. Programele scrise în limbaj de asamblare sunt denumite cod sursă. Fiecare instrucţiune din programul sursă corespunde unei declaraţii în limbaj de asamblare. Declaraţia trebuie să specifice care operaţie va fi executată şi care operand data va fi procesat. Pe acest considerent o instrucţiune poate fi divizată în două părţi distincte, o parte opcode şi o parte operand. Aşa că prin opcode vom înţelege aceea parte a instrucţiuni prin care se indentifică operaţia ce va fi executată, iar prin operand vom înţelege partea instrucţiuni care indentifică data care va fi procesată. INSTRUCŢIUNE = OPCODE + OPERAND EXEMPLU ADD AX, BX În exemplul precedent ADD este opcode. Conţinutul regiştrilor AX şi BX este adunat iar suma obţinută este depusă în registrul AX. Registrul BX este considerat operand-ul sursă iar registru AX este considerat operand-ul destinaţie.

Page 198: Microprocesoare Si Microcontrolere

198 Setul de Instrucţiuni al Familiei de Microprocesoare 80X86

Prin asamblor înţelegem un program care face conversia din limbaj de asamblare sursă în cod obiect, limbaj masină. Prin modurile de adresare înţelegem un set de mecanisme prin care o instrucţiune specifică cum este obţinut operand-ul sursă eventual destinaţie. Modurile de adresare disponibile pentru microprocesorul 8086 sunt:

• Adresare Registru • Adresare Imediată • Adresare Directă • Adresare Indirectă prin Registru • Adresare Bazată • Adresare Indexată • Adresare Bazată Indexată • Adresare Şir • Adresare Port.

În modul de adresare registru operand-ul este accesat prin specificarea registrului în care acesta se află. De exemplu prin instrucţiunea MOV AX,BX conţinutul registrului BX, operand-ul sursă, este transferat în operand-ul destinaţie, registrul AX. Atât operand-ul sursă cât şi operand-ul destinaţie sunt specificaţi ca şi conţinut a unor regiştri interni din microprocesorul 8086. Dacă operand-ul sursă este parte a instrucţiuni atunci avem modul de adresare imediată, exemplul tipic este dat de un operand de tip data constantă: MOV AL, 015h. Operand-ul de tip imediat poate fi atât de tip octet (byte) cât şi de tip cuvânt (word). Modul de adresare directă diferă de modul de adresare imediată prin faptul că locaţia următoare instrucţiunii opcode reţine o adresă efectivă de memorie, de exemplu: MOV CX, BETA. Această adresă efectivă este un offset pe 16-biţi a unei adrese de memorie a operandul-ui aflat în segmentul de memorie indicat de conţinutul registrului DS. Prin combinarea conţinutului celor doi regiştri se obţine adresa fizică a operand-ului în memorie. Adresarea indirectă prin registru este similară cu adresarea directă, diferenţa constă în faptul că offset-ul de această dată este într-un registru pointer sau un registru index din microprocesorul 8086. Registrul pointer poate fi registrul de bază BX sau registrul de bază pointer BP şi ca registru index poate fi utilizat registrul index sursă SI sau registrul index destinaţie DI. Instrucţiunea MOV AX, [SI], transferă conţinutul locaţiei de memorie din segmentul curent DS, cu offset-ul dat de conţinutul registrului SI, în registrul AX. În modul de adresare bazată adresa fizică a operand-ului este obţinută prin adunarea unui deplasament la conţinutul registrului de bază BX sau registru pointer de bază BP şi combinarea acestui conţinut cu conţinutul registrului de segment de memorie curent diponibil, DS sau

Page 199: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

199

SS. De exemplu instrucţiunea: MOV [BX], BETA, AL utilizează registru bază BX şi un deplasament direct pentru a determina offset-ul operand-ului în segmentul data de memorie, specificat de conţinutul registrului DS. Operandul sursă astfel adresat va fi transferat în registrul acumulator AL. Dacă în locul regiştrilor BX sau BP se vor utiliza regiştri index pentru determinarea adresei fizice a operand-ului obţinem modul de adresare indexată. În exemplul următor: MOV AL, ARRAY[SI] notaţia ARRAY este un prefix la registrul SI şi semnifică un deplasament al registrului index. Dacă combinăm adresarea bazată cu adresarea indexată obţinem un nou mod de adresare, adresarea bazată indexată. În instrucţiunea MOV AH, [BX].BETA [SI] operand-ul sursă este accesat utilizând modul de adresare bazată indexată. Adresa offset de această dată este obţinută prin însumarea conţinutului registrului BX cu deplasamentul BETA şi respectiv conţinutul registrului SI. Adresarea şir în cazul microprocesorului 8086 utilizează în mod automat registrul sursă şi destinaţie index. Instrucţiunea MOVS deşi nu specifică nici un operand în mod explicit pe timpul execuţiei va fi utilizat registrul index sursă SI şi registrul destinaţie DI. Pentru adresarea port-ului sunt utilizate în conjuncţie două instrucţiuni IN şi OUT pentru a accesa porturile de intrare respectiv de ieşire. De exemplu prin executarea instrucţiunii: IN AL, 15h registrul AL va fi încărcat cu conţinutul portului de la adresa 15h din spatiul de adrese I/O. Microprocesorul 8086 are un set puternic de instrucţiuni format din 117 instrucţiuni de bază. La nivel de cod maşină aceste instrucţiuni se expandează funcţie de operand-ul utilizat şi modurilor de adresare disponobile. Setul de instrucţiuni este divizat într-un număr de grupuri de instrucţiuni cu funcţionaliate relativ identică. Instrucţiuni de transfer

Aceste instrucţiuni au drep scop de a transfera date între regiştri microprocesorului 8086 sau între regiştri şi locaţiile de memorie destinate stocării acestor date.

• Instrucţiunea MOV este utilizată pentru a transfera un octet sau un cuvânt de la un

operand sursă la un operand destinaţie.

Memonic Meaning Format Operation Flags Affected MOV Move MOV dest, src (src) (dest) None

Page 200: Microprocesoare Si Microcontrolere

200 Setul de Instrucţiuni al Familiei de Microprocesoare 80X86

• Instrucţiunea XCHG dest, src (exchange) schimbă conţinutul sursei cu destinaţia fără a afecta vreun flag.

• Instrucţiunea XLAT/XLATB (translate) modifică octeul din registrul Al cu un octet din tabelul utilizator adresat de conţinutul registrului BX. Valoarea iniţială din registrul AL este un index în tabelul de translatare. Um mod simplu de a transcrie această instrucţiune este: MOV AL, [BX+AL] echivalentă cu XLAT Tralslation-Table. Această instrucţiune nu modifică nici unul din flag-urile microprocesorului.

• Instrucţiunea LEA dest,src (Load Efective Address) calculează offset-ul operand-ului sursă şi îl incarcă în registrul destinaţie. Nu modifică flag-urile microprocesorului.

• Instrucţiunea LES dest,src (Load Pointer Using ES) transferă patru octeţi consecutivi de la un operand sursă din memorie la o pereche de regiştri de 16 biţi. Unul din regiştri destinaţie este specificat de instrucţiune iar celălat este implicit registrul ES. Această instrucţiune nu modifică flag-urile microprocesorului.

• Instrucţiunea LDS dest,src (Load Pointer Using DS) este identică cu instrucţiunea precedentă numai că registru implicit de această dată este registrul DS. Nu modifică flag-urile microprocesorului. Ultimile două instrucţiuni simplifică încărcarea unor pointer de tip far din stivă sau tabela vectorilor de întrerupere.

Instrucţiuni Aritmetice Cu ajutorul acestor instrucţiuni microprocesorul 8086 poate realiza operaţi

aritmetice ca: adunare, scădere, înmulţire şi împărţire. • Instrucţiuni de adunare

Mnemonic Meaning Format Operation Flags Affected ADD Addition ADD dest, src (src)+(dest) (dest) OF,SF,ZF,AF,PF,CF ADC Add with carry ADC dest, src (src)+(dest)+(CF) (dest) OF,SF,ZF,AF,PF,CF INC Increment by 1 INC dest (dest)+1 (dest) OF,SF,ZF,AF,PF,CF AAA ASCII adjust

for addition AAA OF,SF,ZF,AF,PF,CF

DAA Decimal adjust for addition

DAA OF,SF,ZF,AF,PF,CF

• Instrucţiuni de scădere

Mnemonic Meaning Format Operation Flags Affected SUB Subtraction SUB dest, src (src)-(dest) (dest) OF,SF,ZF,AF,PF,CF SBB Subtract with

barrow SBB dest, src (src)-(dest)-(CF) (dest) OF,SF,ZF,AF,PF,CF

DEC Decrement by 1

DEC dest (dest)-1 (dest) OF,SF,ZF,AF,PF,CF

AAS ASCII adjust for subtraction

AAS OF,SF,ZF,AF,PF,CF

Page 201: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

201

DAS Decimal adjust for subtraction

DAS OF,SF,ZF,AF,PF,CF

• Instrucţiuni de înmulţire şi împărţire

Mnemonic Meaning Format Operation Flags Affected MUL Multiply

(Unsigned) MUL src (AL).src8 (AX) OF,SF,ZF,AF,PF,CF

DIV Division (unsigned)

DIV src Q(AX)/src8 (AL) R(AX)/src8 (AH)

OF,SF,ZF,AF,PF,CF

IMUL Integer Multiply

IMUL src (AL).src8 (AX) OF,SF,ZF,AF,PF,CF

IDIV Integer Divide

IDIV src Q(AX)/src8 (AL) R(AX)/src8 (AH)

OF,SF,ZF,AF,PF,CF

AAM Adjust AL for multiplication

AAM Q(AL)/10 (AH) OF,SF,ZF,AF,PF,CF

AAD Adjust AX for division

AAD (AH).10+AL (AL) OF,SF,ZF,AF,PF,CF

CBW Convert byte to word

CBW (MSB of AL) (All bits of AH)

None

CWD Convert word to word

CWD MSB of AX) (All bits of DX)

NONE

Instrucţiuni Logice Instrucţiunile logice disponibile la microprocesorul 8086 sunt: AND, OR, Exclusive OR şi NOT.

Mnemonic Meaning Format Operation Flags Affected AND Logical AND AND dest, src (src).(dest) (dest) OF,SF,ZF,AF,PF,CF OR Logical

inclusive OR OR dest, src (src)+(dest) (dest) OF,SF,ZF,AF,PF,CF

XOR Logical Exclusive -OR

XOR dest, src (src)⊕ (dest) (dest) OF,SF,ZF,AF,PF,CF

NOT Logical NOT NOT dest (dest) (dest) OF,SF,ZF,AF,PF,CF

Page 202: Microprocesoare Si Microcontrolere

202 Setul de Instrucţiuni al Familiei de Microprocesoare 80X86

Instrucţiuni de Shift-are Operaţiile de bază realizate de aceste instrucţiuni sunt shift-ul logic şi shift-ul aritmetic.

• SAL/SHL dest, count (Shift Arithmetic Left / Shift Logical Left) shift-ează operand-ul destinaţie cu un număr de biţi la stânga (count, pentru 8086 shift-ul disponibil este numai cu un bit) prin inserţie de biţi zero la dreapta. Flag-ul CF (Carry Flag) conţine ultimul bit shift-at în afara operand-ului destinaţie. Această instrucţiune afectează următoarele flag-uri: CF, OP, PF, SF, ZF iar starea flag-ului AF este nedefinită. Aceste instrucţiuni asigură un mecanism foarte eficient pentru dublarea unui număr. Deoarece nu se face distincţie între dublarea unui numar cu semn şi a unui număr fără semn SAL şi SHL sunt două mnemonici diferite pentru aceeaşi instrucţiune.

• SAR dest, count (Shift Arithmetic Right) shift-ează operand-ul destinaţie cu un număr de biţi la dreapta (count, pentru 8086 shift-ul disponibil este numai cu un bit) fără a modifica bit-ul de semn. Flag-ul CF (Carry Flag) conţine cel mai puţin semnificativ bit shift-at în afara operand-ului destinaţie, care dacă este setat în "1" arată că numărul nu a fost par. Această instrucţiune afectează următoarele flag-uri: CF, OP, PF, SF, ZF iar starea flag-ului AF este nedefinită. Acestă instrucţiune asigură un mecanism foarte eficient pentru înjumătăţirea unui număr cu semn.

• SHR dest, count (Shift Logical Right) ) shift-ează operand-ul destinaţie cu un număr de biţi la dreapta (count, pentru 8086 shift-ul disponibil este numai cu un bit) prin inserţie de biţi zero la stânga. Flag-ul CF (Carry Flag) conţine ultimul bit shift-at în afara operand-ului destinaţie. Această instrucţiune afectează următoarele flag-uri: CF, OP, PF, SF, ZF iar starea flag-ului AF este nedefinită.

Instrucţiuni de Salt Ramificările într-un program sunt realizate prin instrucţiuni de salt condiţionat, acest tip de instrucţiuni sunt prezentate în tabelul următor. Mnemonic Meaning Jump Condition JA Jump if Above CF=0 and ZF=0 JAE Jump if Above or Equal CF=0 JB Jump if Below CF=1 JBE Jump if Below or Equal CF=1 or ZF=1 JC Jump if Carry CF=1 JCXZ Jump if CX Zero CX=0 JE Jump if Equal ZF=1 JG Jump if Greater (signed) ZF=0 and SF=OF JGE Jump if Greater or Equal (signed) SF=OF

Page 203: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

203

JL Jump if Less (signed) SF != OF JLE Jump if Less or Equal (signed) ZF=1 or SF != OF JMP Unconditional Jump Unconditional JNA Jump if Not Above CF=1 or ZF=1 JNAE Jump if Not Above or Equal CF=1 JNB Jump if Not Below CF=0 JNBE Jump if Not Below or Equal CF=0 and ZF=0 JNC Jump if Not Carry CF=0 JNE Jump if Not Equal ZF=0 JNG Jump if Not Greater (signed) ZF=1 or SF != OF JNGE Jump if Not Greater or Equal (signed) SF != OF JNL Jump if Not Less (signed) SF=OF JNLE Jump if Not Less or Equal (signed) ZF=0 and SF=OF JNO Jump if Not Overflow (signed) OF=0 JNP Jump if No Parity PF=0 JNS Jump if Not Signed (signed) SF=0 JNZ Jump if Not Zero ZF=0 JO Jump if Overflow (signed) OF=1 JP Jump if Parity PF=1 JPE Jump if Parity Even PF=1 JPO Jump if Parity Odd PF=0 JS Jump if Signed (signed) SF=1

JZ Jump if Zero ZF=1

De asemenea în scrierea unui program apar situaţii în care unica soluţie este un salt necondiţionat.

• JMP target (Unconditional Jump) transferă necondiţionat controlul la eticheta "target". Dacă nu este specificat saltul se consideră a fi în domeniul relativ de adrese, de la -32768 la 32767. Un salt apropiat (NEAR) sau un salt scurt (SHORT) modifică conţinutul registrului IP. Un salt îndepărtat (FAR) va modifica atât conţinutul registrului IP cât şi conţinutul registrului CS.

Instrucţiuni de Rotire Aceste instrucţiuni pot roti conţinutul unui registru intern sau a unei locaţii de memorie.

• RCL/RCR dest, count (Rotate Through Carry Left / Rotate Through Carry Right) roteşte biţi din operand-ul destinaţie la stânga, respectiv la dreapta cu un număr de biţi

Page 204: Microprocesoare Si Microcontrolere

204 Setul de Instrucţiuni al Familiei de Microprocesoare 80X86

definit de "count". Bitul de la un capăt este adus în urma rotirii pentru a ocupa pozitia flag-ului CF, iar vechea valoare a flag-ului CF va ocupa poziţia vacantă în celălat capăt. Aceaste instrucţiuni afectează flag-urile CF şi OP.

• ROL/ROR dest, count (Rotate Left / Rotate Right) roteşte biţi din operand-ul destinaţie la stânga, respectiv la dreapta cu un număr de biţi definit de "count". Bitul de la un capăt este adus în urma rotirii pentru a ocupa poziţia vacantă în celălat capăt. În acelaşi timp acest bit va ocupa şi potiţia din flag-ul CF. Aceaste instrucţiuni afectează flag-urile CF şi OP.

Instrucţiuni de Comparare Acestă instrucţiune pote să compare numere pe 8 sau 16 biţi.

• CMP dest, src (Compare) scade conţinutul sursei din conţinutul destinaţiei şi fixează flag-urile funcţie de acest rezultat fără a modifica conţinutul sursei sau destinaţiei. Flag-urile mofificate sunt: AF, CF, OF, PF, SF, ZF şi pot fi testate pentru a verifica îndeplinirea unei condiţii într-un program.

Instrucţiuni de Control al Flag-urilor Executarea acestor instrucţiuni duce la modificarea flag-urilor.

• LAHF (Load Register AH From Flags) copiază biţi 0-7 ai registrului de flag-uri în registrul AH, fără a le afecta. Conţinutul registrului AH va fi de forma AH:= SF ZF xx AF xx PF xx CF.

• SHAF (Store AH Register into Flags) transferă biţi 0-7 ai registrului AH în registrul de flag-uri. Flagurile transferate sunt: AF; CF, PF, SF, şi ZF.

• CLC (Clear Carry) poziţionează flag-ul CF în "0". • STC (Set Carry) poziţionează flag-ul CF în "1". • CMC (Complement Carry Flag) inversează starea flag-ului CF. • CLI (Clear Interrupt Flag) dezactivează întreruperea mascabilă hardware (INTR, flag-

ul IF are valoarea "0") fără a afecta şi întreruperea NMI sau întreruperile software. • STI (Set Interrupt Flag) activează întreruperea mascabilă hardware (INTR) prin setarea

flag-ului IF în "1". Dacă o întrerupere mascabilă este generată de un dispozitiv hardware trebuie să introducem în program o secvenţă EOI (End of Interrupt) pentru a activa o altă întrerupere de aceeşi prioritate sau de prioritate mai scăzută.

Page 205: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

205

Instrucţiuni pentru Subrutine şi controlul Subrutinelor Nu de puţine ori programul principal trebuie să execute o funcţie care este definită printr-o subrutină. Pentru a executa aceasta funcţie se face un apel la subrutina care o defineşte, aşa că programul principal trebuie să transfere controlul microprocesorului la începutul acestei subrutine. Executarea programului va continua cu subrutina apelată şi în final va trebui să se întoarcă în programul principal la istrucţiunea următoare celei care a realizat apelul. Deşi instrucţiunile de lucru cu stiva pot fi utilizate ori de câte ori este nevoie într-un program, ele sunt prezentate în acest grup deoarece utilizarea lor în scrierea unor aplicaţii bine structurate implică folosirea frecventă a acestora în cadrul subrutinelor.

• CALL destination (Procedure Call) pune conţinutul registrului IP (care în acest moment al execuţiei instrucţiunii CALL conţine deja adresa următoarei instrucţiuni, respectiv conţinutul registrului CS pentru CALL FAR) pe stivă şi încarcă registrul IP (respectiv CS) cu adresa unde începe subrutina. Execuţia codului continuă cu instrucţiunea de la adresa CS:IP. Execuţia acestei instrucţiuni nu modifică flag-urile.

• INT n (Interrupt) asigură o întrerupere software (întrerupere internă), procedând ca la recunoaşterea unei întreruperi hardware de către microprocesor. De această dată tipul instrucţiuni este specificat în instrucţiune (n), în loc de a fi dat de un dispozitiv extern. Este salvată pe stivă adresa CS:IP a instrucţiunii următoare şi în plus registrul de flag-uri. Noua adresă (CS:IP) este obţinută din tabelul vectorilor de întrerupere folosind ca bază de calcul tipul întreruperii.

• RET nBytes / RETF nBytes / RETN nBytes (Return From Procedure) este operaţia inversă apelului de subrutină, readucând din stivă valoarea lui IP (respectiv CS) avută la momentul apelării subrutinei. Dacă în stivă avem un număr de cuvinte încărcaţe peste cuvântul ce conţine adresa salvată de instrucţiunea CALL atunci în mod opţional istrucţiunea RET poate fi urmată de un operand imediat a cărui conţinut se adună la conţinutul registrului SP.

• IRET (Interrupt Return) plasată la sfârşitul unei proceduri de întrerupere are ca efect refacerea valoriilor CS:IP salvate anterior pe stivă. Spre deosebire de returul intersegment (far) această instrucţiune reface şi registrul de flag-uri.

• PUSH src (Push Word into Stack) salvează din operand-ul sursă un cuvânt în stivă (SS:SP) şi decrementează registrul SP cu doi pentru ca registrul SP să conţină offset-ul următoarei locaţii în care poate fi salvat un cuvânt. Instrucţiunile de acest tip nu modifică flag-urile.

• POP dest (Pop a Word from the Stack) extrage un cuvânt din stivă (SS:SP) în operand-ul destinaţie şi incrementează registrul SP cu doi pentru ca registrul SP să conţină offset-ul următorului cuvânt ce poate fi extras din stivă (vârful stivei). Cu excepţia instrucţiuni POPF (extrage din stivă un cuvânt care va fi încărcat în registrul de flag-uri) celelalte instrucţiuni de acest tip nu modifică flag-urile.

Page 206: Microprocesoare Si Microcontrolere

206 Setul de Instrucţiuni al Familiei de Microprocesoare 80X86

Instrucţiuni de Ciclare Instrucţiunile de ciclare permite programatorului realizarea cu uşurinţă a unor bucle în program.

• LOOP label ( Loop until Count Complete, Decrement CX and Loop if CX Not Zero) decrementează conţinutul registrului CX cu 1 şi transferă controlul la operand-ul "label" (etichetă) dacă conţinutul registrului CX nu este zero. Operand-ul "label" trebuie să fie în domeniul de adrese de la -128 până la 127 octeţi, domeniu raportat la adresa următoarei instrucţiuni.

• LOOPE/LOOPZ label (Loop While Equal / Loop While Zero) decrementează conţinutul registrului CX cu 1 (fără a modifica flag-urile) şi transferă controlul la operand-ul "label" (etichetă) dacă conţinutul registrului CX nu este zero şi ZF = 1. Operand-ul "label" trebuie să fie în domeniul de adrese de la -128 până la 127 octeţi, domeniu raportat la adresa următoarei instrucţiuni.

• LOOPNZ/LOOPNE label (Loop While Not Zero / Loop While Not Equal) decrementează conţinutul registrului CX cu 1 şi transferă controlul la operand-ul "label" (etichetă) dacă conţinutul registrului CX nu este zero şi ZF = 0. Operand-ul "label" trebuie să fie în domeniul de adrese de la -128 până la 127 octeţi, domeniu raportat la adresa următoarei instrucţiuni.

Instrucţiuni cu Şiruri Prin intermediul acestor instrucţiuni pot fi uşor executate operaţile cu şiruri. Aceste instrucţiuni sunt printre cele mai complexe şi utilizarea lor este nu de puţine ori evitată. Lucrul eficient cu un număr mare de date nu poate fi realizat fără utilizarea intensivă a acestui tip de instrucţiuni.

• MOVS dest, src (Move Data from String to String) realizează transferul datelor dintr-un şir, cu offset-ul în registru SI, într-un şir obligatoriu în extrasegmentul de date (ES) cu offset-ul în DI. De obicei operandul sursă se află în segmentul de date (DS). După executare instrucţiuni regiştri index sunt incrementaţi sau decrementaţi (cu 1, 2, 4 pentru MOVSB, MOVSW, MOVSD) funcţie de starea flag-ului de direcţie DF. Numărul de elemente ale şirului este specificat de conţinutul registrului CX. Execuţia acestor instrucţiuni nu modifică flag-urile microprocesorului.

• CMPS dest, src (Compare String Operands) compară două secvenţe de octeţi/cuvânte/dublu-cuvânte (CMPSB, CMPSW, CMPSD) şi anume conţinutul adreselor de memorie adresate de conţinutul registrului SI, respectiv DI. Numărul de elemente de comparat este dat de conţinutul registrului CX, iar regiştri index sunt incrementaţi sau decrementaţi (1, 2, 4) funcţie de starea flag-ului DF. Flag-urile modificate sunt: AF, CF, OF, PF, SF, ZF.

• SCAS string (Scan String) execută operaţia de scanare a elementelor unui şir octeţi/cuvânte/dublu-cuvânte (SCASB, SCASW, SCASD) şi anume conţinutul

Page 207: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

207

adreselor de memorie adresate de conţinutul registrului DI, comparaţia făcându-se în raport cu conţinutul registrului AL/AX/EAX. Numărul de elemente de comparat este dat de conţinutul registrului CX, iar registrul index este incrementat sau decrementat (1, 2, 4) funcţie de starea flag-ului DF. Nu se depune nici un rezultat dar sunt afectate flag-urile: AF, CF, OF, PF, SF, ZF.

• LODS src (Load String Element) realizează operaţia de încărcare a octetului/cuvântului/dublu-cuvântului (LODSB, LODSW, LODSD) a cărui offset în memorie este dat de conţinutul registrului SI, în AL/AX/EAX. Numărul de elemente de transferat este dat de conţinutul registrului CX, iar registrul index este incrementat sau decrementat (1, 2, 4) funcţie de starea flag-ului DF.

• STOS dest (Store String) realizează operaţia de stocare a octetului/cuvântului/dublu-cuvântului (STOSB, STOSW, STOSD) din registrul AL/AX/EAX în locaţia de memorie a cărui offset este dat de conţinutul registrului DI. Numărul de elemente de transferat este dat de conţinutul registrului CX, iar registrul index este incrementat sau decrementat (1, 2, 4) funcţie de starea flag-ului DF.

Instrucţiuni cu Porturi Lucrul cu porturile este mult simplificat prin utilizarea unui spatiu de adresare saparat de cel de memorie. În evoluţia microprocesorului lipsa de eficienţă în transferul de date prin porturi a dus la diversificarea acestor instrucţiuni în sensul accesării porturilor prin operaţii de trasfer de tip şir.

• IN AL, port / IN AL, DX (Input) citeşte un octet de la operand-ul sursă care poate fi specificat în mod direct printr-un octet pentru un port cu adresa mai mică sau egală cu FFh. Pentru porturi cu adresa în domeniul de la 100h până la FFFFh este obligatorie utilizarea registrului DX, acesta va conţine adresa curentă a portului (indirect).

• OUT port, AL / OUT DX, AL (Output) scrie conţinutul acumulatorului AL la un port de ieşire specificat direct sau indirect prin registrul DX.

Microprocesorul 80286 Microprocesorul Intel 80286 este o extensie a versiuni de bază 8086, principalele facilităţii introduse de această versiune sunt legate de modul de exploatare a memoriei. Începând cu această versiune au fost introduse capabilităţi de protejare a memoriei cu scopul de a susţine sisteme de operare multi-user/multitasking (primele versiuni Windows, practic necunoscute marelui public). Acest microporocesor este capabil să adreseze un spaţiu fizic de memorie de 16MB şi 1 GB de memorie virtuală per task. Microprocesorul 80286 are două moduri de operare - modul de adresare real şi modul de adresare virtual protejat. În modul de

Page 208: Microprocesoare Si Microcontrolere

208 Setul de Instrucţiuni al Familiei de Microprocesoare 80X86

operare real un microprocesor 80286 nu este compatibil la nivel de cod obiect cu 8086 dar este compatibil la nivel de cod sursă. De asemenea sistemul de operare MS-DOS nu a utilizat modul de adresare a memoriei virtual protejat. Setul de Instrucţiuni al Microprocesorului 80286

Microprocesorul 80286 poate executa tot setul de instrucţiuni al

microprocesorului 8086, precum şi următoarele instrucţiuni cu rol de suport al sistemului de operare.

• ARPL (Adjusted Requested Privilege Level of Selector) • CLTS (Clear Task Switched Flag) • LAR (Load Access Rights) • LGDT (Load Global Descriptor Table) • LIDT (Load Interrupt Descriptor Table) • LMSW (Load Machine Status Word) • LSL (Load Segment Limit) • LSS (Load Pointer Using SS) • LTR (Load Task Register) • SGDT (Store Global Descriptor Table) • SIDT (Store Interrupt Descriptor Table) • STR (Store Task Register) • VERR (Verify Read Usage: VERR src) • VERW (Verify Write)

Microprocesorul 80386 Microprocesorul 80386 şi cele de după el au regiştri de 32 de biţi. Toţi cei opt regiştri de 16 biţi au echivalenţi de 32 de biţi. Aceştia sunt: EAX, ABX, ECX, EDX, ESI, EDI, EBP, şi ESP. Dacă microprocesorul de pe placa de bază este un 80386 sau unul mai recent aceşti registri pot fi utilizaţi ca operand cu unele instrucţiuni. Odată cu introducerea microprocesorului 80386 au fost generalizate modurile de adresare a memoriei. Spre deosebire de 8086 care poate utiliza ca regiştri de bază doar regiştri BX şi BP iar ca regiştri index doar regiştri SI şi DI, microprocesorul 80386 permite utilizarea oricărui registru de uz general de 32 de biţi ca registru bază sau index. De asemenea odată cu microprocesorul 80386 au fost introduse noi moduri de adresare scalată şi indexată a memoriei simplificând astfel

Page 209: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

209

accesul la date de tip array. Pe lângă creşterea la 32 de biţi a dimensiuni regiştrilor probabil noile moduri de adresare a memoriei sunt cele mai importante înbunătăţiri ale microprocesorului în acest stadiu de dezvoltare. La acest nivel de dezvoltare microprocesoarele Intel au avut suficientă putere şi faciliţăţi software pentru a suporta un sistem de operare multi-user/multitasking de uz profesional cum ar fi de exemplu UNIX (LINUX). Setul de Instrucţiuni al Microprocesorului 80386 Setul de instrucţiuni amicroprocesorului 80386 include setul de instrucţiuni a microprocesorului 80286 şi adaugă următoarele instrucţiuni.

• BST (Bit Scan Forward) • BSR (Bit Scan Reverse) • BT (Bit Test) • BTC (Bit Test with Compliment) • BTR (Bit Test with Reset) • BTS ( Bit Test and Set) • CD0 (Convert Double to Quad ) • CWDE (Convert Word to Extended Doubleword ) • LGS (Load Pointer Using GS) • LSS (Load Pointer Using SS ) • MOVSX ( Move with Sign Extend ) • MOVZX ( Move with Zero Extend ) • SETAE/SETNB (Set if Above or Equal / Set if Not Below ) • SETB/SETNAE (Set if Below / Set if Not Above or Equal ) • SETBE/SETNA (Set if Below or Equal / Set if Not Above) • SETE/SETZ (Set if Equal / Set if Zero) • SETNNE/SETNZ ( Set if Not Equal / Set if Not Zero ) • SETL/SETNGE (Set if Less / Set if Not Greater or Equal) • SETGE/SETNL (Set if Greater or Equal / Set if Not Less) • SETLE/SETNG (Set if Less or Equal / Set if Not greater or Equal) • SETG/SETNLE (Set if Greater / Set if Not Less or Equal ) • SETS (Set if Signed) • SETNS (Set if Not Signed) • SETC (Set if Carry) • SETNC (Set if Not Carry ) • SETTO (Set if Overflow) • SETNO (Set if Not Overflow) • SETP/SETPE (Set if Parity / Set if Parity Even) • SETNP/SETPO (Set if No Parity / Set if Parity Odd) • SHLD/SHRD (Double Precision Shift)

Page 210: Microprocesoare Si Microcontrolere

210 Setul de Instrucţiuni al Familiei de Microprocesoare 80X86

Microprocesorul 80486 Odată cu versiunea 80486 a microprocesorului, Intel a lansat şi coprocesorul RISC i860, fiecare conţinând mai mult de 1 milion de tranzistori. Microprocesorul RISC are o unitate aritmetică şi logică de 32 de biţi (această unitate a microprocesorului este responsabilă de execuţia unor operaţii cum ar fi adunarea sau scăderea) dublată de o unitate în virgulă flotantă pe 64 de biţi. Toate acestea au fost oferite iniţial la o frecvenţă de ceas de 33 Mhz. Deşi microprocesorul 80486 a rămas similar cu 80386 setul de instrucţiuni a fost optimizat iar adăugarea unui cache intern precum şi înglobarea în acelaşi chip pentru prima dată a coprocesorului în virgulă flotantă a dus la dublarea performantelor fară o creştere a frecvenţei de tact. Setul de Instrucţiuni al Microprocesorului 80486 Setul de instrucţiuni ale microprocesorului 80486 include setul de instrucţiuni ale microprocesorului 80386 la care s-au mai adăugat următoarele:

• BSWAP (Byte Swap) • INVD ( Invalidate Cache) • INVLPG (Invalidate Translation Look-Aside Buffer Entry) • WBINVD (Write-Back and Invalidate Cache)

Microprocesorul PENTIUM PENTIUM este un microprocesor de 32 de biţi. Setul de instrucţiuni şi modurile de adresare sunt aproape similare cu ale microprocesorului 80486. Începând cu versiunea MMX a microprocesorului au fost introduse o serie de instrucţiuni noi care oferă suport pentru aplicaţiile multimedia. Evoluţia microprocesorului este de natură hardware şi constă într-o diversificare şi mai eficientă utilizare a resurselor interne susţinută de o viteza de rulare a instrucţiunilor din ce în ce mai mare.

Page 211: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

211

B. Setul de Instrucţiuni al Microcontrolerului 68HC11 Instrucţiunile microcontrolerului 68HC11 prezentate în continuare sunt organizate în următoatele categorii:

• load, store, şi instrucţiuni de transfer • instructiuni aritmetice • operaţii logice • instrucţiuni de manipulare pe bit şi testare • instrucţiuni de shift-are şi rotire • istrucţiuni cu registri index şi de stivă • instrucţiuni de salt

Tabele din paginile următoare sunt preluate din Motorola's M68HC11 Reference Manual. Load, Store, şi Instrucţiuni de Transfer

• Conţinutul acumulatorilor A, B, şi D poate fi încărcat (load) sau stocat (stored) în

memorie. • Conţinutul acumulatorilor A, B poate fi transferat înapoi şi înainte.

Page 212: Microprocesoare Si Microcontrolere

212 Setul de Instrucţiuni al Microcontrolerului 68HC11

• Conţinutul acumulatorilor A, B poate fi transferat în şi din stivă. • Conţinutul registrului acumulator D (double-precision, A concatenat cu B) poate fi

schimbat cu conţinutul regiştrilor index X şiY. Instrucţiuni Aritmetice Instrucţiunile aritmetice de bază includ adunarea, scăderea, incrementare, decrementare şi comparare, cele mai multe instrucţiuni sunt în simplă precizie.

Notă: Nu sunt posibile intrucţiuni aritmetice memorie-memorie, un operant trebuie să fie de tip registru.

Page 213: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

213

Opreraţii Logice

• Conţinutul acumulatorului A poate fi utilizat pentru operaţii logice (AND, OR, sau exclusive-OR) cu memoria.

• Conţinutul acumulatorilor A, B, şi locaţile de memorie specificate pot fi complementate logic (bit-wise).

Instrucţiuni de Manipulare pe Bit şi Testare

• Biţi individuali din memorie pot fi setaţi sau resetaţi, sau pot fi făcute salturi condiţionate de valoarea acestora.

Page 214: Microprocesoare Si Microcontrolere

214 Setul de Instrucţiuni al Microcontrolerului 68HC11

Instrucţiuni de Shift-are şi Rotire

• Conţinutul acumulatorilor A, B, D precum şi conţinutul unor locaţii de memorie specificate poate fi shif-at stânga sau dreapta cu un bit atât aritmetic cât şi logic.

• Conţinutul acumulatorilor A, B, D precum şi conţinutul unor locaţii de memorie specificate poate fi rotit stânga sau dreapta cu un bit cu transfer prin bitul C din registrul CCR (Condition Code Register).

Notă: Nu sunt diferenţe între shift-ul logic şi aritmetic spre stânga.

Page 215: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

215

Instrucţiuni cu Registri Index şi de Stivă

• Conţinutul regiştrilor index X, Y, poate fi încărcat, stocat sau comparat cu memoria şi poate fi salvat sau încărcat în/din stivă.

• Conţinutul registrilor index X, Y, şi al registrului de sivă SP poate fi incrementat sau decrementat.

• Conţinutul registrilor index X, Y, poate fi transferat în/din SP sau schimbat cu registrul dublu D.

Page 216: Microprocesoare Si Microcontrolere

216 Setul de Instrucţiuni al Microcontrolerului 68HC11

Instrucţiuni de Salt Instrucţiunile de salt pot fi necondiţionate sau condiţionate de unul sau mai mulţi biţi din registru CCR (Condition Code Register):

• Un salt simplu este condiţionat numai de un bit de condiţie. • Un salt comparat este condiţionat de instrucţiunea precedenta de scădere sau comparare

şi de regulă este dependent de mai mult decât un singur bit din registrul CCR.

Page 217: Microprocesoare Si Microcontrolere

Microprocesoare şi Microcontrolere

217

C. Setul de Instrucţiuni al Microcontrolerului PIC 16F84 În tabelul de mai jos este rezumat setul de instrucţiuni al microcrocontrolerului PIC16F84 având drept bază specificaţia corporaţiei MicroChip Tehnology.

Note: - Când un registru I/O este modificat ca o funcţie de sine însuşi (de exemplu, MOVF PORTB, 1), valoarea utilizată va fi aceea valoare prezentă pe pini. De exemplu, dacă data lach este '1' pentru un pin configurat ca input şi acest pin este forţat în '0' de un dispozitiv exterior, data va fi rescrisă cu zero. - Dacă o instrucţiune va fi executată în registrul TMR0 (şi, unde este aplicabil, d = 1), prescalerul va fi resetat dacă este referit de TMR0. - Dacă registrul PC (Program Counter) este modificat sau un test condiţional este adevărat, instrucţiunea va fi executată pe timpul a două perioade de ceas. Pe timpul celei de a doua perioade va fi executată o instrucţiune NOP.

Page 218: Microprocesoare Si Microcontrolere

218 Setul de Instrucţiuni al Microcontrolerului PIC 16F84