Sunteți pe pagina 1din 151

DORIN

PETREUȘ

ENIKŐ
SZILÁGYI

RADU
ETZ

TOMA
PĂTĂRĂU

MICROCONTROLERE –
APLICAȚII
Cuprins

1 Mediul Keil uVision..................................................1


2 Simulator de sistem Proteus ....................................12
3 Testarea memoriei RAM externă ............................26
4 Rutină de întârziere soft ..........................................36
5 Stocarea datelor în memoria ROM .........................47
6 Programare modulară ..............................................57
7 Programare în C ......................................................66
8 Porturile de intrare – ieșire ......................................77
9 Instrucțiuni aritmetico-logice ..................................89
10 Timer-ele și numărătoarele .................................. 103
11 Portul Serial .......................................................... 116
12 Întreruperile .......................................................... 129
Bibliografie ............................................................... 143
Mediul Keil uVision

1 Mediul Keil uVision


1 Scopul lucrării
• Familiarizarea cu mediul Keil uVision.
• Crearea unui proiect și compilarea lui.
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision.
3 Considerații teoretice
3.1. Ce este Keil uVision?
Keil uVision este un mediu de dezvoltare integrat – IDE (Integrated
Development Environment) care permite scrierea, compilarea și depanarea
programelor. Acesta conține următoarele:
- Un manager de proiect.
- Mijloc de configurare.
- Editor.
- Un mediu de depanare foarte puternic.
- Help-online.
- Corector de erori interactiv.
- Un ghid al utilizatorului precum și fișiere *.pdf cu documentația
aferentă
3.2. Descărcarea mediului Keil uVision

Fig. 1.1 Descărcarea mediului Keil uVision

1
Mediul Keil uVision

Mediul de dezvoltare Keil uVision se găsește pe site-ul:


www.keil.com/download și se poate descărca gratis. Se alege C51 de la
Product Downloads. Versiunea gratuită permite scrierea programelor până la
o dimensiune de maxim 2KB.
3.3. Ciclul de dezvoltare al programelor
Când folosim Keil, ciclul de dezvoltare al unui proiect este același ca și
pentru orice alt tip de mediu de programare. Vom enumera în continuare pașii
ce trebuie urmați pentru crearea unui aplicații, ca apoi, pe parcursul lucrării,
să revenim la fiecare în parte:
START

Crearea aplicației cu managerul de


Crearea proiectului proiect

Setarea opțiunilor hardware Corectarea erorilor din fișierul


sursă

Crearea fișierului sursă (ASM sau C) Testarea aplicației

STOP

Fig. 1.2 Ciclu de dezvoltare a programelor

3.4. Crearea proiectelor


Pentru a crea un proiect nou vom selecta din meniul Keil uVision:
Project/New uVision Project.

Fig. 1.3 Crearea proiectului

Apoi selectăm directorul în care vrem să se afle fișierul de proiect și vom


introduce un nume – de exemplu: “test”. Programul generează un nou fișier
proiect cu numele: test.uvproj.

2
Mediul Keil uVision

La pasul următor, va apărea o fereastră de dialog cu baza de date a


diferitelor familii de microcontrolere:

Fig. 1.4 Bază de date a diferitelor familii de microcontrolere

Din această bază de date se va alege microcontrolerul care urmează să fie


utilizat în proiect.
Pentru fiecare microcontroler folosit, putem găsi foaia de catalog pe site-ul
firmei producătoare. În foaia de catalog vom găsi schema bloc a
microcontrolerului, descrierea regiștrilor și descrierea generală.
Odată ce a fost selectat un dispozitiv, din baza de date putem deschide foaia
de catalog din: Project Windows/Books.
3.5.Setarea opțiunilor hardware
Din Keil uVision putem seta opțiunile pentru dispozitivul hardware folosit.
Selectăm Project/Options for Target ‘Target1’ (sau click dreapta pe Target în
Managerul de proiect - Options for Target ‘Target1’).
Apare o nouă fereastră în care, dacă selectăm fila Target, vom putea seta
frecvența de ceas dorită. Nu este nevoie să setăm modelul de memorie pentru
circuitul folosit, modelul implicit având setările optime pentru majoritatea
aplicațiilor.
Dacă este cazul se poate modifica dispozitivul selectat din fila Device.
Atenție, în acest caz și frecvența de ceas trebuie să fie setată din nou.

3
Mediul Keil uVision

Fig. 1.5 Setare frecvenței de ceas

După ce am creat și am testat aplicația este necesar să creăm un fișier HEX,


pe care apoi să-l scriem în memoria de program a microcontrolerului
(EEPROM sau FLASH), cu ajutorul unui programator. Pentru crearea
fișierului HEX este necesară bifarea opțiunii „Create HEX File” din meniul
Output.

Fig. 1.6 Crearea fișierului HEX

4
Mediul Keil uVision

3.6. Crearea unui nou fișier sursă


Se poate crea un fișier sursă din meniul File/New. Această comandă va
deschide o fereastră de editare goală, în interiorul căreia vom putea introduce
codul sursă. Odată creat și salvat fișierul sursă (cu extensia *.c sau *.asm.)
trebuie adăugat la proiectul existent. Pentru a-l adăuga selectăm Source
Groups/Add Existing Files to Group.
A doua modalitate permite adăugarea directă a fișierului sursă în momentul
creării: selectăm Source Groups/Add New Item to Group (Fig. 1.7).

Fig. 1.7 Adăugare de fișiere la proiect

3.7.Crearea proiectului, corectarea eroilor și rularea programului


Putem translata toate fișierele sursă folosind butonul Build Target (F7) din
bara de meniuri.

Fig. 1.8 Compilarea și link editarea proiectului

Când se creează o aplicație cu erori de sintaxă, programul va afișa erorile


și mesajele de avertizare în fereastra Output Window-Build.

Fig. 1.9 Fereastra Build Output

5
Mediul Keil uVision

În figura Fig. 1.9 se observă că există o eroare de sintaxă la linia 11. Cu un


dublu click pe linia de mesaj corespunzătoare unei erori sau mesaj de
avertizare, Keil selectează linia corespunzătoare din program.
În urma translatării cu succes trecem la executarea programului folosind
butoanele Start/Stop Debug Session (Ctrl + F5) și apoi Run (F5) din meniul
Debug, sau se pot folosi și icoanele din bara de meniu:

Fig. 1.10 Rularea programului

Pentru depanarea programelor scrise în mediul Keil ne stau la dispoziție


comenzile aparținând submeniului Debug: Pentru a depana un program se
recomandă parcurgerea pas cu pas folosind Step și Step Over.
Insert/Remove Breakpoint (stabilirea unor puncte de suspendare a execuției)
permite selectarea unor linii de cod la care programul să se oprească pentru a
facilita parcurgerea în timpul depanării a părților deja verificate din program
a căror durată de execuție este lungă. În același timp este facilitată vizualizarea
valorilor unor variabile sau a unor locații de memorie. Stabilirea punctului de
suspendare se realizează prin selectarea liniei de cod corespunzătoare.
3.8. Compilatorul C51 și asamblorul A51
Fișierele sursă sunt create de Keil uVision IDE fiind apoi preluate de
compilatorul C51 sau asamblorul A51. Acesta procesează fișierele sursă după
care creează fișierele obiect relocabile.
Compilatorul C51 conține o implementare completă a limbajului de
programare C, care suportă toate standardele caracteristice limbajului C. În
plus, sunt numeroase caracteristici adăugate pentru suportul direct al
arhitecturii microcontrolerului 8051.
Asamblorul Keil A51 suportă setul complet de instrucțiuni pentru 8051 şi
instrucțiunile sale derivate.
3.9. Meniul Help
Meniul Help se poate accesa din Help/uVision Help. Dacă este selectat de
exemplu setul de instrucțiuni pentru 8051, mediul Keil oferă informații despre
instrucțiuni: ce face instrucțiunea, variante ale instrucțiunii, timpul necesar de

6
Mediul Keil uVision

execuție, numărul de octeți ocupați în memorie, codificare instrucțiunii (codul


mașină) și exemple. Mai departe Meniul Help oferă informații și despre
descrierea regiștrilor care sunt folosiți, tipurile de memorie, modul în care este
afectat PSW etc.

Fig. 1.11 Meniul Help și instrucțiunea ADD

De exemplu: instrucțiunea ADD a,#55H are codul mașină: 00100100


immediate. În cazul prezentat “immediate” este 55H. Dacă transformăm
codul în hexa o să avem valoarea 24H 55H. Instrucțiunea ocupă 2 octeți în
memoria de program, și este nevoie de un ciclu mașină pentru executarea ei.
4 Modul de lucru
• Se deschide Keil uVision.
• Familiarizarea cu meniurile existente.
5 Prelucrarea rezultatelor
1. Se va crea un proiect pentru microcontrolerul Generic 8051. Frecvența
de ceas se alege de 11.0592 MHz.
2. Adăugați un fișier sursă care conține următoarele linii de program:
org 0000h
palier_n:
mov a, #55h
mov P2,a
nop
nop
palier_p:
add a, #55h
mov P2, a

7
Mediul Keil uVision

nop
nop
sjmp palier_n
end
3. Analizați programul și explicați cum funcționează.
4. Convertiți programul în cod mașină folosind meniul Help!
Observație: Conversia se face unu la unu, adică fiecare linie din
program se transformă într-o instrucțiune în binar.
Tab. 1-1 Program
Cod ASM Cod mașină Locație de memorie
mov a, #55h
mov P2,a
nop
nop
add a, #55h
mov P2, a
nop
nop
sjmp palier_n
*) Să se verifice fișierul c:\Keil_v5\C51\ASM\ reg51.inc
5. Rulați secvența de cod pas cu pas (Debug/F11/Step) și:
- verificați conținutul acumulatorului în fereastra Registers (Fig. 1.12)
- verificați codul mașină în fereastra Disassembly (Fig. 1.13)
- verificați fereastra de memorie de cod (Fig. 1.14)

Fig. 1.12 Fereastra Registers

8
Mediul Keil uVision

Fereastra Register se găsește în meniul View/Register Window.

Fig. 1.13 Fereastra Disassembly

Fereastra Disassemby se poate adăuga din meniul View/Disassembly


Window.

Fig. 1.14 Fereastra Memorie

Aceste ferestre se pot adăuga și folosind scurtăturile din bara de meniu:

Fig. 1.15 Bara de meniu

- din meniul Peripherals adăugați portul 2 (Peripherals → I/O Ports →


Port2).

Fig. 1.16 Portul 2

- din Meniul View → Analysis Window alegeți Logic Analyzer-ul și a)


adăugați P2 („Analog”) și b) cele 8 semnale generate (P2.0, P2.1, ... P2.7):

9
Mediul Keil uVision

Fig. 1.17 Portul 2 – Analog

Fig. 1.18 Exemplu: P2.0 și P2.1

6) Modificați proiectul alegând microcontrolerul Aduc841 din familia


Analog Devices. Setați frecvența de ceas la 11.0592 MHz.
6 Aplicații
1. Completați tabelul următor:
Tab. 1-2 Tabel - Tema pentru acasă

Cod ASM Cod mașină Locație de memorie


mov r1,#05h
mov r2,#10h
mov a,#00h
add a,r1
add a,r2
mov P3, a
inc a
here: sjmp here
1. Folosind depanatorul monitorizați valorile R1, R2 și A!
2. Verificați conținutul portului P3.

10
Mediul Keil uVision

3. Cât este valoarea lui A la sfârșitul programului?


4. Cum se calculează adresa din memoria de cod pentru instrucțiunea
SJMP.

11
Simulator de sistem Proteus

2 Simulator de sistem Proteus


1 Scopul lucrării
• Familiarizarea cu Proteus VSM cu scopul de a simula circuite și de
a rula aplicații software folosind microcontrolere 8051.
• Învățarea elementelor fundamentale ale programului Proteus; Taste
și comenzi importante.
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision și Proteus.
3 Considerații teoretice
Mediul specific de programare/simulare care va fi folosit în continuare -
Proteus VSM - este un mediu integrat de simulare care, pe lângă uneltele
clasice de implementare a schemelor electrice și simulare de tip Spice, are
modelată și arhitectura unor familii de microcontrolere/microprocesoare astfel
încât se poate simula și funcționarea unei aplicații software/scheme care
conține și un microcontroler/microprocesor.
3.1. Implementarea unei scheme în Proteus
Se va lansa aplicația ISIS (editorul de scheme și mediul integrat de
simulare): Meniu Start – ISIS sau prin iconița de pe desktop. În meniul File
se alege opțiunea New Design și se alege formatul Default.
Pagina de lucru care se deschide va arăta asemănător cu cea din figură:

Fig. 2.1 Pagina de lucru Proteus

12
Simulator de sistem Proteus

Pentru a adăuga componentele pasive sau active care urmează să fie folosite
există trei posibilități:
1. butonul Pick Component (P)
2. meniu Library-Pick Device/Symbol
3. click dreapta pe pagina de lucru: Place-Components-From Libraries

Fig. 2.2 Adăugarea componentelor

Va apărea o listă cu toate bibliotecile (Libraries) cunoscute de Proteus


VSM. Microcontrolerele și microprocesoarele sunt în biblioteca
„Microprocessor ICs”, organizate pe familii: 8051, ARM, AVR, PIC, etc.
Se poate facilita căutarea oricărei componente tastând direct numele
componentei sau o parte a acestuia. Apoi, se alege componenta/linia respectivă
cu click pe ea și apoi OK. Se va observa cum componenta apare (este
adăugată) în lista curentă de componente. De aici ea poate fi utilizată ori de
cate ori este nevoie.

Fig. 2.3 Alegerea componentelor

Sursa de tensiune continuă se poate plasa folosind butonul Terminals


Mode din toolbar-ul cu unelte din stânga. Se alege opțiunea Power. Similar
se procedează dacă este nevoie de o conexiune la masa circuitului.

13
Simulator de sistem Proteus

Fig. 2.4 Toolbar-ul cu unelte

3.2. Plasarea componentelor și interconectarea lor


Pentru a adăuga componente trebuie selectat butonul Component Mode.
După ce componenta dorită este selectată din lista de componente sau din
toolbar-ul din stânga, componenta se plasează cu un click în spațiul de lucru
la locația dorită. După plasare urmează interconectarea lor cu fire (Wire).
Ducând Pointer-ul mouse-ului pe terminale, pointer-ul (indicatorul) se
transformă într-un creion (verde). Asta înseamnă că programul a trecut
automat în modul de trasare a legăturilor (fire între componente). Trecerea în
modul Wire se poate face și prin apăsarea butonului Junction Dot Mode (Fig.
2.4).
3.3. Editarea componentelor
O componentă plasată în spațiul de lucru și selectată poate fi „editată” cu
un click dreapta. În urma acestei selecții se deschide un meniu contextual prin

14
Simulator de sistem Proteus

intermediul căruia pot fi accesate proprietățile (Edit Properties) sau


componenta poate fi orientată sau deplasată corespunzător.
În meniul contextual ne interesează de multe ori, de exemplu, orientarea
componentei prin diverse rotiri (Rotate) în sens orar (Clockwise)/anti-orar
(Anti-Clockwise) sau oglindiri (Mirror) față de orizontală sau verticală. De
exemplu componenta R1 din figura de mai jos poate fi rotită cu 90◌ în sens
orar:

Fig. 2.5 Rotire cu 90⁰

La proprietățile propriu-zise ale componentei (Edit Properties) se poate


ajunge și prin Dublu Click direct pe componenta în cauză.
3.4. Programarea microcontrolerului și simularea în Proteus
După realizarea completă a schemei urmează “programarea”
microcontrolerului.
Se presupune cunoscută utilizarea mediului de programare Keil uVision
descris sumar în prima lucrare, unde rezultatul final este, printre altele, un
fișier *.hex.
Urmează „încărcarea” programului în simulatorul Proteus VSM (de fapt în
memoria de program a microcontrolerului 8051): după un dublu click aplicat

15
Simulator de sistem Proteus

pe microcontroler apare o fereastră de editare componentă. Cu butonul


Browse al câmpului Program File se alege locația unde a fost salvat proiectul
uVision și de acolo se alege fișierul *.hex corespunzător programului creat.
Apoi, se setează și frecvența de ceas a microcontrolerului.

Fig. 2.6 Încărcarea programului în simulatorul Proteus VSM

Validați modificările cu OK, și circuitul ar trebui să fie gata pentru


simulare.
Desfășurarea simulării (Pornire - Play, execuție pas cu pas - Step, pauză -
Pause, oprire/ întrerupere - Stop) se controlează cu opțiunile din meniul Debug
sau cu butoanele situate într-un toolbar sub spațiul de lucru, în partea stângă
jos.

Fig. 2.7 Pornirea simulării - Meniu Debug

Fig. 2.8 Pornirea simulării - butoane

În principiu este suficientă apăsarea butonului Play pentru pornirea


simulării și apăsarea butonului Stop pentru oprirea acesteia.

16
Simulator de sistem Proteus

3.5. Depanarea programelor scrise în asamblare în Proteus


Depanarea programelor pas cu pas în programul Proteus va fi prezentată
printr-un exemplu.
Programul de test în asamblare este următorul:
ORG 0000h
START:
MOV P2,#55h
NOP
NOP
MOV P2,#0AAh
HERE: SJMP START
END
Acest program scurt pune în P2 valorile 55h și AAh cu o întârziere de două
cicluri mașină între ele.
Pentru a testa acest program în Proteus se realizează schema următoare.
Este folosit microcontrolerul 8051(80C51) și două afișaje pe 7 segmente
(7SEG-BCD):

Fig. 2.9 Schema în Proteus - Depanarea programelor

După ce fișierul *.hex a fost încărcat în memoria microcontrolerului, pentru


a depana programul se recomandă parcurgerea pas cu pas apăsând prima data
butonul Step (sau Start și Pause), și apoi Step Over (F10) sau Step Into
(F11).

17
Simulator de sistem Proteus

Fig. 2.10 Depanare program: Step – Butonate

Fig. 2.11 Depanare program: Step – Meniu Debug

În momentul când a fost pusă pe pauză rularea programului se poate adăuga


fereastra cu regiștrii CPU.

Fig. 2.12 Regiștrii CPU

Se poate observa că această fereastră conține registrul PC, afișează


instrucțiunea corespunzătoare pasului actual, se poate vizualiza acumulatorul,
regiștrii B, DPTR, R0…R7, porturile, adică toți regiștrii SFR.
Apăsând butonul F10 (Meniu Debug/Step Over) se execută instrucțiunea
și se încarcă în PC adresa instrucțiunii următoare.

F10

Fig. 2.13 Fereastra CPU înainte și după Step

18
Simulator de sistem Proteus

Se poate vedea și rula pas cu pas codul sursă în asamblare dacă în meniul
Source/Add Remove Source Files este adăugat fișierul *.a51:

Fig. 2.14 Adăugare fișier sursă ASM

Acum apăsând butonul Step apare și fereastra cu codul sursă:

Fig. 2.15 Fișier sursă ASM

Atenție: schema din Proteus trebuie să fie în directorul în care este salvat
proiectul din Keil.
3.6. Depanarea în Proteus programelor scrise în C
Pentru depanarea programelor scrise în C utilizând mediul Keil se urmează
pașii necesari realizării unui proiect C în Keil urmând să se genereze fișierul
*.hex asemenea proiectelor în asamblare. În urma compilării și link editării o
să genereze un fișier OMF (absolute object module). Acest fișier de ieșire al
link editorului conține informațiile necesare pentru realizarea debugului. În
mod implicit acest fișier este salvat în subdirectorul „Objects” din directorul
proiectului cu aceeași denumire cu cea a proiectului doar că nu are nici o
extensie. Pentru a putea folosi acest fișier în Proteus este nevoie să îi fie
atribuită extensia *.omf. Odată atribuită această extensie, în Proteus se poate
utiliza ca fișier sursă pentru proiect în loc de fișierul *.hex acest fișier *.omf.

19
Simulator de sistem Proteus

Fișier *.omf:

Fig. 2.16 Încărcarea programului C în simulatorul Proteus VSM

În cazul rulării pas cu pas se poate vizualiza programul scris în Keil în


fereastra „Source code” din Proteus.

Fig. 2.17 Adăugare fișier sursă C

Acum apăsând butonul Step apare și fereastra cu codul sursă:

Fig. 2.18 Fișier sursă C

20
Simulator de sistem Proteus

Atenție: schema din Proteus trebuie să fie în directorul în care este salvat
proiectul din Keil.
3.7. Interconectarea programelor KEIL și PROTEUS
Folosind această metodă codul sursă în ASM sau C se rulează și depanează
în programul Keil, dar între timp se poate vizualiza comportarea circuitului
simulat în programul Proteus. Ca să se realizeze interconectarea acestor două
programe următorii pași trebuie efectuați:
− Dacă Keil C51 și Proteus sunt instalate corespunzător în directorul
C:\Program Files atunci fișierul VDM51.dll din directorul C:\
Program Files\ Labcenter Electronics\ Proteus N Professional\
MODELS\ VDM51.dll se copiază în directorul C:\Keil_v5\C51\BIN\.
unde N reprezintă versiunea instalată a programului Proteus.
− Se deschide fișierul TOOLS.INI din directorul C:\Program
Files\keil_v5\TOOLS.INI și la secțiunea [C51] se adăugă linia
următoare: TDRVX = BIN\VDM51.DLL ("Proteus VSM Monitor-
51 Driver") Unde X în TDRVX reprezintă situația actuală, nu se vor
duplica TDRV-urile existente

Fig. 2.19 Fișier Tools.ini

Configurare programului KEIL:


Faceți clic pe opțiunea Project/Options for Target ‘Target1’ (sau click
dreapta pe Target în Managerul de proiect - Options for Target ‘Target1’).
Apare o nouă fereastră în care trebuie selectată fila Debug:

21
Simulator de sistem Proteus

Fig. 2.20 Fereastra Options for Target

În caseta de dialog care apare în meniul derulant, coloana din dreapta sus,
selectați „Proteus VSM Monitor-51 Driver” și activați opțiunea „Use”. Apoi
faceți clic pe butonul „Settings” pentru a seta interfața de comunicare:

Fig. 2.21 Setarea VDM51 Target Setup

Introduceți valoarea „127.0.0.1” în căsuța Host IP. Dacă rulați programele


pe calculatoare diferite aici trebuie introdusă adresa IP a dispozitivului unde e
instalat programul Proteus. Completați apoi căsuța de Port cu valoare “8000”
și faceți clic pe butonul „OK”. După configurările făcute mai compilați încă o
dată proiectul și generați fișierul executabil.
Configurare programului Proteus:
În ISIS Proteus, alegeți meniul „Debug” din bara meniului și selectați „Use
Remote Debug Monitor”. După aceea, se poate realiza conexiunea Keil cu
depanarea în Proteus.
Rulați programul pas cu pas folosind Keil: Build All, Debug și Step (F11).

22
Simulator de sistem Proteus

Fig. 2.22 Interconectarea programelor Keil și Proteus

4 Modul de lucru
• Se deschide Keil uVision și se generează fișierul *.hex.
• Se deschide programul Proteus.
• Vă veți familiariza cu meniurile existente.
• Se va depana programul în Proteus.
• Se va simula programul în Proteus.
5 Aplicații
1. Testarea exemplului prezentat în capitolul 3.5. Depanarea programelor
scrise în asamblare în Proteus.
2. Să se scrie și să se testeze programul următor în Keil uVision.
DEL EQU 05H
REPET EQU 01H
MAIN:
MOV A,#REPET
ACALL INTARZIERE
CPL P3.4
SJMP MAIN
INTARZIERE:
MOV R0,#DEL
DELAY:
NOP
NOP

23
Simulator de sistem Proteus

NOP
NOP
DJNZ R0, DELAY
DJNZ ACC, INTARZIERE
RET
HERE: SJMP HERE
END
a. Verificați folosind meniul Help instrucțiunile:
acall intarziere
ret
cpl Px.pin
djnz acc, intarziere
b. Cum funcționează problema prezentată?
c. Cât este perioada semnalului generat?
d. Modificați valoarea ‚del’ astfel încât să aveți un semnal
dreptunghiular cu o perioadă de 1 ms și factorul de umplere 50
% (Ton = Toff = 0.5 ms).
e. Modificați valoarea ‚repet’ astfel încât să aveți un semnal
dreptunghiular cu o perioadă de 100 ms și factorul de umplere
50 % (Ton = Toff = 50 ms).
f. Modificați programul astfel încât să aveți un semnal
dreptunghiular cu o perioadă de 1s și factorul de umplere 50 %
(Ton = Toff = 0.5 s)
3. Pregătiți schema următoare și testați în Proteus programul scris:

Fig. 2.23 Schema LED în Proteus

24
Simulator de sistem Proteus

Observație: Rulați codul pas cu pas folosind modalitățile prezentate.


4. Modificați programul astfel încât să obțineți un semnal dreptunghiular
cu factorul de umplere 25 %.

25
Testarea memoriei RAM externă

3 Testarea memoriei RAM externă


1 Scopul lucrării
• Familiarizarea cu utilitarul Keil uVision și cu limbajul de
asamblare;
• Studierea rutinei de scriere/citire a datelor în/din memoria RAM
externă;
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision;
3 Considerații teoretice
3.1. Generalități
Memoria microcontrolerului 8051 este organizată în trei spații diferite
așa cum se poate observa în figura de mai jos. Fiecare spațiu de memorie este
un spațiu continuu care începe de la adresa 0 și se întinde până la adresa
maximă.

FFFF FFFF
FF FF
IDATA
Regiștri cu (nu este
funcții disponibilă la
speciale toate
dispozitivele)
80 80

7F
Memorie de cod Memorie Memoria Externă
(CODE) RAM de uz (XDATA)
general
2F
Memorie
adresabilă
la nivel de
bit
1F
Bancuri de
regiștri

0000 00
Memorie de date(DATA) 0000
Fig. 3.1 Organizarea memoriei la microcontrolerul 8051

Memoria de cod poate fi internă (de la 0000h la 0FFFh), externă de la


0FFFh la 0FFFFh sau în totalitate externă de la 0000h la 0FFFFh (ROM

26
Testarea memoriei RAM externă

externă). Este segmentul de memorie de tip read-only în care se stochează


programul și constantele. Poate să aibă maxim 64K. Este de obicei o memorie
EEPROM. Cel de-al doilea spațiu are 128 octeți de memorie RAM internă.
Acest segment de memorie este numit segment de date (DATA SEGMENT).
El poate fi accesat în unu sau două cicluri mașină depinzând de instrucțiunea
folosită. Microcontrolerele din familia 8052 mai au un spațiu de memorie
suplimentar de 128 de octeți numit IDATA. Adresa acestui segment de
memorie așa cum se observă în figura de mai sus se suprapune cu spațiul de
memorie ocupat de regiștrii cu funcții speciale. Poate să apară deci un conflict
când se adresează acest segment de memorie care este rezolvat prin faptul că
acest spațiu poate fi accesat doar folosind adresare indirectă.
Variabilele folosite des în program vor fi stocate în segmentul de date
(DATA) datorită vitezei ridicate cu care poate fi accesată această memorie.
Acest lucru trebuie făcut cu grijă din cauza spațiului de memorie limitat din
acest segment de memorie. Dacă avem nevoie de mai multă memorie pentru
date se poate conecta la porturile microcontrolerului o memorie RAM
externă. Microcontrolerul 8051 permite adresarea unui spațiu de 64K octeți
de memorie RAM externă numită XDATA. Operațiile de scriere și de citire a
acestei memorii durează cel puțin două cicluri mașină. Acest segment de
memorie se poate accesa folosind regiștrii DPTR, R0 sau R1.
3.2. Registrul DPTR și PC
8051 conține doar doi regiştri de 16 biţi: registrul pointer DPTR și
numărătorul de program PC. Acești regiștri se pot utiliza pentru a marca adresa
unui octet din memorie. Registrul DPTR este utilizat pentru a furniza o adresă
de cod sau date. Poate fi controlat de programator fie în întregime, fie prin
intermediul regiștrilor componenți DPH – 8 biți, respectiv DPL – 8 biți.
Registrul DPTR nu are o adresă însă regiștrii DPH, DPL au fiecare câte o
adresă: 82h și 83h. PC este incrementat după fiecare octet parcurs din memoria
program și nu poate fi modificat direct, însă valoarea sa poate fi modificată
prin instrucțiuni de salt. Nu are o adresă.

Exemplul 1: Operația de citire folosind registrul DPTR


Instrucțiunea MOVX, prezentată în figura Fig. 3.2, necesită două cicluri
mașină, în memoria de cod ocupă un singur octet și are codul mașină E0h.

27
Testarea memoriei RAM externă

Fig. 3.2 Operația de citire folosind registru DPTR

În cazul utilizării registrului DPTR mai avem nevoie de două cicluri


mașină suplimentare pentru a încărca registrul cum este prezentat și în figura
Fig. 3.3. Instrucțiunea ocupă 3 octeți în memoria de cod.

Fig. 3.3 Încărcarea registrului DPTR

MOV DPTR,#XBUFFER ;în DPTR se pune valoarea lui XBUFFER


MOVX A,@DPTR ;în A se mută data de la adresa indicată de DPTR
;În total patru cicluri mașină sunt necesare

Exemplul 2: Operația de scriere folosind registrul Ri


Instrucțiunea MOVX, prezentată în figura Fig. 3.4, necesită două cicluri
mașină și are un singur octet.

Fig. 3.4 Operația de scriere folosind registru R0 sau R1

28
Testarea memoriei RAM externă

Similar, dacă folosim registrul R0 sau R1 este nevoie de un ciclu mașină


suplimentar pentru a încărca registrul, Fig. 3.5. În acest caz este nevoie de trei
cicluri mașină.

Fig. 3.5 Încărcarea registrului R0 sau R1 cu o valoare

Se observă că pentru accesarea memoriei externe este necesar un număr


minim de trei cicluri mașină.
Pentru adresarea memoriei externe, dacă microcontrolerul utilizează
memorie externă, de date sau de program, portul P0 este utilizat ca şi
magistrală de adrese multiplexată cu magistrala de date iar P2 este utilizat ca
magistrală pentru biții adresei superioare. O schemă bloc generală de
conectare a memoriei externe RAM este prezentată în figura următoare:
8 biti Date

P0 Date

uC 8051 Memorie RAM


externă
A0-A7

Latch Adrese
ALE
A8-A15

P2 Adrese

RD Enable Date

WR WR

Fig. 3.6 Conectarea memoriei externe la microcontrolerul 8051

3.3. Subrutina de scriere și de citire


Mutarea datelor între diferite locații ale memoriei RAM se face utilizând
instrucțiunile MOV, PUSH, POP și XCH (pentru memoria RAM internă),
respectiv MOVX (pentru memoria RAM externă).

29
Testarea memoriei RAM externă

Lucrarea aceasta are ca scop înțelegerea funcționării instrucțiunilor MOV


și MOVX folosind un program care scrie în memoria externă valoarea 55h
pornind de la adresa 0000h (adresă de start) până la 2000h (adresă de stop).
Programul trebuie să verifice și dacă datele au fost scrise corect în memoria
externă.
Organigrama care descrie funcționarea programului este prezentată în
figura Fig. 3.7.
START Citire din memoria externă

Citirea conținutului adresei salvate în


Inițializarea constantelor: DPTR și salvarea lui în acumulator
pattern = 55h;
ram_start = 0000h; ram_stphi = 20h
good = K
Verificare conținut:
acumulator == pattern
Inițializarea registrului DPTR: NU
DA
DPTR = ram_start
Increment adresă
Scriere în memoria
actuală (DPTR)
externă:
Scrierea pattern-ului în memoria RAM NU
externă. adresă actuală ==
Increment adresă actuală (DPTR) adresă de stop
NU
DA

adresă actuală (dph) == Apariția pe portul P3 a valorii good certifică faptul


adresă de stop (ram_stophi) ca la fiecare locație de memorie de la 0000h până
la 2000h se află pattern-ul

DA

Resetarea registrului DPTR:


DPTR = ram_start Apariția pe P1 și P2
STOP
a valorii DPTR

Fig. 3.7 Organigrama - Testarea memorei RAM externă

Programul prezentat scrie în memoria RAM externă valoarea 55h începând


de la adresa 0000h până la adresa 2000h. Sunt definite 4 constante: pattern,
ram_start, ram_stphi și good. Registrul DPTR este inițializat cu ram_start.
Apoi urmează rutina de scriere în memoria externă folosind instrucțiunea
MOVX. După această rutină are loc verificarea datelor scrise: datele de la
locațiile de memorie cuprinse între 0000h și 2000h sunt comparate cu valoare
55h (pattern). Apariția pe portul P3 a valorii ‘K’ certifică faptul că la fiecare
locație de memorie de la 0000h la 2000h se află 55h. În caz de eroare prima
adresă la care nu este înscrisă valoarea 55h se regăsește pe porturile P1 și P2
(DPH, DPL).

30
Testarea memoriei RAM externă

3.4. Descrierea programului:


Atenție, programul nu conține erori de compilare, dar poate conține greșeli
intenționate. Se va înțelege funcționarea programului și se vor face
modificările necesare pentru a rula conform descrierii prezentate anterior.

;Scrieți un program care scrie în memoria externă valoarea 55h


;a). pornind de la adresa 0 pâna la adresa de stop 2000h
;b). iar apoi citește aceste valori și verifică dacă au fost scrise
corect.

ram_start equ 0000h ;valoarea de la care începem sa scriem în RAM


ram_stphi equ 20h ;valoarea din acumulator cu care se compară
;DPTR-ul pentru a scrie până la 2000h
pattern equ 55h ;valoarea cu care vom scrie locațiile din RAM
good equ 'K' ;valoarea de pe portul P3 care semnifică
;funcționarea corectă a scrierii

org 0000h ;setează locația pentru numărătorul de


;program din segmentul curent
mov p3, #0ffh
mov dptr, #ram_start ;mutã în dptr 0000h

write:
mov a, #pattern ;pune în acumulator 55h
movx @dptr,a ;scrie conținutul lui a în memoria RAM externã
;începând cu 0000h
inc dptr ;incrementeazã dptr pentru a scrie la
;urmãtoarea locație de memorie
mov a,#ram_stphi ;mutã în acumulator adresa de stop
cjne a,dpl,write ;scrie în RAM pânã la adresa de stop

mov dptr,#ram_start ;reînscrie în dptr 0000h pentru a începe


;operațiunea de citire și comparare
check:
1). ;1 - mutã DPTR în A

2). ;2 - comparã conținutul lui A cu 'pattern',


;dacă nu sunt egale sare la fail
3). ;3 - în caz de egalitate incrementeazã DPTR-ul
4). ;4 - mutã 'ram_stphi' în A

31
Testarea memoriei RAM externă

5). ;5 - verificã dacã s-a ajuns la ultima adresã

mov p3,#good ;apariția pe portul p3 a valorii ‘K’


;certificã faptul cã la fiecare locație de
;memorie de la 0000 la 2000h
;se aflã ’pattern’-ul (55h)
here:
sjmp here

fail:
6). ;6 & 7 - în caz de eroare scoate la
7). ;porturile P1 și P2 valorile lui DPH și DPL

there:
sjmp there ;de ce s-au utilizat două
;JUMP-uri(bucle infinite)?
end

4 Modul de lucru
• Se completează codul.
• Se va rula programul pas cu pas utilizând depanatorul de program
inclus în Keil uVision:

Fig. 3.8 Rulare pas cu pas, fereastra cu registri din debugger.


• Se poate observa că în memorie sunt scrise valori până la adresa
20h:

Fig. 3.9 Rezultat: Datele în memoria externă

32
Testarea memoriei RAM externă

• Dacă funcționează corect programul propus, valoarea 55h se va găsi


înscrisă la fiecare locație de memorie cuprinsă între 0000-2000h.
o Verificați funcționarea corectă a problemei folosind TAB-ul
fereastră de memorie din Keil!
Adresa de start: 0h -> 55h

Fig. 3.10 Fereastra de memorie – Adresa de start

Adresa de stop: 2000h -> 00h

1FFFh: Ultima adresa cu


continut 55h
Fig. 3.11 Fereastra de memorie – Adresa de stop

*Fereastra de memorie se găsește în meniul: View/Memory Windows.


o Verificați conținutul porturilor P1, P2 și P3.

K - Codul ASCII

Fig. 3.12 Porturile – Peripherals/Port

Fig. 3.13 Analizorul de semnal cu valorile de pe portul P3

33
Testarea memoriei RAM externă

o Să se modifice conținutul adresei 0010h și să se verifice din nou


dacă programul funcționează corect folosind fereastra de
memorie și porturile.
10h -> AAh

Fig. 3.14 Fereastra de memorie – 10h -> AAh

P1 = DPL = 10h =16dec

P2 = DPH = 00h =00dec

DPH = 00h DPL = 10h

DPTR = 0010h

Fig. 3.15 Porturi

5 Aplicații
1. Să se scrie un program care:
a). Scrie valoarea AAh în memoria RAM externă începând cu adresa
0002h până la adresa 2112h
b). Verificați dacă valorile au fost scrise corect în memoria RAM
externă. În caz de eroare adresa eronată se va afișa pe P1 și P2.
2. Se va scrie un program care scrie în memoria RAM externă valoarea
AAh pornind de la adresa 0003h până la adresa 0105h, iar apoi se citesc
aceste valori și se verifică dacă au fost scrise corect (folosind fereastra
de memorie). Adresa eronată va fi scrisă pe porturile P1 și P2.
3. Se va scrie un program care scrie alternativ valorile AAh si 55h în
memoria RAM externă începând de la adresa 0249h până la adresa
0251h .

34
Testarea memoriei RAM externă

4. Se va scrie un program care scrie în memoria RAM externă valoarea


AAh pornind de la adresa 0003h până la adresa 00F5h folosind regiștrii
R0 și R1. Se citesc apoi aceste valori și se verifică dacă au fost scrise
corect (folosind fereastra de memorie). Adresa eronată va fi scrisă pe
porturile P1 și P2.

35
Rutină de întârziere soft

4 Rutină de întârziere soft


1 Scopul lucrării
• Studierea metodei de realizare a unei rutine de întârziere soft pentru
diferite microcontrolere.
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision.
• Placa de dezvoltare ADUC841.
3 Considerații teoretice
Rutina ce urmează a fi prezentată, figura Fig. 4.1, generează întârzieri
între 1 şi 65 535 ms utilizând registrul R7 pentru generarea unei întârzieri de
bază de 1ms (subrutina ’onemil’). Întârzierea care se doreşte a fi realizată se
va încărca în regiștrii A (LSB) şi B (MSB), înainte de a apela ’softime’.

START

Date inițiale

A=0 Întârziere de bază


NU
B=0 de 1ms

Decrementare A
DA

DA A=0 NU

Stop DA A=B NU Decrementare B

Fig. 4.1 Organigrama rutinei de întârziere soft

Funcționarea programului se bazează pe calcularea timpului exact necesar


executării fiecărei instrucțiuni la frecvența ceasului utilizat. Microcontrolerul
are nevoie de un anumit număr de cicluri mașină pentru a executa fiecare
instrucțiune.

36
Rutină de întârziere soft

În familia 8051, durata unui ciclu mașină depinde de frecvența de ceas.


Pentru varianta originală a uC 8051, un ciclu mașină durează 12 perioade de
tact. Astfel, putem folosi ecuația următoare pentru a calcula durata unui ciclu
mașină:
TCM 8051 = 12  T Quartz ec. 1
Durata unei instrucțiuni depinde de durata unui ciclu mașină și de numărul
de cicluri necesare pentru executarea unei instrucțiuni (a se vedea în Help
numărul de cicluri necesare fiecărei instrucțiuni), ecuație 2:
Tinstr = CM  TCM 8051 ec. 2
Unde:
TCM8051 – perioada unui ciclu mașină la microcontrolerul 8051;
TQuartz – perioada oscilatorului care furnizează tactul pentru controler;
CM – numărul de cicluri mașină pentru o instrucțiune dată.

Pentru cristalul de cuarț cu frecvența de 11.0592 MHz fiecare ciclu mașină


este egal cu 1.085 us în cazul microcontrolerului 8051 standard.

Exemplu:
În meniul Help găsim informații despre numărul de cicluri necesare pentru
executarea unei instrucțiuni. În Fig. 4.2 este prezentată instrucțiunea MOV
A,#55h, care are nevoie de un ciclu mașină pentru execuție. De aceea, timpul
exact pentru executarea ei este 1.085 us.

uVision Help:

MOV A,#55h

CM=

Tinstr = CM  TCM 8051 =


= 1  1.085 us = 1.085 us

Fig. 4.2 Exemplu pentru a calcula timpul de execuție a unei instrucțiuni

Subrutina Întârziere de bază de 1ms (‘onemil’) generează o întârziere de


bază de 1ms (Fig. 4.1). Subrutina ’softime’ va realiza o întârziere egală cu un
număr de n milisecunde exprimată de un număr binar, de la 1 la 65535 găsit

37
Rutină de întârziere soft

în A (LSB) și B (MSB). Prin intermediul programului se încarcă timpul de


întârziere dorit în regiștrii A și B și se sare la eticheta softime.
În continuare se va prezenta subrutina ’onemil ’. Folosirea acestei subrutine
va fi exemplificată printr-un program care generează un semnal
dreptunghiular.

Descrierea subrutinei ‘onemil’:


delay equ 99h

onemil:
mov r7,#delay ;inițializează r7; 1 ciclu mașină = 1.085us

timer:
nop ;1 ciclu = 1.085 us
nop ;2 cicluri = 1.085 us + 1.085 us = 2.17 us
nop ;3 cicluri = 2.17 us + 1.085 us = 3.255 us
nop ;4 cicluri = 3.255 us + 1.085 us = 4.34 us
djnz r7,timer ;se decrementeazã r7 ;djnz se execută în
;2 cicluri = 2.17 us, deci avem o întârziere
;totalã de 6 cicluri (6*1.085us = 6.51 us)
;6.51 us x 153 = 996.03 us
nop
ret ; + cicluri suplimentare de la onemil: ≈ 1ms

Bucla ’timer ’ conține 4 instrucțiuni NOP și o instrucțiunea de tip salt DJNZ


R7,timer. Folosind meniul Help se poate determina numărul de cicluri mașină
pentru aceste instrucțiuni: NOP – un ciclu mașină, DJNZ – două cicluri
mașină. Bucla timer se repetă de R7 ori, timpul de execuție al acesteia se poate
exprima cu formula următoare:
Ttimer = (4  Tnop + Tdjnz )  R7 = 6  CM  R7 ec. 3
Unde CM este durata unui ciclu mașină.
R7 este inițializat cu valoare ‘delay’, un ciclu mașină este egal cu 1.085 us:
Ttimer = 6 1.085us  delay = 996.03us ec. 4
Subrutina ’onemil’ conține și instrucțiunile MOV R7,#delay și RET
(însumând încă 3 CM). A fost introdusă și o instrucțiune NOP suplimentară
înainte de RET, ca să rezulte o valoare a întârzierii cât mai apropiată de 1 ms:
Tonemil = Ttimer + 4CM = 996.03 + 4.34 1ms ec. 5

38
Rutină de întârziere soft

Testarea subrutinei ’onemil’


Exemplul 1:
În exemplul următor se verifică dacă subrutina ’onemil’ generează întârzieri
de 1 ms. În programul main se apelează subrutina ’onemil’ și se
complementează pinul P3.4 generând astfel un semnal dreptunghiular:

org 0000
setb P3.4
main:
acall onemil ;apelul subrutinei
cpl P3.4 ;complementare bit
sjmp main ;bucla infinită

delay equ 99h


onemil:
mov r7,#delay ;inițializează r7
timer:
nop ;1 ciclu = 1.085 us
nop ;2 cicluri = 1.085 us + 1.085 us = 2.17 us
nop ;3 cicluri = 2.17 us + 1.085 us = 3.255 us
nop ;4 cicluri = 3.255 us + 1.085 us = 4.34 us
djnz r7,timer ;se decrementeazã r7 ;djnz se execută în
;2 cicluri = 2.17 us, deci avem o întârziere
;totalã: 6.51 us x 153 = 996.03 us
;+cicluri suplimentare: 996.03 + 4CM ≈ 1ms
nop
ret
end

Fig. 4.3 Valoarea de la pinul 4 al portului 3.

Rezultatul este un semnal dreptunghiular cu o perioada de aproximativ 2ms


cu factor de umplere de 50% pe pinul 4 al portului P3.

39
Rutină de întârziere soft

Descrierea subrutinei ‘softime’:


Prin intermediul subrutinei ’softime’ se decrementează numărul n (care a
fost salvat în A și B). După fiecare decrementare se realizează o întârziere de
1 ms:
• se verifică dacă valorile MSB și LSB sunt diferite de 0;
• decrementează LSB-ul până la 0 și la fiecare decrementare
generează o întârziere de 1ms;
• dacă LSB-ul este 0 și MSB-ul este diferit de zero se decrementează
MSB-ul o dată urmând ca LSB-ul sa fie baleiat de la valoare FF la
zero (trecere din 0200 → în 01FF sau 0100 → în 00FF, etc.);
• când LSB și MSB sunt 0, întârzierea de n milisecunde a fost
generată și programul poate ieși din subrutină.
Se poate observa că 3 linii de cod lipsesc. Studentul trebuie să adauge aceste
linii după analizarea subrutinei.

softime:
push 07 ;este salvat registrul r7 pe stivă
push acc ;salveazã A în stivă ca să nu îi
;pierdem valoarea
;A este folosit pentru testul A = A ORL B
orl a,b ;în cazul în care A și B sunt 0 rezultatul
;lui SAU va fi 0
1). ;programul face salt la eticheta ‘ok’ dacă
;rezultatul testului este diferit de 0
pop acc ;se extrage valoarea acumulatorului din vârful
;stivei
pop 07 ;preluarea valorii registrului r7 din stivă
ret ;se iese din rutina softime
ok:
pop acc ;se extrage valoarea acumulatorului din vârful
;stivei
;dacă LSB = 0 care este pasul următor?
decLSB:
acall onemil ;apelul subrutinei onemil
2). ;decrementeazã acc, în cazul în care A(LSB)
;nu este 0 se face salt la decLSB
cjne a,b,decMSB ;în cazul în care conținutul lui b(MSB)
;este diferit de 0 (în acest moment LSB=A=0)
;se decrementează (decMSB) și se sare la decLSB

40
Rutină de întârziere soft

pop 07
ret ;se iese din subrutina softime
decMSB:
3). ;se dercrementează B și se sare la decLSB

sjmp decLSB

delay equ 99h


onemil:
mov r7,#delay
timer:
nop
nop
nop
nop
djnz r7, timer
nop
ret ;se iese din subrutina onemil
end

Testarea subrutinei ’softime’– Keil uVision


Exemplul 2:
Scrieți un program pentru 8051 care să complementeze în mod continuu
valoarea de la pinul P3.4 la fiecare 500 ms.
Rezolvare:
Numărul 500 în binar este 000111110100b, 01FE în hexa. Datorită faptului
că funcția ’main’ conține pe lângă apelul subrutinei ‘softime’ și alte
instrucțiuni, trebuie calculat numărul de cicluri mașină provenite în plus și
ajustate valorile salvate în MSB și LSB. Astfel numărul salvat în LSB este
egal cu 0FEH – 0AH = 0F4H. Acumulatorul trebuie inițializat cu partea low a
numărului (A = F4h), registrul B conține partea high a numărului (B = 01h).
Acum întârzierea generată va fi exact de 500ms.

MSB equ 01h


LSB equ 0F4h
delay equ 99h
org 0000h
main:
mov A,#LSB ;A = partea low a numărului

41
Rutină de întârziere soft

mov B,#MSB ;B = partea high a numărului

acall softime ;apelarea subrutinei care reprezintă delay-ul

cpl P3.4 ;se complementează pinul

sjmp main

500 ms

Fig. 4.4 Testarea subrutinei ’softime’– Keil uVision

Testarea subrutinei ’onemil’ – Keil uVision – uC Aduc841


Înainte testării rutinei ‘softime’ pe placa de dezvoltare Aduc841 este
necesară testarea programului în Keil uVision folosind microcontrolerul de la
firma Analog Devices, Aduc841:

Fig. 4.5 Alegerea uC-ului Aduc841 în programul Keil uVision

Frecvența oscilatorului este și acum 11.0592 MHz, iar pentru a calcula


durata unui ciclu mașină este folosită ecuația următoare:
1
TCM _ Aduc = T Quartz = = 1/11.0592MHz = 0.0905us ec. 6
fQuartz
Ca urmare este necesar să se modifice subrutina ‘onemil’ astfel încât să
genereze întârzieri de 1 ms:
delay equ 99h
delayAduc equ 1).
org 0000

42
Rutină de întârziere soft

setb P3.4
main:
acall onemil ;apelul subrutinei
cpl P3.4 ;complementare bit
sjmp main ;bucla infinită

onemil:
2).

delaymic:
mov r7,#delay
timer:
nop
nop
nop
nop
djnz r7,timer
nop
3).
ret
end
* Observație: ca să aveți întârzierea de bază de 1 ms, bucla delaymic trebuie
repetată de ‘?’ ori.

Subrutina onemil - nemodificat:

98.47 us

Subrutina onemil - modificat:


{

~1 ms

Fig. 4.6 Teste Aduc841 în programul Keil uVision

43
Rutină de întârziere soft

Testarea subrutinei ’softime’ – placa de dezvoltare


Folosind programul ‘softime’ să se scrie un program care aprinde și stinge
ledul conectat la P3.4 cu o perioadă de 4 s (Ton = Toff = 2 s).
Pentru a rezolva problema trebuie recalculate valorile MSB și LSB:
MSB equ 1).
LSB equ 2).
org 0000h
main:
mov A,#LSB
mov B,#MSB
acall softime ;apelarea subrutinei care reprezintă întârzierea
;atenție subrutina softime trebuie să apeleze
;subrutina onemil modificată: 1 ms
cpl P3.4
sjmp main

Pregătirea plăcii de dezvoltare:

Alimentarea plăcii:
LED: P3.4

CABLU
SERIAL:
Conectat la
PC

Osciloscop digital:
1+ -> P3.4
1- -> GND

Fig. 4.7 Placa de dezvoltare Aduc841 împreună cu osciloscopul digital: Analog


Discovery

Se poate observa că placa de dezvoltare este alimentată la 5V și este


conectată la PC folosind un cablu serial RS-232. Liniile 1+ și 1- sunt conectate
la pinul P3.4 și la DGND. După încărcarea programului în memoria
microcontrolerului se poate observa că ledul conectat la P3.4 se aprinde și se
stinge cu o perioadă de timp de 4 s. Formele de undă se pot vizualiza folosind
programul Waveforms.

44
Rutină de întârziere soft

Încărcarea fișierului executabil: *.hex


Pentru încărcarea fișierului executabil în memoria uC-ului se folosește
programul LossieASP:

PASUL 2:
PASUL 1:

PASUL 3:

PASUL 4

Fig. 4.8 Programul LossieASP

PASUL 1: Trebuie adăugat fișierul *.hex în locul indicat.


PASUL 2: Conform manualului pașii sunt următorii: Pentru a intra în
modul download se ține apăsat butonul SERIAL DOWNLOAD, și se apasă și
eliberează butonul RESET.
PASUL 3: Se apasă butonul GO din interfața LossieASP.
PASUL 4: Se eliberează butonul SERIAL DOWNLOAD după apariția
mesajului „Succesfully programed”.
Pentru pornirea programului se apasă scurt o dată butonul RESET. Acum
se poate observa că ledul conectat la P3.4 se aprinde și se stinge. Folosind
programul Waveforms se poate măsura perioada semnalului generat:

Fig. 4.9 Programul Waveforms

45
Rutină de întârziere soft

Waveforms este interfața care afișează pe calculator datele de la


osciloscopul digital Analog Discovery.
4 Modul de lucru
• Se va rula exemplul cu subrutina ’onemil’ pas cu pas utilizând
depanatorul de program inclus în Keil uVision.
• Se va completa și rula programul ’softime’ pas cu pas utilizând
depanatorul de program inclus în Keil uVision.
• Se va testa programul ’softime’ pe placa de dezvoltare Aduc841.
5 Aplicații
1. Să se testeze exemplul 1 și să se măsoare perioada semnalului.
2. Să se testeze exemplul 2 și să se măsoare perioada semnalului.
3. Să se modifice exemplul 2 astfel încât să genereze un semnal
dreptunghiular cu o perioadă de 800 ms.
4. Să se schimbe microcontrolerul Generic cu Aduc841.
a. să se modifice subrutina ’timer’ astfel încât să furnizeze o
întârziere de 1 ms
b. să se modifice rutina de întârziere soft astfel încât să
furnizeze o întârziere de 500 ms
5. Să se genereze un semnal dreptunghiular cu factor de umplere 25%
la pinul P3.4 cu o frecvență de 0.25 Hz.
6. Să se scrie un caracter din 1s în 1s în memoria RAM externă
începând cu adresa 0000h până la adresa 0010h.

46
Stocarea datelor în memoria ROM

5 Stocarea datelor în memoria ROM


1 Scopul lucrării
• Deprinderea lucrului cu tabele definite în memoria ROM
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision.
• Placa de dezvoltare Aduc841
3 Considerații teoretice
Memoria de cod a microcontrolerului este memoria în care se regăsește
programul scris de utilizator. Aceasta este reprezentată în figura următoare.

FFFF FFFF
FF FF
IDATA
Regiștri cu (nu este
funcții disponibila la
speciale toate
dispozitivele)
80 80

7F
Memorie de cod Memorie Memoria Externă
(CODE) RAM de uz (XDATA)
general
2F
Memorie
adresabilă
la nivel de
bit (BIT)
1F
Bancuri de
regiștri

0000 00
Memorie de date(DATA) 0000

Fig. 5.1 Organizarea memoriei la 8051 – Memoria de cod

Acest spațiu de memorie este adresat de registrul PC (numărător de


program – registru de 16 biți). Poate să aibă maxim 64K octeți (216 = 65 536).
Nu toate microcontrolerele din familia 8051 au instalată toată această cantitate
de memorie (de exemplu microcontrolerul original de la Intel are 4K octeți de
memorie ROM, seria de microcontrolere 8052 are 8K octeți de memorie).
După resetare numărătorul de program este inițializat cu 0000 ceea ce
înseamnă că citirea memoriei program începe întotdeauna de la adresa 0000.
Există și posibilitatea de a conecta memorie de program externă la pinii
microcontrolerului 8051. În cazul în care există 4K octeți de memorie internă

47
Stocarea datelor în memoria ROM

în momentul în care numărătorul de program depășește adresa 0FFF


microcontrolerul va accesa memoria externă automat. Pentru acest lucru pinul
EA trebuie conectat la 1 logic. Dacă se dorește ca tot programul să fie citit
doar din memoria ROM externă atunci se conectează pinul EA la 0 logic iar
microcontrolerul va ignora complet memoria ROM internă.
Pe lângă programul executabil în memoria de cod se pot stoca și datele
predefinite. Aceste date se pot defini folosind pseudoinstrucțiunile (directive)
DB și DW.
DB – define byte: Definește constante de un octet sau un șir de date, fiecare
cu lungimea de un octet. Elementele listei sunt separate prin virgulă.
Exemplu:
șir: DB 00h, 01h, 02h, 00h
șir2: DB ‘E’, ‘x’, ‘e’, ’m’, ’p’, ’l’, ’u’

șir: DB 00h, 01h, 02h, 00h


șir2: DB E , x , e , m , p , l , u

Fig. 5.2 Fereastra de memorie - Date predefinite

DW – define word: Definește mărimi cu lungimea de doi octeți.


Elementele listei sunt separate prin virgulă.
Exemplu:
Șir: DW 4023h,”TEST”
Există instrucțiuni care permit accesul rapid la aceste tabele folosind
registrul DPTR (data pointer) sau registrul PC (numărătorul de program). În
continuare se vor studia două subrutine care vor utiliza date predefinite salvate
în memoria de program.
3.1. Subrutina “PCLook”
Folosirea instrucțiunii MOVC presupune copierea datelor din memoria
program (ROM) în acumulatorul A al microcontrolerului. Câteodată avem
nevoie să apelăm date predefinite, ca de exemplu tabele. Aceste date trebuie
să poată fi accesate permanent și de aceea sunt stocate în memorii ROM.

48
Stocarea datelor în memoria ROM

Accesul la aceste date este posibil utilizând adresarea indirectă folosind


instrucțiunea MOVC.

Fig. 5.3 Instrucțiunea MOVC

Presupunând că în registrul acumulator A este un număr între 00 și 0Fh, cu


ajutorul subrutinei PCLook se obține pătratul numărului conținut în
acumulator. Programul utilizează un tabel stocat în memoria de program
pentru a calcula pătratul unui număr de la 0 la 15. Deoarece, valoarea lui PC
poate fi modificată doar prin instrucțiuni de salt, conținutul lui A necesită o
ajustare.
Organigrama care descrie funcționarea subrutinei este reprezentată în
figura următoare:

START
Citește din acumulator pătratul
numărului: MOVC A,@A+PC
Încarcă numărul în acumulator:
MOV
Afișează pătratul pe P0
Ajustarea conținutului A
- număr de octeți inserați între MOVC
și tabel - Stop

Fig. 5.4 Organigrama subrutinei "PCLook"

Descrierea programului PCLook:


org 0000h ;începutul programului
ajust equ
main:

49
Stocarea datelor în memoria ROM

mov a, #00h ;în registrul a avem numărul 00h


pclook:
add a,#ajust ;ajustare
movc a,@a+PC ;în a se mută conținutul locației de
;memorie: a+PC
mov P0,a
sjmp over
sqr:
db 00h ; 00^2 = 00
db 01h ; 01^2 = 01
db 04h ; 02^2 = 04
db 09h ; 03^2 = 09
db 10h ; 04^2 = 16
db 19h ; 05^2 = 25
db 24h ; 06^2 = 36
db 31h ; 07^2 = 49
db 40h ; 08^2 = 64
db 51h ; 09^2 = 81
db 64h ; 0A^2 = 100
db 79h ; 0B^2 = 121
db 90h ; 0C^2 = 144
db 0a9h ; 0D^2 = 169
db 0c4h ; 0E^2 = 196
db 0e1h ; 0F^2 = 225
over: sjmp over
end
Ca să se înțeleagă mai bine funcționarea subrutinei PCLook trebuie să fie
studiat codul mașină generat pentru această subrutină, respectiv
comportamentul registrului PC.
Codul mașină generat pentru prima instrucțiune “mov a,#00h”, este 74 00h
și ocupă 2 octeți în memoria de cod (meniu Help). Valoarea lui PC nu poate fi
modificată decât prin modurile prezentate mai sus (de ex: instrucțiuni de salt),
dar cunoscând comportamentul lui știm că se incrementează în funcție de
numărul de octeți ai instrucțiunilor parcurse. Altfel zis, PC indică adresa de
început a următoarei instrucțiuni. Asta înseamnă că are valoare doi după
executarea primei instrucțiuni, adică după “MOV A,#00h”, cum este prezentat
și în figura Fig. 5.3. Valoarea PC se poate găsi și folosind depanatorul de
program, tasta F11 și verificarea conținutului registrului PC în fereastra
Registers.

50
Stocarea datelor în memoria ROM

Debugger + Help => Codul mașină

Meniu Help

Fereastra de memorie
Fig. 5.5 Verificarea codului mașină și valorii PC

Atenție, numărul de octeți pe care îi ocupă instrucțiunea nu are legătura cu


câte cicluri mașină durează instrucțiunea.
După afișarea codului mașină pentru fiecare instrucțiune, se poate observa
că valoarea PC-ului, în momentul citirii tabelului de căutare (instrucțiunea
MOVC), este 5, Fig. 5.6. Problema este că la adresa 05h se află octetul MSB
al codului mașină al instrucțiunii “MOV P0, A“ (F5 80h), și nu tabelul. Tabelul
de căutare începe la adresa 09h. De aceea este nevoie de o ajustare: trebuie
adunat la A un număr care reflectă numărul de octeți ocupat de instrucțiunile
inserate între instrucțiunea MOVC și tabelul de căutare. Numărul de octeți dat
de instrucțiunea „MOV P0, A” și „SJMP over” este 4.

Fig. 5.6 Explicarea subrutinei

51
Stocarea datelor în memoria ROM

Rezultate:

mov a, #00h mov a, #02h mov a, #0Ah

Fig. 5.7 Testarea programului în Keil uVision

A = 0Ah -> 0Ah x 0Ah = 64h (0110 0100) = 100 dec

P2

P2: DIO 0 -> DIO 7;


1-: GND
Fig. 5.8 Fereastra Static I/O din programul WaveForms și conectarea analizorului
digital Analog Discovery

Atenție: pe monajul experimental a fost folosit portul P2 ca și port de


afișare.

0
1
1
0
0
1
0
0

Fig. 5.9 Fereastra Logic: Bus (DIO 0 - DIO 7), Programul WaveForms

52
Stocarea datelor în memoria ROM

3.2. Subrutina “DPLook”


Subrutina utilizează două tabele de căutare, Fig. 5.10, pentru a afla pătratul
unui număr aflat în acumulator al cărui rezultat este pe 16 biți:

Fig. 5.10 Tabele de căutare: hibyte și lowbyte

Anulând restricția ca numărul conținut de acumulator să fie mai mic decât


10h, în acumulator se stochează orice număr cuprins între 00h și FFh. Orice
număr mai mare decât 0Fh ridicat la pătrat, are ca rezultat un număr
reprezentat pe mai mult decât 8 biți. Rezultatul este stocat în regiștrii R0 (LSB)
și R1 (MSB). În consecință se vor construi două tabele: unul pentru LSB și al
doilea pentru MSB.
Organigrama care descrie funcționarea programului este reprezentată în
figura următoare:
START

Încarcă numărul în acumulator

Setare DPTR cu adresa de început a Setare DPTR cu adresa de început a


tabelului 1: lowbyte tabelului 2: hibyte

Stocare în R0 a părții LSB a pătratului Stocare în R1 a părții MSB a pătratului


numărului numărului

Stop

Fig. 5.11 Organigrama subrutinei DPLook

53
Stocarea datelor în memoria ROM

De notat că aici nu avem salt peste tabele, aici ambele sunt plasate la
sfârșitul programului. Conținutul lui A nu necesită nici o ajustare pentru că
adresarea se face utilizând registrul DPTR a cărui valoare poate fi scrisă direct
de utilizator. Astfel poate fi introdusă direct adresa de început a tabelului:
MOV DPTR,#sir
...
sir:
DB 00, 01h, 02h

Descrierea programului DPLook:


lowbyte equ 0200h ;adresa de bază a tabelului 1 ce conține
;partea low a numărului ridicat la puterea
;a doua
hibyte equ 0300h ;adresa de bază a tabelului 2 ce conține
;partea high a numărului ridicat la puterea
;a doua

org 0000h
dplook:
mov a, #5ah ;se calculează pătratul lui 5Ah
mov r1,a ;reține A pentru a fi utilizat mai târziu
mov dptr, #lowbyte ;setează DPTR la adresa de bază a LSB
movc a,@a+dptr ;mută în A conținutul locației de memorie
;(a+dptr) - LSB
mov r0,a ;stochează LSB în r0 (A4h)
mov a,r1
mov dptr,#hibyte ;setează DPTR la adresa de bază a MSB
movc a,@a+dptr ;mută în a partea MSB
mov r1,a ;stochează MSB în r1

here:
sjmp here

org lowbyte ;început tabel de căutare pentru LSB-uri


db 00h ;00^2 = 0000
db 01h ;01^2 = 0001
;restul tabelului de căutare ...

org lowbyte+5ah
db 0a4h ;5A^2 = 1FA4h

54
Stocarea datelor în memoria ROM

;LSB este A4
;restul tabelului de căutare ...

org hibyte ;început tabel de căutare pentru MSB-uri


db 00h ;00^2 = 0000
db 00h ;01^2 = 0001
;restul tabelului de căutare ...

org hibyte+5ah
db 1fh ;5A^2 = 1FA4h
;MSB este 1F
;restul tabelului de căutare ...

end ;sfârșit program

4 Modul de lucru
• Se vor rula programele pas cu pas utilizând depanatorul de program
inclus în Keil uVision.
• Se vor verifica formele de undă generate.
• Se vor testa programele pe placa de dezvoltare.
5 Aplicații
1. Folosind depanatorul de program și meniul Help se corectează
programul PCLook astfel încât să afișeze:
i. pătratul lui 0
ii. pătratul lui 5
2. Să se modifice programul astfel încât să afișeze pătratele numerelor
pe portul P2 de la 0 până la 15 - repetat la infinit (din memoria de
cod cu A si PC).
Rezultate:

...

Fig. 5.12 Pătratele numerelor pe portul P2

55
Stocarea datelor în memoria ROM

255 255
196 196
169 169
144 144
121 121
100 100
81 81
64 64
49 49
25 36 25 36
0 1 4 9 16 0 1 4 9 16

Fig. 5.13 Keil - Pătratele numerelor pe portul P2 de la 0 până la 15 - repetat la infinit

Fig. 5.14 Programul WaveForms

3. Modificați subrutina “DPLook” astfel încât să se calculeze


pătratul valorii 69h. LSB-ul rezultatului să fie memorat în R5,
iar MSB-ul în R4.
4. Sa se scrie un program care afișează pătratele numerelor pe
portul P3 de la 0 până la 15 - repetat la infinit - din memoria de
cod cu A și DPTR.
5. Realizați o subrutină care să citească din memoria de program
textul:
‘E’
‘T’
‘T’
‘I’
‘!’
6. În memoria de cod la adresa 100h este mesajul “HELLO
WORLD”. Sa se scrie un program care citește mesajul și
afișează literele pe portul P3 la infinit (reg A + DPTR).
7. Sa se citească cuvintele „Laborator uC” (memoria de cod) și să
se pună în memoria externă (începând cu adresa 050h).

56
Programare modulară

6 Programare modulară
1 Scopul lucrării
• Înțelegerea folosirii tehnicilor segmentelor și a modulelor
• Scrierea și testarea unor programe folosind segmente și module.
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision.
3 Considerații teoretice
Programarea modulară este o paradigmă de programare care are la bază
utilizarea modulelor. În acest stil de programare unitățile de cod ce oferă
funcționalitate specifică sunt grupate în module separate.
Avantajele programării modulare:
• Permite reutilizarea modulelor. Modulele odată create pot fi incluse
în alte aplicații.
• Ușurează lucrul în echipă. Module diferite pot fi scrise/testate de
persoane diferite.
• Permite o mai bună organizare și structurare a codului sursă.
Un segment este o unitate de cod care poate fi relocabil sau absolut.
Segmentele absolute sunt atribuite în mod specific de către programator la
scrierea codului sursă și sunt amplasate la adrese fixe. Segmentele relocabile
sunt amplasate la adrese stabilite ulterior, la editarea legăturilor.
Un modul este un fișier care deține o colecție de unul sau mai multe
segmente și numele lui este dat de programator.
O bibliotecă este un fișier care conține unul sau mai multe module. În
general, modulele pot fi împărțite în module de obiecte transferabile de
compilator sau asamblor care vor fi combinate cu celelalte module la
momentul link editării. Link editorul selectează dintr-o bibliotecă numai
modulele la care se referă alte module.
Directive de segmentare
Declararea unui segment relocabil se face sub forma:
<nume> SEGMENT <clasa>
Unde:
- <nume> - este numele asociat segmentului

57
Programare modulară

- <clasa> - specifică tipul de memoriei unde se află segmentul


declarat, prezentat în figura Fig. 6.1:
o CODE: ROM (offset pentru programul principal: 0x800)
o DATA: RAM: 0x00-0x7F (Bancul 1, R0: 0x08)
o IDATA: Microcontrolerele din familia 8052 mai au un spațiu de
memorie suplimentar: 0x80-0xFF
o BIT: memoria adresabilă la nivel de bit în DATA: 0x20 → 0x2F
o XDATA: memoria externă: 0x00000 – 0x0FFFF

FFFF FFFF
FF FF
IDATA
Regiștrii cu (nu este
funcții disponibila la
speciale toate
dispozitivele)
80 80

7F
Memorie de cod Memorie Memoria Externă
(CODE) RAM de uz (XDATA)
general
2F
Memorie
adresabilă
la nivel de
bit (BIT)
1F
Bancuri de
regiștri

0000 00
Memorie de date(DATA) 0000

Fig. 6.1 Organizarea memoriei la microcontrolerul 8051

Exemplu:
• MainProg SEGMENT CODE
• Data_Segment SEGMENT DATA

Segmentul CODE, folosit pentru program și date constante, nu se modifică


pe parcursul execuției. Aceste tip de segmente sunt rezidente într-o memorie
de tip ROM (memorie program). Segmentul de date (variabilele programului)
se modifică în timpul execuției; amplasarea lor se poate face numai în memorii
de tip RAM (memorie de date).
Selectarea segmentelor relocabile deja definite se face cu cuvântul cheie
RSEG. Cuvintele cheie BSEG, CSEG, DSEG, ISEG și XSEG selectează
segmentele absolute în spațiul de memorie.
Exemplu:
CSEG at 50h ;închide segmentul curent şi (re)deschide segmentul
absolut de cod

58
Programare modulară

DSEG at 50h ;închide segmentul curent şi (re)deschide segmentul


absolut de date

Declararea variabilelor și tabelelor


Declararea unei variabile se face sub forma:
<nume_variabila> <directivă > <număr de octeți/biți>
Unde:
- <nume_variabilă> - este numele variabilei
- <directivă>:
o db (define byte): Directiva DB rezervă spații în memoria de
cod cu valori pe 8 biți (octeți);
o dw (define word): Directiva DW rezervă spații în memoria de
cod cu valori pe 16 biți;
o ds (define storage): Directiva DS rezervă un număr specificat
de octeți în memoria de date. Putem defini variabile;
o dbit (define bit): Directiva DBIT rezervă un număr specificat
de biți în segmentul de biți.

Mai jos este prezentată o variantă simplificată a programului șablon


TEMPLATE.A51 din directorul \C51\ASM:

; Module name (optional)


;------------------------------------------------------------------
NAME module_name
;------------------------------------------------------------------
; Here, you may import symbols form other modules.
;------------------------------------------------------------------
EXTRN CODE (code_symbol) ; May be a subroutine entry declared in
; CODE segments or with CODE directive.
EXTRN DATA (data_symbol) ; May be any symbol declared in DATA
; segments or with DATA directive.
EXTRN NUMBER (typeless_symbol) ; May be any symbol declared with
; EQU or SET directive
;------------------------------------------------------------------
; You may include more than one symbol in an EXTRN statement.
;------------------------------------------------------------------
EXTRN CODE (sub_routine1, sub_routine2), DATA (variable_1)
;------------------------------------------------------------------
; Here, you may export symbols to other modules.
;------------------------------------------------------------------

59
Programare modulară

PUBLIC data_variable
PUBLIC code_entry
;------------------------------------------------------------------
; You may include more than one symbol in a PUBLIC statement.
;------------------------------------------------------------------
; Put segment and variable declarations here.
;------------------------------------------------------------------
data_seg_name SEGMENT DATA ; segment for DATA RAM.
RSEG data_seg_name ; switch to this data segment
data_variable: DS 1 ; reserve 1 Bytes for data_variable
data_variable1: DS 2 ; reserve 2 Bytes for data_variable1
;------------------------------------------------------------------
; Provide an LJMP to start at the reset address (address 0) in the
main module.
; You may use this style for interrupt service routines.
;------------------------------------------------------------------
CSEG AT 0 ; absolute Segment at Address 0
LJMP start ; reset location (jump to start)
segment_name SEGMENT CODE
RSEG segment_name ; switch to this code segment
start:
;------------------------------------------------------------------
; Insert your assembly program here.
;------------------------------------------------------------------

Exemplul 1:
Verificați sintaxa programului, tipul segmentelor utilizate și valorile mya,
myb, flag și tabel în fereastra de memorie.

Descrierea programului:
;------------------------------------------------------------------
; Module name (optional)
;------------------------------------------------------------------
NAME TESTPROGRAM
;------------------------------------------------------------------
; Put segment and variable declarations here.
;------------------------------------------------------------------
data_seg SEGMENT DATA ;segment de date
RSEG data_seg ;selectarea segmentului data_seg
mya: DS 2 ;rezervă 2 octeți pentru mya
myb: DS 2 ;rezervă 2 octeți pentru myb

60
Programare modulară

bit_seg SEGMENT BIT ;segment de date la nivel de bit


RSEG bit_seg ;selectarea segmentului bit_seg
flag: dbit 2 ;rezervă 2 biți pentru flag

CSEG at 50h
table: db 'Hello', 00h
;------------------------------------------------------------------
; Provide an LJMP to start at the reset address (address 0) in the
main module.
; You may use this style for interrupt service routines.
;------------------------------------------------------------------
CSEG AT 0 ; absolute Segment at Address 0
LJMP start ; reset location (jump to start)
MainProg SEGMENT CODE
RSEG MainProg
start:
mov mya,#20h ;mya – primul octet
mov mya+1,#30h ;mya – al doilea octet
mov mya+2,#40h ;mya+2 = myb – primul octet
mov myb+1,#50h ;myb – al doilea octet

mov P0,R0 ;R0 - bancul de registri 0

setb PSW.3 ;bitul rs0 = 1


clr PSW.4 ;bitul rs1 = 0 - > rs1 rs0 = 01 = b1
mov P0,R0 ;R0 - bancul de regiștrii 1

setb flag ;flag -> 2bit; setb flag = 01


setb flag+1 ;flag -> 2bit; setb falg+1 = 11 = 3dec
jmp $
end

La verificarea ferestrei de memorie în programul Keil uVison sunt


următoarele opțiuni:
c: 0x00 (sau 00h) → memorie cod;
d: 0x00 (sau 00h) → memorie date;
d: 0x20 (sau 20h) → memorie date, memoria adresabilă la nivel de bit;
x: 0x00 (sau 00h) → memorie externă;
i: 0x00 (sau 00h) → memorie idata disponibilă la microcontrolerele din
familia 8052

61
Programare modulară

Segmentul mainProg este un segment relocabil, localizarea lui în memorie


este făcută de link editor și se află la adresa 800h, figura Fig. 6.2. Tabelul
“table” se află la adresa 50 (segment absolut).

Fig. 6.2 Memorie cod

Variabilele “mya” și “myb” sunt la adresa 08h în memoria date. Variabila


flag se află la adresa 20h, cum e prezentat și în figura Fig. 6.3.

Fig. 6.3 Memorie date

Exemplul 2:
În memoria de cod la adresa 100h este mesajul “HELLO WORLD”. Să se
scrie un program care citește mesajul și afișează literele pe portul P3 la infinit
(reg A + DPTR).

62
Programare modulară

Descrierea programului:
Programul are două module: modulul main și modulul extern Printport.
Programul main citește caractere din tabelul ‘text’ și apelează modulul extern
Printport pentru afișarea caracterelor pe P3.
Tab. 6-1 Exemplu 2

Main.asm: Printport.asm:

$title (ModularProgramming) NAME PUT_C

;Definiție Segmente Relocabile Public printPort


MainP SEGMENT Code
Rutina Segment code
;Modulul extern
EXTRN CODE (printPort) Rseg Rutina

;Definiție Segment Absolut printPort:


cseg at 100h mov P3,a
text: db 'Hello world',0 inc dptr
ret
;start program end
CSEG AT 0
LJMP Start
;selectare segmentului MainP
RSEG MainP
Start:
mov dptr,#text
again:
mov a,#00h
movc a,@a+dptr
jz here

;mov P3,a -> PrintPort subr


;inc dptr
acall printPort
jmp again
here: sjmp Start
end

4 Modul de lucru
• Se vor rula exemplele/programele pas cu pas utilizând depanatorul
de program inclus în Keil uVision.

63
Programare modulară

• Se verifică fereastra de memorie pentru valorile folosite în


exemple/probleme.
5 Aplicații
1. Să se rescrie programul Softime folosind programare
modulară:

Fig. 6.4 Programare Modulara – Main_Softime

Fig. 6.5 Programare Modulară - Subrutina Softime cu module timer8051 și timer841

2. Să se citească următoarele caractere „Laborator uC” (memorie


de cod, adresă 100h) la intervale de o secundă și să se pună în
P3 folosind programare modulară.
3. Să se citească următoarele caractere „Laborator uC” (memorie
de cod, adresă 100h) și să se pună în memoria externă (la adresa
050h) folosind programarea modulară.
4. Rescrieți programul “DPLook” folosind programarea
modulară, astfel încât să aveți 3 module: main, dplook_MSB și

64
Programare modulară

dplook_LSB. Modulele dplook_MSB și dplook_LSB conțin


tabele de căutare pentru a afla pătratul unui număr pe 16 biți.

Fig. 6.6 DPLook - Programare modulară

65
Programare în C

7 Programare în C
1 Scopul lucrării
• Scrierea și testarea unor programe în C
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision.
3 Considerații teoretice
Un limbaj de programare este de nivel "înalt" atunci când, înainte de a putea
fi executat codul, acesta trebuie mai întâi să treacă prin unul sau chiar mai
multe filtre de interpretare (compilatoare, medii de rulare).
Niveluri ale limbajelor de programare:
• Nivel Scăzut: asamblare - interacționează aproape direct cu procesorul
• Nivel Mediu: C/C++, Pascal - sursele sunt transformate de compilator
în cod mașină
• Nivel Înalt: de exemplu Java - pe lângă procesul de compilare, necesită
JRE - Java SE Runtime Environment (la fel ca Visual C# și .Net
Framework)
Cu cât crește nivelul limbajului (gradul de abstractizare), cu atât acesta este
mai ușor de înțeles de către programator, iar cu cât scade nivelul limbajului,
cu atât acesta este mai ușor de "înțeles" pentru calculator. Pentru eficientizare
în codul C/C++, Visual C/C++, Basic, Pascal, etc. pot fi integrate și porțiuni
de cod de asamblare, obținându-se astfel un cod hibrid.
Codul scris în limbaj de asamblare se traduce direct în codul mașină care
va fi executat de microcontroler, fără cod suplimentar adăugat de compilator
sau de mediu. Deși compilatoarele C/C++ performante pot uneori să producă
un cod mașină foarte eficient din punct de vedere al vitezei sau al necesarului
de memorie, programarea în limbaj de asamblare conferă programatorului
controlul absolut asupra codului binar rezultat. De cele mai multe ori codul în
asamblare are mai puține linii de cod, este mai rapid, mai previzibil din punct
de vedere al necesarului de memorie și de timp și este mai ușor de depanat.
Utilizarea limbajului C pentru programarea microcontrolerelor devine
foarte comună. De cele mai multe ori realizarea aplicației în asamblare nu este
ușoară, dar în schimb se poate face cu ușurință în C. Deoarece va fi folosit
compilatorul Keil C51, în cele ce urmează 8051 C va fi denumit Keil C. Cea

66
Programare în C

mai mare diferență a Keil C față de standardul ANSI C este capacitatea sa de


a accesa componentele arhitecturale ale microcontrolerului 8051 precum
porturile I/O, întreruperi, regiștri CPU și memorie.
3.1. Cuvinte cheie
Compilatorul Keil C51 adaugă câteva cuvinte cheie în plus față de limbajul
C. Cuvintele cheie cele mai des folosite sunt enumerate în tabelul următor.
Tab. 7-1 Cuvinte cheie în C

_at_ data sfr

bdata idata sfr16

bit interrupt using

code sbit xdata

Tipurile de memorie și directivele folosite:


• data/idata: Variabila va fi stocată în memoria de date internă
(RAM intern: 0x00-0x7F) a controlerului. Exemplu:
unsigned char data x;
//sau
unsigned char idata y;
• bdata: Variabila va fi stocată
în memoria adresabilă la nivel de bit
(RAM intern: 0x20 → 0x2F). Exemplu:
unsigned char bdata x;
//fiecare bit al variabilei x poate fi accesat după cum
urmează
x ^ 1 = 1; //bitul 1 al x este setat
x ^ 0 = 0; //bitul 0 al x este șters
• xdata: Variabila va fi stocată în memoria externă a
microcontrolerului. Exemplu:
unsigned char xdata x;
• code: Acest cuvânt cheie este utilizat pentru a stoca o constantă în
memoria de cod. De exemplu un șir/tablou mare care nu va suferi
modificări nicăieri în program. În acest caz este recomandată
folosirea memorie de cod în loc de a pierde locații libere din
memoria RAM (memoria de date). Exemplu:
unsigned char code str="this is a constant string";

67
Programare în C

Alte tipuri de cuvinte cheie:


• _at_: Este utilizat pentru a stoca o variabilă la o locație definită în
RAM. Exemplu:
unsigned char idata x _at_ 0x30;
// variabila x este stocată la locația 0x30
// în memoria internă de date
• sbit: asignează un nume unui bit din memoria adresabilă la nivel
de bit sau definește un bit special din memoria SFR. Exemplu:
sbit Port0_bit0 = 0x80;
// Bitul special (Special bit) cu numele Port0_bit0 este
definit la adresa 0x80
• sfr: este utilizat pentru a defini un registru de 8 biți din zona de
memorie SFR. Exemplu:
sfr Port1 = 0x90;
// Registru cu funcții speciale cu numele Port1 este definit
la adresa 0x90
• sfr16: acest cuvânt cheie este utilizat pentru a defini (aloca 16 biți)
două secvențe pe 8 biți în zona de memorie SFR. Exemplu:
sfr16 DPTR = 0x82;
// Registru cu funcții speciale pe 16-biți
// octetul inferior: DPL la 0x82, octetul superior DPH la //
// 0x83
• using: este utilizat pentru a selecta bancul de regiştri folosit.
Exemplu:
void function () using 2
{
//cod
}
//bancul 2 este selectat
• interrupt: Acest cuvânt cheie va spune compilatorului că funcția
descrisă este o rutină de întrerupere. Compilatorul C51 acceptă în
cazul microcontrolerului 8051 rutine de tratare a întreruperii pentru
5 întreruperi. Exemplu:
void External_Int0() interrupt 0
{
//cod
}

3.2. Pointeri în Keil C


În standardul C pointerul este definit ca și o variabilă ce conține adresa unei
locații de memorie. În Keil C sunt două tipuri de pointeri: pointeri generici și

68
Programare în C

pointeri de memorie specifici. Aceștia sunt similari cu cei din standardul C


putând efectua aceleași operații.
Pointeri generici
Acești pointeri sunt declarați ca și pointerii din standardul C:
char *ptr; //pointer către un caracter
int *num; //pointer către un număr întreg (int)
Pointerii generici sunt întotdeauna stocați folosind trei octeți. Primul octet
este tipul de memorie, urmat de octetul MSB al offset-ului, și de octetul LSB
al offset-ului. Pointerii generici pot fi folosiți pentru a accesa orice variabilă
indiferent de locația sa.
Pointeri specifici de memorie (Memory-Specific Pointers)
Pointerii specifici de memorie sunt definiți împreună cu tipul de memorie
la care se referă indicatorul, de exemplu:
char data *c;
// Pointer către un caracter stocat în memoria de date

char xdata *c1;


// Pointer către un caracter stocat în memoria externă

char code *c2;


// Pointer către un caracter stocat în memoria de cod
Deoarece pointerii specifici sunt definiți cu un tip de memorie la momentul
compilării, octetul tipului de memorie nu este necesar. Pointerii specifici
memoriei pot fi stocați folosind 1 octet (pentru idata, data, bdata și pdata) sau
2 octeți (pentru code și xdata).

3.3. Funcții
Formatul funcțiilor definit în Keil C este:
[tip_rezultat] <nume_functie> ([argumente])[…][interrupt n][using n]{
[declaratii locale]
[instructiuni]
[return]
}
• tip_rezultat:
o tipul de date returnat de funcție. Tipurile de date predefinite
în Keil C sunt următoarele: char (signed char, unsigned
char), int (signed short, signed int, unsigned int,
signed long, unsigned long), double, enum, struct,
float, bit, sbit, sfr, sfr16

69
Programare în C

o poate să fie predefinit sau definit de utilizator


o implicit este int, dacă nu returnează un rezultat este void
• nume_funcție:
o identificator, respectă regulile de denumire de la
identificatori
• argumente:
o lista valorilor cu care funcția va opera, poate să lipsească
• interrupt n:
o opțional, este folosit în cazul întreruperilor
• using n:
o opțional, este folosit în cazul selectării altui banc de regiștri

3.4. Primul program în Keil C


După cum a fost anterior menționat, diferențele între Keil C și un program
ANSI C sunt minore.
În standardul ANSI C, toate programele au cel puțin o funcție, care este
punctul de intrare pentru aplicație, funcția fiind numită funcția “main”. În mod
similar, în Keil, vom avea o funcție principală.
Programele C rulate pe calculator, se rulează ca un program secundar și
sunt procesate de sistemul de operare, astfel încât la ieșirea din program (ieșire
din funcția “main” a programului) are loc o revenire la sistemul de operare.
În cazul microcontrolerelor pentru a nu ajunge în zone de memorie de cod
goale care ar putea duce la un comportament neprevăzut al acestuia și pentru
a asigura funcționare continuă este nevoie de o buclă infinită uneori aceasta
având rol de funcție IDLE. Acest lucru se poate face cu ajutorul buclelor
infinite: while(1) sau for(;;).
Când se scrie codul, trebuie adăugat și fișierul antet specific al
controlerului. Astfel e asigurat accesul la regiștri, la porturi, la timere, la
sistemul de întreruperi, etc ale microcontrolerului selectat.
Șablonul unui program C pentru controlerul 8051 este următorul:
#include <REG51.h> //fișierul antet

void main()
{
//inițializare
while (1) {
//while(1) – bucla infinită

70
Programare în C

//bucla conține codul care va rula la infinit


}
}

Conținutul fișierului antet se poate insera făcând click dreapta în fereastra


editor:

Conținut fișier:

Fig. 7.1 Inserarea fișierului antet și a conținutul lui

Exemplul 1:
Verificați sintaxa programului, tipul variabilelor utilizate și valorile
myByte, myBit și aByte în fereastra de memorie.
Descrierea programului:
#include <REG51.H>

unsigned char data myByte; //myByte e stocat în memoria de date


//și nu este inițializat
unsigned char bdata aByte = 0xAA; //aByte este stocat în memoria
//adresabilă la nivel de bit și este inițializat cu valoarea AAh
sbit myBit = aByte^1; //myBit este bitul 1 al octetului aByte

void main()
{
while (1)
{
myByte = 0x55;
myBit = !myBit;
myByte = 0xAA;
}
}

71
Programare în C

În Fig. 7.2 este prezentată fereastra de memorie și fereastra Quick Watch.


Se poate observa că valoarea variabilei myByte este modificată direct
modificând conținutul variabilei. Valoarea variabilei aByte se modifică pentru
că e negat bitul myBit la fiecare iterație.

Iterația 1: myByte

aByte

Iterația 2:

Fig. 7.2 Fereastra de memorie și Quick Watch

Exemplul 2:
Să se scrie un program care generează un semnalul dreptunghiular cu o
perioadă de 4 ms și un factor de umplere de 50 %.

#include <REG51.H>
sbit LED = P3^4;
//pinul 4 de la portul 3

void delay(int);
//prototip funcția delay cu 1 parametru de intrare

void main()
{
while (1) //bucla infinită
{
delay(2); //întârziere 2 ms
LED = ~LED; //complement pin
}
}

void delay(int count)


{

72
Programare în C

unsigned int i,j;


for (i=0;i<count;i++)
for (j=0;j<112;j++) {} //întârziere de 1 ms
}

Ton = Toff = 2 ms

T = 4 ms

Fig. 7.3 Rezultate Exemplul 2

Exemplul 3:
Să se scrie un program care afișează pătratele numerelor pe portul P2 de la
0 până la 15 - repetat la infinit.
#include <REG51.H>
#define Byte unsigned char
Byte* patrat(Byte);

void main()
{
unsigned int i;
while (1) //bucla infinită
{
for (i=0;i<16;i++)
P2 = patrat(i);
}
}

Byte* patrat(Byte c)
{
return c*c;
}

73
Programare în C

...

255 255
196 196
169 169
144 144
121 121
100 100
81 81
64 64
49 49
25 36 25 36
0 1 4 9 16 0 1 4 9 16

Fig. 7.4 Keil - Pătratele numerelor pe portul P2 de la 0 până la 15 - repetat la infinit

Fig. 7.5 Rezultate experimentale preluate cu osciloscopul digital Analog Discovery

Exemplul 4:
Să se scrie un program care afișează mesajul ’HELLO’ pe portul P2.
Mesajul este stocat în memoria externă.
#include <REG51.H>
#define Byte unsigned char
Byte xdata sir[] = "Hello"; //declarăm șirul în memoria externă

void main()
{
unsigned int i;
P2 = 0xFF;
while (P2>0)

74
Programare în C

{
P2 = sir[i++];
}
while(1); // bucla infinită
}

Fig. 7.6 Rezultate Exemplul 4

4 Modul de lucru
• Se vor rula exemplele pas cu pas utilizând depanatorul de program
inclus în Keil uVision.
• Se verifică fereastra de memorie pentru valorile folosite în exemple.
• Se vor testa exemplele 2 și 3 pe placa de dezvoltare Aduc841.
5 Aplicații
1. Să se scrie un program care să afișeze mesajul ’HELLO’ pe
portul P2. Mesajul este stocat în memoria de cod (ROM
internă).
2. Să se scrie un program care să afișeze mesajul ’HELLO
WORLD’ pe portul P2 cu o întârziere de 1s între litere. Mesajul
este stocat în memoria de cod (ROM internă).
3. Să se scrie un program care generează un semnal ca cel din
figura de mai jos utilizând șirul de valori pentru pătratele
numerelor.

Fig. 7.7 Semnal

75
Programare în C

4. Să se scrie un program care generează un semnal ca cel din


figura de mai jos utilizând șirul de valori pentru pătratele
numerelor.

Fig. 7.8 Semnal

5. Să se scrie un program care afișează pătratele numerelor de la


0 până la 225 folosind două porturi.
6. Să se scrie un program care scrie valoarea 55h în memoria
externă de la adresa 0002h până la adresa 0050h. Verificați
dacă datele au fost scrise corect.
7. Să se citească mesajul “uC Laborator” din memoria de cod și
să fie copiat în memoria externă.

76
Porturile de intrare – ieșire

8 Porturile de intrare – ieșire


1 Scopul lucrării
• Familiarizarea cu porturile I/O
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision.
3 Considerații teoretice
3.1. Generalități
Cel mai simplu mod de comunicare între µC și mediul exterior este realizat
de porturile digitale de intrare/ieșire. Schema generală a microcontrolerului
8051 este prezentată în Fig. 8.1. Se pot vedea 3 intrări de sistem (XTAL1,
XTAL2, Reset), 3 semnale de control (EA, PSEN, ALE), pinii de alimentare
(VCC, GND) și 4 porturi (pentru interfațare externă), numite port 0 (P0), port
1 (P1), port 2 (P2) și port 3 (P3).
+5V 0.1 µF
Intrări de sistem

VCC
XTAL1
Port 0
XTAL2
Reset circuit RESET Port 1 Porturi

+5V EA
Port 2
Semnale de
control

PSEN Port 3
ALE
GND

Fig. 8.1 Schema și caracteristicile unui microcontroler din familia 8051

Aceste porturi au corespondență cu mediul exterior prin pinii circuitului


integrat. Deoarece arhitectura 8051 este pe 8 biți iar porturile corespund unor
registre interne, acestea vor avea la rândul lor 8 pini.
Semnalele de control External Access (EA), Program Store Enable (PSEN)
și Adddress Latch Enable (ALE) sunt utilizate pentru interfațarea memoriei
externe. Dacă nu există nicio cerință de interfațare cu o memorie externă,

77
Porturile de intrare – ieșire

atunci pinul EA se conectează la “1” logic și celelalte două PSEN și ALE sunt
neconectate. Condensatorul de decuplare de 0.1µF, conectat între Vcc și masă
cât mai aproape de pinul de alimentare al microcontrolerului, este folosit
pentru a evita zgomotul de înaltă frecvență de pe linia de alimentare. XTAL1
și XTAL2 sunt destinate intrărilor de ceas ale sistemului.
Pinii portului 0 și portului 2 servesc fie ca dispozitive I/O (intrări/ieșiri) fie
ca magistrală de adrese sau de date pentru lucrul cu memoria externă. Pinii
portului P1 nu au funcții duale: sunt utilizați doar ca și pini I/O. Portul 3 este
un port de intrare – ieșire similar portului 1, dar are și funcții de intrare – ieșire
care pot fi programate controlând bistabilele portului P3 sau regiștrii SFR
specifici.
Descrierea pinilor unui microcontroler din familia 8051 este prezentată în
figura următoare:
P1.0 1 40 Vcc
P1.1 2 39 P0.0 (AD0)
P1.2 3 38 P0.1 (AD1)
P2.3 4 37 P0.2 (AD2)
P1.4 5 36 P0.3 (AD3)
P1.5 6 35 P0.4 (AD4)
P1.6 7 34 P0.5 (AD5)
8 33
P1.7
RST 9 8051 32
P0.6 (AD6)
P0.7 (AD7)
(RXD) P3.0 10 31 EA
(TXD) P3.1 11 30 ALE
(INT0) P3.2 12 29 PSEN
(INT1) P3.3 13 28 P2.7 (AD15)
(T0) P3.4 14 27 P2.6 (AD14)
(T1) P3.5 15 26 P2.5 (AD13)
(WR) P3.6 16 25 P2.4 (AD12)
(RD) P3.7 17 24 P2.3 (AD11)
XTAL2 18 23 P2.2 (AD10)
XTAL1 19 22 P2.1 (AD9)
GND 20 21 P2.0 (AD8)

Fig. 8.2 Descrierea pinilor ai unui uC din familia 8051

Schema unui pin al portului 1 este prezentată în figura Fig. 8.3. Cum a fost
menționat și mai sus, portul 1 nu are funcții duale. De aceea bistabilul de ieșire
este conectat direct la grila tranzistorului FET. Dacă folosim portul ca intrare
trebuie să înscriem un unu logic în bistabil blocându-se astfel tranzistorul FET.
Pinul şi intrarea buffer-ului sunt menținute în stare „high” de către rezistența
de pull-up internă (această rezistență este implementată tot cu tranzistoare
FET). Un circuit extern poate aduce acest pin în stare ”0” sau să îl lase în stare
”1”.

78
Porturile de intrare – ieșire

Dacă portul se utilizează ca ieșire, bistabilul conținând un „1” logic


blochează tranzistorul de ieșire. Dacă în bistabil este înscris „0” tranzistorul
FET este adus în stare de conducție aducându-se astfel pinul 1.x în stare
„LOW”.
Citire Latch
Vcc

Magistrala Rezistența pull-up


internă D Q (intern)
Pin
P1.X
P1.X
Clk Q
Scriere Latch

Citire Pin
Fig. 8.3 Schema unui pin de la portul 1

Atenție, portul 0 nu are rezistente de pull-up interne. Toate bistabilele


programate în starea „1” vor avea ieșirile în stare de înaltă impedanță astfel
vor fi necesare rezistențe ce se vor lega la sursa de alimentare (pull-up extern)
când P0 este utilizat ca port de ieșire.
3.2. Rezistențe de pull-up și pull-down externe
Rezistențele de tip pull-down și pull-up sunt utilizate în circuitele logice
pentru a asigura în toate condițiile un nivel logic bine definit la un pin. După
cum bine știm circuitele logice au trei stări posibile: LOW, HIGH și HIGH
IMPEDANCE. Starea de înaltă impedanță este întâlnită, atunci când un
terminal nu se află în niciuna dintre stările LOW și HIGH, dar în schimb este
lăsat flotant. În cazul unui microcontroler, dacă la un pin de I/O nu este
conectat nimic, aceasta ar putea interpreta eronat valoarea de intrare fie ca
fiind o valoare LOW, fie ca HIGH. Rezistențele de pull-up rezolvă această
problemă.
Rezistențele de tip pull-down funcționează în aceeași manieră ca și cele de
pull-up, cu excepția faptului ca în acest caz rezistența rezolvă dilema stării
logice prin punerea nivelului la masă.

79
Porturile de intrare – ieșire

Vcc Vcc

R1 Switch
Pull-Up

MCU MCU

R1
Switch
Pull-Down

GND GND

Fig. 8.4 Rezistențe de tip pull-up și pull-down

Valoarea corespunzătoare pentru aceste rezistențe este limitată de doi


factori. Primul factor este disiparea puterii. Dacă valoarea rezistenței este prea
mică, un curent mare va curge prin rezistență, încălzind dispozitivul și
consumând o cantitate inutilă de energie când de exemplu întrerupătorul este
închis. Al doilea factor este tensiunea de la pin atunci când comutatorul este
deschis. Dacă valoarea rezistenței e prea mare, combinată cu un curent de
scurgere mic al pinului de intrare, tensiunea de intrare poate deveni
insuficientă când comutatorul este deschis. Valoarea reală a rezistenței
depinde de impedanța pinului de intrare, care este strâns legată de curentul de
scurgere al pinului.
3.3. Portul 2 ca și port de ieșire
În exemplul următor portul 2 este folosit ca și port de ieșire:

Exemplul 1:
org 0000h ;începutul programului
mov A,#55H ;în registrul A avem numărul 55h
back:
mov P2, A
acall delay ;salt la eticheta “delay”
cpl A ;ce face instrucțiunea CPL?
sjmp back
end
Atenție, în exemplul prezentat subrutina ‘delay’, care generează întârzieri
de 1ms, nu este implementată. Se va adăuga o subrutină de întârziere pentru
ca programul să funcționeze corect.

80
Porturile de intrare – ieșire

170d = AAh
85d
P2 =
55h
P2

= 0x55

Fig. 8.5 Rezultat Exemplul 1 - Port de ieșire P2 – Keil uVision

În Portul 2 sunt scrise valorile 85 (0x55) și 170 (0xAA) pe rând cu o


întârziere de ~1 ms între ele. Acest lucru înseamnă că la fiecare pin al portului
P2 este generat un semnal dreptunghiular cu o perioadă de 2 ms:

P2_7

P2_6

P2_5

P2_4

P2_3

P2_2

P2_1

P2_0

P2 = 0 1 0 1 0 1 0 1 = 55h P2 = 1 0 1 0 1 0 1 0 = AAh

Fig. 8.6 Rezultat Exemplul 1 - Port de ieșire - 8 semnale digitale

81
Porturile de intrare – ieșire

Fig. 8.7 Forme de undă de pe osciloscop (canal analogic)

Fig. 8.8 Forme de undă (Analizor logic)

În figura Fig. 8.7 se vede ca amplitudinea semnalelor generate este 5V,


perioada Ton = Toff = 98.88 us. Știind faptul că este utilizată subrutina ‘delay’
(primul exemplu din lucrarea „rutina de întârziere soft”, explicați de ce nu
avem o întârziere de exact 1ms conform cerințelor? Modificați programul
astfel încât să rezulte un semnal cu perioada de 2 ms!

82
Porturile de intrare – ieșire

3.4. Portul 1 ca și port de intrare, portul 2 ca și port de ieșire


Când un pin/port urmează să fie utilizat ca intrare, utilizatorul trebuie să
înscrie un „1” în bistabilul corespunzător prin intermediul programului.
Pentru citirea portului/pinului de intrare există două posibilități: se poate
citi statusul pinului sau al bistabilului intern în funcție de instrucțiunile
utilizate.
Citire stare pin/port de intrare:
• MOV A, Px
• JNB P1.1, TARGET ;salt dacă bitul P1.1 nu este setat
• JB P1.1, TARGET ;salt dacă bitul P1.1 este setat

Exemplul 2:
Programul preia date de la portul P1 și le trimite la P2.
org 0000h
mov P1, #0FFh ;P1 setat ca port de intrare; P1 = 1111 1111b
back: mov A, P1 ;citire port P1
mov P2, A ;transfer data către P2
sjmp back
end

Latch intern
Pini externi

P1 = port de intrare P2 = port de ieșire

Fig. 8.9 Preluarea datelor (Keil) de la portul P1 și trimiterea lor la P2

P1:
port de intrare
P2:
port de
ieșire

Fig. 8.10 Schema realizată în programul Proteus

83
Porturile de intrare – ieșire

După cum se poate observa în figura Fig. 8.10, la controllerul 80C51 au


fost legate 8 leduri la Portul 2 (port de ieșire) și 8 selectoare de stare (logic
state) pe Portul 1 (port de intrare). Componentele logic state se pot înlocui și
cu butoane.
Câteva exemple pentru citirea bistabilului intern:
• ANL P1, A ;P1 ← P1 AND A
• ORL P1, A ;P1 ← P1 OR A
• INC P1 ;incrementează P1

Exemplul 3:
Programul scrie în portul P1 valorile 55h și AAh continuu folosind o
instrucțiune de tip read-modify-write.
org 0000h
mov P1, #0FFh ;P1 = 1111 1111b
start: mov P1,#55h ;P1 = 01010101b
again: xrl P1,#0FFh ;P1 <- P1 ^ FFh
acall delay
sjmp again
end

xrl P1,#0FFh
mov P1, #0FFh mov P1,#55h ;P1 <- P1 ^ FFh
;AAh = 55H ^ FFh

Fig. 8.11 Rularea exemplului 3 - pas cu pas

Instrucțiunea xrl (sau-exclusiv) între 55h și FFh dă rezultatul AAh,


rezultatul sau-exclusiv între AAh și FFH este 55h. Instrucțiunea xrl P1,#0FFh
citește bistabilul portului P1 (nu pinii din exterior). Rezultatul instrucțiunii
este scris în bistabil și apoi transferat la pini.
3.5. Conectarea memoriei externe la uC
Dacă microcontrolerul utilizează memoria externă, de date sau de program,
portul P0 este utilizat ca și magistrală de adrese (pentru biții cei mai puțin
semnificativi) multiplexat cu magistrala de date. De asemenea, portul P2 poate

84
Porturile de intrare – ieșire

fi utilizat ca magistrală pentru biții adresei superioare pentru a adresa memoria


externă.

Fig. 8.12 Conectarea memoriei externe la uC

Exemplul 4:
Programul scrie valoarea AAh în memoria RAM externă începând cu
adresa 0010h până la adresa 0300h și apoi verifică dacă valorile au fost scrise
corect.
org 0000h
ram_start equ ___
ram_stphi equ ___
pattern equ ___
good equ ___

mov P1, #00h


mov A, #00h
mov DPTR, #ram_start
write:
mov A, #pattern
movx @DPTR,A ;scrie conținutul lui A în
;memorie RAM externa
inc DPTR
mov A,#ram_stphi
cjne A,dph,write

mov DPTR,#ram_start
check:

85
Porturile de intrare – ieșire

movx A,@DPTR ;mută ce se găsește la adresa


;indicată de DPTR în A
cjne A,#pattern,fail
;compară conținutul lui a cu 'pattern'
inc DPTR ;caz de egalitate
mov A, #ram_stphi
cjne a,dph,check
mov p1,#good
sjmp here
fail: ___________ ;se completează de utilizator
here:
sjmp here
end

Fig. 8.13 Conectarea memoriei externe (62256) la uC8051 în Proteus

Fig. 8.14 Rularea programului cu butonul Step folosind Proteus

86
Porturile de intrare – ieșire

Fig. 8.15 Rezultate intermediare - Rularea programului pas cu pas - tasta F11

4 Modul de lucru
• Se vor rula programele de mai sus pas cu pas utilizând depanatorul de
program inclus în Keil uVision.
• Se vor face simulări în Proteus.
• Se vor testa programele pe placa de dezvoltare.
5 Aplicații
1. Să se scrie un program care citește un singur pin al portului P1.
2. Să se scrie un program care modifică portul P2 continuu.
3. Să se scrie un program care monitorizează bitul P1.5. Dacă este high
trimite 55h la P0, altfel trimite AAh la P2.
4. Să se scrie un program care generează un semnal dreptunghiular
folosind un delay format din 2 NOP-uri:
a. Folosind instrucțiunile SETB și CLR.
Cât este factorul de umplere al semnalului generat?
b. Modificați programul astfel încât să aveți un factor de umplere
de 50%.
5. Să se scrie un program ASM care realizează următoarele:
a. Monitorizați bitul 4 al portului P3 până când acesta trece în
stare “HIGH”.
b. Când acesta devine “HIGH” să se scrie valoarea 45h la portul
P0.
c. Apoi, să se scrie impulsul H-to-L în P2.3.
d. Să se scrie programul și în C
Generați fișierul *.hex și testați programul în Proteus și pe placa de
dezvoltare Aduc841.
6. Să se scrie un program care primește un octet de date de pe P1. Dacă
este mai mic decât 100, trimiteți-l la P2, altfel, trimiteți-l la P3.
7. La pinul P3.2 este conectat un buton. Să se scrie un program care la
apăsarea butonului aprinde un led conectat la P3.4. C+ASM

87
Porturile de intrare – ieșire

8. Să se scrie un program care scrie în memoria externă o anumită


valoare, pornind de la adresa 0 până la adresa „n” (unde “n” este un
număr preluat de la P1). Realizați schema în programul Proteus.
9. Să se scrie un program care monitorizează bitul P3.4. Dacă este “high”
se generează un semnal dinte de fierăstrău pe P1, altfel un semnal
triunghiular pe P2.
10. Să se scrie un program care primește un octet de la P1. Octetul
reprezintă nota studentului la examenul de uC. Dacă nota este sub 5
trimite la P2 mesajul “Respins”. Dacă octetul este un număr între 5 și
10 apare mesajul “Admis” pe P2. Dacă octetul recepționat este un
număr mai mare decât 10 programul trimite la P2 șirul de caractere
,,Eroare”. Tabelele cu mesajele (“Respins”, “Admis”) se află în
memorie la adresa 100h și 200h, mesajul ,,Eroare” este luat din
memoria externă de la adresă 00h.

88
Instrucțiuni aritmetico-logice

9 Instrucțiuni aritmetico-logice
1 Scopul lucrării
• Înțelegerea și utilizarea instrucțiunilor logice
• Scrierea și testarea programelor simple folosind instrucțiuni logice
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision.
3 Considerații teoretice
Este evident că în cazul programării microcontrolerelor un rol deosebit de
important îl joacă setul de instrucțiuni al microcontrolerului. Trebuie
menționat că în setul de acțiuni se disting câteva clase de instrucțiuni, și
anume: instrucțiuni de transfer de date, instrucțiuni aritmetico-logice și
instrucțiuni de salt (pot fi instrucțiuni de salt absolut sau relativ, condiționat
sau nu). Acest capitol se concentrează mai ales pe instrucțiunile aritmetico-
logice: ADD, ADDC, SUBB, ORL, MUL, DIV, ANL, ORL, XRL, RL, RR,
RLC, SWAP etc.
3.1.Operații aritmetice
Deoarece 8051 are o arhitectură cu acumulator, operațiile aritmetice, în
afară de increment și decrement, trebuie să folosească acumulatorul. Se pot
utiliza toate modurile de adresare pentru sursă: imediată, cu registru, directă
și indirectă. Mai departe, indicatorii de stare/condiție (flag-urile) din PSW sunt
foarte importanți în operațiile aritmetice (Exemplul 1).
De exemplu instrucțiunea ADD A, 020h va adăuga valoarea din locația de
memorie internă RAM 0x20 în acumulator folosind adresare directă.
Mnemonicele:
INC dest ;Adună 1 la destinație
DEC dest ;Scade 1 din destinație
ADD A, sursă ;Adună acumulatorul cu sursă
ADDC A, sursă ;Adună acumulatorul cu sursă şi cu C
SUBB A, sursă ;Scade sursa din acumulator
MUL AB ;Înmulțește A şi B
DIV AB ;Împarte registrul A la B
DA A ;Ajustare zecimală

89
Instrucțiuni aritmetico-logice

Instrucțiunea ADD - Exemplul 1:


Verificați cum sunt afectate flag-urile în exemplul următor (de reamintit că
toate flag-urile se află în registrul PSW):
După adunare, A = 00h iar indicatorii de
stare au valorile:
C =1 - are loc un trasport de la bitul 7 la 8;
P = 0 - avem un număr par de 1 (0);
AC =1- are loc un trasport de la bitul 3 la
bitul 4;

Fig. 9.1 Exemplul 1 – Instrucțiunea ADD

Exemplul 2:
Presupunem că locațiile de memorie RAM intern 40-44h conține valorile
următoare:

Fig. 9.2 Exemplul 2 – Instrucțiunea ADD, memoria RAM internă

Să se scrie o secvență de program care adună numerele și pune rezultatul


în R6(LSB) și R7(MSB).
Rezolvare:
MOV R0,#40H ;adresa de start
MOV R2,#5 ;număr elemente
CLR A ;A=0
MOV R7,A ;șterge R7

AGAIN: ADD A,@R0 ;adunare


JNC NEXT ;daca nu este un transport de la bitul 7 la 8
;nu trebuie adunat flag-ul Carry la MSB
INC R7 ;daca C=1 -> increment MSB
NEXT: INC R0 ;increment pointer
DJNZ R2,AGAIN ;se repeta până când R2 devine 0
MOV R6, A ;R6 = LSB

90
Instrucțiuni aritmetico-logice

Fig. 9.3 Exemplul 2 – Instrucțiunea ADD, adunarea numerelor pe 8 biți

Instrucțiunea ADDC - Exemplul 3:


Să se scrie o secvență de program care adună două numere pe 16 biți ținând
cont că suma celor două este o valoare tot pe 16 biți. Rezultatul este salvat în
R6 și R7. R6 ar trebui să conțină partea LOW și R7 partea HIGH a sumei.
Rezolvare:

CLR C ;CY=0 CY = 1
MOV A, #0E7H ;A=E7H
ADD A, #8DH ;A = E7H + 8DH = 74H
MOV R6, A ;salvare LSB
MOV A, #30H ;A = 30H
ADDC A, #39H ;A = CY(=1) + 30H + 39H = 6AH
MOV R7, A ;salvare MSB

Fig. 9.4 Exemplul 4 – Adunarea numerelor pe 16 biți

Instrucțiunea SUBB - Exemplul 4:


Analizați comportarea instrucțiunii SUBB și valoarea flag-ului Carry în
exemplul următor:

CLR C
MOV A,#60H ;A = 60H 60H – 87H - 0 = D9H; CY = 1
SUBB A,#87H ; 60H-87H = D9H; CY = 1
MOV R7,A ;salvare rezultat

MOV A,#21H ;A = 21H


21H – 10H - 1 = 10H; CY = 0
SUBB A,#10H ;21H - 10H - 1 = 10H; CY = 0
MOV R6,A ;salvare rezultat

Fig. 9.5 Exemplul 5 - Instrucțiunea SUBB

Instrucțiunea MUL ȘI DIV - Exemplul 5:


Analizați comportarea instrucțiunilor MUL și DIV în exemplul următor:
MOV A,#25H ;A = 25H

91
Instrucțiuni aritmetico-logice

MOV B,#65H ;B = 65H


MUL AB ;25H * 65H = E99 unde B = 0EH și A = 99H
MOV A,#95 ;A = 95d
MOV B,#10 ;B = 10d
DIV AB ;95 = 9*10 + 5; A = 09(câtul) și B = 05(restul)

Instrucțiunea DA - Exemplul 6:
Dacă numerele sunt reprezentate în cod BCD rezultatele operațiilor de
adunare pot fi eronate. Instrucțiunea “DA A” corectează conținutul
acumulatorului, când acesta conține rezultatul adunării a două numere
împachetate în format BCD.

După efectuarea adunării în acumulator este valoarea


BDh. Rezultatul trebuie să fie 56 + 67 = 123 (0001 0010
MOV A,#56H
0011).
ADD A,#67H
DA A
Instrucţiunea DA A va altera valoarea acumulatorului de la 0BDh
la 23h, indicând faptul că 23 este partea cea mai nesemnificativă din
rezultatul însumării lui 56 şi 67. În urma acestei instrucţiuni se va seta
flagul carry, indicând faptul că s-a produs o depăşire, rezultatul corect
fiind 123:

Fig. 9.6 Exemplul 6 - Instrucțiunea DA

Fig. 9.7 Tabelul BCD

92
Instrucțiuni aritmetico-logice

3.2.Operații logice
Cu ajutorul instrucțiunilor logice se pot realiza teste la nivel de bit, ceea
ce permite un răspuns prompt al aplicației la schimbări și o dimensiune redusă
a codului utilizatorului.
Există zone din memorie și regiștri din SFR care pot fi adresate la nivel de
bit. Adresabilitatea pe biți conferă o serie de avantaje în aplicațiile industriale,
unde de cele mai multe ori este nevoie de memorarea stării unor comutatoare
sau alte periferice cu stări binare. În locul grupării variabilelor de tip bit
aferente mai multor periferice într-un singur octet apoi manipularea acelui
octet, se preferă stocarea variabilelor independent, în zona adresabilă pe biți.
Astfel, manipularea acestui tip de date devine mult mai rapidă.
Operațiile logice sunt aplicabile la nivel de bit sau octet.
Operații logice la nivel de octet:
ANL A,#15h ;A ȘI 15h
ORL 15h, #88h ;conținutul adresei 15h SAU numărul 88h
XRL A, R0 ;R0 SAU EXCLUSIV acumulator
CLR A ;ŞTERGE fiecare bit din acumulator; A devine 00h;
CPL A ;COMPLEMENTEAZĂ fiecare bit din A
;1 devine 0 şi 0 devine 1
Exemple:
Instrucțiunea ANL dest, source realizează operația ŞI logic între dest şi
source, rezultatul este salvat în dest.

Se foloseşte la operaţia
de "mascare (șterge
anumiți biți)

Fig. 9.8 ANL

Instrucțiunea ORL dest, source realizează operația SAU logic între dest
şi source, rezultatul este salvat în dest.

Se foloseşte pentru a
seta diferiţi biţi

Fig. 9.9 ORL

93
Instrucțiuni aritmetico-logice

Instrucțiunea XRL dest, source realizează operația SAU EXCLUSIV


între dest şi source, rezultatul este salvat în dest.

Se foloseşte pentru a
anula sau seta diferiţi
biţi.

Fig. 9.10 XRL

Unde:
- dest poate fi acumulatorul sau o adresă în memoria RAM internă
- source este o valoare imediată, conținutul unei adrese, conținutul
registrului Rn sau conținutul adresei din registrul Rn
Observații:
• Operațiile logice la nivel de octet utilizează toate cele 4 moduri de
adresare a operatorului sursă.
• Dacă adresa directă destinație este cea a unui port, se utilizează
întotdeauna pentru operația logică bistabilul asociat portului şi nu
informația prezentă la pinii acestuia.
• Prin operațiile logice menționate nu este afectat nici un indicator de
condiție (FLAG) (excepție face cazul când adresa directă este cea a
registrului PSW).
• Numai memoria RAM internă și SFR suportă operații logice.
Lista operațiilor logice la nivel de bit:
ANL C, bit ;ŞI logic între bitul adresabil şi Carry
;rezultatul în C
ORL C, bit ;SAU logic între bitul adresabil şi Carry
;rezultatul în C
CLR bit ;șterge bitul adresabil ‘bit’
CLR C ;șterge indicatorul C
SETB bit/C ;setează bitul adresabil ‘bit’/indicatorul C
CPL bit ;complementează bitul adresabil ‘bit’
CPL C ;complementează indicatorul C
JB bit, label ;salt relativ dacă bit este 1
JNB bit, label ;salt relativ dacă bit este 0
JC bit, label ;salt relativ dacă Carry este 1
JNC bit, label ;salt relativ dacă Carry este 0
MOV C, bit ;copiază bitul adresabil ‘bit’ în C
MOV bit, C ;copiază C în bitul adresabil ‘bit’

94
Instrucțiuni aritmetico-logice

Atenție: La instrucțiunea MOV <dest>, <src-bit> unul dintre operanzi


trebuie să fie Carry flag.

Instrucțiuni de rotire
Instrucțiunile de rotire sunt aplicabile doar la nivel de octet. Instrucțiunea
RL A rotește un octet la stânga. Cel mai semnificativ bit (MSB) devine cel mai
puțin semnificativ bit (LSB) și nici un indicator de stare nu este afectat.

7 6 5 4 3 2 1 0 Înainte: 1001 1100


După: 0011 1001

Fig. 9.11 Instrucțiunea RL

Instrucțiunea RLC A rotește un octet la stânga prin Carry. Bitul LSB ia


valoarea indicatorului Carry, fiecare bit fiind mutat cu o poziție spre stânga iar
bitul C devine fosta valoarea a bitului MSB. Alți indicatori de condiție nu sunt
afectați de operație.

C 7 6 5 4 3 2 1 0 Înainte: CY = 0, A = 1001 1100


După: CY = 1, A = 0011 1000

Carry Flag

Fig. 9.12 Instrucțiunea RLC

Instrucțiunea RR A rotește un octet la dreapta; LSB – devine MSB:


7 6 5 4 3 2 1 0 Înainte: 1001 1100
După: 0100 1110

Fig. 9.13 Instrucțiunea RR

Instrucțiunea RRC A rotește un octet la dreapta prin C. LSB devine C, iar C


devine MSB:
7 6 5 4 3 2 1 0 C
Înainte: A = 1001 1100, CY = 1
După: A = 1100 1110, CY = 0
Carry Flag

Fig. 9.14 Instrucțiunea RRC

Instrucțiunea SWAP A schimbă între ei cei mai puțini semnificativi 4 biți


(nibble) cu cei mai semnificativi:

95
Instrucțiuni aritmetico-logice

7 6 5 4 3 2 1 0
MSB LSB Înainte: 1001 1100
După: 1100 1001

Fig. 9.15 Instrucțiunea SWAP

Exemplul 7:
Programul numără biții de 1 dintr-un număr salvat în acumulator folosind
instrucțiunea RLC A. Pune în Carry (pe rând) biții și verifică dacă ei sunt
egali cu 0 sau nu. Dacă Carry este 0, urmează bitul următor, altfel se
incrementează rezultatul și apoi este verificat bitul următor. Rezultatul este
salvat în R1.

ORG 0000
MOV R1, #0H
MOV R7,#08H ;contor
MOV A,#97H
CLR C C 7 6 5 4 3 2 1 0
AGAIN:
RLC A Carry Flag
JNC NEXT
INC R1 ;daca CY == 1 -> increment rezultat
NEXT: ;salt la bitul urmator
DJNZ R7,AGAIN
END

Fig. 9.16 Exemplul 7 - Numărul de 1 într-un număr binar

3.3.Stiva și SP (indicatorul de stivă)


Stiva este o zonă din memorie utilizată pentru a stoca anumite informații
pentru o anumită perioadă urmând ca ulterior să fie folosite.
Registrul de 8 biți (SP) este utilizat pentru a indica adresa numită „vârful
stivei”. Adresa menținută în SP este locația RAM unde a fost stocat octetul
ultimei operații cu stiva.
Când data este plasată în stivă SP se incrementează, înainte ca data să fie
stocată, astfel că stiva crește pe măsura stocării datelor.
La extragerea unei date din stivă, SP se decrementează.
Când microcontrolerul este resetat SP este setat la 07h. Această adresă nu
este convenabilă pentru majoritatea aplicațiilor, deoarece orice operație cu
stiva corupe bancul de regiștrii B1. În acest scop este indicată modificarea

96
Instrucțiuni aritmetico-logice

SP din program, astfel încât acesta să se situeze în zona de RAM intern de uz


general (peste adresa 30h). Stiva este limitată de dimensiunea memoriei RAM.

Exemplul 8:
Programul salvează în stivă numerele de la 1 până la 5. După salvarea
numerelor programul le preia de pe stivă și le afișează pe P2.
org 0000H
main:
mov a,#01h
stiva:
push acc ;adăugarea elementului salvat în acumulator
;la vârful stivei
inc a ;increment acumulator
cjne a,#06h,stiva ;programul se oprește daca numărul 5 a fost
;salvat în stivă
display:
pop acc ;extragerea datei din stivă și salvarea ei
;în acumulator
mov P2,a
cjne a,#01h,display

sjmp $
end

În figura următoare este prezentată salvarea și extragerea elementelor din


stivă. Se poate observa cum se modifică indicatorul de stivă în funcție de
instrucțiunea folosită: pop sau push.
Stochează date în Etichetă display Addr:
SP = 0CH
stivă 0CH 05H
Addr: ACC = 05H POP ACC
SP = 0CH
0CH 05H Addr:
PUSH ACC SP = 0BH
10H 04H
... ... ACC = 04H POP ACC
... ...
PUSH ACC
Addr: Extrage date din
SP = 08H stivă
08H 01H Addr:
SP = 08H
PUSH ACC 08H 01H
ACC = 01H POP ACC
Etichetă start SP = 07H
SP = 07H

Fig. 9.17 Instrucțiunile pop și push, valoarea indicatorului de stivă

Valoarea indicatorului de stivă, respectiv conținutului stivei se poate


verifica și în programul Keil uVision:

97
Instrucțiuni aritmetico-logice

SP = 08H

Fig. 9.18 Fereastra Watch și Fereastra de Memorie (RAM intern)

Cum a fost menționat și mai sus, când lucrăm cu stiva trebuie să avem grijă
să nu suprascriem date din memorie, stiva putând creşte peste o zonă de
memorie utilizată pentru alte scopuri. În exemplu următor pentru a evita
această problemă valoarea SP este inițializată cu 30h:
mov SP,#30h.

SP = 31H

Fig. 9.19 SP = 0x30

4 Modul de lucru
• Se deschide Keil uVision și folosind meniul Help se verifică sintaxele
posibile pentru instrucțiunile aritmetico-logice.
• Se vor testa programele folosind depanatorul de program inclus în Keil
uVision.
• Se va simula în Proteus.
• Se vor testa programele pe placa de dezvoltare.
5 Aplicații
1. Verificați următoarele secvențe de program:
a).
MOV A,#23H
ANL A,#F0H ;A = ?
b).
MOV A,#23H

98
Instrucțiuni aritmetico-logice

ORL A,#0FH ;A = ?
c).
MOV P1,#0FFH
START:
MOV A,#0FH
XRL P1, A ; P1 = ?; A = ?
SJMP START
d).
MOV A,#54H
SWAP A ;A=?
Ce valoare se găsește în acumulator? În absența unei instrucțiuni SWAP,
cum ați schimba nibble-urile? Scrieți un program simplu pentru
exemplificare.
2. Scrieți un program care adună patru numere salvate în memoria externă
începând de la adresa 50h:

Fig. 9.20 Problema 2 – Memoria externă

Puneți rezultatul în R0 (MSB) și R1 (LSB).


3. Scrieți un program care preia un octet de la portul P2. Dacă numărul preluat
este mai mic decât 127 trimiteți-l pe portul P1, altfel pe portul P3.
4. Scrieți un program care preia un octet de la portul P2 și numără biții de 0.
Folosiți portul P1 să afișați rezultatul numărătorii. Testați programul scris și
în Proteus.

10010001b = 91h

a). b).

Fig. 9.21 Testare în programul Keil; b). Testare în programul Proteus

5. Scrieți un program care calculează pătratul lui 69h și stochează partea LOW
în R5 și partea HIGH în R4:

99
Instrucțiuni aritmetico-logice

69h x 69h = 2B11h → R4 = 2Bh; R5 = 11h

Fig. 9.22 Problema 4 - Fereastra cu regiștri

Modificați problema astfel încât să meargă în mod continuu la infinit iar


numărul al cărui pătrat trebuie determinat să fie preluat de la portul P2.
6. Să se scrie un program care primește un număr în hexa aflat în intervalul
00h-0ffh din portul 3 și îl convertește în zecimal. Numărul în zecimal este
salvat în R0 (unitățile), R1 (zecile) și R2 (sutele).

Fig. 9.23 Problema 5: A2h = 162d

7. Să se scrie două subrutine care transferă o valoarea pe 8 biți bit cu bit prin
P3.1:
a). Primul bit transferat e bitul LSB.
b). Primul bit transferat e bitul MSB.
Să se pună două valori HIGH la începutul și la sfârșitul transferului. Să fie
transferate valorile: 14h, 54h, 91h și 82h folosind subrutinele
implementate.

100
Instrucțiuni aritmetico-logice

Fig. 9.24 Problema 6 – Rezultate – Subrutina LSB.

8. Să se scrie un program care preia un bit la un moment dat de la pinul P1.7.


După recepționarea a 8 biți aceștia sunt salvați în registrul R0 și trimiși
către portul P2.

Fig. 9.25 Problema 7 - Rezultate

9. Se presupune că portul P2 conține o valoarea codificată BCD. Scrieți un


program pentru a converti BCD-ul în două numere ASCII și așezați-le în
R0 și R1.

Fig. 9.26 Problema 8 - Rezultate

101
Instrucțiuni aritmetico-logice

10. Se presupune că cei trei pini superiori ai P3 (P3.7, P3.6 și P3.5) sunt
conectați la 3 comutatoare. Să se scrie un program pentru a trimite
următoarele caractere ASCII la P1 pe baza stării comutatoarelor:

000 → ‘0’
001 → ‘1’
010 → ‘2’
011 → ‘3’
100 → ‘4’
101 → ‘5’
110 → ‘6’
111 → ‘7’
Fig. 9.27 Problema 9 – Rezultate Keil

Fig. 9.28 Problema 9 – Rezultate Proteus

102
Timer-ele și numărătoarele

10 Timer-ele și numărătoarele
1 Scopul lucrării
• Studiul metodelor de realizare a rutinelor de întârziere hard
(utilizând metoda interogării);
• Studiul funcționării numărătoarelor;
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision.
• Placa de dezvoltare Aduc841 și osciloscopul digital Analog
Discovery.
3 Considerații teoretice
Multe aplicații cu microcontrolere presupun contorizarea unor evenimente:
✓ numărarea impulsurilor externe (când timer-ul îndeplinește funcția
de numărător) sau
✓ realizarea unor întârzieri precise.
Pentru a adresa punctele menționate anterior microcontrolerele din familia
8051 au periferice interne Timer/Counter.
Timer-ele sunt divizate (fiecare) în 2 regiștri de câte 8 biți: octetul inferior
(TL0, TL1) și octetul superior (TH0, TH1).
Toate acțiunile timere-lor sunt controlate de starea biților din registrul de
mod TMOD și cel de control TCON.
MSB LSB
GATE C/T M1 M0 GATE C/T M1 M0

TIMER 1 TIMER 0
GATE - Setat, porneşte timerul 1/0 dacă bitul TR1/0 = 1 şi INT1/0 = 1 (Control hardware)
Şters, validează timerul dacă TR1/0 = 1 (Control software)
C/T - Setat, numără impulsurile externe de la pinii P3.5(T1) sau P3.4 (T0)
Şters determină funcţionarea ca timer

M1 M0 Modul de funcţionare
0 0 Mod 0
0 1 Mod 1
1 0 Mod 2
1 1 Mod 3
Fig. 10.1 Registrul TMOD

103
Timer-ele și numărătoarele

Timer-ele pot funcționa în 4 moduri determinate de biții M1 și M0 din


registrul TMOD.
MSB LSB
TF1 TR1 TF0 TR1 IE1 IT1 IE0 IT0

BIT SIMBOL FUNCȚIE


TCON.7 TF1 Flag depăşire pentru T1. Este setat când registrul timer se resetează. Şters când
procesorul execută un salt la adresa 001Bh ce conţine rutina ce deserveşte această
întrerupere sau șters din software.
TCON.6 TR1 Bit de control PORNIT/OPRIT. Setat de program validează T1 să numere. Şters
aduce T1 în stare oprit.
TCON.5 TF0 Flag depăşire pentru T0. Este setat când registrul timer se resetează. Şters când
procesorul execută un salt la adresa 000Bh ce conţine rutina ce deserveşte această
întrerupere sau șters din software.
TCON.4 TR0 Bit de control PORNIT/OPRIT. Setat de program validează T0 să numere. Şters
aduce T0 în stare oprit; nu resetează conţinutul T0.
TCON.3 IE1 Flag întrerupere externă 1. Setat când apare un front căzător (din 1 în 0) la pinul 3
al portului 3 (INT1). Şters când apare un salt la adresa 0013h unde se află rutina de
tratare a întreruperii.
TCON.2 IT1 Tipul întreruperii externe. Setat, va valida întreruperile pe frontul căzător. Şters, va
genera întrerupere pe nivelul LOW al semnalului.
TCON.1 IE0 La fel ca IE1 dar pentru INT0 (pin P3.2)
TCON.0 IT0 La fel ca IT1 dar pentru cazul INT0.
Fig. 10.2 Registrul TCON

3.1. Modul 0
Registrul THx este setat ca numărător pe 5 biţi iar TLx este setat ca
numărător pe 8 biţi, în acest fel frecvența de intrare este divizată la 32 de
primul numărător şi cu 384 în total.

Fig. 10.3 Structura timer-ului în modul 0

3.2. Modul 1: 16-bit Timer


Registrul THx, respectiv TLx sunt setați ca numărătoare pe 8 biți.

Fig. 10.4 Structura timer-ului în modul 1

104
Timer-ele și numărătoarele

Exemplul 1:
Să se genereze un semnal dreptunghiular cu un factor de umplere de 50%
la pinul P3.4. Întârzierea necesară este generată de TIMER-ul 0, modul 1.
Programul va fi scris în asamblare.

Rezolvare:
Pentru a genera o întârziere utilizând TIMER-ul în modul 1 trebuie parcurși
următorii pași:
1. Se încărcă registrul TMOD cu o valoare corespunzătoare prin care se
alege modul de funcționare.
2. Se încărcă regiștrii TH, respectiv TL cu valoarea inițială.
3. Se pornește timer-ul: setb TRx sau setb TCON.6 (Timer 1)/ setb TCON.4
(Timer 0)
4. Se monitorizează flag-ul de depășire TF cu o instrucțiune de tipul JNB
TFx, label
5. Se oprește timer-ul: clr TRx
6. Se șterge flag-ul de depășire: clr TFx;
7. Se merge înapoi la pasul 2 şi se reîncărcă regiştrii TLx şi THx cu valoarea
corespunzătoare.

ORG 0000H
LED equ P3.4
CONFIG:
ORL TMOD,#01 ;este selectat modul 1 pentru timer-ul 0
START:
MOV TL0, #67h ;se încarcă valoarea inițială în registrul TL0
MOV TH0, #0A2h ;se încarcă valoarea inițială în registrul TH0
CPL LED ;se complementează bitul P3.4
ACALL DELAY
SJMP START
DELAY:
SETB TR0 ;se pornește timer-ul 0; SETB TCON.4
AGAIN: JNB TF0, AGAIN ;se monitorizează flag-ul de depășire
CLR TF0 ;se șterge flag-ul; CLR TCON.5
CLR TR0 ;oprire timer; CLR TCON.4
RET
END

105
Timer-ele și numărătoarele

...

Valoare
de start: A267 A268 FFFF 0000
A267h TFx = 0 TFx = 0 TFx = 0 TFx = 1

Fig. 10.5 Rularea codului pas cu pas - Fereastra Timer (Meniu Peripherals/Timer)

TH0 = A2h
TL0 = 67h

 DELAY = FFFFH – A267H =


5D98H = 23960 23960 + 1 =23961
23961 × 1.085 μs = 25.99 ms

Fig. 10.6 Formă de undă - Keil uVision: uC8051

 DELAY = FFFFH – A267H =


5D98H = 23960 23960 + 1 =23961
23961 × 0.0905 μs = 2.16 ms

Fig. 10.7 Formă de undă - Keil uVision: Aduc841

 DELAY = FFFFH – A267H =


5D98H = 23960 23960 + 1 =23961
23961 × 0.0905 μs = 2.16 ms

Fig. 10.8 Formă de undă - placa de dezvoltate, WaveForms

106
Timer-ele și numărătoarele

Exemplul 2:
Să se modifice portul P2 continuu cu o întârziere de 1 ms. Utilizați Timer-
ul 0, modul 1 pentru a genera întârzierea. Programul va fi scris în C. Fclk =
11.0592 MHz, uC8051.
Calculul valorii ce trebuie încărcată în timer (MODUL 1) pentru a realiza
o anumită întârziere (frecvența de tact având valoarea 11.0592 MHz):
1. Se divide întârzierea dorită: n = delay_dorit/TCM (TCM = 1.085 us)
2. Se calculează valoarea 65536-n, unde n este valoarea calculată în pasul 1.
Se transformă valoarea obținută în hexa.
3. Se încărcă regiştrii TL respectiv TH cu valoarea astfel obținută

Dacă întârzierea dorită este 1 ms:


1. 1000 us/1.085 us = 921
2. 65536 – 921 = 64615 = (FC67)h
3. TH0 =FCh; TL0 = 67h

#include <reg51.h>
void T0Delay(void);
void main(void)
{
while (1)
{
P2=0x55;
T0Delay();
P2=0xAA;
T0Delay();
}
}
void T0Delay(){
TMOD=TMOD | 0x01;
TL0=0x67;
TH0=0xFC;
TR0=1;
while (TF0==0);
TR0=0;
TF0=0;
}

107
Timer-ele și numărătoarele

Fig. 10.9 Pinul P2.0 - formă de undă: Keil uVision (uC8051)

Fig. 10.10 Fereastra Performance Analyzer

Fereastra Performance Analyzer este în meniul View/Analysis


Windows/Performance Analyzer. În fereastra Setup se selectează funcția
T0Delay() și se apasă butonul Define. Acum în fereastra Performance
Analyzer se poate verifica timpul mediu al întârzierii generat: 0.001 s = 1 ms.

Exemplul 3:
Se folosește microcontrolerul Aduc841 în loc de uC 8051.
Dacă întârzierea dorită este 1 ms:
1. 1000 us/0.095 us = 11049
2. 65536 – 11049 = (54487)dec = (D4D7)hex → TH0 =D4h; TL0 = D7h

Se va modifica exemplul 2 astfel:


TL0=0x67; TL0=0xD7;
TH0=0xFC; TH0=0xD4;

Fig. 10.11 Pinul P2.0 - formă de undă: Keil uVision (Aduc841)

108
Timer-ele și numărătoarele

Fig. 10.12 Formă de undă - placa de dezvoltare, WaveForms

3.3. Modul 2: 8-bit Auto-Reload Timer (autoîncărcare)

Fig. 10.13 Structura timer-ului în modul 2

TLx este setat să lucreze ca un timer pe 8 biți. THx este utilizat să mențină
valoarea care este reîncărcată în TLx de fiecare dată când TLx trece de la
valoarea FFh la 00h. Flag-ul TFx este de asemenea setat când TLx trece din
FFh în 00h.

Exemplul 4:
Să se genereze un semnal dreptunghiular cu un factor de umplere de 50%
la pinul portului P3.4. Întârzierea necesară este generată de timer-ul 1, modul
2 în ASM
Rezolvare:
Pentru programarea timer-ului în modul 2 se parcurg următorii pași:
1. Se încărcă registrul TMOD cu o valoare corespunzătoare;
2. Se încărcă regiștrii TL și TH cu valoarea inițială;
3. Se pornește timer-ul;
4. Se monitorizează flag-ul TF;
5. Se șterge flag-ul TF;
6. Se merge înapoi la pasul 4.

109
Timer-ele și numărătoarele

ORG 0000h
ORL TMOD, #20h ;pas1: este selectat modul 2 pentru timer-ul 1
MOV TH1, #5 ;pas2: se încarcă valoarea inițială în TH0
MOV TL1, TH1 ;255 + 1 - 5 = 251 x 1.085usec = 272.3
SETB TR1 ;pas3: se pornește timer-ul 0;
TIMER:
DO: JNB TF1, DO ;pas4: se monitorizează flag-ul de depășire;
CLR TF1 ;pas5: se șterge flag-ul TF;
CPL P3.4
SJMP TIMER ;pas6: se merge înapoi la pasul 4
END

 DELAY = 255 – 5 = 250


250 + 1 =251
251 × 1.085 μs = 272.3 us

Fig. 10.14 Pinul P3.4 - formă de undă: Keil uVision (uC8051)

 DELAY = 255 – 5 = 250


250 + 1 =251
251 × 0.0905 μs = 22.71 us

Fig. 10.15 Formă de undă - placa de dezvoltate, WaveForms (Aduc841)

Exemplul 5 (8051):
Să se genereze un semnal dreptunghiular cu o frecvență de 10 kHz și factor
de umplere 50% la pinul P2.7. Întârzierea necesară este generată de timer-ul 1
în modul 2. Fclk = 11.0592MHz. Programul se va scrie în C.

110
Timer-ele și numărătoarele

Calculul valorii ce trebuie încărcată în timer (MODUL 2) pentru a realiza


o anumită întârziere (frecvența de tact având valoarea 11.0592 MHz):
1. Se divide întârzierea dorită la 1.085 us (ciclu mașină):
n=delay_dorit/TCM
2. Se calculează valoarea 256-n, unde n este valoarea calculată în pasul 1.
Se transformă valoarea obținută în hexa.
3. THx = valoarea (h - hexazecimal) astfel obținută SAU THX = -n (d-
zecimal).

Dacă frecvența dorită este 10 kHz perioada semnalului este egală cu 100
µs. Ton = Toff este 50 us.
1. CM = 12/11.0592 MHz = 1.085 µs
2. n = Ton/CM = 50 µs /1.085 µs = 46
3. FF + 1 = 256 – n = 210 = D2h
4. THX = D2h sau THX = -n = -46d

MOV TH1,#D2h MOV TH1,#-46


Fig. 10.16 Se încărcă registrul TH cu valoarea inițială

#include <reg51.h>
void T1M2Delay(void);
sbit mybit=P2^7;
void main(void){
TMOD= TMOD | 0x20;
H1=-46;
TL1 = TH1;
TR1=1;
while (1) {
mybit=~mybit;
T1M2Delay();

111
Timer-ele și numărătoarele

}
}
void T1M2Delay(void){
while (TF1==0);
TF1=0;
}

Fig. 10.17 Pinul P2.7 - formă de undă: Keil uVision (uC8051)

3.4. Modul 3
Timer-ul 0 va funcționa ca 2 numărătoare independente de 8 biți.
Timer-ele 0 şi 1 pot fi programate în modul 0, 1 şi 2 să lucreze independent,
lucru ce nu se mai întâmplă pentru modul 3.
Dacă se alege modul 3 pentru timer-ul 0, timer-ele nu mai pot funcționa
independent. Punând timer-ul 1 în modul 3, acesta va înceta să numere. Bitul
de control TR1 şi flag-ul TF1 vor fi utilizați de timer-ul 0.
3.5. Numărătoare
Ne amintim că bitul C/T din registru TMOD decide dacă timer-ul numără
impulsurile interne sau impulsurile externe. Dacă C/T= 0, timer-ul primește
impulsurile de la oscilatorul intern, în caz contrar sunt numărate impulsurile
externe (pinul T0 – P3.3, respectiv T1 – P3.4).
Fiecare front descrescător (tranziție 1-0) va incrementa numărătorul.
Fiecare stare „high” sau „low” va trebui menținută stabilă pentru cel puțin un
ciclu mașină.

Exemplul 6:
Se presupune că impulsurile vin la pinul T1.
• Numărătorul 1 este programat în modul 1;
• Starea registrului TL1 este livrată la pinii portului P1;

112
Timer-ele și numărătoarele

• Starea registrului TH1 este livrată la pinii portului P2;

Cod ASM:
ORG 0000H
CONFIG:
ORL TMOD,#01010000b ;este selecționat modul 1 pentru counter-ul 1;
SETB T1 ;T1 pin de intrare (p3.5)
START:
MOV TL1, #00h ;se încarcă valoarea inițială în registrul TL0;
MOV TH1, #00h ;se încarcă valoarea inițială în registrul TH0;
SETB TR1 ;se pornește timer-ul 0; SETB TCON.4
COUNTER:
MOV P1,TL1
MOV P2,TH1
JNB TF1, COUNTER ;se monitorizează flag-ul de depășire
;TF0=TCON.5
CLR TF1 ;CLR TCON.5
JMP START
RET

Rezultat: 0003

Fiecare front descrescător


(tranziție 1-0) va incrementa
numărătorul

T1 Pin

Fig. 10.18 Numărătorul T1 - Test în Keil uVision

Cod C:
#include <reg51.h>
void main(void){
TMOD=0x50;
TH1 = 0;
TL1 = 0;
TR1 = 1;
while (1) {
do {
P1 = TL1;

113
Timer-ele și numărătoarele

P2 = TH1;
}
while (TF1==0);

TF1=0;
}
}

4 Modul de lucru
• Se vor rula programele de mai sus pas cu pas utilizând depanatorul de
program inclus în Keil uVision.
• Se vor face simulări în Proteus.
• Se vor testa programele pe placa de dezvoltare.
5 Aplicații
1. Indicați care timer și în ce mod a fost programat pentru fiecare din
instrucțiunile următoare:
a. MOV TMOD,#01h
b. MOV TMOD,#20h
c. MOV TMOD,#12h

Timer 0 & 1 – Modul 1

2. Scrieți un program care să comute în mod continuu valoarea bitului


P3.4 la fiecare 50ms. Utilizați Timer-ul 1 în modul 1 pentru a crea
întârzierea.
3. Scrieți un program care să comute în mod continuu valoarea bitului
P3.4 la fiecare 100ms. Utilizați Timer-ul 0 în modul 1 pentru a crea
întârzierea (Factor de umplere: 50%, Perioada 200 ms). C+ASM
Observație:
10Hz; T=1/10 Hz = 100 ms
100 000µs/1.085 µs = 92 165
65 536 - 92 165 = -29 629 < 0
Timer-ul în modul 1 poate numără de la 0000 pănă la FFFFh,
întârzierea generată este (FFFF+1) x 1.085 = 71ms. Dacă se doresc
întârzieri mai mari atunci trebuie realizată o întârziere de bază (de ex.
de 50 ms) care se repetă de n ori (2x50 ms = 100 ms).

114
Timer-ele și numărătoarele

4. Scrieți un program pentru a obține o frecvență de 10 Hz la pinul P3.4.


Utilizați Timer-ul 0 în modul 1 pentru a crea întârzierea (Factor de
umplere: 40%)
Observație:
40 ms – delyON: THx, TLx → 40 ms
60 ms – delayOff: THx, TLx → 60 ms
5. Un buton este conectat la P3.2 Scrieți programele pentru 8051 în
ASM+C care monitorizează bitul P3.2 și generează un semnal
dreptunghiular cu următoarele frecvențe la P1.7:
SW=0: 500 Hz
SW=1: 750 Hz
Utilizați Timer-ul 1 în modul 1 pentru ambele frecvențe.
6. Scrieți un program care monitorizează bitul P3.2 până când acesta trece
în LOW. Când acesta trece în LOW scrieți prenumele vostru pe portul
P0 cu o întârziere de 70ms. Utilizați Timer-ul 1 în modul 1. Testați
exemplul în programul Proteus și pe placa de dezvoltare.

Timer 0 & 1 – Modul 2

7. Scrieți un program care generează un semnal dreptunghiular cu o


frecvență de 5 kHz la pinul P2.7. Utilizați Timer-ul 1 în modul 2 pentru
a genera întârzierea (Factor de umplere: 50%).
8. Scrieți un program care generează un semnal dreptunghiular cu o
frecvență de 2.5 kHz la pinul P2.7. Utilizați Timer-ul 1 în modul 2
pentru a genera întârzierea (Factor de umplere: 60%).
9. Scrieți un program care generează un semnal dreptunghiular cu o
frecvență de 500Hz la pinul P2.5. Utilizați Timer-ul 0 în modul 2 pentru
a genera întârzierea.

Numărătoare

10. Scrieți un program presupunând că un buton este conectat la T0 (P3.4),


care să folosească numărătorul 0 în modul 1 și să afișeze pe portul P2
starea acestuia. Porniți numărătoarea de la 05h.
11. Un buton este conectat la P3.5. Scrieți un program care numără de câte
ori a fost apăsat butonul folosind un counter.

115
Portul Serial

11 Portul Serial
1 Scopul lucrării
• Studiul rutinelor de transmisie și recepție serială folosind metoda
interogării
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision.
• Placa de dezvoltare Aduc841 și osciloscopul digital Analog
Discovery
3 Considerații teoretice
Un calculator trebuie să fie capabil să comunice cu alte calculatoare în
sistemele multiprocesor. O modalitate de comunicare este portul serial. 8051
are un periferic dedicat de comunicație serială (UART full duplex) ce
utilizează registrul SBUF pentru stocarea datelor. Pentru SBUF există doi
regiștri care se găsesc la aceeași adresă. Modul în care este utilizat registrul
depinde de ce operație se efectuează:
• Scriere - este inițiată o transmisie;
• Citire - se preiau datele recepționate.
Registrul SCON controlează comunicația serială în timp ce PCON
controlează rata de comunicație alături de timer-ul 1.
MSB LSB
SM0 SM1 SM2 REN TB8 RB8 TI RI

SM0 SM1 Mod Descriere


0 0 0 8 biţi, baud = f/12
0 1 1 8 biţi, baud variabil
1 0 2 9 biţi, baud = f/32 sau f/64
1 1 3 9 biţi, baud variabil
SM2 - Bit pentru comunicaţia multiprocessor.
REN - Setat în 1 pentru a valida recepţia.
TB8 - Conţine cel de-al 9-lea bit de transmis (modurile 2 și 3)
RB8 - Conţine cel de-al 9-lea bit de recepționat (modurile 2 și 3)
TI - Flag întrerupere la transmisie
RI - Flag întrerupere la recepție
Fig. 11.1 Registrul SCON

116
Portul Serial

3.1. Rata de comunicație în modul 1


Pentru generarea ratei de transfer este utilizat Timer-ul 1 în modul 2 (timer
de 8 biți cu autoîncărcare). Pentru a determina valoarea ce trebuie încărcată în
registrul TH1 al timer-ului se utilizează următoarea relație:
2SMOD Fclk
fbaud =  ec. 1
32 12  (256 − TH1)
Unde:
- SMOD este bitul 7 din registrul PCON, bitul de modificare a ratei de
comunicație. Setat în “1” va dubla rata de comunicație în modurile 1, 2
și 3.

Dacă se dorește o rată de transfer standard frecvența oscilatorului uC


trebuie aleasă cu grijă pentru a obține o eroare cât mai mică la generarea ratei
de transfer a caracterelor. De exemplu, dacă Fclk=11.0592 MHz și rata de
transfer se alege 9600 biți/s atunci TH1 va avea valoarea:
 20 11.0592 106 
TH 1 = 256 −    = 256 − 3 = 253 = FDh ec. 2
 32 12  9600 
În tabelul de mai jos sunt prezentate valorile uzuale pentru viteza de
transfer a caracterelor și modalitatea de obținere a acestora atunci când se
folosește ca și generator de baudrate timer-ul T1 și Fclk=11.0592 MHz, pe baza
relației de mai sus.
Tab. 11-1 Ratele de baud uzuale - uC8051

TH1 (zecimal) TH1 (hex)


Baud Rate
9600 -3 FD
4800 -6 FA
2400 -12 F4
1200 -24 E8
Atenție, la microcontrolerul Aduc841 formula este modificată în felul
următor. Pe baza cunoștințelor deja acumulate explicați care este diferența și
de ce apare ea:

2SMOD Fclk
fbaud =  ec. 3
32 256 − TH1

117
Portul Serial

 20 11.0592 106 
TH1 = 256 −    = 256 − 36 = 220 = DCh ec. 4
 32 9600 
3.2. Transmisia datelor
Transmisia serială începe ori de câte ori un octet este înscris în SBUF. TI
este setat în “1” când octetul este transmis și SBUF este gol, astfel un alt octet
poate fi transmis.

Exemplul 1:
Scrieți un program care să transmită în continuu litera “A” pe portul serial
cu 4800 baud, 8N1 (8-biți de date, fără paritate, 1 bit de stop).

Rezolvare:
Pentru trimiterea caracterelor pe portul serial se parcurg următorii pași:
1) Timer-ul 1 este oprit prin intermediul bitului TR1=0.
2) În registrul TMOD este încărcată valoarea 20H, pentru a utiliza
T1&M2 timer-ul 1 în modul 2 (8-bit auto-reload).
3) În regiștrii TL1 și TH1 este încărcată valoarea corespunzătoare
pentru baud rate-ul dorit.
4) În registrul SCON este încărcată valoarea 40H, pentru modul 1
(al portului serial), 8 biți de date și câte un bit de start și stop.
5) Bitul TR1 ia valoarea “1” pentru pornirea timer-ului 1.
6) Octetul ce reprezintă caracterul transferat folosind portul serial
este încărcat în registrul SBUF.
7) Flag-ul TI este monitorizat folosind instrucțiunea JNB TI,xx
pentru a ști când a fost transmis întregul caracter.
8) Flag-ul TI este trecut înapoi în “0” folosind instrucțiunea CLR
TI.
9) Pentru a transfera următorul byte trecem iar la pasul 6.
Obs: Transmisia serială poate fi realizată și fără a interoga bitul TI, dacă
programatorul ține cont de durata de timp necesară pentru transmiterea
datelor, scriind o nouă valoare în SBUF după trecerea acestui interval de timp.

Test 8051:
Cod ASM:
ORG 0000H

118
Portul Serial

CLR TR1
MOV TMOD,#20H ;T1M2 -> Baud Rate
MOV TH1,#-6 ;BR = 4800
MOV TL1,TH1
MOV SCON,#40H ;SM0 = 0; SM1 = 1
SETB TR1 ;pornire timer
TRANS:
MOV SBUF,#"A" ;caracterul 'A' este încărcat în registrul SBUF
HERE: JNB TI, HERE ;monitorizare flag de transmisie
CLR TI ;dacă transferul a fost terminat se șterge TI
SJMP TRANS

Fig. 11.2 Transmisia caracterului 'A'

Fereastra ‘UART’ este în meniul View/Serial Windows/UART #1.


Fereastra ‘Serial Channel’ se găsește în meniul Peripherals/Serial. Se poate
observa că baudrate-ul setat este 4800 biți/s, valoarea FAh este încărcată în
registrul TH1 și registrul SBUF conține codul ASCII pentru caracterul ‘A’. De
fiecare dată când o transmisie este efectuată, flag-ul TI devine ‘1’. Pentru a
transfera următorul byte flag-ul TI trebuie șters, în caz contrar nu poate fi
inițiată o nouă transmisie.
În următorul program este exemplificată transmiterea pe portul serial a
caracterului `A` în C.

Cod C:
#include <reg51.h>
void Tx(unsigned char x);
void main(void)
{
SCON = 0x40;

119
Portul Serial

TR1 = 0;
TMOD = 0x20;
TH1 = -6; //BR=4800; 8051
TL1 = TH1;
TR1 = 1;
TI = 0;
while(1){
Tx('A');
}
}
void Tx(unsigned char x)
{
SBUF = x;
while(TI == 0);
TI = 0;
}

Test Aduc841:
Pentru a avea baudrate-ul dorit de 4800 biți/s, trebuie recalculată valoarea
încărcată în TH1 folosind ec. 3.
Pasul 1: Se testează codul în programul Keil uVision. Se pregătește fișierul
*.hex.

Fig. 11.3 Test Aduc841 - Programul Keil uVision

Pasul 2: Se pornește programul Lossie ASP și se încarcă fișierul *.hex în


memoria microcontrolerului cu Baud Rate-ul setat 9600 biți/s:

120
Portul Serial

Fig. 11.4 Programul Lossie ASP: Încărcarea fișierului *.hex

Pasul 3: Se setează baud rate-ul cerut în fereastra Preferences (4800 biți/s


în cazul nostru):

Fig. 11.5 Programul Lossie ASP: Fereastra Preferences

Pasul 4: Se alege modul ‘Terminal’ (Lossie ASP) și se apasă butonul


RESET (pe placă de dezvoltare) pentru pornirea programului:

RESET

Fig. 11.6 Transmisie serială - Lossie ASP

121
Portul Serial

3.3. Recepția datelor


Recepția începe când bitul REN (Receive Enable) din registrul SCON este
setat în “1”. Flag-ul RI este setat după ce data a fost recepționată.

Exemplul 2:
Scrieți un program care să recepționeze date pe portul serial (câte un octet)
și să le trimită la P2, baud rate 4800, 8N1.

Rezolvare:
Pentru recepționarea caracterelor pe portul serial se parcurg următorii pași:
1) În registrul TMOD este încărcată valoarea 20H, pentru a utiliza
T1&M2 timer-ul 1 în modul 2 (8-bit auto-reload) pentru a seta baud rate-
ul.
2) În registrul TH1 este încărcată valoarea corespunzătoare pentru
baud rate-ul dorit.
3) În registrul SCON este încărcată valoarea 50H, pentru modul 1
(al portului serial), 8 biți de date și câte un bit de start și stop.
4) Bitul TR1 ia valoarea 1 pentru pornirea timer-ului 1.
5) Flag-ul RI este trecut în 0 folosind instrucțiunea CLR RI.
6) Flag-ul RI este monitorizat folosind instrucțiunea JNB RI, xx
pentru a ști dacă a fost recepționat caracterul.
7) Atunci când flag-ul RI are valoarea 1, registrul SBUF conține
datele, iar acestea pot fi prelucrate.
8) Pentru recepționarea următorului byte se reiau pașii începând cu
pasul 5.

Test 8051:
Cod ASM:
ORG 0000H
MOV TMOD,#20H ;T1M2 -> Baud Rate
MOV TH1,#0FAH ;BR=4800, 8051
MOV SCON,#50H ;SM0 = 0; SM1 = 1; REN = 1
SETB TR1 ;pornire timer
RECEPTIE:
CLR RI
HERE: JNB RI, HERE ;monitorizare flag de recepție
MOV P2, SBUF ;caracterul recepționat în SBUF este afișat pe P2

122
Portul Serial

SJMP RECEPTIE ;salt la următoare recepție


END

2. După ce RI devine 1 3. Caracterul e afișat pe P2.


1. Tasta a a fost apăsată. registrul SBUF conține datele
MOV P2, SBUF
recepțipnate:
HERE: JNB RI, HERE
Fig. 11.7 Recepția caracterului 'a'

Baudrate-ul este 4800 biți/s. Tasta apăsată nu este vizibilă în fereastra


UART, dar este recepționată și afișată în P2. Tasta apăsată apare în fereastra
UART doar în urma transmiterii. Dacă doriți să o vedeți, codul trebuie
completat cu subrutina de transmitere.

Cod C:
#include <reg51.h>

unsigned char Rx();


//funcția returnează caracterul recepționat
void main(void)
{
SCON = 0x50;
TMOD = 0x20;
TH1 = -6; //BR=4800; 8051
TR1 = 1;
RI = 0;

while(1){
P2 = Rx();
}
}

unsigned char Rx()

123
Portul Serial

{
unsigned char received;
while(RI == 0);
received = SBUF;
RI = 0;

return received;
}

Test Aduc841:
Pentru a avea baudrate-ul dorit de 4800 biți/s, trebuie recalculată valoarea
încărcată în TH1 folosind ec.3.
Se repetă pașii prezentați la Exemplu 1 (Transmisie serială). Pentru
verificarea conținutului P2 se folosește programul Waveforms.

Fig. 11.8 Test Aduc841 - LossieASP și Waveforms

3.4. Comunicația multiprocesor


Bitul SM2 din registrul SCON se numește ‘Bit pentru comunicaţia
multiprocesor’. Acesta este setat sau șters de programator pentru a valida
comunicația în modurile 2 şi 3.
Modul 2
Modul de comunicație multiprocesor este similar modului 1, cu excepția
faptului că sunt transmiși 11 biți. 1 bit de start, 9 biți de informație și 1 bit de
stop. Al 9-lea bit de date este obținut din TB8 al registrului SCON pe durata

124
Portul Serial

transmisiei și stocat în RB8 pe durata recepției. Atât biții de start cât și biții de
stop sunt pierduți.
Rata de transfer se calculează cu formula:
2SMOD
fbaud = x Fclk ec. 5
64
Modul 3
Modul 3 este identic cu modul 2 cu excepția faptului că rata de transfer este
determinată exact ca în modul 1 utilizându-se timer-ul 1 pentru a genera
frecvența de comunicație.
Comunicația multiprocesor
Modurile 2 şi 3 au fost create pentru realizarea comunicației seriale
multiprocesor. În general într-o configurație multiprocesor unul dintre
procesoare este master, iar celelalte slave. O caracteristică particulară a unei
conexiuni master –slave constă în aceea că o dată este transmisă de la master
la slave. Intenția este ca la un moment dat un singur procesor slave să
recepționeze data transmisă de master. Există mai multe posibilități prin care
se poate rezolva problema adresării. Dacă se utilizează modul 1, fiecare mesaj
sosit de la master începe cu adresa procesorului slave care urmează să
primească mesajul. Când mesajul este primit, toate procesoarele slave îl
recepționează dar reacționează doar acela căruia îi era adresat. Dacă mesajele
sunt transmise frecvent, procesoarele slave vor pierde foarte mult timp cu
procesarea mesajelor care nu le sunt adresate. Din acest motiv, pentru
comunicația multiprocesor se utilizează modurile 2 şi 3.
După cum s-a văzut în aceste moduri sunt recepționați 9 biți de date, cel
de-al 9-lea bit fiind transferat în RB8 din SCON.
Portul serial al unui microcontroler din familia 8051 poate fi programat
astfel ca data să fie recepționată numai dacă RB8 = 1. Această facilitate se
stabilește prin intermediul bitului SM2 din SCON. Pentru a ilustra
funcționarea în regim multiprocesor se consideră schema din figura următoare,
în care procesorul MASTER comunică cu procesoarele SLAVE prin
intermediul interfeței seriale. Deoarece liniile RxD şi TxD nu sunt linii “three-
state”, procesoarele SLAVE transmit informația către procesorul MASTER
prin intermediul unei porți “ŞI”. Dacă procesorul MASTER dorește să
transmită un bloc de date unui procesor Slave mai întâi transmite un octet de
tip adresă de identificare. Un octet de adresă diferă de unul de date prin aceea
că cel de-al 9-lea bit este “1” pentru date fiind “0”.

125
Portul Serial

RxD
Master
TxD

RxD
Slave 1
TxD
.
.
.
RxD
Slave n
TxD

Fig. 11.9 Comunicația multiprocesor

Inițial toate microcontrolerele slave lucrează cu SM2 = 1. Un octet de


adresă transmis va întrerupe toate procesoarele slave, fiecare putând examina
octetul primit pentru a verifica dacă este adresat. De exemplu, dacă master-ul
dorește să dialogheze cu Slave 3, atunci va transmite un cuvânt de forma
100000011B. Slave-ul adresat va recunoaște adresa și va reseta bitul SM2,
pregătind-se astfel pentru recepția datelor. Celelalte procesoare Slave nu-şi vor
dezactiva bitul SM2 şi vor rămâne în așteptarea adresei proprii, ignorând
datele transmise de master. Bitul SM2 nu are nici un efect în modul 0 însă în
modul 1 poate fi utilizat pentru verificarea validității bitului de stop. La
recepție în modul 1, dacă SM2 = 1 data va fi citită numai dacă bitul de stop
recepționat va fi valid (“1”).
4 Modul de lucru
• Se vor rula codurile de mai sus pas cu pas utilizând depanatorul de program
inclus în Keil uVision.
• Se vor face simulări în Proteus.
• Se vor testa programele pe placa de dezvoltare.
5 Aplicații
1. Completați programul următor astfel încât să transmită în continuu
mesajul “YES” pe portul serial cu 9600 baud, mod 1, utilizând registrul
DPTR.

126
Portul Serial

ORG 0000H
MOV TMOD,____ ;T1M2
MOV TH1,_____ ;BR = 9600 biți/s
MOV SCON,____
_____________ ;start timer
START:
MOV DPTR,____ ;Inițializează DPTR
AGAIN:
CLR A
_____________ ;mută în A conținutul locației de memorie
;(a+dptr) – instrucțiunea movc
JZ START
MOV SBUF,______ ;salvează în SBUF caracterul
HERE: JNB ____, HERE ;monitorizare flag de transmisie
CLR ___
INC DPTR
SJMP AGAIN
ORG 100H
TABLE: DB "YES ",00H

Se va testa funcționarea programului în Keil uVision și pe placa de


dezvoltare. Se va implementa codul în C.

2. Să se scrie un program care transmite pe portul serial caracterul


recepționat pe portul serial (programul “Echo”). Baud rate 2400, 8N1.
3. Să se scrie un program care transmite două șiruri de caractere diferite
folosind portul serial în funcție de starea unui buton conectat la P3.2:
• SW = 0: Transmiteți numele vostru
• SW = 1: Transmiteți prenumele vostru
XTAL = 11.0592 MHz, baud rate 9600, 8N1.

Fig. 11.10 Rezultate – Problema 3

127
Portul Serial

4. Să se scrie un program care transmite șirul de caractere “Hello world”


(aflat în memoria ROM, începând de la adresa 100h) pe portul serial cu
19600 baud, 8N1.

Fig. 11.11 Rezultate - Problema 4

5. Să se scrie un program care transmite șirul de caractere “MEM X” (aflat


în memoria externă RAM) pe portul serial cu 2400 baud, 8N1.
6. Să se scrie un program care recepționează pe portul serial octeți
reprezentând litere ale alfabetului latin și le transferă la P2 dacă sunt
majuscule; altfel, acestea sunt transferate la P3. (baud rate 2400, 8N1).
7. Să se scrie un program care verifică conținutul portului P2 și dacă:
• este o valoare pară: se transmite data curentă pe portul serial
(exemplu: 12.05.2021)
• este valoare impară: se generează un semnal dreptunghiular la
pinul P3.4 cu o perioadă de 80 ms utilizând timer-ul.
XTAL = 11.0592 MHz, baud rate 9600, 8N1.

128
Întreruperile

12 Întreruperile
1 Scopul lucrării
• Studiul subrutinelor pentru generarea întreruperilor
2 Aparatura necesară
• Stații de lucru care au instalat Keil uVision.
• Placa de dezvoltare Aduc841 și osciloscopul digital Analog
Discovery
3 Considerații teoretice
Un procesor are doar două metode pentru a determina condițiile/stările
circuitelor interne și externe:
• Polling: metoda care utilizează instrucțiunile software pentru a
interoga starea anumitor flag-uri sau a pinilor porturilor care pot
provoca salturi în funcție de valorile citite: TFx, RI, TI,...
Exemplu: Back: jnb RI, Back
• Întreruperi: presupune reacția la anumite semnale, numite
întreruperi, care forțează procesorul să efectueze un salt la o adresă
aflată în tabelul vectorilor de întreruperi

Tehnicile soft mențin procesorul ocupat acesta neputând deservi alte


procese. Spre exemplu în cazul interogării unui bit procesorul execută doar
instrucțiunea de interogare. Trecerea la o altă instrucțiune este condiționată de
îndeplinirea cerinței sau de activarea unei întreruperi dacă este cazul.
Întreruperile permit executarea unei bucăți de cod doar în momentul în care
condiția de activare a întreruperii este îndeplinită. În timpul dintre două
momente succesive de activare a întreruperii procesorul poate fi utilizat pentru
a îndeplini alte sarcini.
8051 dispune de 6 surse de întreruperi. Trei dintre acestea sunt generate
automat de operații interne: timer 0, timer 1 și portul serial, iar două sunt
generate de semnale externe ce apar la pinii INT0 și INT1. Cea de-a șasea se
referă la întreruperea cu cea mai ridicată prioritatea și anume întreruperea
Reset. În cazul apariției acestei întreruperi microcontrolerul începe execuția
programului de la adresa 0000h din memoria de cod.

129
Întreruperile

Întreruperile pot fi generate de operațiile interne sau de surse externe. Orice


întrerupere poate chema o subrutină de tratare a întreruperii, subrutină situată
la o adresă fixă din memoria program:
Tab. 12-1 Întreruperile

Întrerupere Adresă ROM (hex) Flag Pin


Reset 0000 9
Întrerupere externă 0003 IE0 P3.2 (INT0)
Timer 0 000B TF0
Întrerupere externă 0013 IE1 P3.3 (INT1)
Timer 1 001B TF1
Portul Serial 0023 RI sau TI RI și TI
Toate întreruperile sunt sub controlul programului. Programatorul poate să
modifice biții din registrul de validare al întreruperilor (IE) (sau din registrul
de prioritate (IP) și TCON (timer control)). Programatorul poate bloca
întreruperile prin setarea corespunzătoare a biților din regiștri respectivi.
Registrul IE:
7 6 5 4 3 2 1 0
EA - -/ET2* ES ET1 EX1 ET0 EX0
Fig. 12.1 Registrul IE

Bit Simbol Funcție


7 EA Bitul de validare globală a întreruperilor
6 - Neimplementat
5 - Neimplementat/ET2*
4 ES Validează întreruperile portului serial
3 ET1 Validează întreruperea dată de timer-ul 1
2 EX1 Validează întreruperea externă 1
1 ET0 Validează întreruperea dată de timer-ul 0
0 EX0 Validează întreruperea externă 0

*Observație: În cazul microcontrolerului Aduc841 pinul 5 reprezintă bitul


de validare al întreruperii dată de timer-ul 2.
Exemplu:
;întreruperile serial, timer0 și EX1 sunt validate
;varianta 1 - număr binar
orl ie,#10010110b
;varianta 2 - număr hexazecimal

130
Întreruperile

mov ie,#96h
;varianta 3 - cu setb
setb ie.7
setb ie.4
setb ie.2
setb ie.1
;dezactivarea tuturor întreruperilor
clr ie.7

După ce întreruperea a fost servită, programul întrerupt trebuie să-și reia


funcția din locul în care a fost întrerupt. În momentul servirii întreruperii
registrul PC este salvat în stivă (intern fiind salvată și starea celorlalte
întreruperi) iar după instrucțiunea RETI se marchează sfârșitul rutinei de
servire a întreruperii, PC ia valoarea avută anterior (o extrage din stivă).
3.1. Întrerupere timer
Când un timer/numărător trece din starea FFh în 00h flag-ul corespunzător
TF0 sau TF1 este setat în 1.
Exemplul 1:
Să se scrie un program care preia date de la portul P0 și le trimite la P1. În
același timp programul generează un semnal dreptunghiular cu o frecvență de
5 kHz la portul P2.1. Se va folosi Timer-ul 0, cu întreruperi în modul 1,
frecventa Fclk= 11.0592MHz.
Rezolvare:
1/5 kHz = 200 us → Ton = Toff = 100 us
TCM = 12/11.0592MHz = 1.085 us
100us/TCM = 100us/1.085us ≈ 92
TH0 = -92 sau TH0 = 256 – 92 = 164 = A4h

Cod ASM:
ORG 0000
LJMP MAIN
ORG 000Bh ;adresa fixă pentru întrerupere timer 0
CPL P2.1
RETI

ORG 30H
MAIN:

131
Întreruperile

MOV P1,#0FFh
MOV IE,#10000010b ;este activată întrerupere timer 0
MOV TMOD,#02H
MOV TH0,#-92
SETB TR0 ;start timer
BACK:
MOV A, P0 ;timer-ul numără de la A4H până la FFh
MOV P1, A ;când trece din starea FFh în 00h flag-ul
;TF0 este setat în 1
SJMP BACK
END

Programul prezentat începe cu instrucțiunea LJMP MAIN. Subrutina


MAIN se află la adresa 30h. Acest salt este necesar ca să fie evitată
suprascrierea programului în zonele de memorie unde se găsesc subrutinele de
tratare a întreruperilor (vezi Tab. 12-1 Întreruperile). Din același motiv de a
nu suprascrie zona de memorie rezervată întreruperilor în general la adresa de
tratarea a întreruperilor se include o instrucțiune de salt la o altă adresă unde
se găsește codul ce urmează să fie executat. În cazul prezentat este activată
întreruperea timer-ului 0. În momentul când flag-ul TF0 devine 1, programul
termină de executat instrucțiunea curentă, salvează adresa următoarei
instrucțiuni pe stivă, salvează intern statusul curent al întreruperilor și sare la
adresa vectorului întreruperii corespunzătoare (în cazul prezentat la adresa
0Bh). Se execută rutina de tratare a întreruperii și la întâlnirea instrucțiunii
RETI, se șterge flag-ul TF0 și se ia de pe stivă valoarea PC. Apoi se execută
programul în continuare. În Fig. 12.2 este prezentat codul mașină aflat în
memoria de cod. În Fig. 12.3 sunt prezentate rezultatele programului în Keil.

Intrerupere Timer 0 -> c: 0x0B Meniu Help:

B2h A1h
LJMP MAIN

Subrutina Main

Fig. 12.2 Cod mașină pentru program

132
Întreruperile

T = 200 us

Fig. 12.3 Preluarea datelor de la portul P0 și trimiterea lor la P1 + semnalul


dreptunghiular generat la P2.1

Fig. 12.4 Semnalul dreptunghiular generat la P2.1 - programul Waveforms

Atenție, un ciclu mașină la microcontrolerul Aduc841 este 0.0905 us. Dacă


doriți să aveți perioada semnalului tot 200 us, programul prezentat trebuie
modificat. Cum se poate modifica?

Rezolvare în C:
Pentru tratarea întreruperilor în C se folosește tabelul următor:
Tab. 12-2 Întreruperile - C

Întrerupere Flag Număr


Întrerupere externă IE0 0
Timer 0 TF0 1
Întrerupere externă IE1 2
Timer 1 TF1 3
Portul Serial RI și TI 4

133
Întreruperile

Numărul prezentat în Tab. 12-2 este dat de poziția bitului corespunzător


activării întreruperii în registrul IE:
7 6 5 4 3 2 1 0
EA - ET2 ES ET1 EX1 ET0 EX0
Fig. 12.5 Poziția bitului corespunzător activării întreruperii în registrul IE
#include <reg51.h>
sbit pin = P2^1;

void timer0() interrupt 1


{
pin =~pin;
}

void main ()
{
P1 = 0xFF; //port de intrare
IE = 0x82;
TMOD = 0x02;
TH0 = -92;
TR0 = 1;
while(1)
P1=P0;
}
Starea întreruperilor se poate verifica și folosind fereastra “Interrupt
System”:

Fig. 12.6 Întrerupere Timer 0

134
Întreruperile

Exemplul 2:
Să se scrie un program care generează un semnal dreptunghiular cu
porțiune HIGH egală cu 1085 us și LOW 15 us. Între timp programul preia
date de la portul P0 și le trimite la P1. Se va folosi Timer-ul 1, cu întreruperi,
frecventa Fclk = 11.0592MHz.
Rezolvare:
Pentru rezolvarea acestei cerințe se inițializează timer-ul 1 astfel încât să
genereze întârzieri de 1085 us: 1085/1,085 = 1000. 65536 – 1000 = FC18h.
TH1 = FCh, TL1 = 18h. Se pornește timer-ul. Între timp programul preia date
de la portul P0 și le trimite la P1. În momentul când TF1 devine 1
microcontrolerul o să execute subrutina de tratare a întreruperii care generează
o întârziere de 15 us. Întârzierea soft trebuie să conțină și oprirea timer-ului 1,
reinițializarea și pornirea lui. În Fig. 12.7 este prezentată organigrama
programului.
START

Inițializare regiștri TMOD, IE


TH1, TL1 -> porțiune HIGH
;Urmează generarea porțiunii LOW
Pornire Timer 1
CLR TR1 ;stop Timer 1
MOV R2,#4
CLR P2.1 ;P2.1 = 0, porțiune low; 1CM
HERE: DJNZ R2,HERE ;4x2CM = 8MC + 1CM = 9CM
MOV TL1,#18H ;2MC + 9CM = 11CM
P1 = P0 RETURN
MOV TH1,#0FCH ;2MC + 11CM = 13CM
SETB TR1 ;pornire time 1MC: 1CM + 13CM = 14CM
;14CM = 14x1.085 us = 15.19 us
SETB P2.1 ;P2.1=1, porțiune HIGH
RETI
NU

TF1 =? 1 DA, SALT LA ADRESĂ: 1Bh

Fig. 12.7 Organigramă de funcționare a exemplului 2

ORG 0000H
LJMP MAIN
ORG 001BH ;adresa vectorului întreruperii corespunzătoare
LJMP ISR_T1 ;salt la ISR
;--PROGRAMUL MAIN
ORG 0030H ;după vectorul întreruperii
MAIN: MOV TMOD,#10H ;Timer 1, mod 1
MOV P0,#0FFH ;P0 – port de intrare
MOV TL1,#018H ;TL1=18
MOV TH1,#0FCH ;TH1=FC
MOV IE,#88H ;10001000 – întrerupere Timer 1 activat
SETB TR1 ;start Timer 1

135
Întreruperile

BACK: MOV A,P0 ;preia datele P0


MOV P1,A ;trimite la P1
SJMP BACK
ISR_T1:
CLR TR1
MOV R2,#4
CLR P2.1 ;P2.1 = 0, porțiune low; 1CM
HERE: DJNZ R2,HERE ;4x2CM = 8MC + 1CM = 9CM
MOV TL1,#18H ;2MC + 9CM = 11CM
MOV TH1,#0FCH ;2MC + 11CM = 13CM
SETB TR1 ;pornire timer; 1MC: 1CM + 13CM = 14CM
;14CM = 14x1.085 us = 15.19 us
SETB P2.1 ;P2.1=1, porțiune HIGH
RETI
END

Ton = 1085 us

Toff = 15 us

Fig. 12.8 Rezultate Exemplul 2 - Keil

3.2. Întreruperile externe


Sunt generate de semnalele care apar pe pinii INT0 și INT1 și sunt utilizate
pentru a monitoriza circuite externe. Semnalele de pe acești pini pot seta flag-
urile IE0 sau IE1 din registrul TCON în 2 moduri diferite:
• Flag-urile IEx pot fi setate când INTx atinge nivelul 0 logic
sau
• când apare o tranziție din „high” în „low”
Biții IT0 (TCON.0) și IT1 (TCON.2) din TCON stabilesc modul în care
are loc întreruperea.
Flag-urile IEx vor fi șterse atunci când întreruperea este acceptată de uC și
este apelată subrutina de servire a întreruperii. Circuitele externe trebuie să
treacă INTx în starea high înainte de executarea instrucțiunii RETI altfel se va
activa o nouă întrerupere.

136
Întreruperile

Exemplul 3:
Pe pinul INT1 (P3.3) este conectat un buton care în starea “idle” este
„high”. La apăsarea tastei un LED trebuie să se aprindă pentru o fracțiune de
secundă. LED-ul este conectat pe P1.2 și este normal stins. Cât timp butonul
e apăsat LED-ul trebuie să fie aprins.

INT1

Buton P1.3

LED

Fig. 12.9 Conexiuni - exemplul 3

Rezolvare:
LED EQU P1.3
ORG 0000H
LJMP MAIN
ORG 0013H ;INT1 ISR
SETB LED ;aprinde LED-ul
MOV R3,#255
BACK: DJNZ R3,BACK ;ține LED-ul aprins
CLR LED ;stinge LED-ul
RETI ;se revine din întrerupere
;--PROGRAMUL MAIN
ORG 30H
MAIN: MOV IE,#10000100B ;întreruperea INT1 este activată
CLR LED
HERE: SJMP HERE ;așteaptă până când întreruperea devine
;activă
;până când INT1 devine 0
END

137
Întreruperile

P3.3

P3.3

Buton apăsat
Buton neapăsat LED: ON
LED: OFF

ZOOM – LED:

Fig. 12.10 Formele de undă în programul Keil – Exemplul 3

Exemplul 4:
Modificați exemplul 3 astfel încât LEDul să fie aprins doar în momentul
apăsării butonului pentru o fracțiune de timp. După acest interval de timp
LEDul se stinge, chiar dacă butonul este încă apăsat.
Rezolvare:
Trebuie adăugată linia de cod care activează întreruperea INT 1 în momentul
când apare o tranziție din „high” în „low” (în loc de nivelul 0 logic):
SETB TCON.2

Cod ASM:
LED EQU P1.3
ORG 0000H
LJMP MAIN
ORG 0013H ;INT1 ISR
SETB LED ;aprinde LED-ul
MOV R3,#255
BACK: DJNZ R3,BACK ;tine LED-ul aprins
CLR LED ;stinge LED-ul
RETI ;se revine din întrerupere
;--PROGRAMUL MAIN
ORG 30H
MAIN: MOV IE,#10000100B ;întreruperea INT1 e activată
CLR LED
SETB TCON.2
HERE: SJMP HERE ;așteaptă până la întrerupere:
;până când INT1 devine 0
END

138
Întreruperile

Tranziție din
high în low

LED aprins
pentru o
fracțiune de
secundă

Fig. 12.11 Formele de undă în programul Keil – Exemplul 4

LED

Button

EXEMPLUL 4

LED

Button
EXEMPLUL 3

Fig. 12.12 Formele de undă - programul Proteus

3.2. Întreruperile portului serial


Dacă un octet de date este recepționat bitul RI din SCON este setat în “1”
iar când un octet este transmis bitul TI din SCON va fi setat în “1”. Cei doi
biți TI și RI sunt trecuți printr-o poartă SAU. Dacă rezultatul este “1” logic se
va genera o întrerupere.
În acest caz biții nu sunt șterși automat la apelarea subrutinei ce servește
întreruperea. Programatorul trebuie să se asigure că este șters bitul care a dus
la activarea întreruperii (RI sau TI) pentru a valida recepția sau transmisia
următorului octet.
Exemplul 5:
Modificați programul ca să aibă următoarea funcționalitate: preia date de
la portul P1 și le trimite la P2, în timp ce trimite o copie a acestora și pe portul
serial. Fclk = 11.0592MHz, baud rate 9600 bps, modul 1.

139
Întreruperile

ORG 0000H
LJMP MAIN
ORG 23H
LJMP SERIAL ;sare la etichetă serial
ORG 30H
MAIN: MOV P1,#0FFH ;P1 – port de intrare
MOV TMOD,#20H ;timer 1, modul 2
MOV TH1,#0FDH ;9600 baud rate
MOV SCON,#50H ;8-bit,1 stop, Ren enabled
MOV IE,#10010000B ;întreruperea portului serial este activată
SETB TR1 ;pornire timer 1
MOV A,P1 ;citește datele pe P1
MOV SBUF, A ;le copiază în SBUF
MOV P2,A ;trimite la P2
BACK: SJMP BACK ;bucla infinită
;-----------------SERIAL PORT ISR
ORG 100H
SERIAL:
JB TI, TRANS ;dacă TI == 0 programul sare la eticheta
;TRANS
MOV A, SBUF ;altfel copiază în acumulator conținutul
;registrului SBUF
CLR RI ;șterge flag-ul
RETI ;revine din întrerupere
TRANS:
CLR TI ;șterge flag-ul
RETI ;revine din întrerupere
END

Varianta în C:
#include <reg51.h>

void serial0() interrupt 4 {


if (TI==1) {
TI=0;
}
else {
RI=0;
}}

140
Întreruperile

void main() {
unsigned char x;
P1=0xFF;
TMOD=0x20;
TH1=0xF6;
SCON=0x50;
IE=0x90;
TR1=1;
x=P1;
P2=x;
SBUF=x;

while(1);
}

P2

Port Serial

Fig. 12.13 Exemplul 5 - Rezolvare

4 Modul de lucru
• Se vor rula programele de mai sus pas cu pas utilizând depanatorul de
program inclus în Keil uVision.
• Se vor testa programele pe placa de dezvoltare.
5 Aplicații
1. Modificați exemplul 5 astfel încât programul să funcționeze în mod
continuu la infinit:

Fig. 12.14 Problema 1 - Keil

141
Întreruperile

2. Să se genereze un semnal dreptunghiular la pinul P3.4 cu frecvență de


20 Hz cu timer-ul 0 cu întreruperi.
a. D = 50 %
b. D = 25 %
3. Să se genereze un semnal dreptunghiular cu factor de umplere 50% la
pinul P3.4 cu frecvență de 5 Hz. Utilizând timer cu întreruperi.
4. Să se genereze un semnal dreptunghiular cu Ton = 1000 us, Toff = 20
us la pinul P3.4. Cu timer cu întreruperi.
5. Să se scrie un program care preia date de la portul P0 și le trimite la P1.
În același timp programul generează un semnal dreptunghiular la pinul
P2.0. Perioada semnalului este 100 ms. Cu timer cu întreruperi. XTAL
= 11.0592 MHz.
a. D = 50 %
b. D = 40 %
6. Să se scrie un program care preia date de la portul serial și le trimite la
P0 dacă octetul recepționat este mai mic decât 100h, în caz contrar
datele sunt trimise la P1. 1200 bps, 8N1.
7. Să se scrie un program care transferă din memoria de cod șirul de
caractere „Homework” repetat la infinit pe serial cu baudrate de 1200
8 biți de date 1 bit de stop fără paritate, frecventa Fclk = 11.0592MHz:
a) cu A și PC
b) cu dptr
c) cod C
8. Să se scrie un program care preia date de la portul P0 și le trimite la P1.
În același timp programul generează două semnale dreptunghiulare:
Semnal 1 →la pinul P2.0. Perioada semnalului este 5kHz.
Semnal 2 →la pinul P2.1. Perioada semnalului este 2.5Hz.
Cu timer cu întreruperi.
9. Să se scrie un program care preia date de la portul P0 și le scrie în
memoria externă la adresa 123h. În același timp programul generează
și un semnal dreptunghiular cu o perioada de 60ms. Cu timer cu
întreruperi.
10. Pe pinul P3.3 este conectat un buton care în starea” idle” este „high”.
Să se scrie un program care numără de câte ori a fost apăsat butonul
conectat valoarea fiind transmisă la P2.

142
Bibliografie

Bibliografie
1. D. Petreuş, Note de Curs Microcontrolere, Anul 3, Electronică Aplicată,
Facultatea de Electronică și Telecomunicații, Universitatea Tehnică din
Cluj-Napoca
2. D. Petreuş, G. Munteanu, Z. Juhos, N. Palaghiţă, Aplicaţii cu
microcontrolere din familia 8051, Editura Mediamira, Cluj-Napoca, 2005
3. Ș. Lungu, D. Petreuş, S. Pleşa, Microcontrolere. Familia Intel 8051,
Editura Comprex, Cluj-Napoca, 1993;
4. S. Ghosal, 8051 Microcontroller: Internals, Instructions, Programming
and Interfacing, Editura Pearson - 2nd edition, 2014
5. David Calcutt, Frederick Cowan, Hassan Parchizadeh, 8051
Microcontroller: An Applications Based Introduction, Editura Newnes,
2004.
6. Thomas Schultz, C and the 8051, Inc. PageFree Publishing, 3rd edition,
2004
7. Thomas Schultz, Vol.I: Hardware, Modular Programming & Multitasking
(2nd Edition, Inc. Prentice Hall; 2nd edition, 1997
8. M. A. Mazidi, J. Gillispie, The 8051 Microcontroller and Embedded
Systems, Prentice Hall, Inc. SUA, 2000;
9. T. V. Sickle, Programming microcontrollers in C, LLH Technology
Publishing - Second Edition, 2000;
10. *** – Microcontrollers DataBook, Atmel Corporation, 2000;
11. *** – AT89C2051 - DataSheet, Atmel Corporation, 2000:
https://datasheetspdf.com/pdf-file/1308338/ATMEL/AT89C51/1
12. *** – ADuC841/ADuC842/ADuC843 - DataSheet, Analog Devices,
https://www.analog.com/media/en/technical-documentation/data-
sheets/ADUC841_842_843.pdf
13. *** – Analog Devices ADUC841 User Manual, Analog Devices, One
Technology Way, https://www.analog.com/en/products/processors-
microcontrollers/microcontrollers.html
14. *** – A Keil µVision4 Getting Started Guide for 8051 pdf,
https://www.keil.com/product/brochures/uv4.pdf
15. *** – Keil Embedded C Tutorial:
https://www.8051projects.net/wiki/Keil_Embedded_C_Tutorial#Introduc
tion_to_Keil_C
15. *** – Ax51 Macro Assembler and Utilities User’s Guide, Keil Software,
2001;
16. *** – C51 Compiler User’s Guide, Keil Software, 2001;

143
Lista de figuri și de tabele

Lista de figuri
Fig. 1.1 Descărcarea mediului Keil uVision ________________________________________ 1
Fig. 1.2 Ciclu de dezvoltare a programelor ________________________________________ 2
Fig. 1.3 Crearea proiectului ____________________________________________________ 2
Fig. 1.4 Bază de date a diferitelor familii de microcontrolere _________________________ 3
Fig. 1.5 Setare frecvenței de ceas _______________________________________________ 4
Fig. 1.6 Crearea fișierului HEX __________________________________________________ 4
Fig. 1.7 Adăugare de fișiere la proiect ___________________________________________ 5
Fig. 1.8 Compilarea și link editarea proiectului ____________________________________ 5
Fig. 1.9 Fereastra Build Output _________________________________________________ 5
Fig. 1.10 Rularea programului _________________________________________________ 6
Fig. 1.11 Meniul Help și instrucțiunea ADD _______________________________________ 7
Fig. 1.12 Fereastra Registers ___________________________________________________ 8
Fig. 1.13 Fereastra Disassembly ________________________________________________ 9
Fig. 1.14 Fereastra Memorie ___________________________________________________ 9
Fig. 1.15 Bara de meniu ______________________________________________________ 9
Fig. 1.16 Portul 2 ____________________________________________________________ 9
Fig. 1.17 Portul 2 – Analog ___________________________________________________ 10
Fig. 1.18 Exemplu: P2.0 și P2.1 ________________________________________________ 10
Fig. 2.1 Pagina de lucru Proteus _______________________________________________ 12
Fig. 2.2 Adăugarea componentelor ____________________________________________ 13
Fig. 2.3 Alegerea componentelor ______________________________________________ 13
Fig. 2.4 Toolbar-ul cu unelte __________________________________________________ 14
Fig. 2.5 Rotire cu 90⁰ ________________________________________________________ 15
Fig. 2.6 Încărcarea programului în simulatorul Proteus VSM ________________________ 16
Fig. 2.7 Pornirea simulării - Meniu Debug _______________________________________ 16
Fig. 2.8 Pornirea simulării - butoane ___________________________________________ 16
Fig. 2.9 Schema în Proteus - Depanarea programelor ______________________________ 17
Fig. 2.10 Depanare program: Step – Butonate____________________________________ 18
Fig. 2.11 Depanare program: Step – Meniu Debug ________________________________ 18
Fig. 2.12 Regiștrii CPU _______________________________________________________ 18
Fig. 2.13 Fereastra CPU înainte și după Step _____________________________________ 18
Fig. 2.14 Adăugare fișier sursă ASM ____________________________________________ 19
Fig. 2.15 Fișier sursă ASM ____________________________________________________ 19
Fig. 2.16 Încărcarea programului C în simulatorul Proteus VSM ______________________ 20
Fig. 2.17 Adăugare fișier sursă C_______________________________________________ 20
Fig. 2.18 Fișier sursă C _______________________________________________________ 20
Fig. 2.19 Fișier Tools.ini ______________________________________________________ 21
Fig. 2.20 Fereastra Options for Target __________________________________________ 22
Fig. 2.21 Setarea VDM51 Target Setup _________________________________________ 22
Lista de figuri și de tabele

Fig. 2.22 Interconectarea programelor Keil și Proteus ______________________________ 23


Fig. 2.23 Schema LED în Proteus _______________________________________________ 24
Fig. 3.1 Organizarea memoriei la microcontrolerul 8051 ___________________________ 26
Fig. 3.2 Operația de citire folosind registru DPTR _________________________________ 28
Fig. 3.3 Încărcarea registrului DPTR ____________________________________________ 28
Fig. 3.4 Operația de scriere folosind registru R0 sau R1 ____________________________ 28
Fig. 3.5 Încărcarea registrului R0 sau R1 cu o valoare ______________________________ 29
Fig. 3.6 Conectarea memoriei externe la microcontrolerul 8051 _____________________ 29
Fig. 3.7 Organigrama - Testarea memorei RAM externă ____________________________ 30
Fig. 3.8 Rulare pas cu pas, fereastra cu registri din debugger. _______________________ 32
Fig. 3.9 Rezultat: Datele în memoria externă _____________________________________ 32
Fig. 3.10 Fereastra de memorie – Adresa de start _________________________________ 33
Fig. 3.11 Fereastra de memorie – Adresa de stop _________________________________ 33
Fig. 3.12 Porturile – Peripherals/Port ___________________________________________ 33
Fig. 3.13 Analizorul de semnal cu valorile de pe portul P3 __________________________ 33
Fig. 3.14 Fereastra de memorie – 10h -> AAh ____________________________________ 34
Fig. 3.15 Porturi ____________________________________________________________ 34
Fig. 4.1 Organigrama rutinei de întârziere soft ___________________________________ 36
Fig. 4.2 Exemplu pentru a calcula timpul de execuție a unei instrucțiuni _______________ 37
Fig. 4.3 Valoarea de la pinul 4 al portului 3. ______________________________________ 39
Fig. 4.4 Testarea subrutinei ’softime’– Keil uVision ________________________________ 42
Fig. 4.5 Alegerea uC-ului Aduc841 în programul Keil uVision ________________________ 42
Fig. 4.6 Teste Aduc841 în programul Keil uVision _________________________________ 43
Fig. 4.7 Placa de dezvoltare Aduc841 împreună cu osciloscopul digital: Analog Discovery _ 44
Fig. 4.8 Programul LossieASP _________________________________________________ 45
Fig. 4.9 Programul Waveforms ________________________________________________ 45
Fig. 5.1 Organizarea memoriei la 8051 – Memoria de cod __________________________ 47
Fig. 5.2 Fereastra de memorie - Date predefinite _________________________________ 48
Fig. 5.3 Instrucțiunea MOVC __________________________________________________ 49
Fig. 5.4 Organigrama subrutinei "PCLook" _______________________________________ 49
Fig. 5.5 Verificarea codului mașină și valorii PC ___________________________________ 51
Fig. 5.6 Explicarea subrutinei _________________________________________________ 51
Fig. 5.7 Testarea programului în Keil uVision _____________________________________ 52
Fig. 5.8 Fereastra Static I/O din programul WaveForms și conectarea analizorului digital
Analog Discovery ___________________________________________________________ 52
Fig. 5.9 Fereastra Logic: Bus (DIO 0 - DIO 7), Programul WaveForms __________________ 52
Fig. 5.10 Tabele de căutare: hibyte și lowbyte ____________________________________ 53
Fig. 5.11 Organigrama subrutinei DPLook _______________________________________ 53
Fig. 5.12 Pătratele numerelor pe portul P2 ______________________________________ 55
Fig. 5.13 Keil - Pătratele numerelor pe portul P2 de la 0 până la 15 - repetat la infinit ____ 56
Fig. 5.14 Programul WaveForms ______________________________________________ 56
Lista de figuri și de tabele

Fig. 6.1 Organizarea memoriei la microcontrolerul 8051 ___________________________ 58


Fig. 6.2 Memorie cod________________________________________________________ 62
Fig. 6.3 Memorie date _______________________________________________________ 62
Fig. 6.4 Programare Modulara – Main_Softime __________________________________ 64
Fig. 6.5 Programare Modulară - Subrutina Softime cu module timer8051 și timer841 ____ 64
Fig. 6.6 DPLook - Programare modulară ________________________________________ 65
Fig. 7.1 Inserarea fișierului antet și a conținutul lui ________________________________ 71
Fig. 7.2 Fereastra de memorie și Quick Watch ____________________________________ 72
Fig. 7.3 Rezultate Exemplul 2 _________________________________________________ 73
Fig. 7.4 Keil - Pătratele numerelor pe portul P2 de la 0 până la 15 - repetat la infinit _____ 74
Fig. 7.5 Rezultate experimentale preluate cu osciloscopul digital Analog Discovery ______ 74
Fig. 7.6 Rezultate Exemplul 4 _________________________________________________ 75
Fig. 7.7 Semnal ____________________________________________________________ 75
Fig. 7.8 Semnal ____________________________________________________________ 76
Fig. 8.1 Schema și caracteristicile unui microcontroler din familia 8051 _______________ 77
Fig. 8.2 Descrierea pinilor ai unui uC din familia 8051 ______________________________ 78
Fig. 8.3 Schema unui pin de la portul 1 __________________________________________ 79
Fig. 8.4 Rezistențe de tip pull-up și pull-down ____________________________________ 80
Fig. 8.5 Rezultat Exemplul 1 - Port de ieșire P2 – Keil uVision ________________________ 81
Fig. 8.6 Rezultat Exemplul 1 - Port de ieșire - 8 semnale digitale _____________________ 81
Fig. 8.7 Forme de undă de pe osciloscop (canal analogic) ___________________________ 82
Fig. 8.8 Forme de undă (Analizor logic) _________________________________________ 82
Fig. 8.9 Preluarea datelor (Keil) de la portul P1 și trimiterea lor la P2 _________________ 83
Fig. 8.10 Schema realizată în programul Proteus _________________________________ 83
Fig. 8.11 Rularea exemplului 3 - pas cu pas ______________________________________ 84
Fig. 8.12 Conectarea memoriei externe la uC ____________________________________ 85
Fig. 8.13 Conectarea memoriei externe (62256) la uC8051 în Proteus _________________ 86
Fig. 8.14 Rularea programului cu butonul Step folosind Proteus _____________________ 86
Fig. 8.15 Rezultate intermediare - Rularea programului pas cu pas - tasta F11 __________ 87
Fig. 9.1 Exemplul 1 – Instrucțiunea ADD_________________________________________ 90
Fig. 9.2 Exemplul 2 – Instrucțiunea ADD, memoria RAM internă _____________________ 90
Fig. 9.3 Exemplul 2 – Instrucțiunea ADD, adunarea numerelor pe 8 biți________________ 91
Fig. 9.4 Exemplul 4 – Adunarea numerelor pe 16 biți ______________________________ 91
Fig. 9.5 Exemplul 5 - Instrucțiunea SUBB ________________________________________ 91
Fig. 9.6 Exemplul 6 - Instrucțiunea DA __________________________________________ 92
Fig. 9.7 Tabelul BCD_________________________________________________________ 92
Fig. 9.8 ANL _______________________________________________________________ 93
Fig. 9.9 ORL _______________________________________________________________ 93
Fig. 9.10 XRL ______________________________________________________________ 94
Fig. 9.11 Instrucțiunea RL ____________________________________________________ 95
Fig. 9.12 Instrucțiunea RLC ___________________________________________________ 95
Lista de figuri și de tabele

Fig. 9.13 Instrucțiunea RR ____________________________________________________ 95


Fig. 9.14 Instrucțiunea RRC ___________________________________________________ 95
Fig. 9.15 Instrucțiunea SWAP _________________________________________________ 96
Fig. 9.16 Exemplul 7 - Numărul de 1 într-un număr binar ___________________________ 96
Fig. 9.17 Instrucțiunile pop și push, valoarea indicatorului de stivă ___________________ 97
Fig. 9.18 Fereastra Watch și Fereastra de Memorie (RAM intern) ____________________ 98
Fig. 9.19 SP = 0x30__________________________________________________________ 98
Fig. 9.20 Problema 2 – Memoria externă ________________________________________ 99
Fig. 9.21 Testare în programul Keil; b). Testare în programul Proteus _________________ 99
Fig. 9.22 Problema 4 - Fereastra cu regiștri _____________________________________100
Fig. 9.23 Problema 5: A2h = 162d _____________________________________________100
Fig. 9.24 Problema 6 – Rezultate – Subrutina LSB.________________________________101
Fig. 9.25 Problema 7 - Rezultate ______________________________________________101
Fig. 9.26 Problema 8 - Rezultate ______________________________________________101
Fig. 9.27 Problema 9 – Rezultate Keil __________________________________________102
Fig. 9.28 Problema 9 – Rezultate Proteus_______________________________________102
Fig. 10.1 Registrul TMOD ___________________________________________________103
Fig. 10.2 Registrul TCON ____________________________________________________104
Fig. 10.3 Structura timer-ului în modul 0 _______________________________________104
Fig. 10.4 Structura timer-ului în modul 1 _______________________________________104
Fig. 10.5 Rularea codului pas cu pas - Fereastra Timer (Meniu Peripherals/Timer) ______106
Fig. 10.6 Formă de undă - Keil uVision: uC8051 __________________________________106
Fig. 10.7 Formă de undă - Keil uVision: Aduc841 _________________________________106
Fig. 10.8 Formă de undă - placa de dezvoltate, WaveForms ________________________106
Fig. 10.9 Pinul P2.0 - formă de undă: Keil uVision (uC8051) ________________________108
Fig. 10.10 Fereastra Performance Analyzer _____________________________________108
Fig. 10.11 Pinul P2.0 - formă de undă: Keil uVision (Aduc841) ______________________108
Fig. 10.12 Formă de undă - placa de dezvoltare, WaveForms _______________________109
Fig. 10.13 Structura timer-ului în modul 2 ______________________________________109
Fig. 10.14 Pinul P3.4 - formă de undă: Keil uVision (uC8051) _______________________110
Fig. 10.15 Formă de undă - placa de dezvoltate, WaveForms (Aduc841) ______________110
Fig. 10.16 Se încărcă registrul TH cu valoarea inițială _____________________________111
Fig. 10.17 Pinul P2.7 - formă de undă: Keil uVision (uC8051) _______________________112
Fig. 10.18 Numărătorul T1 - Test în Keil uVision _________________________________113
Fig. 11.1 Registrul SCON ____________________________________________________116
Fig. 11.2 Transmisia caracterului 'A' ___________________________________________119
Fig. 11.3 Test Aduc841 - Programul Keil uVision _________________________________120
Fig. 11.4 Programul Lossie ASP: Încărcarea fișierului *.hex _________________________121
Fig. 11.5 Programul Lossie ASP: Fereastra Preferences ____________________________121
Fig. 11.6 Transmisie serială - Lossie ASP________________________________________121
Fig. 11.7 Recepția caracterului 'a' _____________________________________________123
Lista de figuri și de tabele

Fig. 11.8 Test Aduc841 - LossieASP și Waveforms ________________________________124


Fig. 11.9 Comunicația multiprocesor __________________________________________126
Fig. 11.10 Rezultate – Problema 3 ____________________________________________127
Fig. 11.11 Rezultate - Problema 4 _____________________________________________128
Fig. 12.1 Registrul IE _______________________________________________________130
Fig. 12.2 Cod mașină pentru program _________________________________________132
Fig. 12.3 Preluarea datelor de la portul P0 și trimiterea lor la P1 + semnalul dreptunghiular
generat la P2.1 ___________________________________________________________133
Fig. 12.4 Semnalul dreptunghiular generat la P2.1 - programul Waveforms ___________133
Fig. 12.5 Poziția bitului corespunzător activării întreruperii în registrul IE _____________134
Fig. 12.6 Întrerupere Timer 0 ________________________________________________134
Fig. 12.7 Organigramă de funcționare a exemplului 2 ____________________________135
Fig. 12.8 Rezultate Exemplul 2 - Keil ___________________________________________136
Fig. 12.9 Conexiuni - exemplul 3 ______________________________________________137
Fig. 12.10 Formele de undă în programul Keil – Exemplul 3 ________________________138
Fig. 12.11 Formele de undă în programul Keil – Exemplul 4 ________________________139
Fig. 12.12 Formele de undă - programul Proteus _________________________________139
Fig. 12.13 Exemplul 5 - Rezolvare _____________________________________________141
Fig. 12.14 Problema 1 - Keil _________________________________________________141
Lista de figuri și de tabele

Lista de tabele
Tab. 1-1 Program ___________________________________________________________ 8
Tab. 1-2 Tabel - Tema pentru acasă ___________________________________________ 10
Tab. 6-1 Exemplu 2 _________________________________________________________ 63
Tab. 7-1 Cuvinte cheie în C ___________________________________________________ 67
Tab. 11-1 Ratele de baud uzuale - uC8051 _____________________________________117
Tab. 12-1 Întreruperile _____________________________________________________130
Tab. 12-2 Întreruperile - C __________________________________________________133

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