User Tools

Site Tools


Sidebar

Laboratorul 1: USART, LCD

1. Ce este un datasheet?

Orice componentă electronică, de la un senzor de temperatură la un microcontroller la un motor la… orice are un document în care este descrisă în detaliu. Acest document se numește datasheet (fișă tehnică). Pe parcursul laboratoarelor și al proiectului de PM aceste datasheet-uri vor fi cei mai buni prieteni ai voștri :). În ele veți găsi toate detaliile necesare pentru înțelegerea funcționării și folosirea componentei respective.

Pentru cei care nu se descurcă în cele câteva sute de pagini ale datasheet-ului unui microcontroller am pregătit un mic ghid bazat pe datasheet-ul ATmega324

Capitole utile din Datasheet ATmega324

  • 1. Pin Configurations - pag. 2
  • 19. USART - pag. 174
    • secțiunile 19.1 - 19.3 pentru overview
    • secțiunea 19.4.1 pentru generarea ceasului
    • secțiunile 19.5 - 19.8 pentru formatul frame-ului, modul de a programa inițializarea și funcționarea
    • secțiunea 19.11 este referința pentru registrele I/O

2. Interfața serială

Interfața serială este cel mai facil mod de a comunica cu microcontroller-ul vostru pentru citirea de date sau trimiterea de comenzi. Din perspectiva microcontroller-ului, comunicația serială se bazează pe doar două linii de date:

  • linie pentru transmisie, notată Tx,
  • linie pentru recepție, notată Rx.

Comunicația este full-duplex, se poate transmite concomitent cu recepția.

Transmisia asincronă de date se face la nivel de cadre(frames), fiecare cadru fiind format din mai mulți biți, având formatul descris în figura 1.

 Transmisia serială Fig. 1: Transmisia serială

Se transmite un bit de start, apoi un cuvânt de date. Urmează un bit de partitate, opțional, cu rolul de a face o verificare simplă a corectitudinii datelor, și unul sau doi biți de stop.

2.1 Registre

Microcontroller-ul Atmega324 include două periferice USART (Universal Synchronous-Asynchronous Receiver/Transmitter) pentru interfața serială, care sunt controlate de registrele descrise în secțiunile următoare. În partea de inițializare a acestui periferic trebuie efectuați următorii pași:

  • alegerea vitezei pentru transmisia de date - baud rate-ul
  • alegerea formatului cadrului (câți biți de date, de stop, dacă va conține sau nu bit de partitate)
  • activarea transmisiei și recepției datelor pe liniile RX și TX.

Ambele părți implicate în comunicație trebuie să aibă aceeași configurație! De exemplu, în terminalul serial folosit pe calculator, trebuie configurat același baud rate și același format al cadrului ca cel din codul de pe microcontroller.

Baud rate este numărul de simboluri/pulsuri pe secundă al semnalului. În esență, reprezintă viteza de transmisie și este foarte important ca și transmițătorul și receptorul să folosească același baud rate pentru transmisia corectă a datelor. Una dintre cele mai comune probleme cu USART este setarea diferită a baud rate-ului pe transmițător și pe receptor. Această neconcordanță se manifestă prin recepția unor date greșite (transmițătorul trimite caracterul 'a', receptorul primește caracterul '&')

Descrierea completă a celor trei registre de control, a registrului pentru baud rate și a celui pentru buffer-ele de transmisie/recepție o puteți găsi în datasheet la capitolul 19. Registrele au un 'n' la sfârșit care distinge între cele două periferice USART de pe microcontroller-ul nostru. 'n' va lua valoarea 0 pentru USART0, respectiv 1 pentru USART1.

USART Data Register n (UDRn)

Registrul UDRFig. 2: Registrul UDR

RXB și TXB sunt buffer-ele de recepție, respectiv transmisie. Ele folosesc aceeași adresă de I/O. Deci RXB este accesat citind din UDRn, TXB scriind în UDRn. Buffer-ul de transmisie poate fi scris numai atunci când bitul UDRE (USART Data Register Empty) din portul UCSRnA este 1. În caz contrar, scrierile vor fi ignorate.

USART Control and Status Register n A (UCSRnA)

Registrul de control UCSRnAFig. 3: Registrul de control UCSRnA

UCSRnA este registrul de stare al controller-ului de comunicație. Biții cei mai importanți sunt:

  • RXCnReceive Complete – devine 1 când există date primite și necitite. Când buffer-ul de recepție este gol, bitul este resetat automat
  • TXCnTransmit Complete – devine 1 când buffer-ul de transmisie devine gol
  • UDREnData Register Empty – devine 1 când buffer-ul de transmisie poate accepta noi date

USART Control and Status Register n B (UCSRnB)

Registrul de control UCSRnBFig. 4: Registrul de control UCSRnB

UCSRnB este un registru de control. Biții importanți:

  • RXCIEnReceive Complete Interrupt Enable – când este 1, controller-ul de comunicație va genera o întrerupere când au fost primite date
  • TXCIEnTransmit Complete Interrupt Enable – când este 1, controller-ul de comunicatie va genera o întrerupere când buffer-ul de transmisie devine gol
  • UDRIEnData Register Empty Interrupt Enable – când este 1, controller-ul de comunicație va genera o întrerupere când buffer-ul de transmisie mai poate accepta date
  • RXENnReceiver Enable – dacă este 0, nu se pot recepta date
  • TXENnTransmitter Enabler – dacă este 0, nu se pot transmite date
  • UCSZn2 – împreună cu UCSZ1 și UCSZ0 din portul UCSRC, selectează dimensiunea unui cuvânt de date

USART Control and Status Register n C (UCSRnC)

Registrul de control UCSRnCFig. 5: Registrul de control UCSRnC

UCSRnC este tot un registru de control. Biții importanți:

  • UMSELnMode Select – 0 pentru funcționare asincronă, 1 pentru funcționare sincronă
  • UPMn1, UPMn0Parity Mode - Fiind vorba de doi biți, împreună pot avea 4 valori posibile, detaliate în tabelul ce urmează:

 Biții UPMFig. 6: Stabilirea parității folosind biții UPMn1,0 din UCSRnC

  • USBSnStop Bit Select – 0 pentru un bit de stop, 1 pentru doi biți de stop

 Biții USBSFig. 7: Stabilirea numărului de biți de stop folosind USBSn0

  • UCSZn1, UCSZn0 – împreună cu UCSZn2 din portul UCSRnB, selectează dimensiunea cuvântului de date

Biții UCSZFig. 8: Stabilirea dimensiunii datelor folosind biții ''UCSZn0,1,2''

USART Baud Rate Registers (UBRRn)

Registrul UBRRnFig. 9: Registrul UBRRn

UBRRn este registrul care selectează baud rate-ul. Are 12 biți. Primii 4 se află în UBRRnH, ceilalți 8 în UBRRnL. Valoarea pe care o scriem în UBRRn depinde de frecvența procesorului și de baud rate-ul dorit. În tabelul următor găsiți valorile pentru frecvența de 16 Mhz.

Fig. 10: Corespondența dintre valoarea din UBRRn și baud rate

2.2 Exemplu de utilizare

void USART0_init(unsigned int baud) {
    /* setează baud rate */
    UBRR0H = (unsigned char)(baud>>8);
    UBRR0L = (unsigned char)baud;
    /* UBRR0 este un registru pe 16 biți
    Alternativ se poate scrie UBRR0 = baud, pentru că la nivel de compilator 
    se vor face două scrieri de 8 biți */
 
    /* pornește transmițătorul */
    UCSR0B = (1<<TXEN0);
 
    /* setează formatul frame-ului: 8 biți de date, 2 biți de stop, fără paritate */
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
 
void USART0_transmit(unsigned char data) {
    /* așteaptă până când buffer-ul e gol */
    while(!(UCSR0A & (1<<UDRE0)));
 
    /* pune datele în buffer; transmisia va porni automat în urma scrierii */
    UDR0 = data;
}

Scrieri pe 16 biți:

Pentru că scrierea în registre I/O are efecte imediate, scrierea în registre de 16 biți trebuie făcută cu grijă. Există o ordine prestabilită (și proprie fiecărui registru) în care trebuie făcută scrierea, altfel ne expunem la efecte tranzitorii nedorite.

De exemplu, registrul UBRR0 (format din UBRR0H și UBRR0L) se scrie întotdeauna cu byte-ul HIGH înaintea byte-ului LOW, pentru că scrierea byte-ului LOW este trigger-ul pentru schimbarea baud rate-ului. În cazul scrierii în C a locației UBRR0, compilatorul va face automat cele două scrieri în ordinea corectă.

(3 << x)

Pentru biți de configurație care se găsesc întotdeauna unul după altul se folosește și o mască cu mai mulți biți shiftați cu index-ul celui mai din dreapta: (3 << UCSZ00) înlocuiește astfel (1 << UCSZ01) | (1 << UCSZ00)

(1 << x) | (1 << y)

De cele mai multe ori o să facem măști compuse, pe care le vom aplica unui registru I/O în același timp. Această metodă este mai eficientă decât a face aceste operații pe rând. Atenție! Pot doar să compun măști pentru aceeași operație, nu pot aplica o mască SAU în același timp cu o mască ȘI pentru că rezultatul ar fi complet eronat!

Pentru ca cele două dispozitive, în cazul nostru PC-ul și placa de laborator, să poată comunica între ele prin USART, trebuie configurate identic. Dacă placa este configurată cu baud rate 115200, 9 biți de date, 1 bit de stop și fără paritate atunci PC-ul trebuie configurat exact la fel pentru a comunica.

3. Interfațarea unui LCD text

Display-urile, și în principal cele care folosesc cristale lichide (eng. LCD - liquid crystal display), reprezintă una din cele mai folosite moduri de a prezenta informații utilizatorului sau de a oferi un aspect profesional unui dispozitiv. O altă utilizare importantă a display-urilor este de a ușura procesul de debugging pe un sistem embedded.

De obicei, un LCD conține pe lângă afisaj și un controller integrat care simplifică folosirea display-ului. Un controller LCD text uzual este Hitachi 44780, ce oferă o modalitate simplă de interfațare între un microcontroller și afișajulul LCD-ului. Din punct de vedere al costului, display-urile care se bazează pe controller-ul Hitachi 44780 sunt de obicei relativ ieftine și răspândite, putând fi ușor recuperate din dispozitive mai vechi și refolosite.

3.1 Interfața de conectare

Conectorul folosit în laborator pentru LCD-ul text are 14 pini, dispuși pe o linie, cu distanță de 0.1” (inch) între pini, semnificația lor fiind cea descrisă în table 1.

Pin number Symbol I/O Function
1 Vss - Power supply (GND)
2 Vdd - Power supply (+5V)
3 Vee - Contrast adjust
4 RS I Register select: 0 - Instruction, 1 - Data
5 R/W I 0 - Write to LCD module, 1 - Read from LCD module
6 E I Enable signal
7 D0-D7 I/O Data bus line 0 (LSB) - 7 (MSB)
Tab. 1: Pinii controller-ului Hitachi 44780

Interfața de comunicație este una paralelă, permițând astfel să se efectueze scrieri sau citiri de date într-un mod simplu și rapid. Controller-ul Hitachi 44780 suportă 2 moduri de comunicație: un mod extins, pe 8 biți, și un mod restrâns, pe 4 biți.

Placa de laborator folosește o interfațare în modul restrâns, pe 4 biți de date. Se preferă această abordare deoarece folosește doar 7 pini ai microcontroller-ului pentru controlul complet al LCD-ului (chiar dacă la jumătate din viteză): 3 pini de control (RS, R/W și E) și 4 pini de date (D4-D7). Toți cei 7 pini pot fi mapați în același port de I/O al microcontroller-ului simplificând astfel și software-ul de control al LCD-ului.

Fig. 11: Interfațarea unui LCD 2x16 cu microcontroller-ul ATmega16 (compatibil pin la pin cu ATmega324)

Din punct de vedere hardware interfațarea se efectuează pin la pin cu microcontroller-ul, precum în schema din figure 11. Pinii Vss și Vdd se conectează la masă, respectiv la alimentare. Pinul 3 este pinul de contrast și se conectează direct la masă, pentru contrast maxim, sau printr-un potențiometru între Vss și Vdd (divizor de tensiune) dacă se dorește un reglaj al constrastului.

În cazul în care se dorește interfațarea în modul extins, cu 8 biți de date, este suficient să se conecteze toți pinii de date (D0-D7) la același port, iar pinii de control (RS, R/W și E) la un alt port. Software-ul de control va trebui scris ținând cont de această structură.

3.2 Modul de funcționare

Funcționarea unui LCD text bazat pe controller-ul Hitachi 44780 este bazată pe modificarea valorilor din memoriile interne ale controller-ului. Modificarea acestor valori se face prin transmiterea de instrucțiuni către controller folosind pinii de control și de date, conform protocolului înțeles de către controller.

3.2.1 Memorii

Memoriile controller-ului Hitachi 44780 sunt:

  • DDRAM - Display Data RAM
    • stochează caracterele afișate pe display
    • capacitate de 80 x 8 biți
    • DDRAM address corespunde poziției cursorului și reprezintă locația care va fi modificată de o instrucțiune de scriere
    • adresa 0x00 corespunde primului caracter de pe prima linie a display-ului (colț stânga-sus)
    • fiecare byte reprezintă codul caracterului afișat la poziția respectivă
  • CGRAM - Character Generator RAM
    • conține pattern-urile de pixeli (8 linii, 5 coloane) afișați pentru caracterele predefinite
    • anumite locații pot fi rescrise pentru a crea pattern-uri pentru caractere noi (custom)
    • organizată pe cuvinte de câte 8 biți
    • începând cu adresa 0x00, fiecare byte reprezintă o linie dintr-un caracter, 8 linii fiind grupate pentru a forma pattern-ul unui caracter (ex: primul caracter custom începe la adresa 0x00 și se sfârșește la 0x07)
    • sunt folosiți efectiv doar cei mai puțin semnificativi 5 biți ai unui byte deoarece pattern-ul unui caracter conține 5 coloane

3.2.2 Instrucțiuni

Comunicarea dintre microcontroller și controller-ul LCD-ului se realizează printr-o serie de instrucțiuni, descrise în table 2.

Instruction RS R/W D7 D6 D5 D4 D3 D2 D1 D0 Description Execution time
Clear display 0 0 0 0 0 0 0 0 0 1 Clears display and returns cursor to the home position (address 0x00) 1.64ms
Cursor home 0 0 0 0 0 0 0 0 1 * Returns cursor to home position (address 0x00) and resets display shift offset 1.64ms
Entry mode set 0 0 0 0 0 0 0 1 I/D S Sets cursor move direction (I/D), enables display shift (S) 40us
Display control 0 0 0 0 0 0 1 D C B Sets display on/off (D), cursor on/off (C) and cursor blink (B) 40us
Cursor/display shift 0 0 0 0 0 1 S/C R/L * * Sets cursor-move or display-shift (S/C), shift direction (R/L) 40us
Function set 0 0 0 0 1 DL N F * * Sets interface data length (DL), number of display lines (N) and character font (F) 40us
Set CGRAM address 0 0 0 1 CGRAM address Sets the CGRAM address. CGRAM data will be modified by read and write intructions 40us
Set DDRAM address 0 0 1 DDRAM address Sets the DDRAM address. DDRAM data will be modified by read and write intructions 40us
Read busy-flag and address counter 0 1 BF CGRAM/DDRAM address Reads Busy-flag (BF) and CGRAM or DDRAM address counter (depending on previous instruction) 0us
Write to CGRAM or DDRAM 1 0 Data Writes data to CGRAM or DDRAM 40us
Read from CGRAM or DDRAM 1 1 Data Reads data from CGRAM or DDRAM 40us
Tab. 2: Instrucțiunile controller-ului Hitachi 44780

Biții din table 2 au următoarea semnificație:

  • Setarea direcției de deplasare a cursorului:
    • I/D – Incrementează (1) / Decrementează (0) cursorul după fiecare byte scris
    • S – Shiftează (1) display-ul atunci când este scris un caracter
  • Activarea display-ului / cursorului
    • D – Activează display-ul on (1) / off (0)
    • C – Activează cursorul on (1) / off (0)
    • B – Setează cursorul pe blink on (1) / off (0)
  • Mutarea cursorului / Shiftarea display-ului
    • S/C – Activează shiftarea display-ului on (1) / off (0)
    • R/L – Setează direcția de shiftare right (1) / left (0)
  • Setarea lățimii interfeței
    • DL – Lățimea interfeței de conectare este 8 biți (1) / 4 biți (0)
    • N – Numărul de linii afișate pe display 1 linie (0) / 2 linii (1)
    • F – Fontul caracterelor afișate 5×10 dots (1) / 5×8 dots (0)
  • Citirea stării controller-ului
    • BF – 1 - controller-ul procesează informațiile primite și nu poate primi alte instrucțiuni, 0 - controller-ul poate accepta instrucțiuni

Mai multe informații referitoare la structura controller-ului (mod de funcționare, registre etc.) pot fi găsite în datasheet-ul său.

3.3 Protocolul de comunicație

3.3 Protocolul de comunicație

3.3 Protocolul de comunicație

Pentru a comunica cu controller-ul Hitachi 44780 un microcontroller trebuie să respecte protocolul impus de către controller. Acesta constă în anumite restricții asupra ordinii și duratelor minime ale semnalelor care sunt transmise pe pinii de control/date. Mai jos este descris pe scurt acest protocol, el fiind prezentat în întregime în datasheet.

 Protocolul de comunicatie cu controller-ul Hitachi 44780

  1. Se setează pinul RS pentru a indica dacă urmează o instrucțiune de control sau de date
  2. Se setează pinul R/W pentru a indica dacă urmează o instrucțiune de citire sau de scriere
  3. Se transferă codul instrucțiunii
    • Interfața pe 8 biți (care nu este cea din laborator):
      1. Se setează pinii D0-D7 la valoarea biților 0-7 ai instrucțiunii
      2. Se activează pinul E
      3. Se așteaptă cel puțin 230ns (PWeh: enable pulse width)
      4. Se dezactivează pinul E
    • Interfața pe 4 biți:
      1. Se setează pinii D4-D7 la valoarea biților 4-7 ai instrucțiunii
      2. Se activează pinul E
      3. Se așteaptă cel puțin 230ns (PWeh: enable pulse width)
      4. Se dezactivează pinul E
      5. Se asteaptă cel putin 270ns (Tcycle - PWeh: enable cycle time - enable pulse width)
      6. Se setează pinii D4-D7 la valoarea biților 0-3 ai instrucțiunii
      7. Se activează pinul E
      8. Se așteaptă cel puțin 230ns (PWeh: enable pulse width)
      9. Se dezactivează pinul E
  4. Se așteaptă cel puțin 10ns (Th: data hold time)
  5. Se pot dezactiva pinii RS, R/W și D0-D7
  6. Se așteaptă timpul de execuție al instrucțiunii sau se citește Busy Flag până când devine 0

3.4 Bibliotecă LCD

Pentru a facilita lucrul cu LCD-ul, vom defini (implementa) o bibliotecă de funcții pentru interacțiunea cu controller-ul Hitachi 44780. Un API minimal pentru această bibliotecă conține:

void LCD_init(void);                                // Initializare LCD considerand o interfatare cu 4 pini de date.
uint8_t LCD_read(void);                             // Executa secventa de citire a unui octet de date de la LCD.
uint8_t LCD_readStatus(void);                       // Citeste starea LCD-ului (contine busy flag).
uint8_t LCD_readData(void);                         // Citeste un octet din ultima memorie folosita (DDRAM sau CGRAM).
uint8_t LCD_isBusy(void);                           // Returneaza starea LCD-ului: 1 - busy, 0 - available
void LCD_waitNotBusy(void);                         // Asteapta pana cand LCD-ul devine disponibil pentru o noua comanda.
void LCD_write(uint8_t data);                       // Executa secventa de trimitere a unui octet de date catre LCD.
void LCD_writeInstr(uint8_t instr);                 // Trimite o instructiune de control catre LCD.
void LCD_writeData(uint8_t data);                   // Trimite o instructiune de scriere date catre LCD.
void LCD_putChar(char c);                           // Afiseaza caracterul pe LCD la adresa curenta.
void LCD_putCharAt(uint8_t addr, char c);           // Afiseaza caracterul pe LCD la adresa primita.
void LCD_print(const char* msg);                    // Afiseaza string-ul pe LCD incepand de la adresa curenta.
void LCD_printAt(uint8_t addr, const char* msg);    // Afiseaza string-ul pe LCD incepand de la adresa primita.

3.5 Bonus: caractere custom (click to show)

3.5 Bonus: caractere custom (click to show)

3.5 Bonus: caractere custom (click to show)

Controller-ul Hitachi 44780 permite afișarea unor caractere definite de utilizator (caractere custom) prin modificarea valorilor din CGRAM. Un caracter este definit de un pattern de dimensiune 8×5 care spune controller-ului care pixeli trebuie aprinși pentru caracterul respectiv.

Definirea unui caracter presupune stocarea pattern-ului de pixeli în adresele corespunzătoare din CGRAM. Pentru afișarea caracterului custom este apoi necesară scrierea codului său în DDRAM. Corespondența dintre codul unui caracter și adresele din CGRAM la care este stocat pattern-ul său poate fi observată în figure 12. Fiecare caracter ocupă 8 locații în CGRAM (corespunzătoare celor 8 linii ale pattern-ului său). O locație din CGRAM memorează 8 biți, dintre care doar ultimii 5 sunt folosiți pentru a controla pixelii dintr-o linie, astfel: 0 - pixel stins, 1 - pixel aprins.

Fig. 12: Corespondența dintre codul unui caracter și adresele CGRAM

Modificarea datelor din CGRAM se face trimițând controller-ului instrucțiunea Set CGRAM address pentru a specifica adresa din CGRAM de unde se începe scrierea. Următoarele instrucțiuni Write to CGRAM or DDRAM vor modifica apoi secvențial (dacă este configurată auto-incrementarea) valorile din CGRAM.

După terminarea scrierilor în CGRAM nu uitați să treceți din nou în modul de modificare a DDRAM-ului folosind comanda Set DDRAM address, pentru a putea afișa caractere.

4. Exerciții

Capitole utile din Datasheet ATmega324

  • 1. Pin Configurations - pag. 2
  • 19. USART - pag. 174
    • secțiunile 19.1 - 19.3 pentru overview
    • secțiunea 19.4.1 pentru generarea ceasului
    • secțiunile 19.5 - 19.8 pentru formatul frame-ului, modul de a programa inițializarea și funcționarea
    • secțiunea 19.11 este referința pentru registrele I/O

USART

Task 0 (0p). Rulați exemplul pentru USART. Pentru configurările serialei, vedeți fisierul usart.c din schelet.

Task 1 (3p). Configurați USART0 cu următorii parametri: baud rate 19200, 8 biți de date, 1 bit de stop, paritate pară. Transmiteți către PC câte un mesaj pentru fiecare eveniment de apăsare/lăsare a unui buton (ex: se apasă PB2, se transmite “PB2 apăsat”, se lasă PB2, se transmite “PB2 lăsat”, câte o singură dată pe apăsare).

Switch-urile mecanice suferă de un efect numit “bounce”. Linia nu va avea o tranziție clară de la 1 la 0 sau invers, ci va oscila un pic (este un efect pur mecanic). Pentru a nu afișa de multiple ori o secvență de apăsat → lăsat → apăsat etc. pentru o singură apăsare, trebuie să aplicăm o tehnică de debouncing:

  • Fie ignorăm orice tranziție după prima pentru o perioadă mică de timp, de ex 10-20ms (varianta simplă)
  • Fie măsurăm cât de lung este un puls continuu și luăm o apăsare doar dacă apare pentru mai mult de câteva ms (de exemplu, cu o buclă cu delay de 10ms, dacă am măsurat 0 de 4 ori consecutiv consider că este cu adevărat o apăsare)

Task 2 (2p). Comandați prin serială generarea de cod Morse folosind buzzer-ul. În scheletul de laborator găsiți variabila morse_alphabet ce conține literele alfabetului în cod Morse. Pe serială veți trimite caractere ASCII litere mici (ex: 'a', 'b', 'c', etc.). Placa va citi caractere de pe serială și va reda semnalul Morse corespunzător de fiecare dată când citește un caracter valid.

Task 3 (Bonus) (1p). Configurați printf astfel încât să printeze direct pe USART0. Refaceți exercițiul 1 folosind printf.

Tips pentru printf (click to show)

Tips pentru printf (click to show)

Tips pentru printf (click to show)

După cum știți de la programare, printf este echivalent cu fprintf(stdout,… ), cu alte cuvinte, folosește stdout ca fișier în care să scrie. Pentru a putea utiliza printf corect pe AVR, trebuie ca stdout trebuie să pointeze către o structură validă FILE.

struct __file {
	char	*buf;		/* buffer pointer */
	unsigned char unget;	/* ungetc() buffer */
	uint8_t	flags;		/* flags, see below */
#define __SRD	 0x0001		/* OK to read */
#define __SWR	 0x0002		/* OK to write */
#define __SSTR 	0x0004		/* this is an sprintf/snprintf string */
#define __SPGM	 0x0008		/* fmt string is in progmem */
#define __SERR	 0x0010		/* found error */
#define __SEOF	 0x0020		/* found EOF */
#define __SUNGET 0x040		/* ungetc() happened */
#define __SMALLOC 0x80		/* handle is malloc()ed */
	int	size;		/* size of buffer */
	int	len;		/* characters read or written so far */
	int	(*put)(char, struct __file *);	/* function to write one char to device */
	int	(*get)(struct __file *);	/* function to read one char from device */
	void	*udata;		/* User defined and accessible data. */
};

#typedef struct __file FILE

Pentru un fișier în care trebuie doar să scriem, nu ne trebuie decât câmpul flags și câmpul put. put este un pointer către o funcție care scrie un caracter, iar flags este un câmp cu flag-uri, printre care există și un flag care spune că putem scrie în fișier, __SWR. Este suficient să faceți o structură cu put și flags corecte și să pointeze stdout către ea ca să vă meargă printf.

LCD

Task 0 (0p). Rulați exemplul pentru LCD.

Task 1 (3p). Implementați funcțiile LCD_putCharAt și LCD_printAt din bibliotecă. Puteți folosi funcțiile LCD_writeInstr și LCD_writeData. Utilizați funcțiile implementate pentru a afișa un mesaj pe prima linie a LCD-ului. Mesajul trebuie să poată fi deplasat la stânga cu butonul PB2 și la dreapta cu butonul PD6. Limitați deplasarea mesajului astfel încât acesta să nu iasă de pe ecran.

Trebuie să folosiți o instrucțiune a LCD-ului (apelată cu LCD_writeInstr) pentru a poziționa cursorul la poziția dorită, apoi să scrieți datele către LCD (cu LCD_writeData). Codul instrucțiunilor LCD le puteți vedea fie în table 2, fie în fișierul lcd.h prezent în scheletul de laborator.

Task 2 (2p). Afișați pe ecranul LCD-ului caracterele primite pe interfața seriala USART0. Utilizați ambele linii ale ecranului astfel: afișați caracterele secvențial, pe prima linie, apoi pe linia a doua, și reveniți la prima linie suprascriind vechile caractere în momentul umplerii ecranului.

Task 3 (Bonus) (2p + bragging rights). Implementați și afișati caracterul custom din figure 13. Inițial Chuck se află pe linia de jos a LCD-ului. El trebuie să poată fi mutat cu o poziție la stânga/dreapta pentru fiecare apasare a butoanelor PB2/PD6. Cât timp ambele butoane sunt apăsate, Chuck își va folosi puterea specială și se va muta pe aceeași coloană a liniei de sus.

Fig. 13: Courageous Chuck

5. Resurse

lab/lab1.txt · Last modified: 2019/04/06 16:55 by andrei [dot] voinescu [at] upb [dot] ro