Sunteți pe pagina 1din 72

Universitatea Tehnică a Moldovei

Departamentul Microelectronica și
Inginerie Biomedicală

Microprocesoare și Interfețe

lect. univ. Postica Vasile (cab. 3-425) *E-mail: vasile.postica@mib.utm.md


1
Chișinău 2020
Modulul T4 (4 ore)

CUPRINS
4.1. Inițiere în ASM.
4.2. Stiva
4.3. Subrutina
4.3.1. MACRO
4.4. Realizarea construcţiilor algoritmice de bază
4.5. Constante
4.6. Logica booleană
4.1. Inițiere în ASM

Un microcontroller in orice moment de timp trebuie sa execute o instructiune definita


de programator. Atunci cand microcontrollerul executa o comanda definita de
programator vom spune ca controllerul se afla sub controlul programului. Si invers, In
cazulin care se executa o comanda care nu a fost definita de catre programator vom
spune ca microcontrollerul a iesit de sub control.
Un program ce ruleaza pe microcontroller trebuie sa mentina microcontrollerul
intotdeauna sub control ceia ce presupune existenta unei bucle infinite in program.

Vom defini doua parti componente principale a unui program:

• Partea de initializare - o secventa de cod la inceputul programului ce serveste pentru


initializarea microcontrollerului pentru lucru.
• Partea de procesare - rezolvarea problemei si mentinerea sub control a
Microcontrollerului cu o bucla infinita.
4.1. Inițiere în ASM
Segmentarea unui program în ASM conform memoriei
4.1. Inițiere în ASM
Testarea în ASM:
; FLASH ===================================================
.CSEG ; Кодовый сегмент
NOP
NOP
NOP

.CSEG ; Кодовый сегмент


NOP
NOP
NOP
JMP 0x000001

.CSEG ; Кодовый сегмент


NOP
NOP
NOP
RJMP PC+2
08 September 2021
NOP
NOP
RJMP PC-6
NOP
4.1. Inițiere în ASM
Testarea în ASM:
.CSEG ; Кодовый сегмент
M1: NOP
NOP
NOP
RJMP M2
NOP
M2: NOP
RJMP M1
NOP

M1 – etichetă (label), denumirea trebuie să fie fără spațiu, să nu se înceapă cu cifre și


să se finiseze cu două puncte.
Valoarea etichetelor este de 2 byte (16 biți)

Diferența principală între RJMP și JMP prezintă numărul de tacturi necesare pentru
efectuarea instrucției.
4.1. Inițiere în ASM
Testarea în ASM:

Diferența principală între RJMP și JMP prezintă numărul de tacturi necesare pentru
efectuarea instrucției.
.CSEG ; Кодовый сегмент
M1: NOP
NOP
LDI ZL,low(M2) ; Загрузили в индекс
LDI ZH,High(M2)
LDI R16, 55
;LDI R1, 20
IJMP

NOP
NOP
NOP
M2: NOP
RJMP M1
NOP
Команда LDI загружает непосредственное значение в регистр старшей (от R16
до R31) группы.
R0 .. R15 - nu sunt disponibili pentru operaţiile cu constante!
4.1. Inițiere în ASM
Testarea în ASM:

Incrementarea, decrementarea, set/clear, comparare

.CSEG ; Кодовый сегмент


M1:
LDI R16, 255
INC R16 ; verificăm dacă s-a pus bitul carry in SREG
; DE ASEMENEA VERIFICM ALTI BITI
DEC R16 ; decrementarea
CLR R16 ; stergem registrul R16 = 0x00
SET R16 ; setăm registrul R16 = 0xFF
LDI R16, 150
LDI R17, 150
ADD R16, R17 ; verificăm bitul carry (C) in SREG
CP R16, R17 ; comparare R16 – R17
CPI R16, 150 ; comparare R16 - constanta

Instrucțiune INC nu schimbă flagul C (carry) din SREG


4.1. Inițiere în ASM
Testarea în ASM:

.CSEG ; Кодовый сегмент


M1: NOP
NOP
LDI ZL,low(M2) ; Загрузили в индекс
LDI ZH,High(M2)
LDI R16, 55
;LDI R1, 20
IJMP

NOP
NOP
NOP
M2: NOP
RJMP M1
NOP

Instrucțiunea IJMP face saltul la adresa din perechea registrilor Z (în care am inclus
adres etichetei M2).
4.1. Inițiere în ASM
Directiva .org
; FLASH ===================================================
.CSEG ; Кодовый сегмент
NOP

.ORG 0x0010
M1: NOP
NOP
LDI ZL,low(M2) ; Загрузили в индекс
LDI ZH,High(M2)

IJMP

NOP
NOP
NOP
M2: NOP
RJMP M1
NOP

Rolul directivei este de a deplasa segmentul de cod, deoarece la începutul


segmentului de cod de obicei se află vectorul de întreruperi.
4.1. Inițiere în ASM
Ca urmare a celor spuse mai sus un program in ASM va avea urmatoarea structura:

init: ; punctul de intrare in program


...
...
... ; partea de initializare
... ; a microcontrollerului
...
end_init: ; indicator de sfarsit al initializarii
main_loop: ; inceputul partii de procesare
...
... ; corpul partii de procesare
... ; inclus in bucla infinita
...
end_main_loop: ; sfarsitul partii de procesare
rjmp main_loop ; salt spre inceputul buclei infinite

Pentru evidentierea zonelor de initializare si procesare a programului se recomanda


utilizarea etichetelor (label).
4.1. Inițiere în ASM
Directive de preprocesare a compilatorului.

Directive de preprocesare a compilatorului sunt comenzi catre compilator care sunt


executate de catre compilator inaintea generarii codului binar. Rolul lor este de a
configura compilatorul si a indica compilatorului modul in care trebuie sa fie tratate liniile
de program care le urmează.

In aceasta faza vom defini cateva directive de preprocesare a compilatorului:

.include <fisier> - indica compilatorului sa includa in locul in care e invocata


comanda fisierul respectiv
.cseg - indica compilatorului ca liniile de cod care urmeaza aceasta directiva fac parte
din segmentul de memorie de program
.org <addr> - indica compilatorului ca liniile de cod care urmeaza se vor inregistra
incepand de la o adresa specificata in sgmentul de emorie curent
4.1. Inițiere în ASM
Alți operatori
.def – se poate redefini denumirea unui registru (I/O sau de uz general).
Se scriu în .dseg
.def contor = R16
.def buffer = R17
; DATA =====================================================================
.DSEG
.def contor = R16
.def buffer = R17

; FLASH ====================================================================
.CSEG; Кодовый сегмент
NOP

.ORG 0x0010
M1: NOP
LDI ZL,low(M2); Загрузили в индекс
LDI ZH,High(M2)
LDI contor, 100
LDI buffer, 200
IJMP

M2: NOP
RJMP M1
NOP
;===========================================================================
4.1. Inițiere în ASM
Lucrul cu registrii I/O

Se poate observa că registrii I/O au și o adresă proprie de la $00 ... $3F.


Adresarea dată poate fi efectuată cu instrucțiunele IN și OUT.
4.1. Inițiere în ASM
Lucrul cu registrii I/O

În rezultat la registrii I/O se poate adresa prin 2 metode:


• Prin instrucțiunele IN/OUT cu adresele scurte ($00 ... $3F);
• Prin instrucțiunele LOAD/STORE utilizând adresa deplină.

Ca exemplu analizăm un registru I/O periferic UDR (la moment nu are importanță care
anume și ce rol are), care are adresa 0x0C (0х2С – adresa lungă)

LDI R18,10 ; Загрузили в регистр R18 число 10. Просто так

OUT UDR,R18 ; Вывели первым способом, компилятор сам


; Подставит вместо UDR значение 0х0С

STS 0x2C,R18 ; Вывели вторым способом. Через команду Store


; Указав адрес напрямую.

Instrucțiunele IN/OUT sunt cu 1 tact mai scurte deoarece lucrează cu adrese mai scurte
decât LOAD/STORE.
4.1. Inițiere în ASM
Lucrul cu registrii I/O

Setarea/resetarea unui bit din PORT I/O


4.1. Inițiere în ASM
Lucrul cu registrii I/O

Setarea/resetarea unui bit din PORT I/O

.cseg
SBI SREG,0
SBI SREG, 7
CLC
SEC

SBI și CBI lucrează doar pentru registrii I/O cu adresa de până la 0x3F

Astfel pentru primele 2 rânduri de cod se va da eroarea:


Operand 1 out of range: 0x3f
Deoarece registrul SREG nu intră în intervalul dat de adrese și în rezultat are instrucțiuni
personale.
4.2. Stiva (Stack)
Stiva este un mecanism care permite stocarea temporara a datelor dupa principiul LIFO (Last Input
First Output) - Primul Intrat Ultimul Iesit.

Introducerea in stiva se va executa prin comanda PUSH R - introducerea continutului unui


Registru de Uz General in Stiva (R -> STACK). Extragerea datelor cu comanda POP R (R <- STACK).

Deasemenea stiva este un mecanism fara de care nu este posibil lucrul cu subrutinele, deoarece
mecanismul stivei permite stocarea temporara a Contorului de Program PC pe durata executiei
subrutinei. Respectiv comenzile de tip CALL si RET deasemenea vor introduce/extrage date din
stiva.

Mecanismul de stiva este realizat in baza memoriei RAM si un Registru Indicator de Stiva - SP
(Stack Pointer).
Indicatorul de stiva SP indica la adresa curenta de scriere in spatiul RAM.
SP este un registru dublu (16 biti), construit in baza [ SPH : SPL ] facilitand accesul la intreg
spatiul de memorie, pana la 64 K.
4.2. Stiva (Stack)

RAM
4.2. Stiva (Stack)
Executand comanda PUSH R continutul registrului se va inregistra la adresa ce se
contine in registrul Indicator de Stiva SP, dupa care are loc decrementarea SP.

PUSH R
1. RAM[SP] = R
2. SP = SP - 1

Pentru comanda POP R executia presupune Incrementarea Indicatorului de stiva SP


urmata de transferul in Registrul de Uz General a valorii de la adresa SP

POP R
1. SP = SP + 1
2. R = RAM[SP]

Adaugarea elementelor in stiva va implica cresterea stivei. reesind din cele spuse mai
sus, vom afirma ca Stiva creste in directia diminuarii adreseilor memoriei RAM.
4.2. Stiva (Stack)
Initializarea Stivei

Registrul Indicator de Stiva SP este localizat in spatiul registrilor periferici, respectiv


citirea si modificarea valorii din SP se va efectua prin comenzile IN si OUT.

Deoarece valoarea indicatorului de stiva SP descreste odata cu cresterea stivei, se


recomanda initializarea stivei la o adresa avansata in spatiul de memorie RAM. O
asemenea valoare pote fi constanta RAMEND care contințe ultima adresa existenta din
memoria RAM interna a Microcontrollerului.

Operatia de Initializare a stivei va consta in initializarea Indicatorului de stiva SP.

SP = RAMEND, [SPH:SPL] = RAMEND

Secventa de cod in ASM pentru operatia de mai sus va arata in felul urmator:

ldi R16, LOW(RAMEND)


out SPL, R16 ; initializare byte inferior SP
ldi R16, HIGH(RAMEND)
out SPH, R16 ; initializare byte superior SP
4.2. Stiva (Stack)
Initializarea Stivei

ldi R16, LOW(RAMEND)


out SPL, R16 ; initializare byte inferior SP
ldi R16, HIGH(RAMEND)
out SPH, R16 ; initializare byte superior SP

unde:
• LOW - macroinstructiunea pentru selectarea byte-ului inferior dintr-o constanta.
• HIGH - macroinstructiunea pentru selectarea byte-ului superior dintr-o constanta.

Intr-un ciclu de program numarul de inregistrari trebuie sa fie egal cu numarul de


extrageri pentru a evita erori de scurgere sau violare de memorie.
Exemple 4.2. Stiva (Stack)

.CSEG ; Кодовый сегмент

LDI R16,Low(RAMEND) ; Инициализация стека


OUT SPL,R16

LDI R16,High(RAMEND)
OUT SPH,R16

LDI R17,0 ; Загрузка значений


LDI R18,1
LDI R19,2
LDI R20,3
LDI R21,4
LDI R22,5
LDI R23,6
LDI R24,7
LDI R25,8
LDI R26,9
Exemple 4.2. Stiva (Stack)
PUSH R17 ; Укладываем значения в стек
PUSH R18
PUSH R19
PUSH R20
PUSH R21
PUSH R22
PUSH R23
PUSH R24
PUSH R25
PUSH R26

POP R0 ; Достаем значения из стека


POP R1
POP R2
POP R3
POP R4
POP R5
POP R6
POP R7
POP R8
POP R9
4.3. Subrutina
Subrutina - Secventa de instructiuni grupata intre o eticheta (label) si instructiune de
returnare din subrutina RET. Eticheta reprezinta o adresa in memoria de programe
fiindui atribuit un nume de acces. In program va fi reprezentata de un nume de eticheta
urmata de (:)

MySub: ; Numele subrutinei reprezentata de


; eticheta inceputui subrutinei
...
... ; Corpul subrutinei
...
...
ret ; returnare din subrutina

Subrutina poate fi apelata prin numele ei cu una din comanzile de chemare subrutinei
CALL, RCALL sau ICALL.

...
rcall MySub ; apelul subrutinei MySub
...
4.3. Subrutina
Mecanismul de chemare a subrutinei consta in salvarea adresei
curente de executie in stiva pentru a avea posibilitatea de a
restabili executia comenzilor urmatoare dupa returnarea din
subrutina.
Instructiunea de apel a subrutinei cu o instructiune de til CALL
va fi interpretata dupa cum urmeaza:
• PC -> STACK - salvarea adresei curente in Stiva
• jmp MySub - salt la adresa etichetei My Sub
Pentru returnare din subrutina vom avea:
• PC <- STACK - restabilirea adresei din stiva
• PC <- PC + 1 - trecerea la comanda urmatoare dupa
comanda de apel a subrutinei
4.3. Subrutina
De mentionat ca Contorul de Program PC este un registru de 16 biti, respectiv va a ocupa
doua locatii in stiva, executandu-se doua operatii de salvare a unui byte in stiva.
Deoarece un apel de subrutina presupune utilizarea stivei, este strict recomandat ca
inainte de un oarecare prim apel stiva sa fie initializata, iar locul cel mai potrivit este in
partea de initializare a programului.

.include "m16def.inc" ; includem fisierul de adrese la


; periferice pentru ATmega16
.cseg ; inicam inceputul segmentului de cod
.org 0 ; programul va fi inregistrat de la
; adresa 0x00
init: ; punctul de intrare in program
ldi R16, LOW(RAMEND) ; initializarea stivei
out SPL, R16
ldi R16, HIGH(RAMEND)
out SPH, R16
...
4.3. Subrutina
Subrutina securizata
Vom numi subrutina securizata subrutina care nu afecteaza valorile registrilor prin
executia sa. Mecanismul subrutinei securizate consta in salvarea registrilor utilizati in
subrutina in stiva la inceputul subrutinei si restabilirea valorilor registrilor inainte de
returnare din subrutina.
MySub: ; Numele subrutinei reprezentata de
; eticheta inceputui subrutinei
push r15 ; salvarea registrului r15
push r16 ; salvarea registrului r16
...
... ; Corpul subrutinei
... ; utilizare registri r15 si r16
...
...
pop r16 ; restabilire r16
pop r15 ; restabilier r15
ret ; returnare din subrutina

De mentionat ca ordinea restabilirii registrilor de lucru este inversa celei de salvare,


conform principiului LIFO al stivei.
4.3. Subrutina
Subrutina cu parametri

In calitate de parametri al unei subrutine pot fi utilizati registrii de uz general. In asa mod
pentru a transmite date de intrare in subrutina, inainte de a apela o subrutina este nevoie
ca registrii utilizati ca parametri sa fie initializati cu valorile de intrare dorite pentru acesti
parametri. Iar dupa executia subrutinei se vor prelua valorile din registrii rezervati
parametrilor de iesire.
De exemplu daca vom avea o subrutina care va utiliza R16 si R17 ca parametri de
intrare si R18 ca parametru de iesire, in care subrutina va stoca rezultatul și de exemplu
vom avea de evaluat o expresie de tipul:

a = MySub(K1, K2)

Apelul de subrutina va arata in felul urmator:


...
...
ldi r16, K1 ; initializarea primului parametru
ldi r17, K2 ; initializarea parametrului al doilea
rcall MySub ; apelul subrutinei MySub
sts a, r18 ; preluarea rezultatului subrutinei
...
...
4.3. Subrutina
Subrutina cu parametri

Registrii utilizati ca parametri de intrare/iesire NU vor fi salvati in interiorul subrutinei.


mecanismul de salvare a registrilor utilizati ca parametri se va implementa dupa cum
urmeaza: paramtrii se vor salva in stiva inainte de initializare si se vor restabili dupa
preluarea rezultatului subrutinei.

...
...
push r16 ; salvarea registrului parametru r16
push r17 ; salvarea registrului parametru r17
push r18 ; salvarea registrului parametru r18
ldi r16, K1 ; initializarea primului paramatru
ldi r17, K1 ; initializarea parametrului al doilea
rcall MySub ; apelul subrutinei MySub
sts a, r18 ; preluarea rezultatului subrutinei
pop r18 ; restabilirea registrului parametru r16
pop r17 ; restabilirea registrului parametru r17
pop r16 ; restabilirea registrului parametru r18
...
...
4.3.1. MACRO

MACRO — оператор макроподстановки. Позволяет присваивать имена целым


кускам кода, можно задавать параметры .

.MACRO SUBI16; Start macro definition


subi @1,low(@0) ; Subtract low byte
sbci @2,high(@0) ; Subtract high byte
.ENDM ; End macro definition

@0, @1, @2 это параметры макроса, они нумеруются по порядку. А при


вызове подставляются в код.
Вызов выглядит как обычная команда:

SUBI16 0x1234,r16,r17

После имени через запятую передаются параметры, которые подставятся в код.


Макросы позволяют насоздавать себе удобных команд на все случаи жизни, по сути
создать свой язык. Но надо помнить, что каждый макрос это кусок кода, поэтому
если макрос получается большой, то его лучше оформить в виде процедуры или
функции — будет резкая экономия места в памяти, но выполняться будет чуток
медленней.
4.4. Realizarea construcţiilor algoritmice de bază
Construcția schemelor bloc a unor algoritmi/programe

Începutul sau sfârșitul

Introducerea
sau afișare (I/O)

Verificarea unor
condiții

Calcule

Se utilizează pentru algoritmi destul de


mici și cu o complexitate redusă
4.4. Realizarea construcţiilor algoritmice de bază
Programarea în limbajul ASM (și nu numai în ASM) se reduce executarea
condiționată sau necondiționată a unor instrucțiuni.

Pentru executarea necondiționată vom avea asa numiții algoritmi seriali, care
sunt compuși dintr-o serie de operații de transfer și prelucrare.
4.4. Realizarea construcţiilor algoritmice de bază
Execuția condiționată presupune execuția unui set de instrucțiuni de transfer sau
prelucrare în dependența de o condiție.

Prin "set de instrucțiuni" vom avea în vedere de la nici o comandă până la


secvențe complexe de program.

Setul de comenzi pentru arhitectura AVR presupune două tipuri de comenzi


condiționale:
Comenzi de salt condiționat - BR_OP LABEL
Comenzi de ignorare a instrucțiunii imediat următoare - SB_OP
4.4. Realizarea construcţiilor algoritmice de bază

BRBC # переход если бит # в регистре SREG=0


BRBS # переход если бит # в регистре SREG=1
BRCS переход если С=1
BRCC переход если С=0
BREQ переход если Z=1
BRNE переход если Z=0
BRSH переход если С=0
BRLO переход если С=1 BRCS=BRLO и BRCC=BRSH
BRMI переход если N=1 А таких команд как BRBS # и
BRPL переход если N=0
BRBC # вообще не существует.
BRGE переход если S=0
BRLT переход если S=1
Это всего лишь иносказательная
запись всех остальных бранчей, в
BRHC переход если H=0
BRHS переход если H=1 зависимости от номера бита #.
BRTC переход если T=0
BRTS переход если T=1
BRVS переход если V=1
BRVC переход если V=0
BRID переход если I=0
BRIE переход если I=1
4.4. Realizarea construcţiilor algoritmice de bază
Implementarea algoritmilor cu comenzi de salt condiționat

Comenzile de acest tip sunt comenzi care după testarea unei anumite condiții,
presupuse de comanda, de obicei fiind un bit din registrul de stare SREG, execută
un salt a execuției la o adresa fixă specificată de eticheta (label). În constext vom
numi acest tip de comenzi ca BR_OP - operații de ramificare. Biții verificați din
SREG pot fi gasiți în tabelul de comenzi a operațiilor de transfer al controlului,
operații de salt condiționat.
4.4. Realizarea construcţiilor algoritmice de bază
Implementarea algoritmilor cu comenzi de salt condiționat

Pentru acest tip de comenzi putem face niște echivalări cu instrucțiunile


condiționale din limbajele de nivel înalt cum ar fi Limbajul C.
De ex:
BREQ if == daca este egalitate
BRNE if != daca este diferit
BRSH if >= daca este mai mare sau egal
BRLO if < daca este mai mic
etc.

O comanda de tip BR_OP de cele mai dese ori este precedată de o instrucțiune
de comparație CP, CPI sau TEST. Comenzile de comparație sunt menite pentru
a evalua relația între elementele participante la TEST având ca rezultat
modificarea registrului de stare SREG. O instrucțiune de tip BR_OP poate să nu
fie precedată de o operație comparație. Acest lucru este posibil în cazul în care
operația de prelucrare de înaintea operației de ramificare configurează corect
registrul SREG în starea dorită pentru ramificare. De exemplu după o
decrementare până la ZERO în cicluri. De fapt în spatele comparației se execută
o operație de scădere fără a salva rezultatul operației, iar ca urmare a operației
de scădere se vor seta biții din registrul de stare SREG.
4.4. Realizarea construcţiilor algoritmice de bază
Implementarea algoritmilor cu comenzi de salt condiționat

Construcția algoritmică de ramificare în ulimbajul ASM poate fi implementată


după cum urmează unde etichetele L1, L2, L3 și L4 corespund punctelor cu
același nume prezentate în figura de mai sus.
Saltul maxim al instrucțiunilor BR*** este de 63 instrucțiuni!!!
4.4. Realizarea construcţiilor algoritmice de bază
Implementarea algoritmilor cu comenzi de salt condiționat
L1: ; inceputul constructiei de ramificare
cp R1,R2 ; operatia de comparare (R2 - R1)
BR_OP L3 ; operatia de salt conditionat - ramificare
L2: ; F - test FALSE
...
... ; OP1 - setul de instructiuni pentru ramura FALS
...
rjmp L4 ; salt neconditionat la sfarsitul
; constructiei de ramificare
L3: ; T - test TRUE
...
... ; OP2 - setul de instructiuni pentru ramura TRUE
...
(rjmp L4) ; poate fi omis
L4: ; sfarsitul constructiei de ramificare
4.4. Realizarea construcţiilor algoritmice de bază
Implementarea algoritmilor cu comenzi de salt condiționat
CPI R16,1 ; Сравниваем R16 с 1
BREQ ActionA ; Переход если равно (EQual, Z=1)
; Если не равно, то идем дальше

CPI R16,2 ; Сравниваем R16 с 2


BREQ ActionB ; Переход если равно
; Если не равно, то идем дальше

CPI R16,13 ; Сравниваем R16. т.е. R16-13


BRCS ActionC ; Если возник перенос, значит R16 меньше 13
; Если не возник - идем дальше
RJMP NoAction ; Переход на выход

ActionA: NOP ; Делаем наш экшн


RJMP NoAction ; Выходим, чтобы не влезть в ActionB

ActionB: NOP ; Делаем наш экшн


RJMP NoAction ; Выходим, чтобы не влезть в ActionC

ActionC: NOP ; Делаем наш экшн

NoAction: NOP

; Вместо NOP, разумеется, должны быть какие-нибудь полезные команды.


4.4. Realizarea construcţiilor algoritmice de bază
Implementarea ramificărilor cu comenzi de ignorare a următoarei comenzi.

Comenzile de acest tip presupun ignorarea execuției comenzii imediat care o


urmează. Vom numi acest tip de comenzi în acest context ca comenzi tip
SB_OP. Aceste comenzi de cele mai dese ori presupun verificarea unui bit dintr-
un Registru de Uz General (din cei 32), Registru Periferic (din cei 64 – nu toți!)
sau registrul SREG. Bitul verificat se poate găsi din tabelul de comenzi pentru
fiecare comandă în parte. Saltul condiționat pentru aceste comenzi va fi
reprezentat prin saltul peste o comandă, și deci nu este nevoie de specificat
adresa la care va avea loc saltul.

Formatul instrucțiunii va arăta după cum urmează:


SB_OP TST_REG, N unde:
 SB_OP - denumirea comenzii care va specifica o testare la bit setat
sau resetat
 TST_REG - numele registrului testat
 N - numărul de ordine a bitului testat în registrul selectat

Iar definiția comenzii va suna în felul următor: Salt peste o comandă (PC =
PC+2) dacă bitul N din registrul TST_REG este setat/resetat. În caz contrar
execută comanda următoare (PC=PC+1).
4.4. Realizarea construcţiilor algoritmice de bază
Implementarea ramificărilor cu comenzi de ignorare a următoarei comenzi.

Echivalările pentru limbajele de nivel înalt


vor fi de tip
if(TST_REG[N]==0)
sau
if(TST_REG[N]==1)

Aceste comenzi nu necesită operații de


pre-comparare, ele execută comparația
necesară și saltul în cadrul aceleiași
instrucțiuni.

SBRS – skip (S) if bit (B) in Register (R) is set (S)


SBRC – skip (S) if bit (B) in Register (R) is clear (C)

SBIS – skip (S) if bit (B) in I/O Register (I) is set (S)
SBIC – skip (S) if bit (B) in I/O Register (I) is clear (S)
În SBI* se include și registrul SREG, care la fel este un registru I/O
Instrucțiunele SBI* pot verifica registrii I/O cu adresa inclusă între 0x00 și 0x1F (pentru
ATmega16A), pentru alte modele a se verifica datasheet.
Ceilalți registri I/O se vor verifica cu măști!
4.4. Realizarea construcţiilor algoritmice de bază
Vom realiza mai jos construcția
algoritmică de ramificare
și implementarea ei în ulimbajul
ASM unde etichetele L1, L2, L3 și L4
corespund punctelor cu același nume.
4.4. Realizarea construcţiilor algoritmice de bază
Implementarea ramificărilor cu comenzi de ignorare a următoarei comenzi.
L1: ; inceputul constructiei de ramificare
SB_OP ; operatia ignorare a comenzii ce urmeaza
rjmp L3 ; salt la executia clauzei FALSE
(rjmp L2) ; salt la executia clauzei TRUE, poate fi omis
L2: ; T - test TRUE
...
... ; OP1 - setul de instructiuni pentru ramura
TRUE
...
rjmp L4 ; salt neconditionat la sfarsitul
; constructiei de ramificare
L3: ; F - test FALSE
...
... ; OP2 - setul de instructiuni pentru ramura
FALSE
...
(rjmp L4) ; poate fi omis
L4: ; sfarsitul constructiei de ramificare
4.4. Realizarea construcţiilor algoritmice de bază
Realizarea construcțiilor algoritmice complexe în baza ramificărilor

După cum s-a putut observa construcțiile algoritmice discutate pana acum se
refera in special implementării instructiunii if ... else a limbajelor de nivel
înalt (cum ar fi C/C++).
Majoritatea limbajelor de nivel inalt au un set de instrucțiuni specializate pentru
implementarea construcțiilor algoritmice condiționale, selecție, și ciclice cum ar fi:
• Condiționale
 if ... else if
 switch/case
• Cicluri
 while
 do ... while
 for
Vom analiza fiecare construcție în parte și von da o realizare în limbajul ASM a
fiecărei din acestea.
4.4. Realizarea construcţiilor algoritmice de bază
Imlementarea instructiunilor if ... else if

Realizarea instrucțiunilor de tip if ... else if coincide cu relizarea


construcțiilor de ramificare expuse mai sus și deci tot ce s-a vorbit la acest capitol
este aplicabil pentru acest tip de instrucțiuni. Vom adăuga doar faptul că clauza
FALSE va conține încă o ramificare de același tip. În acest mod vom obține un
lant de verificări de-a lungul clauzei FALSE. Ramificările se pot face cât cu
instrucțiuni de tip BR_OP cât și cu SB_OP iar utilizarea unui anumit tip va impune
respectarea regulilor de implementare descrise mai sus. Ramificările pot fi cu
același tip de instrucțiuni sau mixate, utilizând ambele tipui de verificări.
4.4. Realizarea construcţiilor
algoritmice de bază
Imlementarea instructiunilor if ... else if

if(R16==15) R17++
else if (R16>20) R17—
else if (R16<10) R17 = 0
else R17 = 255
4.4. Realizarea construcţiilor algoritmice de bază
Imlementarea instructiunilor (if else)

if (А>=B){ action_a }
else { action_b }

; R16 = A (15), R17 = B (19)


CP R16,R17 ; Сравниваем два значения
BRCS action_b ; когда A>=B флага С не будет
; Перехода не произойдет
action_a: NOP ; и выполнится действие А
NOP
NOP
RJMP next_action ; Но чтобы действие B не произошло
; в ходе естественного выполнения
; кода -- его надо перепрыгнуть.

action_b: NOP ; Действие B


NOP
NOP
next_action:
NOP
4.4. Realizarea construcţiilor algoritmice de bază
Imlementarea instructiunilor (if else)

if (А>B){ action_a }
else { action_b }

; R16 = A, R17 = B
CP R16,R17 ; Сравниваем два значения
BREQ action_b ; Если равно (флаг Z), то переход сразу.
; Потом проверяем второе условие.
BRCS action_b ; когда A>B флага С не будет
; Перехода не произойдет

action_a: NOP ; и выполнится действие А


RJMP next_action ; Но чтобы действие B не произошло
; в ходе естественного выполнения
; кода -- его надо перепрыгнуть.

action_b: NOP ; Действие B

next_action: NOP
4.4. Realizarea construcţiilor algoritmice de bază
Imlementarea instructiunilor (if else)
if (C<A AND A<B){ action_a }
else { action_b }
; R16 = A, R17 = B, R18 = C
;IF
CP R16,R18 ; Сравниваем С и А
BREQ action_b ; Переход сразу на ELSE если С=А
BRCS action_b ; Если А оказалось меньше, то будет С
; и сразу выходим отсюда на else
; Но если C<A то идем дальше и проверяем
; Второе условие (A<B)

CP R16,R17 ; Сравниваем два значения A и B


BRCC action_b ; Когда A>B флага С не будет
; А переход по условию С clear сработает.
;THEN
action_a: NOP ; Выполнится действие А
RJMP next_action ; Но чтобы действие B не произошло
; в ходе естественного выполнения
; кода -- его надо перепрыгнуть.
;ELSE
action_b: NOP ; Действие B

next_action: NOP
4.4. Realizarea construcţiilor algoritmice de bază
Instrucțiunea de selectie switch/case

Instrucțiunile de selecție switch/case reprezintă un caz particular al instrucțiunii if


... else if cu constrângerea ca se verifică aceiași variabilă/registru la egalitate cu
diferite valori constante. Operația de verificare la egalitate va fi una de tip
BR_OP și anume BREQ sau BRNE și deci implementarea instrucțiunii de
selecție se va supune regulilor de implementare a acestui tip de instrucțiuni.

Instructiune de ciclu cu pre comparare while

Această instrucțiune permite execuția unei secvențe de cod atîta timp cât o
condiție este adevărată. Adică mai întâi se evaluează condiția și în cazul când
condiția este satisfacută se execută un set de instrucțiuni după care are loc un
salt spre o nouă comparație formând o buclă de execuție. În cazul în care condiția
dă un rezultat FALSE instrucțiunile incluse în secvența ciclului nu se mai execuă
și are loc un salt necondiționat la prima instrucțiune după ciclu. Construcția
algoritmică pentru un asemenea ciclu va arăta în felul urmator:
4.4. Realizarea construcţiilor algoritmice de bază
Instructiune de ciclu cu pre comparare while
4.4. Realizarea construcţiilor algoritmice de bază
Instrucțiune de ciclu cu post comparare do ... while

Pentru această construcție algoritmică vom avea mai întîi execuția setului de
instrucțiuni cuprinse în ciclu după care se va evalua comparația. În cazul când
condiția se satisface vom avea un salt spre începutul blocului de instrucțiuni. În
cazul în care nu se satisface condiția execuția continuă cu urmatoarea comandă
după cea de comparație. Am putea organiza instrucțiunile în așa mod ca ultima
instrucțiune din setul cuprins în corpul ciclului să seteze flagurile din SREG
pentru a fi evaluate de către instrucțiunea de comparație BR_OP, și respectiv
vom putea exclude din ciclu operația de comparație CP.
4.4. Realizarea construcţiilor algoritmice de bază
Instructiune de ciclu for

Această construcție poate fi implementată urmând principiul pentru instrucțiunea


cu pre comparare while. Va conține o pre inițializare a contorului, verificare a
condiției de ieșire din ciclu. Setul de instrucțiuni cuprins în corpul ciclului și la
sfârșitul ciclului o operație de progresare a iteratorului. În calitate de iterator va
servi un registru de uz general.

unde ~BR_OP vom spune


ca este o comparație
complementară, adică în
loc de "<=" vom verifica ">"
4.5. Constante
Realizarea construcțiilor algoritmice complexe în baza ramificărilor

Constantă vom numi un identificator (nume) asociat cu o valoare care nu poate fi


modificată în timpul execuției programului. Utilizînd o constantă în locul unei şi
aceleiași valori specificate în repetate rânduri, se va obține o simplificare a
manipulării și menținerii programului. Mai mult decât atât, dând un nume explicit
identificatorului de constantă, valorile definite ca constante vor da o claritate în
elaborarea programului și o ușurință în menținerea lui.

Utilizarea constantelor sporește nivelul de siguranță și reduce riscul de a


introuce erori în program.

Dispare necesitatea de a ține minte valori concrete deoarece o denumire se


memorizează mai bine. Erorile numelui se verifică de obicei de compilator
automat (în afara de cazurile în care se greșește cu un nume existent de
constantă). Totodată introduce o ușurință de a introduce modificări în program,
deoarece constanta este definită în program o singură dată, iar modificarea ei va
afecta întreg programul în locurile în unde a fost utilizată.
4.5. Constante
Definirea constantelor

Valorile constante se definesc o singură dată și iși păstrează valoarea pe întreg


procesul de execuție a programului. În limbajul ASM pentru definirea valorilor
constante vom avea două directive specializate:

Directiva .EQU va defini un nume unei valori constante.


.EQU SIZE = 10
.EQU PIN7 = 7
Directiva .DEF va defini un nume suplimentar pentru un registru de uz general:
.DEF contor = R16

De aici incolo temp poate fi utilizat ca operand în locul registrului R16, și orice modificre
a lui temp va fi de fapt o modificare a lui R16.

Exemple:

ldi temp, SIZE ; inarcarea constantei SIZE in reg. temp


sbi PORTA, PIN7 ; setarea pinului 7 din portul A
4.5. Constante
Expresii constante
Expresii constante vom numi expresiile la evaluarea căror participa în mod exlusiv doar
numere constante iar rezultatul expresiei va fi la fel o constantă. Expresiile constante sunt
evaluate în faza de precompilare. Pentru formarea expresiilor constante putem folosi oricare
expresii aritmetice și logice, cît și utilizarea maco-funcțiilor. În evaluarea expresiilor constante
se va lua în considerație prioritatea operațiilor.
exemple:
.EQU A = 1023
.EQU B = 1375
.EQU C = (A+B)/2-17
.EQU LOW_VAL = LOW(C)
.EQU PIN7 = 7
.EQU MASK = 1<<PIN7
4.5. Constante
Moduri de reprezentare a numerelor constante si conversii

Numerele cu care suntem obisnuiți să le utilizăm sunt numere reprezentate în


format zecimal, mai drept spus în baza 10. Acest format nu este unicul în care pot
fi reprezentate numerele. Printre formatele de reprezentare a numerelor vom
evidenția: binar, octal, zecimal, hexazecimal etc.
Vom numi baza de enumeratie numărul de semne de disincție necesare scrierii
unui număr. Orice număr poate fi reprezentat în oricare bază de numerație.
https://ro.wikipedia.org/wiki/Baz%C4%83_de_numera%C8%9Bie

Exemplu:

28492(10) = 67514(8) = 6F4C(16) = 0110111101001100(2)

În programare, în afară de baza zecimală, cel mai frecvent utilizate sunt


numerele binare și cele hexazecimle, în special pentru microcontrollere unde se
operează la nivel jos al hardware-ului.

Fiecare cifră zecimală va reprezenta o tetradă în binar, și în așa mod conversia


dintre aceste două sisteme se poate face utilizând tabelul de mai jos, în care se
vor introduce toate cifrele hex și reprezentarea lor binară.
4.5. Constante
Moduri de reprezentare a numerelor constante si conversii

DEC | BIN | HEX După cum vedem fiecărei tedrade binare i se asociază o
0 | 0000 | 0 cifră în hexazacimal. În așa mod un număr pe 16 biți va fi
1 | 0001 | 1 reprezentat de 2 octeți (8bit) adică 4 tetrade respectiv
2 | 0010 | 2 poate fi reprezentat de 4 cifre hexazecimale.
3 | 0011 | 3
4 | 0100 | 4 Exemplu:
5 | 0101 | 5
6 | 0110 | 6
7 | 0111 | 7 Această conversie se poate efectua ușor dintr-o bază în
8 | 1000 | 8 alta, iar exersând se poate ajunge la un automatizm într-
9 | 1001 | 9 un timp scurt.
10 | 1010 | A
11 | 1011 | B 0xFF = 1111 1111 = 255
12 | 1100 | C 0xA1 = 1010 0001 =
13 | 1101 | D
14 | 1110 | E
15 | 1111 | F
4.5. Constante
Moduri de reprezentare a numerelor constante si conversii

O metodă simplificată de conversie a numerelor binare în decimale este de a


memoriza șirul puterilor lui 2: 1, 2, 4, 8, 16, 32 etc. După care trecerea dintr-o
bază în alta se reduce la suma acestor numere după principiul: adunăm dacă
ordinul respectiv este "1"
Exemplu:
11010101 = 213

0xFF = 1111 1111 = 255


0xA1 = 1010 0001 = 1 + 32 + 128 = 161
4.6. Logica booleană
Moduri de reprezentare a numerelor constante si conversii

Luând în considerație ca Microcontrollerul operează cu date la nivel de valori


logice "1" și "0" vom da niște noțiuni introductive în logica booleana și exemple de
utilizare a lor în optimizarea elaborării programelor în limbajul ASM.
În logica booleană vom evidenția următorii operatori logici de bază: AND,
OR,XOR, NOT.
Acești operatori au mai multe însemnări pentru fiecare din ele.

AND & ∙ - Logic SI , intersectie


OR | + - Logic OR , reuniune
XOR ^ ⊕ - Logic Exclusiv OR
NOT ~ x' - Negatie
4.6. Logica booleană 0101 1101
1010 1111
Moduri de reprezentare a numerelor constante si conversii -------------- (AND, OR, XOR)
xxxx xxxx
Vom prezenta mai jos tabela de adevăr pentru fiecare din ele:

Operațiile logice pot avea și alte definiții ca de exemplu:


XOR - inversor comandat, comparator - resultat 1 dacă sunt diferite
AND - cheia electronică cu blocare pe zero (repetor comandat cu blocare pe
zero).
OR - cheia electronică cu blocare pe 1.

Pe acasă: să se realizeze 10 exerciții cu nr. aleatoare cu toate trei operații!


4.6. Logica booleană
Aplicarea măștii de setare.

Presupunem ca avem un numar pe 8 biți cu o valoare 0bxxxx_xxxx și vom dori


să modificăm această valoare astfel încât să avem ca rezultat biții 4 și 7 în "1"
adică 0b1xx1_xxxx celelalte valori ale biților vor trebui sa rămână aceleași.

Facînd o analiză a operațiilor logice (a tabelelor de adevăr) vom observa:

x OR 0 = x - nu modifica valoarea x
x OR 1 = 1 - seteaza in 1

Deci am putea folosi această proprietate de a lăsa neschimbată valoare de intrare


la operația OR cu 0 și de a seta în 1 în celalalt caz.

Respectiv va trebui să formăm un numar pe 8 biți care ne-ar satisface condiția


problemei, adică de a seta anumiți biți în "1" , biții 4 ș i 7.
4.6. Logica booleană
Aplicarea măștii de resetare.

Făcând aceeași analiză a operațiilor logice pentru a găsi o soluție pentru a reseta
locațiile respective vom observa că:

x AND 0 = 0 - reseteaza in 0
x AND 1 = x - nu modifica valoarea x

Ca și în cazul precedent vom folosi această proprietate pentru a forma o mască de


resetare

Masca de resetare vom numi o combinație de biți în care vom avea zerouri în
pozițiile pe care vrem să le resetăm. Operația de resetare va fi realizată în baza
operației AND a numărului cu masca.
4.6. Logica booleană
Inversarea cu masca.

Pentru a inversa anumiți biți dintr-un număr vom aplica operatia XOR cu masca în
care pozițiile de interes pentru inversare vor fi setate cu 1 iar celelalte respectiv cu
zero. Ceia ce rezultă din urmatoarele.

x XOR 0 = x - nu modifica valoarea x


x XOR 1 = ~x - inverseaza valoarea x

respectiv vom avea:


4.6. Logica booleană
Formarea măștilor

Formare mastilor ar putea fi facută prin expresii constante. Stiind numărul de


ordine al bitului care trebuie modificat, de exemplu al 4-lea, am putea să-l
reprezentăm prin expresia constantă 1 << 4 , adică unitatea deplasata cu 4 pozitii
spre stânga.
.EQU MASK = 1<<4

Pentru cazul în care vom avea format o mască cu mai mulți biți de interes, de ex
4,6,7, vom defini o expresie constantă în baza sumei măștilor pentru fiecare bit de
interes, adică:
.EQU MASK = (1<<7)+(1<<6)+(1<<4)
4.6. Logica booleană
Formarea măștilor

Același rezultat il vom avea dacă vom evalua exresia prin funcția OR al
componentelor ce formează masca:

.EQU MASK = (1<<7)|(1<<6)|(1<<4)


4.6. Logica booleană
Formarea măștilor

Lucrul cu măștile este utilizat de obicei la setarea sau resetarea unor biți dintr-un
registru periferic. Fiecare bit în acest caz are un nume definit în fișierul antet
pentru fiecare microcontroller în parte, sau am putea defini un nume în cadrul
programului pentru acești biți, după care să utilizăm numele bitului pentru
formarea măștilor:

.EQU BITA = 7
.EQU BITB = 4
.EQU MASK = (1<<BITA)(1<<BITB)

cbr R16, MASK


4.6. Logica booleană
Inversarea biților cu ajutorul unei măști
Sarcina: Să se inverseze bitul 1, 2, 4 și 7 dintr-un registru de uz general utilizându-se o
mască.
Pentru inversarea biților se va utiliza operația logică EOR (exclusive OR)

Pasul 1. Formarea măștii cu denumirea MASK (ca exemplu)


.EQU MASK = (1<<1)|(1<<2)|(1<<4)|(1<<7)
În rezultat obținem o constantă MASK cu valoarea 1001 0110

Pasul 2. Inversarea biților dintr-un registru aleatoriu Rx cu valoarea 1111 1111 (0xFF)
/* stocarea valorii măștii in registrul Ry */
/* Cauza stocării în registru constă în faptul ca instrucțiunea EOR nu poate fi aplicată
între un registru si o constantă */
Ldi Ry, MASK
/* Inversarea biților din registrul Rx */
EOR Rx, Ry

În rezultat valoarea lui Rx va fi


1111 1111
XOR 1001 0110 Inversarea lui 0
_____________________
0110 1001 Inversarea lui 1
4.6. Logica booleană
Setarea biților cu ajutorul unei măști
Sarcina: Să se seteze bitul 2, 3, 5 și 6 dintr-un registru de uz general utilizându-se o
mască.
Pentru setarea biților se va utiliza operația logica OR

Pasul 1. Formarea măștii cu denumirea MASK (ca exemplu)


.EQU MASK = (1<<2)|(1<<3)|(1<<5)|(1<<6)
În rezultat obținem o constantă MASK cu valoarea 0110 1100

Pasul 2. Setarea biților dintr-un registru aleatoriu Rx cu valoarea 0000 0000 (0x00)
/* Setarea biților din registrul Rx direct cu masca */
ORI Rx, MASK

În rezultat valoarea lui Rx va fi


0000 0000
OR 0110 1100 setarea
_____________________
0110 1100 setarea
4.6. Logica booleană
Resetarea biților cu ajutorul unei măști
Sarcina: Să se reseteze bitul 0, 4, 5 și 7 dintr-un registru de uz general utilizându-se o mască.
Pentru resetarea biților se va utiliza operația logica AND cu masca inversată!

Pasul 1. Formarea măștii cu denumirea MASK (ca exemplu)


.EQU MASK = (1<<0)|(1<<4)|(1<<5)|(1<<7)
În rezultat obținem o constantă MASK cu valoarea 1011 0001
Pasul 2. Inversarea măștii, care se va efectua cu operația logica XOR cu valoarea 1111 1111
/* Incărcarea valorii măștii în registru și încărcarea valorii 1111 1111 în alt registru */
LDI Ry, MASK
LDI Rz, 0xFF
/* Inversarea valorii */
EOR Ry, Rz
/* În rezultat valoarea Ry = 0100 1110 */
Pasul 3. Resetarea biților dintr-un registru aleatoriu Rx cu valoarea 1111 1111 (0xFF) /*
Resetarea biților din registrul Rx cu masca inversată din Ry */
AND Rx, Ry
În rezultat valoarea lui Rx va fi
1111 1111 resetarea
OR 0100 1110
_____________________ resetarea
0100 1110
Bibliografie:
• https://www.upit.ro/_document/23460/curs_2_partea_2_robosmart_11.11.2017.pdf
• https://www.microlab.club/2012/09/curs-aplicatii-cu-microprocesoare.html
• ATmega16 datasheet -
http://ww1.microchip.com/downloads/en/devicedoc/doc2466.pdf
• Atmel Corporation, Manuale AVR. http://www.atmel.com/

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