Sunteți pe pagina 1din 25

LABORATOR 1

.include "m32def.inc"

.dseg

VAR1: .byte 1
VAR2: .byte 1
VAR3: .byte 1
SUMA1: .byte 1
SUMA2: .byte 1

.cseg

RESET:
; Initializare stiva
ldi R16,low(RAMEND)
ldi R17,high(RAMEND)
out SPL,R16
out SPH,R17

START:
; Scrie in variabila VAR1 valoarea 70
ldi R16,70
sts VAR1,R16

; Scrie in variabila VAR2 valoarea 30
ldi R16,30
sts VAR2,R16

; Scrie in variabila VAR3 valoarea -50
ldi R16,-50
sts VAR3,R16

; Calculeaza SUMA1 = VAR1 + VAR2
lds R0,VAR1
lds R1,VAR2
rcall ADUNARE
sts SUMA1,R2

; Calculeaza SUMA2 = VAR1 + VAR3
lds R0,VAR1
lds R1,VAR3
rcall ADUNARE
sts SUMA2,R2

rjmp START

; Procedura de adunare a doua numere
; Parametrii: R0 - operand 1
; R1 - operand 2
; Rezultat: R2 - suma
ADUNARE:
mov R2,R1
add R2,R0
ret


LABORATOR 2

De exemplu, pentru declararea unui vector de numere intregi reprezentate pe 16 biti (2 octeti) avind un
numar de 10 elemente si denumit V1 se va utiliza urmatoarea declaratie:
V1: .byte 20

Accesul la elementele vectorului se face pe baza valorii unei variabile index care indica numarul
elementului care se doreste a fi accesat. Pentru a citi sau scrie valoarea unui element, este necesara
determinarea localizarii acestuia in memorie (adresa elementului).
Deoarece, elementele unui vector sint stocate la adrese succesive de memorie in ordinea crescatoare a
indexului asociat, determinarea adresei unui element se realizeaza cu ajutorul urmatoarei formule de
calcul:

Adresa_element = Adresa_inceput_vector + index * dimensiune_element

Scrieti o procedura:


; Procedura de citire element din vectorul VECT
; Parametrii: R17:R16 = indexul (valoare intreaga pe 16 biti)
; Intoarce: R19:R18 = valoarea elementului citit
; Modifica: R16,R17,R18,R19,X
CITESTE:
...

; Revine din procedura
ret

Care citeste elementul din vector de la indexul primit in R17:R16 in perechea de registrii R19:R18.

.include "m32def.inc"

.dseg

VECT: .byte 20 ; Declara un vector de 10 elemente numere intregi
; pe 16 biti

.cseg

RESET:
; Initializare stiva
ldi R16,low(RAMEND)
ldi R17,high(RAMEND)
out SPL,R16
out SPH,R17

; Program de test
START:
; Incarca in perechea de registrii R17:R16 valoarea indexului
; reprezentata pe 16 biti
ldi R16,low(5)
ldi R17,high(5)

; Incarca in perechea de registrii R19:R18 valoarea care se
; doreste a fi scrisa in vector
ldi R18,low(10000)
ldi R19,high(10000)

; Apeleaza procedura de scriere element
rcall SCRIE

rjmp START

; Procedura de scriere element in vectorul VECT
; Parametrii: R17:R16 = indexul (valoare intreaga pe 16 biti)
; R19:R18 = valoarea care se doreste a fi scrisa
; Intoarce: -
; Modifica: R16, R17, X
SCRIE:
; Inmulteste cu 2 valoarea indexului (prin adunare cu el insusi)
add R16,R16
adc R17,R17

; Incarca in registrul X adresa de inceput a vectorului
ldi XL,low(VECT)
ldi XH,high(VECT)

; Aduna la adresa de inceput indexul inmultit cu 2
add XL,R16
adc XH,R17

; Scrie valoarea din R19:R18 in elementul vectorului
st X+,R18 ; Scrie octetul inferior si trece la
; urmatoarea locatie
st X,R19 ; Scrie octetul superior

; Revine din procedura


; Procedura de citire element din vectorul VECT
; Parametrii: R17:R16 = indexul (valoare intreaga pe 16 biti)
; Intoarce: R19:R18 = valoarea elementului citit
; Modifica: R16,R17,R18,R19,X
CITESTE:

ldi R16,low(5)
ldi R17,high(5)
; Inmulteste cu 2 valoarea indexului (prin adunare cu el insusi)
add R16,R16
adc R17,R17

; Incarca in registrul X adresa de inceput a vectorului
ldi XL,low(VECT)
ldi XH,high(VECT)

; Aduna la adresa de inceput indexul inmultit cu 2
add XL,R16
adc XH,R17

; Citeste valoarea elementului in R19:R18
ld R20,X+
ld R21,X

; Revine din procedura
Ret


LABORATOR 3

Scrieti proceduri de inmultire 24 x 16 biti (rezultat pe 40 de biti) atit pentru operanzi fara semn cit si
pentru operanzi cu semn. In acest caz, operanzii vor fi in registrii R18:R17:R16 si R20:R19 iar rezultatul se
va obtine in R25:R24:R23:R22:R21. Schema de calcul este similara celei utilizate la inmultirea 16 x 16 biti.
In acest caz, operandul de 24 de biti se descopune in trei parti de 8 biti (L, M si H) si se efectueaza 6
inmultiri elementare.

.include "m32def.inc"

.cseg

RESET:
; Initializare stiva
ldi R16,low(RAMEND)
ldi R17,high(RAMEND)
out SPL,R16
out SPH,R17

START:
; Test procedura de inmltire 16x16 biti fara semn
ldi R16,low(10000) ; Operand 1
ldi R17,high(10000)

ldi R18,low(50000) ; Operand 2
ldi R19,high(50000)

rcall MP16U ; Apel procedura de inmultire

; Test procedura de inmltire 16x16 biti cu semn
ldi R16,low(10000) ; Operand 1
ldi R17,high(10000)

ldi R18,low(-20000) ; Operand 2
ldi R19,high(-20000)

rcall MP16S ; Apel procedura de inmultire

; Test procedura de inmltire 24x16 biti fara semn
ldi R16,0xC0 ; Operand 1
ldi R17,0xB4
ldi R18,0xB3

ldi R19,low(20000) ; Operand 2
ldi R20,high(20000)

rcall MP24U ; Apel procedura de inmultire

; Test procedura de inmltire 24x16 biti cu semn
ldi R16,0x40 ; Operand 1
ldi R17,0x4B
ldi R18,0x4C

ldi R19,low(-20000) ; Operand 2
ldi R20,high(-20000)

rcall MP24S ; Apel procedura de inmultire

rjmp START

; Procedura de inmultire 16x16 biti fara semn
; Operanzi: R17:R16
; R19:R18
; Rezultat: R23:R22:R21:R20

MP16U:
clr R2

mul R16,R18
movw R21:R20,R1:R0

mul R17,R19
movw R23:R22,R1:R0

mul R16,R19
add R21,R0
adc R22,R1
adc R23,R2

mul R18,R17
add R21,R0
adc R22,R1
adc R23,R2
ret

; Procedura de inmultire 16x16 biti cu semn
; Operanzi: R17:R16
; R19:R18
; Rezultat: R23:R22:R21:R20

MP16S:
clr R2

mul R16,R18
movw R21:R20,R1:R0

muls R17,R19
movw R23:R22,R1:R0

mulsu R17,R18
sbc R23,R2
add R21,R0
adc R22,R1
adc R23,R2

mulsu R19,R16
sbc R23,R2
add R21,R0
adc R22,R1
adc R23,R2
ret

; Procedura de inmultire 24 x 16 biti fara semn
; Operanzi: R18:R17:R16
; R20:R19
; Rezultat: R25:R24:R23:R22:R21

MP24U:
clr R2

mul R19,R17 ; BL x AM
movw R23:R22,R1:R0

mul R20,R18 ; BH x AH
movw R25:R24,R1:R0

mul R19,R16 ; BL x AL
mov R21,R0
add R22,R1
adc R23,R2
adc R24,R2
adc R25,R2

mul R18,R19 ; AH x BL
add R23,R0
adc R24,R1
adc R25,R2

mul R20,R16 ; BH x AL
add R22,R0
adc R23,R1
adc R24,R2
adc R25,R2

mul R20,R17 ; BH x AM
add R23,R0
adc R24,R1
adc R25,R2

ret

; Procedura de inmultire 24 x 16 biti cu semn
; Operanzi: R18:R17:R16
; R20:R19
; Rezultat: R25:R24:R23:R22:R21

MP24S:
clr R2

mul R19,R17 ; BL x AM
movw R23:R22,R1:R0

muls R20,R18 ; BH x AH
movw R25:R24,R1:R0

mul R19,R16 ; BL x AL
mov R21,R0
add R22,R1
adc R23,R2
adc R24,R2
adc R25,R2

mulsu R18,R19 ; AH x BL
sbc R25,R2
add R23,R0
adc R24,R1
adc R25,R2

mulsu R20,R16 ; BH x AL
sbc R24,R2
sbc R25,R2
add R22,R0
adc R23,R1
adc R24,R2
adc R25,R2

mulsu R20,R17 ; BH x AM
sbc R25,R2
add R23,R0
adc R24,R1
adc R25,R2

ret


LABORATOR 4

.include "m16def.inc"

.cseg

RESET:
; Initializare stiva
ldi R16,low(RAMEND)
ldi R17,high(RAMEND)
out SPL,R16
out SPH,R17

; Program de test
ldi R16,100
mov R0,R16
ldi R16,50
mov R1,R16

ldi R16,5 ; Variabila de selectie pentru <switch>

; Implementare <switch-case> varianta 2
clr R17 ; Extinde valoarea indexului la 16 biti
add R16,R16 ; Inmulteste indexul cu 2 (ca valoare pe 16 biti)
adc R17,R17
ldi ZL,low(2*TABELA) ; Incarca in Z adresa primului octet din tabela
ldi ZH,high(2*TABELA) ; (se inmulteste cu 2 deoarece adresa indicata de eticheta
; se refera la locatia de memorie de program pe 16 biti)
add ZL,R16 ; Aduna adresa de inceput a tabelei cu indexul inmultit
adc ZH,R17 ; cu dimensiunea elementelor (2 octeti)
lpm R24,Z+ ; Citeste elementul tabelei in R25:R24
lpm R25,Z

movw Z,R25:R24
ijmp


CASE0:
mov R2,R0 ; Sectiunea CASE0
add R2,R1
rjmp CONTINUA
CASE1:
mov R2,R0 ; Sectiunea CASE1
sub R2,R1
rjmp CONTINUA
CASE2:
mov R2,R1 ; Sectiunea CASE2
sub R2,R0
rjmp CONTINUA
CASE3:
mov R2,R0 ; Sectiunea CASE3
inc R2
rjmp CONTINUA
CASE4:
mov R2,R0 ; Sectiunea CASE4
dec R2
rjmp CONTINUA
CASE5:
mov R2,R1 ; Sectiunea CASE5
inc R2
rjmp CONTINUA
CASE6:
mov R2,R1 ; Sectiunea CASE6
dec R2
rjmp CONTINUA

TABELA:
.dw CASE0
.dw CASE1
.dw CASE2
.dw CASE3
.dw CASE4
.dw CASE5
.dw CASE6

CONTINUA:
; Instructiunile care urmeaza in program dupa
; sectiunea <switch-case>
rjmp CONTINUA



LABORATOR 5

In acest algoritm, citul se obtine in locul deimpartitului iar pasii algoritmului pentru impartirea unui
operand de n biti sint urmatorii:

Initializeaza Rest si indicatorul de transport C cu 0
Repeta de n ori:
Deplaseaza la stinga cu un bit ansamblul format din C:Rest:Deimpartit
Daca valoarea prezenta in C:Rest este mai mare sau egala cu cea din Impartitor atunci se pune
valoarea 1 in bitul cel mai putin semnificativ din Deimpartit si se scade Impartitor din C:Rest

Pentru compararea valorii din C:Rest cu cea din Impartitor se va proceda astfel:

Daca C este setat atunci sigur C:Rest>Impartitor
Daca C este zero atunci se compara valorile din Rest si Impartitor

Pentru scaderea valorii Impartitor din C:Rest este suficient sa se scada Impartitor din Rest.

Folosingd procedura de inmultire data, scrieti o procedura care primeste in R17:R16 o valoare intreaga
fara semn pe 16 biti si completeaza un vector de 5 elemente din memoria de date cu valorile cifrelor
care formeaza reprezentarea in baza 10 a numarului

.include "m16def.inc"

.dseg

CIFRE: .byte 5

.cseg
; Initializare stiva
ldi R16,low(RAMEND)
ldi R17,high(RAMEND)
out SPL,R16
out SPH,R17

; Program de test
START:
ldi R16,low(56789)
ldi R17,high(56789)
rcall CONVERT

rjmp START

; Procedura de impartire 16:8 biti fara semn
; Operanzi: R17:R16 = deimpartit
; R18 = impartitor
; Rezultat: R17:R16 = cit
; R19 = rest
DIV16:
ldi R20,16 ; Contor iteratii
ldi R19,0 ; Initializeaza Rest cu 0

DIV16A:
lsl R16 ; Deplaseaza la stinga cu un bit
rol R17 ; C:Rest:Deimpartit
rol R19

brcs DIV16C ; Compara C:Rest cu Impartitor
cp R19,R18
brlo DIV16B

DIV16C:
sub R19,R18 ; Scade Impartitor din C:Rest
ori R16,0b00000001 ; Seteaza bit 0 din Deimpartit
DIV16B:
dec R20 ; Repeta de 16 ori
brne DIV16A
ret

; Procedura de conversie in baza 10
CONVERT:
ldi XL,low(CIFRE+5) ; Incarca in X adresa primei locatii de dupa vectorul CIFRE
ldi XH,high(CIFRE+5)

ldi R21,5 ; Contor
ldi R18,10 ; Baza de numeratie
CONVERT1:
rcall DIV16
st -X,R19
dec R21
brne CONVERT1
ret

LABORATOR 6

Pentru calculul radicalului (mai exact a partii intregi a acestuia) se propune un algoritm iterativ care
determina bitii rezultatului unul cite unul. Daca se doreste aflarea lui X reprezentat pe 16 biti ca radacina
patrata a lui N reprezentat pe 32 de biti, se poate proceda astfel:

Se initializeaza X cu zero
Pentru b de la 15 la 0
Seteaza bitul b din X
Calculeaza P = X x X
Daca P>N, sterge bitul b din X

Tema:

Scrieti o procedura care calculeaza partea intreaga a radicalului unui numar de 32 de biti pe baza
algoritmului prezentat anterior. Procedura primeste valoarea numarului N in registrii R19:R18:R17:R16 si
intoarce radicalul in R21:R20.

.include "m16def.inc"

.cseg
; Initializare stiva
ldi R16,low(RAMEND)
ldi R17,high(RAMEND)
out SPL,R16
out SPH,R17

ldi R16,0x11 ; Incarca in R19:R18:R17:R16
ldi R17,0xB3 ; valoarea 3160126225 care este
ldi R18,0x5B ; 56215 la patrat
ldi R19,0xBC

rcall SQRT ; Calculeaza radicalul

STOP:
rjmp STOP

; Procedura de calcul radical
; Intrare: R19:R18:R17:R16 = N
; Iesire: R21:R20 = sqrt(N)
SQRT:
ldi R22,0x00 ; Masca initializata cu 0x8000
ldi R23,0x80
clr R20 ; Valoare initiala 0
clr R21
clr R2 ; Registru temporar cu 0
SQRT1:
or R20,R22 ; Seteaza bitul curent
or R21,R23

mul R20,R20 ; Ridica la patrat
movw R13:R12,R1:R0
mul R21,R21
movw R15:R14,R1:R0
mul R20,R21
add R13,R0
adc R14,R1
adc R15,R2
add R13,R0
adc R14,R1
adc R15,R2

cp R16,R12 ; Compara patratul cu valoarea
cpc R17,R13 ; de intrare
cpc R18,R14
cpc R19,R15
brsh SQRT2

eor R20,R22 ; Daca patratul este mai mare
eor R21,R23 ; decit valoarea de intrare
; sterge bitul curent

SQRT2:
lsr R23 ; Trece la bitul urmator
ror R22
brcc SQRT1
ret











LABORATOR 7

1. Scrieti o procedura care primeste in perechea de registrii R17:R16 o valoare intreaga fara semn pe 16
biti si scrie in memorie la adresa indicata de registrul X sirul de 4 caractere care care corespunde
reprezentarii hexazecimale a valorii din registrii.

Reprezentarea unui sir de caractere in memorie se realizeaza scriind codurile caracterelor in locatii
succesive incepind cu adresa de inceput a sirului (primita in registrul X) si apoi adaugarea unui octet
suplimentar cu valoarea 0 (nu caracterul '0') care marcheaza sfirsitul sirului.

Observatie: obtinerea codului unei cifre hexazecimale pornind de la valoarea numerica a acesteia c se
face astfel:

daca c<10 codul caracterului corespunzator cifrei va fi codul caracterului '0' la care se aduna valoarea
cifrei c;
daca c>=10 codul caracterului corespunzator cifrei va fi codul caracterului 'A' la care se aduna valoarea
cifrei c din care s-a scazut valoarea 10.

2. Scrieti un program de test in care se declara in memoria de date o variabila sir de caracter cu
dimensiunea de 5 octeti, incarca o valoare in perechea R17:R16 si apeleaza procedura de conversie.
Verificarea functionarii procedurii se va face urmarind continutul memoriei de date (zona
corespunzatoare sirului) care trebuie sa contina cifrele valorii reprezentate in hexazecimal.


.include "m16def.inc"

.dseg

SIR: .byte 20

.cseg
; Initializare stiva
ldi R16,low(RAMEND)
ldi R17,high(RAMEND)
out SPL,R16
out SPH,R17

; Test procedura de conversie binar-hex
ldi XL,low(SIR)
ldi XH,high(SIR)
ldi R16,low(45678)
ldi R17,high(45678)
rcall BIN2HEX

; Test procedura de conversie hex-binar
ldi XL,low(SIR)
ldi XH,high(SIR)
ldi R16,'A'
st X+,R16
ldi R16,'1'
st X+,R16
ldi R16,'F'
st X+,R16
ldi R16,'9'
st X+,R16
clr R16
st X,R16
ldi XL,low(SIR)
ldi XH,high(SIR)
rcall HEX2BIN

STOP:
rjmp STOP


; Procedura de conversie din binar in hexazecimal
; Intrare: R17:R16 - valoare binara pe 16 biti
; X - adresa de inceput a sirului care
; va contine reprezentarea hexazecimala
BIN2HEX:
; Cifra 1
mov R18,R17 ; Izoleaza in R18 prima cifra hex
lsr R18
lsr R18
lsr R18
lsr R18

cpi R18,10 ; Test cifra sau litera
brsh BIN2HEX1 ; Este litera
subi R18,-'0'
rjmp BIN2HEX2
BIN2HEX1:
subi R18,10-'A'
BIN2HEX2:
st X+,R18 ; Scrie cifra

; Cifra 2
mov R18,R17 ; Izoleaza a doua cifra
andi R18,0x0F

cpi R18,10 ; Test cifra sau litera
brsh BIN2HEX3 ; Este litera
subi R18,-'0'
rjmp BIN2HEX4
BIN2HEX3:
subi R18,10-'A'
BIN2HEX4:
st X+,R18 ; Scrie cifra

; Cifra 3
mov R18,R16 ; Izoleaza in R18 prima cifra hex
lsr R18
lsr R18
lsr R18
lsr R18

cpi R18,10 ; Test cifra sau litera
brsh BIN2HEX5 ; Este litera
subi R18,-'0'
rjmp BIN2HEX6
BIN2HEX5:
subi R18,10-'A'
BIN2HEX6:
st X+,R18 ; Scrie cifra

; Cifra 4
mov R18,R16 ; Izoleaza a doua cifra
andi R18,0x0F

cpi R18,10 ; Test cifra sau litera
brsh BIN2HEX7 ; Este litera
subi R18,-'0'
rjmp BIN2HEX8
BIN2HEX7:
subi R18,10-'A'
BIN2HEX8:
st X+,R18 ; Scrie cifra

clr R18
st X,R18
ret

; Procedura de conversie din hexazecimal in binar
; Intrare: X - adresa sirului care contine
; reprezentarea hexazecimala
; Iesire: R17:R16 - valoarea binara pe 16 biti
; C - resetat daca conversia s-a efectuat
; setat daca a aparut o eroare
HEX2BIN:
; Cifra 1
ld R18,X+ ; Citeste cifra
cpi R18,'0' ; Test cod sub '0'
brlo HEX2BIN10 ; Este sub '0' - eroare
cpi R18,'9'+1 ; Test cod peste '9'
brsh HEX2BIN1 ; Peste '9' - incearca litere
subi R18,'0' ; Calcul valoare binara
rjmp HEX2BIN2 ; Sare la scriere valoare
HEX2BIN1:
cpi R18,'A' ; Test cod sub 'A'
brlo HEX2BIN10 ; Este sub 'A' - eroare
cpi R18,'F'+1 ; Test cod peste 'F'
brsh HEX2BIN10 ; Este peste 'F' - eroare
subi R18,'A'-10 ; Calcul valoare binara
HEX2BIN2:
lsl R18 ; Aduce valoarea pe bitii 4...7
lsl R18
lsl R18
lsl R18
mov R17,R18 ; Scrie valoarea in R17

; Cifra 2
ld R18,X+ ; Citeste cifra
cpi R18,'0' ; Test cod sub '0'
brlo HEX2BIN10 ; Este sub '0' - eroare
cpi R18,'9'+1 ; Test cod peste '9'
brsh HEX2BIN3 ; Peste '9' - incearca litere
subi R18,'0' ; Calcul valoare binara
rjmp HEX2BIN4 ; Sare la scriere valoare
HEX2BIN3:
cpi R18,'A' ; Test cod sub 'A'
brlo HEX2BIN10 ; Este sub 'A' - eroare
cpi R18,'F'+1 ; Test cod peste 'F'
brsh HEX2BIN10 ; Este peste 'F' - eroare
subi R18,'A'-10 ; Calcul valoare binara
HEX2BIN4:
or R17,R18 ; Completeaza valoarea in R17

; Cifra 3
ld R18,X+
cpi R18,'0'
brlo HEX2BIN10
cpi R18,'9'+1
brsh HEX2BIN5
subi R18,'0'
rjmp HEX2BIN6
HEX2BIN5:
cpi R18,'A'
brlo HEX2BIN10
cpi R18,'F'+1
brsh HEX2BIN10
subi R18,'A'-10
HEX2BIN6:
lsl R18
lsl R18
lsl R18
lsl R18
mov R16,R18

; Cifra 4
ld R18,X+
cpi R18,'0'
brlo HEX2BIN10
cpi R18,'9'+1
brsh HEX2BIN7
subi R18,'0'
rjmp HEX2BIN8
HEX2BIN7:
cpi R18,'A'
brlo HEX2BIN10
cpi R18,'F'+1
brsh HEX2BIN10
subi R18,'A'-10
HEX2BIN8:
or R16,R18

; Test sfirsit sir
ld R18,X
cpi R18,0
brne HEX2BIN10
clc
ret

HEX2BIN10:
clr R16
clr R17
sec
ret



LABORATOR 8

. Scrieti procedura OUT_A care primeste in registrul R16 numarul unui pin din portul A si in R17 o valoare
binara (0 sau 1). Procedura actualizeaza pinul indicat de R16 cu valoarea binara din R17.

2. Scrieti procedura IN_A care primeste in registrul R16 numarul unui pin din portul A. Procedura
intoarce in registrul R17 valoarea logica prezenta pe pinul indicat de registrul R16.

3. Scrieti un program de test care initializeaza portul A cu pinii 0..3 ca intrari si pinii 4..7 ca iesiri si
testeaza procedurile scrise.

.include "m16def.inc"

.cseg
; Initializare stiva
ldi R16,low(RAMEND)
ldi R17,high(RAMEND)
out SPL,R16
out SPH,R17

; Initializare port A
; pinii 0..3 intrari initializarte cu 0
; pinii 4..7 iesiri
ldi R16,0b11110000
out DDRA,R16
ldi R16,0b00000000
out PORTA,R16


STOP:
ldi R16,6
ldi R17,0
rcall OUT_A

ldi R16,6
ldi R17,1
rcall OUT_A

ldi R16,6
rcall IN_A

rjmp STOP

; Procedura de actualizare a unui pin din portul A
; Intrare: R16 = numarul pinului (0..7)
; R17 = 0 daca se doreste actualizarea
; pinului cu 0
; = 1 daca se doreste actualizarea
; pinului cu 1
OUT_A:
ldi R18,0b00000001
mov R19,R16
OUT_A1:
cpi R19,0
breq OUT_A2
lsl R18
dec R19
rjmp OUT_A1
OUT_A2:
cpi R17,0
brne OUT_A3
com R18
in R19,PORTA
and R19,R18
out PORTA,R19
ret

OUT_A3:
in R19,PORTA
or R19,R18
out PORTA,R19
ret

; Procedura de citire stare pin din portul A
; Intrare: R16 = numarul pinului (0..7)
; Iesire: R17 = 0 daca bitul este 0
; = 1 daca bitul este 1
IN_A:
ldi R18,0b00000001
mov R19,R16
IN_A1:
cpi R19,0
breq IN_A2
lsl R18
dec R19
rjmp IN_A1
IN_A2:
ldi R17,0
in R19,PINA
and R19,R18
breq IN_A3
ldi R17,1
IN_A3:
Ret



LABORATOR 9: Timere si intreruperi
In acest laborator se prezinta o aplicatie a timerelor si a sistemului de intreruperi si anume generarea
unei baze de timp precise. O baza de timp reprezinta o procedura apelata periodic la intervale de timp
precise independent de functionarea programului principal. Pentru determinarea momentelor de timp
la care trebuie realizat apelul procedurii se utilizeaza un dispozitiv periferic specializat in gestiunea
timpului care se numeste timer. Apelul propriu-zis al procedurii se realizeaza cu ajutorul sistemului de
intreruperi care permite apelarea procedurilor independent de modul de derulare a programului
principal.
Principiul de functionare al unui timer
Un timer este un circuit care numara impulsurile pe care le primeste la intrare. Aceste impulsuri pot fi
preluate de la un pin al microcontrolerului sau de la un dispozitiv numit prescaler. Acest dispozitiv
genereaza cite un impuls la fiecare P perioade ale oscilatorului care actioneaza microcontrolerul. In cazul
utilizarii prescalerului ca sursa a impulsurilor pentru numarare, timerul va numara de fapt intervale de
timp egale cu P perioade ale oscilatorului. Majoritatea prescalerelor permit alegerea valorii P dintr-un
set de citeva puteri ale lui 2.
Circuitul de numarare lucreaza pe n biti (8,16 sau 32 in functie de tipul timerului) ceea ce conduce la o
capacitate de numarare de 2
n
impulsuri. In cazul in care s-a atins capacitatea maxima de numarare,
urmatorul impuls receptionat va determina trecerea numaratorului la zero iar numararea va continua de
la aceasta valoare. Simultan cu trecerea numaratorului in zero se poate genera (daca este activata) o
intrerupere de tip timer-overflow. Aceasta intrerupere poate fi utilizata pentru apelarea procedurii baza
de timp insa nu reprezinta un mecanism suficient de flexibil pentru aceasta deoarece nu permite decit
obtinerea unor intervale de timp egale cu P x 2
n
perioade ale oscilatorului.
In cazul in care se doreste obtinerea unei game mai largi de intervale de timp, este necesara utilizarea
unui mecanism de limitare a valorii maxime de numarare la o alta valoare decit 2
n
. Acest mecanism este
implementat in majoritatea timerelor si se bazeaza pe compararea permanenta a valorii circuitului
numarator cu cea prezenta intr-un registru special de limitare (OCR). In momentul in care numaratorul
atinge valoarea din acest registru, se poate genera (daca este activata) o intrerupere de tip compare-
match iar urmatorul impuls primit la intrare determina aducerea la zero a numaratorului. Utilizind acest
mecanism se poate genera intreruperea la fiecare P x (OCR+1) perioade ale oscilatorului.
Descrierea timerului 0 din microcontrolerele AVR
Microcontrolerele din familia AVR contin mai multe timere denumite numerotate cu cifre incepind de la
0. Primul timer(TIMER0) functioneaza pe 8 biti si are structura prezentata in figura urmatoare:


Configurarea timerului se realizeaza prin intermediul registrului special TCCR0 care contine urmatoarele
informatii:
Nr. Bit: 7 6 5 4 3 2 1 0
Denumire: FOC0 WGM00 COM00 COM01 WGM01 CS02 CS01 CS00

unde:
FOC0 - este un bit utilizat doar pentru test care forteaza iesirea comparatorului in stare activa. Pentru
functionarea normala a timerului acest bit trebuie scris cu 0;
<WGM01:WGM00> - specifica modul de functionare al timerului. Pentru o functionare de tipul celei
prezentate anterior acesti doi biti trebuie sa contina valorile <1:0>
<COM01:COM00> - specifica modul in care se modifica un pin al microcontrolerului (OC0) in momentul
in care comparatorul detecteaza egalitatea. In cazul aplicatiei de generare a bazei de timp nu este
necesara modificarea acestui pin, acesti doi biti trebuie sa contina valorile <0:0>
<CS02:CS01:CS00> - selecteaza valoarea utilizata de prescaler astfel:
<CS02:CS01:CS00> Timerul este actionat de:
<0:0:0> Timer oprit
<0:0:1> Fosc:1
<0:1:0> Fosc:8
<0:1:1> Fosc:64
<1:0:0> Fosc:256
<1:0:1> Fosc:1024
<1:1:0>
Semnal extern pe pinul T0
(numara la trecerea din 1 in 0)
<1:1:1>
Semnal extern pe pinul T0
(numara la trecerea din 0 in 1)
Pentru utilizarea acestui timer in aplicatia de generare a bazei de timp, sint necesare urmatoarele
operatii de configurare:
Scrierea in registrul TCCR0 a valorii corespunzatoare modului de functionare cu reinitializare la atingerea
valorii limita si prescaler selectat conform cu cerintele de timp;
Scrierea valorii limita in registrul OCR0;
activarea intreruperii de tip compare-match prin scrierea valorii 1 in bitul OCIE0 (bitul 1 din registrul
special de activare a intreruperilor generate de timere TIMSK);
Plasarea la adresa corespunzatoare intrarii in intreruperea de tip compare-match a unei instructiuni de
salt catre procedura de tratare a intreruperii (baza de timp);
Activarea intreruperilor la nivelul procesorului prin instructiunea sei.
Procedura de tratare a unei intreruperi
Procedurile de tratare a intreruperilor se deosebesc de procedurile normale prin faptul ca sint apelate in
mod automat de catre procesor in momentul aparitiei unui eveniment la nivelul unui dispozitiv periferic.
Aceste proceduri intrerup temporar programul rulat de procesor pentru a realiza operatiile solicitate de
periferic. Structura unei proceduri de tratare a unei intreruperi este urmatoarea:
ETICHETA_PROCEDURA_TRATARE_INTRERUPERE:
; Salvare context program
...

; Continut propriu-zis al procedurii
...

; Refacere context program
...

; Revenire din procedura
reti
Salvarea contextului program este necesara pentru a asigura reluarea corecta a programului intrerupt.
Contextul programului este format din valorile registrilor si ale indicatorilor de conditii. Este necesara
salvarea doar a acelor registrii care sint modificati de catre procedura de tratare a intreruperii,
modalitatea de realizare a salvarii fiind adaugarea valorii acestora in stiva procesorului cu ajutorul unor
instructiuni push. Indicatorii de conditii sint pastrati in registrul special SREG.
Refacerea contextului program presupune scoaterea valorilor registrilor si a indicatorilor de conditii din
stiva procesorului si copierea acestora inapoi in registrii respectiv in registrul special SREG.
Revenirea din procedura se face cu ajutorul intructiunii reti (nu ret ca in cazul procedurilor normale).
Un exemplu de program pentru microcontrolerul ATMega16 (functionind la 16Mhz) care implementeaza
o baza de timp este urmatorul:
.include "m16def.inc"

.dseg

CONTOR: .byte 2 ; Contor de intreruperi

.cseg
; Intrare in program la RESET
rjmp INIT

; Intrare corespunzatoare intreruperii de comparatie TIMER0
.org OC0addr
rjmp TIMER0

INIT:
; Initializare stiva
ldi R16,low(RAMEND)
ldi R17,high(RAMEND)
out SPL,R16
out SPH,R17
; Initializeaza variabila contor cu 10
ldi R16,low(10)
ldi R17,high(10)
sts CONTOR+0,R16
sts CONTOR+1,R17

; Initializare port A cu bitul 0 ca iesire si restul ca intrari
ldi R16,0b00000001
out DDRA,R16
ldi R16,0b00000000
out PORTA,R16

; Initializare TIMER0 in mod "Clear timer on Compare Match" si
; prescaler 1:1
ldi R16,0b00001001
out TCCR0,R16

; Valoarea maxima a numaratorului 159 (pentru divizare cu 160)
ldi R16,159
out OCR0,R16

; Activeaza intreruperea de comparatie de la TIMER0
ldi R16,0b00000010
out TIMSK,R16

; Activeaza intreruperile microprocesorului
sei

START:
rjmp START

; Procedura de tratare a interuperilor generate de TIMER0
; (procedura este apelata ciclic la un interval de 1 msec)
TIMER0:
; Salveaza contextul programului
push R24
push R25
in R24,SREG
push R24

; Citeste in R25:R24 variabila CONTOR
lds R24,CONTOR+0
lds R25,CONTOR+1

; Decrementeaza valoarea
sbiw R25:R24,1
; Testeaza valoarea 0
brne TIMER0A

; S-au inregistrat 10 de apeluri ale procedurii (100 microsecunde)
; se apeleaza procedura baza de timp
rcall BT100

; Reinitializeaza R25:R24 cu 10
ldi R24,low(10)
ldi R25,high(10)

TIMER0A:
; Actualizeaza variabila CONTOR
sts CONTOR+0,R24
sts CONTOR+1,R25

; Reface contextul programului si revine din intrerupere
pop R24
out SREG,R24
pop R25
pop R24
reti

; Procedura corespunzatoare bazei de timp de 100 microsecunde
BT100:
; Complementeaza bitul 0 din portul A
in R24,PORTA
ldi R25,0b00000001
eor R24,R25
out PORTA,R24
ret
Programul configureaza timerul 0 sa genereze intreruperi la fiecare 160 perioade ale oscilatorului de
ceas (10 microsecunde). Procedura de tratare a intreruperii contorizeaza un numar de 10 intreruperi
(100 microsecunde) si apeleaza procedura baza de timp BT100. S-a recurs la apelarea procedurii baza de
timp o data la citeva intreruperi deoarece cu un timer de 8 biti nu este posibila generarea intreruperilor
la intervale de timp mai mari (de ordinul secundelor) iar unele aplicatii necesita acest lucru.
Procedura baza de timp realizeaza la fiecare apel complementarea valorii conexiunii 0 din portul A. In
cazul in care pe aceasta conexiune s-ar lega o dioda LED, aceasta va clipi cu frecventa de 5Khz
(insesizabila de ochi). Programul a fost scris sa functioneze la o astfel de frecventa pentru se putea
realiza usor simularea functionarii (durata mica a simularii). O aplicatie reala poate necesita ca LED-ul sa-
si schimbe starea o data la o secunda, caz in care paramterii programului trebuie modificati.