Laboratorul 09 - Configurări
Cheatsheet
GPIO
Folosind GPIO (General-Purpose Input/Output) putem controla un pin al unui circuit integrat. De exemplu, putem aprinde un led folosind instrucțiuni AVR sau putem citi starea unui pin - LOW sau HIGH. Pinii ce suportă GPIO sunt grupați în porturi (grupuri de 8 pini logici numite A
sau B
) controlate de registre speciale (pe câte 8 biți):
DDRx: Data Direction Register
PORTx: Data Register: (Stabilesc cum vreau să fie un pin)
Dacă DDRx e setat ca ieșire ('scriere')
Dacă DDRx e setat ca intrare ('citire')
PINx: Data Input Register (Indică starea reală a unui pin)
În memoria microcontrollerului de la 0x00 la 0x3F gasim I/O Space. Aici se află toate registrele de lucru cu periferice și, desigur, DDRx, PORTx și PINx. De exemplu registrul PORTA are adresa 0x02.
Pentru a scrie citi date din I/O Space putem folosi instrucțiunile LDS/STS, însă recomandat este să folosim instrucțiunile speciale pentru lucru de memoria I/O Space ce se execută mai rapid:
OUT A, Rr
: Scrie (Store) în I/O Space la adresa A valoarea din registrul Rr
IN Rd, A
: Citește (Load) din I/O Space de la adresa A și pune în registrul Rd
Pentru a modifica un singur bit dintr-un registru de configurare putem folosi instrucțiunile SBI
/CBI
.
TIMER
Un timer este un simplu numărător implementat în hardware
Orice timer trebuie să aibă:
O sursă de ceas
Un registru contor
PWM este o tehnică de generare a unui semnal analogic pornind de la unul digital
Timerele de pe ATtiny20 conțin 3 registre importante: TCNT0, OCR0A/OCR0B, TCCR0A, TCCR0B
TCNT0 este registrul cu contor
OCR0A/OCR0B definesc valori de comparație iar OCR0A poate fi folosit la TOP
TCCR0A și TCCR0B sunt registre de control pentru modul de funcționare
Moduri de funcționare:
Normal
CTC
Fast PWM
Timer-ul numără crescător de la 0 la 255 (sau OCR0A), apoi se resetează la 0
Starea pinilor OC0A/OC0B poate fi schimbată la comparaței și BOTTOM
INTRERUPERI
Întreruperile sunt eveniment asincrone execuției programului
Dacă apare o întrerupere, procesorul oprește execuția normală a programului după instrucțiunea curentă și execută o rutină de tratare
Întreruperile pot fi activate/dezactivate la nivel global și demascate/mascate la nivel individual
Pe AVR
Activarea/Dezactivarea la nivel global se face cu instrucțiunile SEI/CLI
Demascarea/Mascarea se face prin registrele de control
Tabela vectorilor de întreruperi se află la adresa 0
O întrerupere este tratată dacă
Întreruperile sunt activate la nivel global (bitul I
din SREG
este 1)
Întreruperea este demascată la nivel individual (masca ei este 1)
Întreruperea este activă (flag-ul ei este activ)
Exerciții
java -jar avrasm.jar input.txt output.txt
În scheletul de laborator veți găsi fișierul de constrângeri configurat astfel:
Port B mapat la primele 8 switch-uri din dreapta.
Port A mapat la primele 8 led-uri din dreapta.
Prescaler mapat pe primele 5 switch-uri din stânga, având valoarea selectată afișată în format binar pe ledurile corespunzătoare switch-urilor.
Cele 2 ieșiri ale Timer0 mapate pe LED-urile 8 și 9.
Task 01 (2p) Scrieți un program care setează portul A ca ieșire, portul B ca intrare, apoi, într-o buclă, citește valoarea de pe portul B și o scrie pe portul A. Folosiți tool-ul avrasm pentru a-l scrie în fișierul rom.v
.
PINA equ 0x00
DDRA equ 0x01
PORTA equ 0x02
PINB equ 0x04
DDRB equ 0x05
PORTB equ 0x06
OCR0B equ 0x15
OCR0A equ 0x16
TCCR0B equ 0x18
TCCR0A equ 0x19
TIMSK equ 0x26
rjmp main ; Adresa 0x0000
reti ; Adresa 0x0001
reti ; Adresa 0x0002
reti ; Adresa 0x0003
reti ; Adresa 0x0004
reti ; Adresa 0x0005
reti ; Adresa 0x0006
reti ; Adresa 0x0007
reti ; Adresa 0x0008
rjmp TIM0_COMPA_ISR ; Adresa 0x0009
reti ; Adresa 0x000A
reti ; Adresa 0x000B
reti ; Adresa 0x000C
reti ; Adresa 0x000D
reti ; Adresa 0x000E
reti ; Adresa 0x000F
reti ; Adresa 0x0010
main:
loop:
rjmp loop
Task 02 (3p) Extindeți programul de la punctul 1 astfel încât să configurați Timer0 folosind valoarea introdusă pe portul B pentru ajustarea factorului de umplere al modulării. Verificați comportamentul celor două ieșiri folosind LED-urile 8 și 9.
Configurează timer-ul 0 in modul fast PWM, TOP == OCR0A
Setează ceasul timer-ului 0 la clkI/O (No prescaling)
Configurează timer-ul 0 să schimbe starea pinului OC0A astfel: Clear OC0A on Compare Match, Set OC0A at BOTTOM (non-inverting mode)
Configurează timer-ul 0 să schimbe starea pinului OC0B astfel: Set OC0B on Compare Match, Clear OC0B at BOTTOM (inverting mode)
Setează valoarea lui OCR0A
la valoarea citită de pe portul B
.
Task 03 (2p) Folosind semnalele de ieșire OC0A
și OC0B
ale Timer-ului configurat anterior controlați unul din LED-urile RGB pentru a obține culoarea verde
. Atenție, nu priviți direct spre LED-urile RGB deoarece intensitatea acestora este ridicată.
Task 04 (3p) Modificați programul existent astfel încât pe LED-urile legate la port A să afișați o bară de încărcare, adică să aprindeți pe rând de la dreapta la stânga (sau invers) fiecare LED.
Activează întreruperea de overflow pentru timer-ul 0.
Modifică prescaler-ul timer-ului 0 dacă este cazul.
Creează logica de shiftare a biților din port A.
Asigurați-vă că shiftarea se realizează la o perioadă suficient de mare încât să fie sesizabilă ochiului uman.
Resurse