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.
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:
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 figură.
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.
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:
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.
Se gaseste î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.
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.
UCSRnA
este registrul de stare al controller-ului de comunicație. Biții cei mai importanți sunt:
UCSRnB
este un registru de control. Biții importanți:
UCSZ1
și UCSZ0
din portul UCSRC
, selectează dimensiunea unui cuvânt de date
UCSRnC
este tot un registru de control. Biții importanți:
UCSZn2
din portul UCSRnB
, selectează dimensiunea cuvântului de date
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.
void USART0_init(unsigned int baud) { /* setează baud rate */ UBRR0 = baud; /* UBRR0 este un registru pe 16 biți, la nivel de compilator se vor face doua scrieri de 8 biti */ /* 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; }
(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.
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!
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.
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 tabelul de mai jos.
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) |
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:
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.
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.
Memoriile controller-ului Hitachi 44780 sunt:
Comunicarea dintre microcontroller și controller-ul LCD-ului se realizează printr-o serie de instrucțiuni, descrise în tabelul de mai jos.
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 |
Biții din tabel au următoarea semnificație:
Mai multe informații referitoare la structura controller-ului (mod de funcționare, registre etc.) pot fi găsite în datasheet-ul său.
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. Mai multe informatii gasiti in link-ul urmator
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.
Capitole utile din Datasheet ATmega324
Task 0 (1p) 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, 2 bit de stop, fara paritate. Transmiteți către PC câte un mesaj pentru fiecare eveniment de apăsare/lăsare a unui buton (ex: se apasă PD6, se transmite “PD6 apăsat”, se lasă PD6, se transmite “PD6 lăsat”, câte o singură dată pe apăsare).
Task 2 (2p) Comandați prin serială generarea in cod Morse a numelui vostru, folosind buzzer-ul.
Task 3 (1p) Rulați exemplul pentru LCD.
Task 4 (3p) Implementați funcțiile din bibliotecă:
Puteți folosi funcțiile LCD_writeInstr și LCD_writeData.
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 <tabref instructiuni_lcd>, fie în fișierul lcd.h
prezent în scheletul de laborator.
Task 5: Bonus USART (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)