Una dintre puternicele utilităţi puse la dispoziţia inginerului proiectant de către microcontrolerele din familia 8051 este fără îndoială portul serial. Faptul că acesta poate funcţiona ca un receptor/transmiţător universal asincron full-duplex (UART), ca un canal de comunicaţie multiprocesor pentru sistemele distribuite sau ca un expandor pentru porturile de intrare/ieşire oferă o serie de aplicaţii deosebit de vastă.
Modul UART permite interfaţarea microcontrolerului cu dispozitive de intrare/ieşire standard: terminale CRT (Cathode Ray Tube), TTY (TeleTypeWriter), imprimante seriale sau modemuri cu o viteză de transfer a datelor de la 122 baud până la 62,5 kbaud pentru o frecvenţă sistem de 12MHz. Dacă se înlocuieşte cuarţul standard de 12MHz cu unul având 11,0592MHz se pot obţine viteze de la 300 baud până la 57,6 kbaud, având valori standard pentru transmisiile seriale. Dacă este necesar, în rutinele de transmisie/recepţie se pot introduce uşor câteva instrucţiuni la nivel de bit pentru a lucra cu paritate pară, respectiv impară.
Modul de comunicaţie multiprocesor este utilizat în sistemele distribuite, putând atinge o viteză de transfer de maxim 375 kbaud (pentru cuarţ de 12MHz) şi având facilităţi hard de recunoaştere a adresei sau datei din mesaj.
Modul de expandare a porturilor de intrare/ieşire permite ca prin conectarea unor registre de deplasare TTL sau CMOS să se obţină ieftin intrări/ieşiri suplimentare, lucrând sincron cu o viteză de transfer superioară celorlalte moduri şi anume 1 Mbaud (pentru un cuarţ de 12MHz).
Implementarea prin hardware a portului serial în cadrul microcontrolerului 8051 economisește spatiu în memoria program şi permite obţinerea unor viteze de transfer mult mai mari decât în varianta implementării prin software a unui port serial. Unitatea centrală nu va trebui decât să citească sau să scrie într-un buffer serial (registrul SBUF); de restul operaţiilor de la formatul paralel la cel serial sau invers ocupându-se circuitele hard asociate portului serial. Chiar dacă locul de citire, respectiv scriere a informaţiei în portul serial este unic (registrul SBUF), în spatele acestuia există registre separate pentru recepţie şi transmisie, eliminând posibilitatea interferenţei între cele două operaţii.
Iată de ce portul serial este full-duplex, adică poate transmite şi recepţiona în acelaşi timp. O scriere în registrul SBUF încarcă de fapt registrul de transmisie şi, dacă transmisia e validată, se declanşează şi operaţia de emisie a primului bit. O citire a registrului SBUF citeşte de fapt registrul de recepţie, unde se găseşte ultimul caracter valid recepţionat. Pentru a preveni citirea eronată de către CPU a unui caracter incomplet, registrul de recepţie este încărcat din tamponul de recepţie doar după ce s-a recepţionat şi ultimul bit al caracterului.
Programarea portului serial, configurarea sa şi informaţiile de stare sunt reunite în registrul de comandă SCON, ai cărui biţi sunt:
SCON.7 – SM0 – bitul 0 de control al modului de lucru (setat/şters prin software).
SCON.6 – SM1 – bitul 1 de control al modului de lucru (setat/şters prin software).
SCON.5 – SM2 – bitul 2 de control al modului de lucru. Este setat prin soft pentru dezactivarea caracterelor (cadrelor) receptionate pentru care bitul RB8 este 0.
SCON.4 – REN – bitul de comandă a validării recepţiei. Setat/şters prin soft pentru a valida/dezactiva recepţia datelor seriale.
SCON.3 – TB8 – bitul 8 al transmisiei (în numerotarea de la 0 la 8 este de fapt al 9-lea). Setat/şters de software pentru a determina starea celui de-al 9-Iea bit de date transmis în modul UART cu 9 biţi de date.
SCON.2 – RB8 – bitul 8 al recepţiei (al 9-lea în numerotarea de la 0 la 8). Setat/şters de hardware pentru a indica starea celui de-al 9-lea bit recepţionat.
SCON.1 – TI – este indicatorul de întrerupere la transmisie. Setat de hardware când s-a transmis întregul caracter. Trebuie şters prin software.
SCON.0 – RI – este indicatorul de întrerupere la receptie. Setat de hardware când s-a recepţionat un caracter valid. Trebuie şters prin software.
Prin combinarea biţilor SM0 şi SM1 din SCON se pot programa patru moduri de lucru. Acestea sunt:
Modul 0 (SM0 = 0, SM1 = 0). Datele seriale intră şi ies prin RXD (P3.0), iar TXD (P3.1) transmite ceasul pentru deplasare. Sunt transmişi/recepţionaţi 8 biţi de date, întâi bitul LSB (cel mai puţin semnificativ). Viteza de transfer este fixă şi egală cu fosc/12.
Modul 1 (SM0 = 0, SM1 = 1). Sunt transmişi prin TXD sau recepţionaţi prin RXD 10 biţi: un bit de start (0), 8 biţi de date (întâi LSB) şi un bit de stop (1). La recepţie, bitul de stop intră automat în bitul RB8 al SCON. Viteza de transfer este variabilă.
Modul 2 (SM0 = 1, SM1 = 0). Sunt transmişi prin TXD sau receptionati prin RXD 11 biți: un bit de start (0), 8 biţi de date (întâi LSB), un al 9-lea bit de date programabil şi un bit de stop (1 ). La transmisie, al 9-lea bit de date (TB8 din SCON) poate primi valoarea 0 sau 1 logic prin software (de exemplu în TB8 poate fi copiat bitul de paritate din PSW). La recepţie, al 9-lea bit de date intră în bitul RB8 al SCON, în timp ce bitul de stop e ignorat. Viteza de transfer este programabilă la fosc/32 sau fosc/64.
Modul 3 (SM0 = 1,SM1 = 1). Este identic cu modul 2, cu excepţia vitezei de transfer, care este variabilă.
În toate cele patru moduri transmisia este iniţiată de orice instrucţiune care foloseşte SBUF ca registru destinaţie. Recepţia este inițiată în modurile 1, 2 şi 3 de bitul de start, dacă bitul REN din SCON a fost setat, iar în modul 0 trebuie îndeplinită şi condiţia suplimentară ca bitul RI din SCON să fie 0.
Modurile 2 şi 3 prezintă facilităţi speciale pentru comunicatiile multiprocesor. În aceste moduri sunt receptionaţi 9 biţi de date, al 9-lea intrând în RB8, apoi urmează bitul de stop. Portul serial poate fi programat, prin setarea bitului SM2 din SCON, astfel încât, după ce se recepţionează bitul de stop, întreruperea hard (setarea Rl) să fie realizată doar dacă RB8 este 1. O modalitate de a folosi această caracteristică în sistemele multiprocesor este următoarea:
-atunci când procesorul master vrea să emită un bloc de date către unul sau mai multe procesoare slave, mai întâi va emite un octet de adresă care identifică slave-ul destinaţie. Octetul de adresă diferă de octeţii de date prin faptul că al 9-lea bit este 1 in octetul de adresă şi 0 în octeții de date. Dacă SM2 = 1, un procesor slave nu va simţi recepţia octeţilor de date. În schimb, octeţii de adresă vor întrerupe toate procesoarele slave, fiecare putând să examineze biţii din octetul recepţionat şi să-i compare cu adresa proprie. Procesoarele slave care nu au fost adresate îşi lasă SM2 setat şi îşi continuă programul curent, ignorând octetii de date care urmează să fie receptionați.
În modul 0, bitul de control SM2 nu are efect, iar în modul 1 ar putea fi folosit pentru validarea bitului de stop recepţionat, în caz de eroarea acestuia octetul recepţionat nefiind luat în seamă (SM2 = 1).
Principalele posibilităţi de compunere a cadrelor de biţi transmise/recepţionate în corespondenţă cu modurile de programare a portului serial se regăsesc în figura 1, unde s-au indicat, de asemenea, şi domeniile uzuale de utilizare.
Viteza de transfer diferă de la un mod la altul. În modul 0 viteza de transfer este fixă şi egală cu fosc/12, deci pentru 12MHz rezultă 1Mbaud. În modul 2, în funcţie de valoarea bitului SMOD din registrul PCON avem relaţia:
deci pentru SMOD = 1 viteza de transfer este fosc/32, respectiv pentru SMOD = 0 (valoarea de la reset) este fosc/64. În modurile 1 şi 3 viteza de transfer este variabilă şi este dată de perioada de temporizare cu care este programat timerul 1 (8 biţi cu autoîncărcare) după relaţia:
Există posibilitatea, la viteze foarte mici, să se utilizeze timerul 1 pe 16 biţi şi cu încărcare prin întreruperi. De asemenea, la microcontrolerele care conţin timerul T2 (8052) e posibil ca viteza de transfer să fie dată de perioada de temporizare a timerului T2 (16 biţi cu autoîncărcare) după relaţia:
Indiferent de modul de lucru, există două mari tehnici de utilizare a portului serial, şi anume prin polling sau prin întreruperi. Tehnica polling presupune ca periodic, sau atunci când trebuie efectuată o operație să fie testați prin software biții indicatori RI și TI, iar in funcţie de valoarea lor se realizează sau nu operaţia dorită, eventual aşteptând până la activarea lor. Tehnica de lucru cu întreruperi (presupunând că a fost validată întreruperea pentru portul serial) permite ca automat, prin hardware, la recepţionarea unui caracter sau la golirea buffer-ului de transmisie să fie activat bitul indicator corespunzator (Rl sau TI) simultan cu o cerere de intrerupere. Unitatea centrală nu va avea decât să testeze, la acceptarea întreruperii care bit este activat şi să citească sau să scrie din/în SBUF octetul de date.
În figura 2 se prezintă două modalităţi de expandare a porturilor de intrare/ieşire atunci când este necesar.
Utilizarea circuitului 74HC165 permite uşoara extindere a numărului de intrări suplimentare. Se observă utilizarea liniei P1.0 pentru comanda încărcării paralel a intrărilor în registrul intern şi apoi prin portul serial are loc deplasarea informaţiei din registrul 74HC165 la pinul RXD al 8051, clock-ul fiind dat de pinul TXD al 8051. Secvenţa de program care realizează citirea stării comutatoarelor DIP—SWITCH în acumulator este:
SETB REN
; iniţializare pentru recepţie
.......
REC_IO: CLR P1.0
; încărcare paralel
SETB P1.0
CLR RI
; şterge RI (condiţie activare
; recepţie REN = 1, RI = 0)
WAIT_REC JNB RI, WAIT_REC
; aşteaptă recepţia a 8 biţi,
; până când RI = 1
MOV A,SBUF
; citeşte SBUF
RET
La extinderea liniilor de ieșire se poate utiliza 74HC164, putând comanda direct ledurile conectate la ieşirile sale. Având în vedere frecvenţa de clock de 1MHz (pentru fosc = 12MHz) şi inerția ledurilor la această frecvenţă, se poate utiliza acest registru de deplasare, chiar dacă nu are tampon (buffer) la ieșire, iar ieşirile vor prezenta până la incarcarea finală 7 perioade cu informaţie falsă. In aplicaţii mai pretențioase va fi necesară utilizarea unui registru de deplasare cu tampon la ieşire (de exemplu 74HC594), având o linie de încărcare paralelă a conţinutului registrului de deplasare intern în registrul tampon de la ieşire. Secvenţa de program care realizează încărcarea ieşirilor circuitului 74HC594 cu octetul din acumulator este:
TRANS_IO: JNB TI,TRANS_IO
; aşteaptă pînă când e gol
; bufferul de transmisie
MOV SBUF,A
; scrie în SBUF
WAIT_TRS: JNB TI,WAIT_TRS
; aşteaptă pînă când e gol
; bufferul de transmisie
CLR P1.1
; comandă strobarea datelor la
; ieşirea 74HC594
SETB P1.1
CLR TI
; şterge TI
RET
În ambele cazuri, numărul intrărilor sau ieşirilor suplimentare se poate mări prin cascadarea corespunzătoare a registrelor de deplasare şi citire/scrierea repetată prin portul serial al 8051.
Deoarece cel mai adesea portul serial este utilizat ca UART pe 8 biţi fără întreruperi, un exemplu de utilizare în modul 1 este ilustrat în continuare. Subrutina TXCH transmite octetul din acumulator la portul serial, înlocuind bitul al 8-lea cu bitul de paritate impară:
TXCH: MOV C,P
; încarcă CARRY cu bitul de
; paritate (PSW.0)
CPL C
; complementează CARRY pentru a
; realiza paritate impară
MOV ACC.7,C
; încarcă bitul MSB din
; acumulator cu CARRY (bitul de
; paritate)
WAIT_TXCH : JNB TI,WAIT_TXCH
; testează bitul indicator de
; întrerupere la transmisie;
; dacă TI=0 aşteaptă (octetul
; anterior nu s-a transmis complet
; din buffer-ul de date
; la ieşirea portului serial)
CLR TI
; bitul Tl este 1. Octetul
; anterior a fost transmis
; complet, buffer-ul de date
; fiind gol. Trebuie şters TI
; înainte de a încărca noul
; octet in buffer-ul de date al
; portului serial pentru
; transmisie.
MOV SBUF,A
; încarcă noul octet din
; acumulator în buffer-ul de
; date al portului serial pentru
; a fi transmis
RET
Subrutina RXCH recepţionează în acumulator octetul sosit la portul serial, salvând bitul de paritate în indicatorul CARRY şi ştergând bitul al 8-lea din acumulator:
RXCH: JNB RI RXCH
; testează bitul indicator de
; întrerupere la recepție pentru
; recepţionarea unui caracter
; complet. Dacă RI = 0 aşteaptă.
MOV A,SBUF
; RI = 1. Biţii de date au fost
; recepţionaţi complet. Citeşte
; buffer-ul de date al portului
; serial şi transferă în
; acumulator.
CLR RI
; şterge Rl. Pregăteşte
; buffer-ul de date al portului
; serial pentru recepţia unui
; nou octet.
MOV C,P
; încarcă bitul de paritate al
; octetului recepţionat (ACC.7
; din octetul transmis) în
; indicatorul CARRY.
CPL C
; complementează indicatorul
; CARRY pentru paritate impară
CLR ACC.7
; maschează bitul ACC.7 (bitul
; de paritate) pentru caracterul
; recepţionat, acesta fiind în
; codul ASCII pe 7 biţi
RET
Programul principal realizează o comunicaţie cu un terminal CRT.
; secvenţa de iniţializare pentru
; portul serial şi viteza de
; transfer
MOV SCON,#52H
; încarcă registrul de control
; al portului serial cu
; constanta 52H. Adică alege
; modul 1 (SM0=0, SM1=1),
; recepţie validată (REN = 1) şi
; buffer de transmisie gol
; (TI = 1).
MOV PCON, #80H
; setează SMOD din PCON (PCON.7)
MOV TMOD, #20H
; încarcă registrul de mod al
; timerelor cu constanta 20H.
; Adică alege modul 2,
; temporizator pe 8 biţi cu
; autoîncărcare pentru
; timerul 1.
MOV TH1, #0F4H
; încarcă constanta de timp
; pentru timerul 1 în registrul
; TH1, pentru o viteză de
; transfer de 4800 baud având
; fosc = 11,059MHz, SMOD = 1,
SETB TR1
; porneşte timerul 1 folosit ca
; generator al vitezei de
; transfer de 4800 baud
LOOP: LCALL INKEY
; apelează subrutina de scanare
; a tastaturii sistemului cu
; 8051; Codul tastei apăsate
; este în acumulator.
LCALL TXCH
; apelează subrutina de
; transmisie a unui caracter,
; pentru a emite codul tastei
; apăsate spre terminalul
; conectat prin portul serial şi
; a-l afişa
RXDATA: LCALL RXCH
; apelează subrutina de recepţie
; pentru a primi caracterul
; transmis de terminal la
; apăsarea unei taste a acestuia
JC RXDATA
; dacă CARRY = 1 (eroare de
; paritate) ignoră octetul
; recepţionat, aşteaptă recepţia
; unui octet fără erori
LCALL AFI
; apelează rutina de afişare a
; unui octet pe un afişaj cu
; leduri conectat la sistemul cu
; 8051
SJMP LOOP
; salt la eticheta LOOP şi reia
; la infinit bucla începând cu
; eticheta LOOP.
În concluzie, prin portul serial s-a legat un sistem cu microcontrolerul 8051 cu un terminal CRT. Sistemul cu 8051 are conectate o tastatură proprie şi un afişaj cu leduri. Programul prezentat realizează, prin intermediul portului serial, într-un sens transmisia de la sistemul cu 8051 a codului tastei apăsate şi afişarea pe ecranul CRT, iar în celălalt sens aşteaptă recepţionarea de către sistemul cu 8051 şi apoi afişează, pe afişajul propriu codul ASCII al tastei apăsate la terminalul CRT. Parametrii comunicaţiei seriale au fost 7 biţi de date, 1 bit de paritate impară, 1 bit de stop şi o viteză de transfer de 4800 baud.
Un ultim amănunt legat de portul serial este faptul că legătura prin interfaţa serială necesită respectarea unor standarde de comunicaţie în linia de legătură. Cel mai popular este standardul RS232, care prevede emisia pentru “1” logic în linie a unui nivel de -12V (-3 … -15V) şi respectiv pentru “0″ logic a unui nivel de +12V (+3 … +15V). Cum microcontrolerul 8051 este alimentat cu o tensiune de 5V, înseamnă că pinii RXD, respectiv TXD nu pot lucra direct cu nivelurile din linia de legătură. Sunt necesare deci, în mod obligatoriu, circuite de translatare a nivelurilor specifice standardului de comunicaţie folosit. Pentru RS232 se pot aminti cunoscutele circuite 1488, 1489 care au dezavantajul major că necesită o sursă de ±12V pe lângă cea de 5V cu care e alimentat 8051. O soluţie la modă în ultima perioadă foloseşte circuite specializate, ca de exemplu MAX232 (vezi articolul din nr. 17 al revistei), care au încorporate în aceeaşi capsulă şi surse în comutație care, plecând de la tensiunea de 5V obţin, cu ajutorul a 4 condensatoare externe, ±10V şi astfel driverele încorporate pot funcţiona în bune condiţii. Bineînţeles că acelaşi circuit conţine circuitele de translatare atât pentru recepţie, cât şi pentru emisie.
Pentru cei care nu au încă la dispoziţie circuite din această ultimă familie, în figura 3 se prezintă o soluţie mai veche, dar care dă satisfacţie şi nu necesită surse de alimentare suplimentare. Se observă că la recepţie tranzistorul T1 este saturat când linia RXDATA este la +12V şi blocat pentru -12V. Rezultă că RXD este 0 logic (T1 saturat) pentru +12V în linie şi 1 logic (T1 blocat) pentru -12V în linie, ceea ce este conform cu standardul RS232. Tensiunea de -12V pentru emisie este obţinută din chiar linia RXDATA şi înmagazinată cu C1, dioda D1 având rol de separare. Cum pauză transmisie în linie înseamnă -12V, rezultă că C1 se poate încărca destul de bine. La transmisie, când TXD este 1 logic, T2 este blocat şi în linia TXDATA apare tensiunea de pe C1, adică -12V aproximativ, deci 1 logic. Când TXD este 0, T2. este saturat şi în linie apare +5V, deci în domeniul în care este recunoscut 0 logic.
Bibliografie:
1. Philips Semiconductors – 80C51- based 8-bit Microcontrollers, 1994
2. MHS – 8-bit Microcontrollers, 1989
3. Byron W Putman – RS232 Simplified, Prentice Hall 1987.
4. Datasheet – max232
Articol publicat in revista RET – Autor articol: asistent inginer Sorin Popescu.