Electronica Port Serial Interfață de Comunicare pe Portul Serial
=== l ===
SINTEZĂ
Proiectul prezintă o interfață de comunicare pe Portul Serial. A fost aleasă comunicarea serială datorită avantajelor pe care aceasta le prezintă, în special pentru comunicații industriale. Astfel:
legăturile seriale pot acoperi distanțe mult mai mari decât cele realizate prin intermediul interfețelor paralele (limitate de obicei la 2m);
interfața serială RS+232 prezintă o imunitate la zgomot mult mărită față de interfețele care realizează un transfer de date în paralel datorită, în special, nivelurilor de tensiune utilizate pentru codarea informației;
compatibilitatea perfectă cu interfețe destinate mediului industrial, cum este de exemplu, interfața RS-485 care prezintă avantaje suplimentare cum sunt: comunicație pe linii diferențiale și posibilitatea evitării buclelor de masă.
În primele două capitole este prezentat Portul Serial cu caracteristicile sale din punct de vedere hardware și software. Au fost astfel prezentate detaliat atât arhitectura hardware cât și un ghid de prigramare software a regiștrilor principalului element destinat transmisiei asincrone, circuitul de tip UART.
În paragraful 2.2. denumit "Caracteristici software" sunt prezentate secvențe de program și programe de transmisie pe Portul Serial.
În capitolul 3 este prezentată interfața serială RS-485, luând în discuție caracteristicile generale prezentate însă pe cazuri concrete, controlul transferului de date și terminațiile specifice acestui tip de interfață.
În capitolul patru sunt prezentate programe de comunicare pe Interfața Serială RS-232, realizate efectiv și verificate. Programele au fost concepute pentru a putea verifica fiecare funcție realizată pe interfața serială: emisie de caracter, recepție de caracter, recunoaștere și interpretare de mesaj.
Deoarece comunicația de fapt are loc pe interfața RS-485, s-a stabilit protocolul de comunicare care este prezentat pe larg în proiect. Comunicarea are loc între două echipamente, un calculator și un sistem cu microcontroler. Prezentul proiect tratează toate problemele legate de comunicația pe RS-485 din punctul de vedere al operatorului uman care supraveghează, prin intermediul calculatorului, rețeaua locală realizată cu RS-485. Programul elaborat este conversațional, condițiile în care se face comunicarea fiind următoarele:
Master-ul, calculatorul de tip PC (care are cea mai mare prioritate) va putea începe emisia după 85 ms de la lansarea în execuție a programului-aplicație dedicat;
stația cu prioritatea imediat următoare va putea începe să transmită după un interval de timp de 125 ms;
viteza la care se face comunicarea este de 9600 BPS;
comunicarea este validată prin utilizarea liniei de control RTS;
lungimea maximă a oricărui mesaj trnsmis prin rețea să nu depășească o secundă;
după fiecare mesaj va fi o pauză de minim 125 ms;
nu este permis nici unui emițător să înceapă o emisie în timpul primelor 80 ms;
emisia după 125 ms;
următoarea stație care poate fi conectată va putea emite după 150 ms;
S-au realizat programe pentru verificarea emisiei și recepției corecte, pentru configurare și verificare a regiștrilor din componența UART-ului, setări de indicatoare de întrerupere.
O dezvoltare ulterioara a programului poate fi avută în vedere în cazul în care se realizează o rețea locală RS-485 multimaster.
CAP. 1. INTRODUCERE
1.1. Interfațarea Portului Serial
Portul Serial este mai greu de interfațat decât portul paralel. În majoritatea cazurilor, orice dispozitiv conectat la portul serial va necesita conversia transmisiei seriale înapoi în transmisie paralelă pentru ca informația să poată fi folosită. Acest lucru poate fi realizat prin intermediul UART-ului. Din punctul de vedere al software-ul sunt mai mulți regiștrii care trebuie accesați, decât în cazul Portului Paralel (SPP).
Există o serie de avantaje ale folosirii transferului serial față de cel paralel.Astfel:
1. Cablurile seriale pot fi mai lungi decât cablurile paralele. Portul serial transmite un “1” ca fiind o tensiune între –3V până la –25V și o tensiune între +3V până la +25V, respectiv un “0”, iar portul paralel transmite un ”0” ca 0V și un”1” ca 5V. De aceea portul serial poate avea o plajă maximă de 50V, în comparație cu un port paralel care are o plajă maximă de 5V. Prin urmare pierderile pe cablu nu sunt o problemă pentru trnsmisia serială, pe când pentru cea paralelă pot duce la interpretări eronate.
2. Transmisia serială nu necesită atât de multe fire precum o transmisie paralelă. Dacă dispozitivul trebuie montat la distanță față de calculator, o legătură de trei fire (configurație Null Modem) va fi mult mai ieftină decât cablarea a 19 sau 25 fire de cablu. Oricum trebuie să se țină cont de costul interfațării (circuitele de interfață cu legătura serială sau paralelă) la fiecare capăt al conexiunii.
Dispozitivele în infraroșu s-au dovedit foarte populare în ultimul timp. Există multe agende electronice care conțin plăci cu posibilitate de emisie/recepție în infraroșu. Este imposibil de imaginat o transmisie paralelă a 8 biți de date simultan la un moment dat, spre celălalt capăt al camerei și posibilitatea, din punctul de vedere al dispozitivului receptor, de a descifra poziția fiecărui bit în secvență. De aceea transmisia serială este cea care se folosește în astfel de cazuri, transmițându-se câte un bit la un moment dat de timp. Prima dintre interfețele corespunzătoare transmisiei seriale a avut o viteză de 115,2k și a fost integrată într-un UART Lungimea impulsului a fost redusă la 3/16 din lungimea bitului RS-232 pentru conservarea energiei considerând că aceste dispozitive sunt folosite mai ales pentru agende electronice și laptop-uri care au surse autonome de tensiune.
Microcontroller-ele s-au dovedit de asemenea foarte utile în ultimul timp. Multe din acestea au încorporate SCI (Interfețe de Comunicare Seriale) care pot fi folosite în comunicațiile cu exteriorul micrcontroller-elor. Comunicația serială reduce numărul pinilor pentru microcontroler, doar doi pini fiind folosiți în mod normal: Transmitere Date (TXD) și Recepție Date (RXD), în comparație cu cel puțin 8 pini dacă folosim o metodă paralelă pe 8 biți (este posibil, în plus, să fie nevoie de un semnal de validare).
CAP. 2. PREZENTAREA PORTULUI SERIAL AL CALCULATORULUI
2.1. Cracteristici hardware
Dispozitivele care folosesc cabluri seriale pentru a comunica sunt împărțite în două categorii.
Acestea sunt DCE (Echipamnte de Comunicații de Date) și DTE (Echipamente Terminal de Date). Echipamentele de comunicații de date sunt dispozitive asemeni modemului, plotter-elor etc., în timp ce echipamentul terminal de date este, de obicei un calculator. Specificațiile electrice ale portului serial sunt conținute în standardul EIA RS-232C.
Acesta stabilește mai mulți parametri cum ar fi:
Un “Spațiu“ (Space) sau “0” logic va fi între +3V și +25V,
Un “Semn” (Mark) sau “1” logic va fi între –3V și –25V,
Regiunea dintre +3V și –3V este nedefinită,
Tensiunea unui circuit în gol nu trebuie să depășească 25V (raportat la masă sau având ca referință GND),
Curentul de scurtcircuit nu trebuie niciodată să depășească 500 de mA (emițătorul – driver-ul – trebuie să poată furniza acest curent fără depășirea condițiilor de putere disipată).
Pe lângă acestea, standardul mai include referiri la: capacitatea liniei, viteza maximă etc. Este interesant de notat că standardul RS-232C specifică o rată a vitezei maxime de 20 000 bps, care este mai mică decât standardele actuale. Un nou standard, RS-232D, variantă îmbunătățită a lui RS-232C a fost deja aprobat. Porturile seriale prezintă două posibilități de comunicare cu exteriorul: există conectorul de tip D cu 25 de pini sau un conector de tip D cu 9 pini, amândoi fiind conector de tip “tată”, conectați în spatele P.C.-ului, ceea ce înseamnă că trebuie utilizat un conector de tip “mamă” pentru asigurarea conectării. Mai jos avem un tabel cu semnificația celor mai utilizate semnale care sunt legate la pinii conectorilor de tip D cu 9 pini, respectiv 25 de pini.
2.1.1. Pini de ieșire seriali: (Conectori D25 și D9)
Tabelul 2.1.1.
2.1.2. Funcțiile pinului:
TD –Transmitere Date –Ieșire de date serială (TXD)
RD –Recepșie Date –Intrare de date serială (RXD)
CTS –Clean to Send –Această linie indică faptul că
modemul este pregătit să execute un
transfer de date
DCD –Data Carier Detect -Când modemul detectează o
purtătoare de la un modem aflat la celălalt
capăt al liniei telefonice, această linie
devine activă
DSR –Data Set Ready – Aceasta spune UART-ului că
Modemul este pregătit pentru a stabili o legătură
DTR –Data Terminal Ready – Opusul lui DSR. Aceasta indică
modemului că UART-ul este
pregătit pentru începerea unei legături
RTS –Request to Send -Această linie informează modemul
că UART-ul este gata să comunice (să realizeze un interschimb) de date
RI -Ring Indicator -Devine activ când modemul
detectează un semnal de apel de la
corespondent
2.1.3. Cablu de tip “Modem Nul” (Null Modem)
Un cablu de tip “Modem Nul” este folosit pentru conectarea a două echipamente de tip DTE. Acesta este cel mai ieftin mod de conectare în rețeaua de jocuri sau transferul de fișiere între calculatoare. Poate fi folosit de asemenea cu multe sisteme de dezvoltare cu microprocesor.
Diagrama firelor Null Modem, necesită doar trei fire pentru a realiza legătura (TD, RD și Signal Ground). Tehnica de funcționare este relativ ușoară. Scopul este de a face calculatorul să creadă că transferă date unui modem și nu "vorbește" unui alt calculator. Orice dată transmisă de la primul calculator trebuie să fie recepționată de al doilea. Din acest motiv TD este conectată la RD. Al doilea calculator are aceeași configurație, astfel RD este conectat la TD. Semnalul de masă (SG) trebuie conectat de asemenea, încât ambele pământări sunt comune ambelor calculatoare. Deci calculatoarele au o masă (referință de tensiune) comună.
DTR-ul este conectat în buclă cu DSR și DCD pe ambele calculatoare. Când DTR este declarat activ, atunci DSR și DCD devin imediat active. În acest moment calculatorul "crede" că și modemul (virtual) cu care este conectat, este pregătit pentru comunicație și a detectat o purtătoare de la modemul corespondent.
Au mai rămas Request to Send și Clear to Send. Cum ambele calculatoare comunică cu aceeași viteză, controlul datelor nu este nscesar iar cele două linii sunt legate împreună în pereche, local, pentru fiecare calculator. Când calculatorul vrea să trimită date, Request to Send este declarat în stare “high” și, deoarece este legat cu Clear to Send, va începe imediat transmisia (calculatorul autovalidându-se).
De notat că indicatorul de sonerie, RI, nu este conectat la nici unul dintre cele două terminale. Această linie este folosită doar pentru a înștiința calculatorul că există un semnal de apel pe linia telefonică. Deoarece noi nu avem un modem conectat la linia telefonică, această linie este deocamdată nefolosită.
2.1.4. LoopBack Plug – Conectare în buclă pentru autotransmisie
Această conectare poate deveni foarte utilă la scrierea programelor de comunicare pentru Portul Serial / RS-232. Acesta are linii de transmisie și recepție conectate împreună, deci ceea ce se transmite în afara Portului Serial este imediat recepționat de același port. Dacă se realizează această conexiune, pentru a încărca un program terminal, tot ce se tastează va fi imediat afișat pe ecran. Această conexiune poate fi folosită cu exemplele care vor fi prezentate, pentru autoverificare.
De notat că această conexiune nu este creată pentru a fi folosită cu programe diagnostic și acestea, foarte probabil, nu vor funcționa. Pentru aceste programe este nevoie de alte conexiuni, ce pot fi diferite de la program la program.
2.1.5. Vitezele DTE/DCE
Un Dspozitiv Terminal de Date tipic este un calculator și un Dispozitiv de Comunicații de Date tipic este un modem. Se vorbește adesea despre viteze DTE la DCE sau DCE la DCE.
DTE la DCE este viteza dintre modem și calculatorul local, câteodată denumită și viteza terminalului. Aceasta ar trebui să fie mai mare decât viteza DCE la DCE, unde DCE la DCE este legătura dintre modemuri și din acest motiv se numește și viteza liniei de comunicație.
Astăzi, există modemuri de 28,8k sau 33,6k. De aceea este de așteptat ca viteza DCE la DCE să fie 28,8k sau 33,6k. Considerând această viteză mare,se poate considera că viteza între DTE și DCE este aproape 115,200 BPS (viteza maximă a UART-ului 16550). Aceasta este capcana în care cad majoritatea utilizatorilor. Programul de comunicare pe care se folosesc setări pentru vitezele DCE la DTE poate fi de 9,6 kBPS sau 14,4 BPS, dar aceasta nu este viteza modemului.
Modemurile actuale trebuie să utilizeze compresia datelor. Procesul este asemănător cu utilizarea executabilului PK-ZIP, dar în plus software-ul din modem va comprima și decomprima datele. Când setăm corect putem să avem o rată a compresiei de 1:4 sau chiar mai mare. Compresia 1 la 4 este tipică pentru un fișier text la 28,8k (DCE-DCE). Atunci când modemul comprimă datele, se transferă de fapt 115,2 kBPS între calculatoare astfel având o viteză DCE-DTE de 115,2kBPS. Acesta este motivul pentru care viteza DCE-DTE ar trebui să fie mult mai mare decât viteza modemurilor de conectare în exterior.
Unele modemuri realizează o rată maximă a compresiei 1:8. Dacă se utilizează un modem mai nou, la 33,6 kBPS se pot atinge viteze maxime de 268,800 kBPS între modem și UART. Dacă UART-ul este un 16550 acesta poate atinge viteze maxime de 115,200kBPS și astfel se utilizează sub capacitatea maximă. Pentru modemul 16C650 se rezolvă problema, acesta având o rată maximă de transfer de 230,400BPS.
Oricum trebuie utilizat modemul la capacitatea maximă. În unele situații dacă se transmite un fișier deja comprimat, modemul va aloca mai mult timp încercând comprimarea, obținănd astfel o viteză de transmisie mai mică decăt viteza de conexiune a modemului. Este indicată în aceste cazuri să nu se facă o compresie a datelor în avans. În plus, deoarece unele fișiere se comprimă mai ușor decât altele, orice fișier care se comprimă mai ușor va avea bineînțeles o rată a compresiei mai mare.
2.1.6. Controlul transferului de date
Deci dacă viteza de transmisie a datelor de la DTE la DCE este de câteva ori mai mare decât viteza DCE la DCE, PC-ul poate trimite date modemului la 115,200BPS. Se poate întâmpla să se piardă date datorită umplerii buffer-ului. Din acest motiv se folosește controlul transmisiei de date. Controlul transmiterii de date este de două feluri: hardware și software.
Controlul software, denumit uneori Xon/Xoff folsește două caractere Xon și Xoff. Xon este indicat în mod normal de caracterul 17 ASCII iar caracterul 19 ASCII este folosi pentru Xoff. Modemul are doar un buffer mic de intrare și deci când se anunță plin, modemul trimite un caracter Xoff pentru a anunța să se oprească trimiterea datelor. O dată ce modemul are loc pentru mai multe date, acesta trimite un caracter Xon și calculatorul trimite din nou alte date. Acest tip de control al transferului de date are avntajul că nu necesită mai multe fire decât cele utilizate pentru emisia/recepția caracterelor. Oricum pe legături lente trebuie să avem în vedere că fiecare caracter necesită zece biți, încetinind astfel comunicația. Controlul hardware este cunoscut sub denumirea de control RTS/CTS. Acesta folosește două fire suplimentare în cablul serial și nu înseamnă trimiterea mai multor caractere pe liniile de date. Astfel controlul hardware al datelor nu va încetini timpul de transmisie prin transmiterea caracterelor corespunzătoare pentru Xon-Xoff. Când calculatorul dorește să transmită date activează linia Request to Send. Dacă modemul poate primi datele în buffer-ul lui de intrare va răspunde prin activarea liniei Clear to Send, sesizată de calculator ca și nivel logic, calculatorul încpând să trimită date. Dacă buffer-ul modemului este plin, modemul nu va activa semnalul Clear to Send, invalidând astfel emiterea datelor.
2.1.7. Circuitul UART 8250 și alte circuite compatibile
UART 8250 este componenta de bază ce se află pe placa de interfață serială care comunică cu modemul sau cu alte dispozitive conectate la portul serial al plăcilor. Cele mai multe plăci de interfață au UART-ul integrat în alte cipuri care pot controla de asemenea portul paralel, portul pentru jocuri, driver-ele floppy sau pentru hard disk și sunt, de obicei, dispozitive de tip SMD. Seria de circuite UART 8250, care include și circuitele 16450, 16650 și 16750, sunt cele mai des întâlnite în PC-uri.
16550 este un cip compatibil cu 8250 și 16450. Singurele două diferențe sunt pinii 25 și 29. Pinul 24 al 8250 este ieșire de tip cip select ce indică doar dacă cipul este activ sau nu. Pinul 29 nu a fost conectat în cazul UART-ului 8250/16450. 16550 prezintă doi pini noi în locul lor. Aceștia sunt Transmit Ready (Transmisie Pregătită) și Receive Ready (Recepție Pregătită) care pot fi implementate cu DMA (acces direct la memorie). Acești doi pini au două moduri diferite de funcționare:
– “Modul 0” este numit de asemenea mod 16450. Acesta este selectat când buffer-ele FIFO sunt dezactivate prin bitul 0 a Registrului de Control al FIFO sau când buffer-ele FIFO sunt validate dar Modul Selecție pentru DMA este pe “0” (bitul 3 al FCR). În acest mod RXRD, pinul 24, este activ, pe nivel coborât (“Low”) când cel puțin un caracter (octet) mai este prezent în buffer-ul de la recepție. RXRDY va deveni inactiv trecând pe nivel ridicat (“High”) când nu vor mai exista caractere în buffer-ul de recepție. TXRDY va fi activ (pe nivel coborât) (“Low”) când nu avem caractere în buffer-ul de emisie și va fi inactiv, având nivel ridicat (“High”) imediat ce s-a înscris un nou caracter în buffer-ul de emisie.
“Modul 1” este când buffer-ele FIFO sunt active și Modul Selecție DMA=1. În “Modul 1” RXRDY va fi activ pe nivel coborât (“Low”) când este atins nivelul de declanșare sau când s-a terminat timpul de acces pentru 16550 și vom reveni la starea inactivă când nu mai există caractere rămaase în FIFO. TXRDY va fi activ când nici un caracter nu va fi prezent în buffer-ul de emisie și va deveni inactiv când buffer-ul de transmisie FIFO este complet plin.
Toți pinii UART sunt compatibili TTL. Este vorba de semnalele TD, RD, DCD, DSR, CTS, DTR și RTS care toate sunt legate la conectorul serial care este un conector de tip D. Din acest motiv este nevoie să se folosească convertoarele de la nivel TTL la nivelele specifice pentru RS-232 (circuite pe care le vom detalia mai târziu). Pentru conversia nivelelor de tensiune se folosesc de obicei: receptorul DS 1489 și emițătorul 1488DS, deoarece PC-ul are alimentări de +12V și –12V care pot fi folosite de aceste dispozitive. Aceste dispozitive vor converti semnalul TTL în nivele logice specifice pentru RS-232.
UART-ul are nevoie de un semnal de tact pentru a funcționa. Se utilizează fie un cuarț de 1,8432 MHz sau unul de 18,432MHz. Cristalul de cuarț este conectat la pinii XIN –XOUT ai UART-ului folosind câteva componente suplimentare ce permit cuarțului să intre în oscilație. Acest tact va fi folosit pentru Generatorul Programabil al vitezei de transmisie (Baud Rate) care apare în circuitele de sincronizare a emisiei, dar nu apare direct în circuitele de sincronizare pentru recepție. Pentru acestea trebuie făcută o conexiune externă de la pinul 15 (Baud Out) la pinul 9 (Receiver Clock In). De notat că semnalul de clock va avea o viteză de 16*Baud Rate.
Date despre UART 16550 se găsesc pentru PC 16550D de la site-ul National Semiconductors disponibil în format PDF. Texas Instruments furnizează circuite UART16750 care au 64 octeți (bytes) de FIFO. Documentația pentru TL16C750 este disponibilă pe site-ul Texas Instruments.
Tabelul 2.1.7.
2.1.8. Tipuri de UART-uri (pentru PC)
8250 este primul UART din această serie. Acesta nu conține nici un registru suplimentar. 8250A a fost o versiune îmbunătățită a lui 8250 care operează mai repede pe magistrală.
8252A- UART mai rapid decît 8250 pe magistrală. Din punct de vedere software este asemenea lui 16450.
8250B- similar cu UART 8250.
16450- folosită în PC-AT; îmbunătățirea vitezei, față de 8250, mai este încă folosit și astăzi în mod obișnuit.
16550- aceasta a fost prima generație de UART cu regiștri tampon (buffer-e). Acesta are un buffer de 16 octeți (bytes), dar nu a funcționat corespunzător și a fost înlocuit cu 16550A.
16550A- cel mai comun UART folosit pentru viteză mare de comunicație, de exemplu cu modemuri de 14,4k sau 28,8k. Este sigur că pe acest UART buffer-ele FIFO funcționează.
16650- o generație foarte nouă de UART. Conține un FIFO pe 32 de octeți, caractere Xon/Xoff programabile, controlul puterii consumate.
16750- produs de Texas Instruments, conține un FIFO de 64 de octeți.
2.1.9. Regiștrii portului serial (ai PC-ului)
Adresele portului și liniile de întrerupere, IRQ:
Tabelul 2.1.9.a.
În Tabelul 2.1.8.a. sunt adresele standard ale porturilor. Acestea ar trebui să funcționeze pentru majoritatea PC-urilor. Dar pentru un IBM/PC2 care are o magistrală micro canal avem un set de adrese cu totul diferit și de asemenea alte linii alocate pentru întreruperi IRQ. Întocmai ca la porturile paralele, adresele de bază pentru porturile seriale (COM) pot fi citite din zona BIOS de date.
Tabelul 2.1.9.b.
2.1.10. Adresele porturilor în zona de date BIOS
Tabelul de mai sus arată adresele la care putem găsi porturile de comunicații (COM) în zona de date BIOS. Fiecare adresă va ocupa doi octeți. Următoarea secvență de program în C, arată cum se pot citi aceste locații, pentru a obține adresele porturilor de comunicații.
#include <stdio.h>
#include <dos.h>
void main (void)
{
unsigned int far * ptraddr; /* Pointer la locația Adreselor
Porturilor */
unsigned int addres; /*Adresa Portului */
int a;
ptraddr=(unsigned int far )0x00000400;
for (a=0;a<=4;a++)
{
address=*ptraddr;
if (address==0)
printf(“no port found for COM%d\n”, a+1,
address);
else
printf (“Address assigned to COM%Xh\n”,a+1,
address);
*ptraddr++;
}
}
2.1.11. Tabelul Regiștrilor
Tabelul 2.1.11.
2.1.12. DLAB
Se remarcă în tabelul regiștrilor că există o coloană DLAB. Când setăm DLAB pe “0” sau pe “1”, unii regiștri își schimbă funcția. Astfel având alocate doar opt adrese de port, UART-ul poate avea 12 regiștrii (incluzând și registrul suplimentar). DLAB este acronimul pentru Bitul de acces al divizorului (“Divisor Latch Access Bit”). Când DLAB este setat pe “1” prin intermediul registrului de control al liniei (LCR), vor putea fi accesați doi regiștrii în care se poate seta mărimea vitezei de comunicare în biți per secundă. UART-ul are un cuarț care oscilează la o frecvență de 1,8432 MHz. UART-ul conține un numărător cu șaisprezece divizoare care divide doar semnalul de intrare al clock-ului cu 16. Presupunând că avem un semnal de tact cu frecvența de 1,8432 MHz, vom avea astfel un semnal cu frecvența maximă de 115,200 MHz, făcând UART-ul capabil de transmiterea și recepționarea la 115,200 biți/secundă (BPS). Aceasta ar fi util pentru unele dintre modemurile mai rapide și dispozitivele care pot funcționa la această viteză, dar altele nu pot funcționa decât la o frecvență mai mică. De aceea UART-ul este prevăzut cu un Generator Programabil de viteză, controlat de doi regiștri.
Dacă de exemplu dorim să comunicăm doar la 2400 BPS, va trebui să divizăm 115,200 cu 48 pentru a obține un tact acceptabil de 2400 Hz. Divizorul, în acest caz 48, este memorat în doi regiștrii controlați de DLAB prin inermediul Bitului de acces la divizor (“Divisor Latch Access Bit”). Acest divizor poate fi orice număr ce poate fi memorat pe 16 biți (adică de la 0 la 65535). UART-ul are o magistrală internă de date de 8 biți și pe această magistrală va ajunge conținutul celor doi regiștri. Primul registru aflat la adresa "Adresa de Bază + 0", când DLAB=1, memorează cei opt biți mai puțin semnificativi, iar registrul de la "Adresa de Bază +1", când DLAB=0, memorează cei opt biți mai semnificativi pentru divizare.
În continuare este prezentat tabelul celor mai utilizate viteze:
Tabelul 2.1.12.
2.1.13. Registrul de Validare al Întreruperilor (“Interupt Enable Register”)
Tabelul 2.1.13.
Registrul de validare al întreruperilor este unul dintre cei mai ușori de înțeles regiștrii din componența UART-ului. Setând “Bitul 0” pe nivel high se validează cererea de întrerupere pentru datele disponibile la recepțiae. FIFO conține date ce trebuie citite de CPU.
“Bitul 0” validează cererea de întrerupere când Registrul Suplimentar (“Transmit Holding Register Empty Interrupt”) este gol. Acesta Întrerupe CPU când buffer-ul de transmisie este gol.
“Bitul 2” validează cererea de întrerupere pentru liniile de recepție. UART-ul solicită o întrerupere când se schimbă starea liniei de recepție.
Asemănător este pentru “Bitul 3” care validează cererea de întrerupere corespunzătoare modem-ului. Biții de la 4 la 7 sunt rezervați.
2.1.14. Registrul de Identificare a Întreruperilor (“Interrupt Identification Register”)
Tabelul 2.1.14.
Registrul de identificare a întreruperilor este un registru doar pentru citire. Buții 6 și 7 indică starea buffer-ului FIFO. Când ambii biți sunt “0”, nu este activ nici un buffer FIFO. Aceasta este starea care se citește la 8250 sau 16450. Dacă bitul 7 este activ dar bitul 6 este pe “0”, UART-ul are buffer-ul validat, dar nefolosit. Această posibilitate este valabilă pentru UART 16550 unde o problemă într-un buffer FIFO face FIFO neutilizabil. Dacă ambii biți sunt “1”, atunci buffer-ele FIFO sunt validate și complet operaționale.
Biții 4 și 5 sunt rezervați.
Bitul 3 arată starea întreruperilor pentru time-out pentru un 16550 sau alternative mai evoluate.
Bitul 0 ne arată dacă a apărut o întrerupere. Originea acestei întreruperi va fi indicată de starea biților 1 și 2. Aceste întreruperi au alocate priorități. Întreruperea de stare a liniei are cea mai mare prioritate, urmată de întreruperea corespunzătoare existenței unei date disponibile, urmează întreruperea golirii registrului de emisie și apoi întreruperea ce indică o modificare de stare a modemului, care are cea mai mică prioritate.
2.1.15. Registrul de Control FIFO (“First In/First Out Control Register”)
Tabelul 2.1.15.
Registrul FIFO este un registru care poate fi doar înscris. Acest registru este folosit doar pentru controlul buffer-elor FIFO care se găsesc în 16550 sau în circuite mai evoluate.
Bitul validează operațiile de recepție și de emisie FIFO. Înscriind un “0” la acest bit se dezactivează emisia și recepția FIFO și astfel se vor pierde toate datele stocate în buffer-ele FIFO.
Biții 1 și 2 controlează neutralizarea emisiei sau recepției FIFO. Bitul 1 este destinat buffer-ului de recepție iar bitul 2 este pentru buffer-ul de emisie. Setarea acestor biți pe “1” va șterge conținutul FIFO și nu va afecta regiștrii de deplasare. Pentru acești doi biți avem funcția de autoreset; astfel nu este nevoie să se seteze acești biți pe “0” când buffer-ele nu mai conțin date: biții 1 și 2 se pun pe zero în mod automat.
Bitul 3 validează selectarea modului DMA care se află implementat în UART 16550 sau în alte tipuri mai evoluate de circuite UART.
Biții 4 și 5 sunt rezervați.
Biții 6 și 7 sunt folosiți pentru setarea pragului pentru declanșare a întreruperilor pentru FIFO-ul de recepție. De exemplu dacă bitul 7 a fost setat pe “1” și bitul 6 a fost setat pe “0”, atunci pragul de declanșare este setat la 8 biți, și prin urmare, când există 8 biți de date în FIFO de recepție atunci se setează întreruperea corespunzătoare pentru date disponibile la recepție – Received Sata Available Interrupt (a se vedea și IIR).
2.1.16. Registrul de control al liniei (LCR)
Tabelul 2.1.16.
Registrul de control al liniei setează parametrii de bază pentru comunicații.
Bitul 7 este bitul de acces la circuitul de memorare pentru divizare, DLAB, prezentat înainte.
Bitul 6 setează validarea anulării recepției (break). Când este activ, linia TD intră într-o stare corespunzătoare lui 0 logic, care provoacă o anulare a recepției UART-ului. Setând acest bit pe “0” dezactivăm anularea.
Biții 3, 4 și 5 selectează paritatea, după cum urmează: dacă bitul 3 este setat pe “0” atunci nu se folosește controlul parității, iar dacă este setat pe “1” atunci folosim paritatea.
Bitul 5 controlează o paritate specială de tip “0” sau “1”, în engleză – "stiky party". "Stiky parity" este atunci când bitul corespunzător parității este transmis întotdeauna (și este și verificat) ca un “1” sau “0”. Acest tip de paritate nu are rol în determinarea erorilor. Astfel, dacă primii 4 biți conțin erori, dar bitul de paritate specială conține fie “1” fie “0”, setat corespunzător, nu rezultă eroare de paritate. Stiky High Parity, paritate de tip Mark, este folosirea lui “1” pentru bitul de paritate. Stiky Low Parity, paritate de tip Space, “0”, folosește pentru bitul de paritate valoarea “0”. Dacă bitul 5 controlează paritatea specială, atunci resetarea acestui bit înseamnă existența parității normale asigurată de bitul 3 (dacă acesta este) setat pe “1”. Paritatea impară este atunci când bitul de paritate este transmis ca “1” sau “0”, astfel încât pentru tot caracterul plus bitul de paritate să avem un număr impar de 1. Paritatea pară va fi când pe ansamblu vom avea un număr par de “1”. Aceasta asigură o mai bună verificare a erorilor dar încă nu este perfectă, astfel că se folosește adesea un cod de corecție CRC-32 pentru corecția erorilor. Dacă se întâmplă ca un bit să fie inversat, având fie paritate pară fie paritate impară, atunci va apare o eroare de paritate. Dar dacă doi biți sunt schimbați în așa fel încât se menține paritatea, atunci nu se detectează eroare de paritate.
Bitul 2 setează lungimea biților de stop. Setând acest bit pe “0” se generează un bit de stop, iar setarea lui pe “1” va produce 1,5 sau 2 biți de stop, acest număr depinzând de lungimea caracterului. De notat că receptorul verifică doar primul bit de stop.
Bitul 0 și bitul 1 setează lungimea caracterului (cuvântului). Cea mai utilizată este lungimea cuvântului (caracterului) de 8 biți.
2.1.17. Registrul de control al modemului
Tabelul 2.1.17.
Registrul de control al modemului este un registru care poate fi scris/citit .
Biții 5, 6 și 7 sunt rezervați.
Bitul 4 activează modul autotest. În acest mod, ieșirea emițătorului serial este plasată în “1”. Intrarea receptorului serial este deconectată. Ieșirea emițătorului este legată (înapoi) la intrarea receptorului. DSR, CTS, RI și DCD sunt deconectate. DTR, RTS, OUT1 și OUT2 sunt conectate la intrările de control ale modemului. La modem, pinii de control ai ieșirii modemului sunt plasați într-o stare inactivă (invalidați). În acest fel orice dată care este plasată în regiștrii emițătorului pentru a fi transmisă este primită de către circuitul receptor din același integrat și sunt disponibile în buffer-ul receptorului. Acest mod poate fi folosit la testarea funcționării UART-ului.
2.1.18. Registrul de stare la liniei
Tabelul 2.1.18.
Registrul de stare al liniei este un registru care poate fi doar citit.
Bitul 7 este bitul de eroare pentru recepția FIFO. Acest bit este pe nivel ridicat când a apărut cel puțin una din următoarele erori: paritate sau eroare de format pentru un byte conținut în FIFO.
Când bitul 6 este setat înseamnă că atât registrul de menținere al emisiei cât și registrul de deplasare sunt vide. Registrul de menținere al UART menține următorul octet de date pentru a fi emis în format paralel. Registrul de deplasare este folosit pentru a converti octetul paralel în format serial, încât să poată fi emis în linie.
Când bitul 5 este setat, registrul suplimentar de menținere de la emisie (transmit holding register) este gol și se poate trimite spre port un alt caracter. În același timp se poate executa o conversie din format paralel în format serial prin intermediul registrului de deplasare. Diferența dintre biții 6 și 5 este următoarea: bitul 6 setat înseamnă că registrul suplimentar de menținere de la emisie și registrele de deplasare sunt goale și deci nu are loc nici o conversie serială, astfel încât nu ar trebui să fie nici o activitate pe linia de emisie a datelor; când bitul 5 este setat, registrul de menținere a emisiei este gol, astfel poate fi trimis alt bit la portul de date, iar o conversie serială ce folosește registrul de deplasare poate avea loc.
Anularea, făcută de bitul 4, apare când linia de recepție de date este menținută în stare logică “0” pentru mai mult timp decât ar lua durata transmiterii unui cuvânt întreg. Această durată include timpul pentru bitul de start, biții de date, biții de paritate și biții de stop.
O eroare de format (bit 3) apare când ultimul bit nu este bit de stop. Aceasta se poate datora unei erori de sincronizare. Cel mai probabil se întâlnește o astfel de eroare fie când folosim un cablu modem nul ce leagă două calculatoare, fie un analizor de protocol, la care vitezacu care datele sunt trimise este diferită de viteza de recepție setată pentru UART.
O eroare de depășire apare în mod normal când programul nu poate citi suficient de repede datele. Dacă octetul recepționat nu este citit (extras) din registru destul de repede, un alt byte receptat se suprapune (se înscrie peste), iar penultimul octet se va pierde și va rezulta o eroare de depășire.
Bitul 0 artă că datele sunt pregătite, ceea ce înseamnă că un octet a fost recepționat de către UART și buffer-ul receptorului conține un octet ce poate fi citit.
2.1.19. Registrul de stare al modemului
Tabelul 2.1.19.
Bitul 0 al registrului de stare al modemului arată o schimbare a stării liniei CTS ceea ce însemnând că există o schimbare în starea liniei CTS (gata de emisie) față de ultima citire a registrului. Avem aceeași interpretare pentru biții 1 și 3.
Bitul 1 artă o schimbare a stării liniei DSR (Data Set Ready), iar bitul 3 arată o schimbare a stării liniei DCD (Data carrier Detect). Bitul 2 indică detectarea unuei modificări a stării de apel RI (Ring Indicator), adică indică existența unei modificări de la starea Low la starea High pe linia indicatorului de apel, RI.
Biții 4 la 7 arată starea curentă a liniilor de date în timpul citirii.
Bitul 7 arată setarea liniei de detecție a purtătoarei.
Bitul 6 arată starea indicatorului de apel RI.
Bitul 5 arată starea linie DSR, iar bitul 4 arată starea Liniei CTS.
2.1.20. Registrul suplimentar (Scratch)
Registrul suplimentar (scratch) nu este folosit pentru comunicații ci este mai degrabă folosit ca un loc în care se poate depune un octet de date. Singura utilizare reală este de a determina dacă UART-ul este un 8250, 8250A sau 8250B, dar chiar și așa nu este foarte utilă această funcție deoarece 8250/8250B nu au fost niciodată proiectate pentru AT și nu pot atinge viteza de magistrală curentă.
2. Caracteristici software
2.2.1. Alegerera indicatorului de întrerupere sau interogare
Când scriem un program de comunicare avem disponibile două metode. Putem interoga (citi) UART-ul pentru a vedea orice dată disponibilă sau putem seta un indicator de întrerupere pentru a citi datele din UART când acesta generează o întrerupere. Interogarea UART-ului este o metodă mult prea înceată, care este foarte folositoare deoarece se obține o viteză maximă de aproximativ 34,8 kBPS fără a pierde date. Pe unele calculatoare noi (Pentium Pro) se ating și viteze mai mari decât aceasta. Cealaltă metodăfolosește un indicator de întrerupere, așa cum vom folosi în continuare. Vom putea avea viteze de 15,2 kBPS, chiar în cazul unor calculatoare lente.
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#define PORT1 0x3F8
/*Definirea adreselor de baza ale porturilor seriale*/
/*COM1 0x3F8*/
/*COM2 0x2F8*/
/*COM3 0x3F8*/
/*COM4 0x2F8*/
void main (void)
{
int c;
int ch;
outportb (PORT1+1,0);/*Oprirea intreruperilor-PORT1*/
/*PORT1-Setarile de comunicatie*/
outportb (PORT1+3,0×08);/*Setare DLAB*/
outportb (PORT1+3,0×03);/*Setarea vitezei, partea low a registrului*/
/* de divizare*/
/*0x03=38400 BPS*/
/*0x01=115200 BPS*/
/*0x02=57600 BPS*/
/*0x06=19200 BPS*/
/*0x0C=9600 BPS*/
/*0x18=4800 BPS*/
/*0x30=2400 BPS*/
outportb (PORT1+1,0×00); /*Setarea vitezei,partea high a registrului*/
/*de divizare*/
outportb(PORT1+3,0×03); /*8 biti, fara paritate, 1 bit de semn*/
outportb(PORT1+2,0xC7); /*Registrul de control FIFO*/
outportb(PORT1+4,0x0B); /*Pornire DTR,RTSsi OUT2*/
printf ("\nExemplu de program de comunicare pe Protul Serial");
printf ("\nApasati 'ESC' sa iesiti!");
do {c=inportb (PORT1+5);/*Verifica daca s-a receptionat un caracter*/
if (c&1){ch=inportb(PORT1)/*Daca da tipareste caracterul pe ecran*/
printf("%c",ch);}
if (kbhit()){ch=getch(); /*Daca apasati o tasta trimiteti caracterul la*/
/*Portul Serial*/
outportb (PORT1,ch);}
}while (ch!=27); /*Se iasa din program cand este apasat */
/*'ESC'-27(ASC)*/
}
Interogarea UART-ului nu trebuie abandonată total. Este o metodă bună de diagnosticare. Dacă nu se cunoaște adresa portului serial sau ce IRQ se folosesc se poate citi (interoga) UART-ul la câteva adrese diferite pentru a găsi mai întâi la care port se atașează modemul. Odată ce se cunoaște această informație puteți seta subrutinele de întrerupere pentru IRQ-ul comun și să fie validată câte o linie IRQ la un moment dat de timp folosind controller-ul de întrerupere programabil și astfel se poate afla IRQ-ul.
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#define PORT1 0x3F8 /*Adresa Portului*/
#define INVECT 0x0C /*Comunicatia Portului */
/*Serial.Trebuie de asemenea*/
/*schimbata seatrea PIC*/
/*Definirea adreselor de baza ale Porturilor*/ /*Seriale*/
/*COM1 0x3F8*/
/*COM2 0x2F8*/
/*COM3 0x3F8*/
/*COM4 0x2F8*/
int bufferin=0;
int bufferout=0;
char c;
char buffer[1025];
void interupt (*oldportlisr)();
void interupt PORT1INT();/*Intrerupe rutina
/*Service (ISR)pentru*/
/*PORT1*/
int c;
do {c=inportb(PORT1+5);
if (c&1){buffer[bufferin]=inportb(PORT1);
bufeerin++;
if(bufferin==1024){bufferin=0;}}
}while (c&1);
outportb(0x20,0x20);
}
void main (void)
{
int c;
outportb(PORT1+1,0);/*Opreste intreruperile*/
/*PORT1*/
oldportlisr=getvect(INTVECT)/*Salveaza*
/*vectorii de intrare*/
/*pentru recunoastere */
setvect (INVECT,PORT1INT);/*Setarea intrarii*/
/*vectorului de */
/*intrerupere*/
/*COM1 0x0C*/
/*COM2 0x0B*/
/*COM3 0x0C*/
/*COM4 0x0B*/
/*PORT1-Setari de comunicatii*/
outportb (PORT1+3,0×80); /*Seatre DLAB*/
outportb (PORT1+0,0x0C); /*Setarea vitezei-*/
/*octetul low al*/
/* divizorului*/
/*0x03=38400 BPS*/
/*0x01=115200 BPS*/
/*0x02=57600 BPS*/
/*0x06=19200 BPS*/
/*0x0C=9600 BPS*/
/*0x18=4800 BPS*/
/*0x30=2400 BPS*/
outportb (PORT1+1,0×00);/*Setarea vitezei*/
/*octetul high al*/
/*divizorului*/
outportb (PORT1+3,0×03);/*8 biti,fara paritate*/
/*1 bit de semn*/
outportb (PORT1+2,0xC7);/*Registrul de control*/
/*FIFO*/
outportb (PORT1+4,0x0B);/*Porneste DTR, RTS si*/
/*OUT2*/
outportb (0x21,(inportb(0x21)&0xEF));/*Setarea*/
/*intreruperilor*/
/*programului*/
/*COM1(IRQ4)-0xEF*/
/*COM2(IRQ3)-0xF7*/
/*COM3(IRQ4)-0xEF*/
/*COM4(IRQ3)-0xF7*/
outportb (PORT1+1,0×01);/*Intrerupere cand se
/*primesc date*/
printf ("\n Exemplu de program de comunicare seriala. Apasati 'ESC'pentru a iesi din program");
do{if (bufferin!=bufferout){ch=buffer[bufferout];
bufferout++;
if bufferout==1024){bufferout=0;}
printf ("%c",ch);}
if(kbhit()){c=getch();
outportb(PORT1,c);}
}while (c!=27);
outportb(PORT1+1,0);/*Opreste intreruperile*/
/*PORT1*/
outportb(0x21,(inportb(0x21))0x10));
/*COM1(IRQ4)-0x10*/
/*COM2(IRQ3)-0x08*/
/*COM3(IRQ4)-0x10*/
/*COM4(IRQ3)-0x08*/
setvect(INTVECT,oldporelisr);/*Redarea vechilor*/
/*vectori(old_interupt_vector)*/
}
Notă: Codul sursă nu este chiar un bun exemplu de programare dar este mai
degrabă o metodă epntru a obține rezultate rapide și este ușor de înteles. Pentru executarea programului de comunicaere, ar fi mai înțelept să memorăm starea regiștrilor UART, pentru a putea fi refăcuți înainte de părăsirea programului. Aceasta pentru a crea cât mai puține probleme celorlalte programe care pot de asemenea să folosească porturile de comunicare.
Primul pas al metodei este utilizarea întreruperii Portului Serial
utilizat. Tabelul arată adrersa de bază și IRQ-ul câtorva porturi de standar. Cele mai utilizate sunt IRQ3 și 4. Se mai utilizează și IRQ5 și 7.
2.2.2. Vectorii de întrerupere
Odată ce știm IRQ-ul, următorul pas este să găsim vectorii de
întrerupere sau întreruperile software. În orincipiu orice procesor 8086 are un set de vectori de întrerupere memorat de la 0 la 255. Fiecare dintre acești vectori conține un cod de 4 octeți reprezentând adresa unei Rutine de deservire a întreruperilor (Interupt Service Routine-ISR). Din fericire C-ul fiind un limbaj de nivel înalt, are implicit cunoscute adrese. Trebuie să știm doar actualul vector de întrerupere.
Tabelul 2.2.2.
Tabelul de mai sus arată doar întreruperile care sunt asociate cu liniile
de întrerupere IRQ. Celelalte 240 nu ne interesează când programăm tipul de comunicație RS-232.
De exemplu, dacă folosim Com3, care are alocată linia IRQ4, atunci vectorul de întrerupere va fi 0C în hexazecimal. Ăn C vom seta vectorul cu ajutorul instrucțiunii:
setvect (0x0C, PORT1INT);
unde PORT1 INT ne conduce la un set de instrucțiuni care vor servi întreruperile.
Oricum înainte de a efectua aceste operații, trebuie să înregistrăm adresesle vechilor vectori și să refacem aceste adrese odată ce programul este terminat. Aceasta se face folosind:
oldport1 isr =getvect(INTVECT);
unde oldport1 isr este definit folosind:
void interupt (*oldport1 isr)();
Nu numai că trebuie să păstrăm vechile adrese ale vectorilor, dar păstrăm de asemenea și configurația UART-ului, deoarece am scris un program de comunicație cu tastatura. Acesta are linii tampon, care include diferite subrutine. Dacă există două programe de comunicare serială, al doilea fiind lansat în execuție din primul, dacă nu se restaurează configurația, programul principal în care survin nu va mai rula (există setări pentru viteza de transmisie, paritate, etc diferite care nu le-am mai restabilit). De aceea salvând vechea configurație putem reveni la ea înainte de a încărca UART-ul cu un alt program. Dacă nu este disponibil nici unul din aceste programe se pot salva câteva linii de cod.
2.2.3. Rutina de servire a întreruperilor
În partea de program care gestionează întreruperile, denumită rutină de tratare a întreruperilor (ISR), se pot include alte instrucțiuni mai puțin apelrea unor rutine DOS care pot fi oproblemă.
void interupt PORT1 INT()
int c;
do c=inportb(PORT1+5);
if (c&1)
bufferbufferin=inportb(PORT1);
bufferin ++;
if (bufferin==1024) bufferin==0;
while (c&1);
outportb (0x20,0x20);
Prin exemplul de mai sus verificăm să vedem dacă avem un caracter la recepție și dacă este așa îl citim din UART ți îl plasăm într-un buffer din memorie. Controlăm în continuare UART-ul, în cazul în care FIFO-ul este validat, așa că putem obține toate datele disponibile la momentul de timp la care a apărut întreruperea.
Ultima linie conține instrucțiunea:
outportb(0x20,0x20);
care spune Controller-ului de programare a întreruperii că nu mai există întrerupere. Ne vom ocupa acum de Controller-ul de programare a întreruperii (PIC). În toate rutinele de mai sus am presupus că totul este setat și gata de funcționare, adicăam presupus că toți regiștrii UART-ului sunt setați corect, iar Controller-ul de programare a întreruperilor este de asemenea setat.
Controller-ul de programare a întreruperilor gestionează întreruperile hardware. Majoritatea PC-urilor au câte două PC-uri, situate la adrese diferite. Unul se ocupă de IRQ0 IRQ7 și celălalt de IRQ8 IRQ15 Întreruperile de comunicare serială se află pe liniile de întrerupere până la IRQ7, astfel PIC1 este folosit, el fiind alocat la 0020 Hex.
Tabelul2.2.3.a.
Cele câteva COM-uri sunt cunoscute, astfel tabelul conține datela pentru PIC2 care este situat la adresa 0xA. PIC2 gestionează liniile IRQ8 la IRQ15. Acesta operează exact la fel ca PIC1, cu deosebirea că EOI (End of Interupt) Sfârșit al întreruperii este pentru portul 0xA0 iar linia de dezactivare (mascare) pentru IRQ-uri se poate realiza folosind portul 0xA1.
Tabelul 2.2.3.b.
Majoritatea inițializărilor PC-ului sunt realizate prin BIOS. Trebuie să avem grijă doar la utilizarea a două instrucțiuni. Prima este:
outportb(inportb(0x21)&EF);
care selectează întreruperile pe care dorim să le dezactivăm (mascăm). Deci dacă dorim să validăm IRQ4 trebuie să scăde 0x01 (16) din 0xFF (255) pentru a realiza 0x EF (239). Aceasta înseamnă că dorim să dezactivăm IRQ-urile 7, 6, 5, 3, 2, 1 ți 0, validând astfel IRQ4.
Dar dacă una dintre aceste linii de întrerupere IRQ este deja validată și o invalidăm prin program, trebuie să introducem valoarea registrului și să folosim funcția & (and) pentru a plasa rezultatul (byte-ul) înapoi în registru cu schimbările noastre. Aceasta se face prin instrucțiunea :
outportb (0x21,(inportb(0x21)&0xEF));
De exemplu dacă IRQ5 a fost deja validat dinainte instrucțiunea mai sus prezentată va valida ambele IRQ4 și IRQ5 așa că nu facem nici o schimbare care ar putea afecta celelalte programe. A doua instrucțiune este:
outportb(0x20,0x20);
care semnalizează terminarea ăntreruperii la PIC. Se folosește această comandă la sfârșitul rutinei de tratare a întreruperii, deci celelalte întreruperi, cu nivel de prioritate mai scăzut vor fi acceptate.
2.2.4. Configurația UART
Acest program prezintă setările UART-ului. Este bine ca prima instrucțiune să blocheze generarea întreruperilor de la UART Astfel inițializarea nu poate fi întreruptă de UART Apoi putem alege setarea vectorilor de întrerupere. Următorul pas este setarea vitezei la care se va realiza transferul datelor. Deci, trebuie să setăm bitul 7 (DLAB) din registrul LCR astfel încât să avem acces la octeții divizorului (Divisor Latch) părții high și low. Dacă dorim să setăm, de exemplu, viteza la 38 400 BPS (valoarea potrivită pentru 16450 și 16550), avem nevoie de un divizor cu 3, astfel partea high a divizorului este de 0x00 și partea low 0x03.
În standardele actuale divizorul high este folosit rar dar este indicat să înscriem 0x00 în registru pentru cazul în care programul anterior a setat UART-ul la o viteză foarte mică (la 50 BPS sau 300 BPS). BIOS va seta UART-ul la 2 400 BPS când se pornește calculatorul, viteză care nu implică setarea octetului high. Pasul următor este să blocăm accesul la latch-ul divizorului astfel încât să putem accesa Registrul de validare a întreruperilor și buffer-ele de recepție/emisie. Ceea ce se poate este să scriem 0x00 în registru,inițializându-l cu 0, dar având în vedere că va trebui să setăm lungimea cuvântului,paritatea (după cum este în registrul de control al liniei), aceste operații putând fi făcute în același timp. Se seteazăn 8 biți, fără paritate și un bit de stop ceea ce este o setare curentă. De aceea csriem 0x03 în Registrul de control al liniei care va avea drept efect și blocarea. Economisim astfel timp pentru că printr-oinstrucțiune de I/O am obținut și blocarea DLAB și setarea parametrilor de comunicare.
Următoarea linie de cod validează buffer-ele FIFO.inițializăm la 14 octeți nivelul de declanșare al întreruperii, astfel biții 6 și 7 trebuie poziționați în stare “on”. Am validat de asemenea FIFO (bitul 0). Este de asemenea bine să ștergem buffer-ele FIFO la inițializare. Aceasta va anula orice rest care putea rămâne de la ultimul ăprogram în buffer-ele FIFO. Datorită faptului că acești doi bițise autosetează nu trebuie să continuăm și să oprim acești biți. Dacă este corect din punct d vedere aritmetic, toți acești biți ajung la 0xC7 sau 199 (în FCR, zecimal).
Apoi DTR, RTS și OUT2 sunt activate prin instrucțiunea:
outportb (PORT1+4,0x0B);
Unele porturi impun ca OUT2 să fie activ pentru cererile de întrerupere, astfel că, în mod normal, OUT2 se pune întotdeauna pe “1”. Tot ce a mai rămas acum este setarea întreruperilor care trebuie să fie lăsate intenționat la urmă pentru a nu ne întrerupe inițializarea. Gestionarul întreruperilor noastre este interesat doar de noi date disponibile deci trebuie doar să setăm UART-ul pentru generarea unei întreruperi în momentul în care s-au primit date.
2.2.5. Rutina principală
Rămâne de idscutat:
do
if (bufferin!=bufferout)
ch=bufferbufferout;
bufferout++;
if (bufferout ==1024) bufferout=0;
printf (“%c”,ch);
if (kbhit ())
c=getch();
outportb (PORT1,c);
while (c!=27);
ceea ce se repetă până când c=27. Aceasta se întâmplă când este apăsată tasta ESC.
Următoarea instrucțiune “if” testează dacă a fost apăsată o tastă (“kbhit()”). Dacă da, se aduce acel caracter folosind instrucțiunea “getch()” și caracterul se înscrie în buffer-ul de emisie al UART-ului. Apoi UART-ul emite caracterul modemului. S-a presupus că persoana care utilizează acest program de comunicații nu poate tasta la fel de repede cât de repede transmite UART-ul. Oricum dacă programul dorește să emită un caracter, atunci trebuie făcută o verificare pentru a dacă bitul 5 al Registruluide stare a liniei este pe “1” și doar după ce acesta este setat să transmită un byte la Registrul de emisie.
2.2.6. Determinarea tipului UART-ului prin software
Tipul UART-ului instalat în sistem poate fi determinat fără a avea nevoie în majoritatea cazurilor de un driver special. Așa cum s-a văzut din “Tipuri de UART-uri” fiecare UART are mici diferențe, mai trebuie făcută doar testarea.
Prima procedură pe care o facem este de a seta bitul 0 la ”1” în Registrul de control FIFO. Apoi citim biții 6 și 7 din Registrul de identificare a întreruperilor. Dacă ambii biți sunt “1”, atunci buffer-ele FIFO sunt validate. Aceasta înseamnă că UART-ul este 16550A. Dacă buffer-ele FIFO au fost validate dar nu pot fi utilizate atunci circuitul este 16550. Dcaă nu avem buffer-e FIFO validate este cel mai probabil un UART 16450, dar poate fi un 8250, 8250A sau 8250B (un sistem faorte vechi).
AT are o rată de transfer mare pe magistrală la care seria 8250 a UART-ului nu funcționează bine. Astfel este foarte probabil să nu existe circuitul 8250 în nici un AT
Dacă biții 6 și 7 sunt “1” –UART 16550A
Dacă biții 6 și 7 sunt “0”, respectiv “1” – UART16550
Dacă biții 6 și 7 sunt “0” – se încearcă scrierea unui octet în scratch și se citește înscrierea comparând rezultatul. Dacă rezultatul există – UART16450 sau 8250A. dacă nu există rezultă circutul este 8250 sau 8250B.
16750 are 64 biți FIFO, încât cea mai ușoară cale de testare este validarea buffer-ului de 64 de biți folosind Registrul de control FIFO și apoi citirea stării Registrului de identificare a întreruperilor (IIR).
2.2.7. Formele de undă ale RS-232
Până acum am introdus comunicațiile RS-232 în relația cu PC-ul. Comunicația RS-232 este asincronă. Aceasta înseamnă că nu este trimis nici un semnal de tact împreună cu datele. Fiecare cuvânt este sincronizat folosind bitul de start și un tact intern la fiecare capăt al liniei de legătură ce impune momentele de eșantionare (citire) a nivelului liogic.
Diagrma arată formele de undă așteptate de UART când folosim formatul comun 8N1. 8N1 semnifică 8 biți de date , fără paritate și 1 bit de stop.Când este nefolosită linia de RS-232 este în stare de nivel coborât de tensiune (tip Mark). O transmisie începe cu un bit de start care este “0” logic. Apoi fiecare bit este trimis pe linie, unul câte unul. LSB (bitul cel mai puțin semnificativ) este trimis primul. Un bit de stop (“1” logic) este apoi adăugat la semnal pentru a se încheia transmisia.
Diagrama, arată următorul bit după bitul de stop ca fiind pe “0” logic. Aceasta înseamnă că urmează un alt caracter și acesta este bitul său de start. Dacă nu mai urmează date, atunci linia de recepție va rămâne neutilizată, în stare “1” logic.
Se întâlnește așa-numitul semnal “pauză”(Break). Aceasta când linia de date e menținută în stare logică ”0” pentru un timp destul de lung pentru a trimite întreg cuvântul. De aceea dacă nu este pusă linia înapoi ăn stare nefolosită, atunci sfârșitul recepției va fi interpretat ca semnal de întrerupere (pauză).
Datele trimise folosind această metodă, se spune că sunt structurate. Acestea sunt datele structurate între bitul de start și bitul de stop. Ar trebui ca bitul de stop să fie receptat ca “0” logic, apoi va apare o eroare de structurare. Aceasta se întâmplă de obicei când ambele părți comunică la viteze diferite.
Diagrama de mai sus este relevantă pentru semnal când nivelele logice ale RS-232 folosesc +3V până la +25V pentru a însemna “0” logic (Space) și –3V până la –25V pentru un “1” logi (Mark). Orice tensiune intermediară acestor regiuni (între +3V și –3V) este nedefinită. De aceea semnalul este pus printr-o RS-232 convertor de nivel. Acesta este esmnalul prezent pe portul RS-232 al calculatorului raătat mai jos.
Formele de undă de mai sus aplicate la liniile de transmisie și recepție pe portul RS-232, care de fapt sunt linii paralele. Aceste linii (RTS, CTS, DCD, DSR, DTR, RTS și RI) sunt deasemenea la nivelele logice RS-232.
2.2.8. Convertoarele de nivel RS-232
Aproape toate dispozitivele care se folosesc cer nivele logice TTL sau CMOS. De aceea primul pas în conectarea unui dispozitiv la portul RS-232 este transformarea nivelelor RS-232 înapoi în 0V și 5V, realizate tot cu ajutorul convertoareloa de nivel RS-232.
Două convertoare de nivel RS-232sunt: emițătoarele și receptoarele 1489. Fiecare din aceste integrate conține câte patru invertoare de fiecare tip, emițătoare respectiv receptoare.1488 are nevoie de două tensiuni de alimentare, o tensiune între +7,5V și +5V și între -7,5V și –15V. Astfel aceasta poate însemna o problemă în multe cazuri unde există doar o tensiune de alimentare de +5V. Singurul avantaj al acestor circuite integrate este că sunt ieftine.
Alt dispozitiv este MAX 232. Acesta include un dublor de tensiune și un invertor, care generează +10V și –10V de la o alimentare unică de +5V. Acest circuit integrat include de asemenea două receptoare și două emițătoare în aceeați capsulă, ceea ce este suficient în multe cazuri când se dorește conectarea doar a liniei de emisie și de recepție. Nu este nevoie să se utilizeze două cipuri: unul pentru linia de recepție și unul pentru linia de emisie. Oricum toate aceste avantaje au un anumit preț, dar, în comparație cu prețul proiectării unei surse de alimentare, este foarte ieftin.
Există multe variante ale acestui dispozitiv. Pentru conectarea lui MAX-232 se folosesc condensatori de valori mari care sunt mai voluminoși și mai scumpi.Se pot utiliza și alte dispozitive care sunt disponibile și care folosesc capacități mai mici și există chiar câteva cu capacități încorporate. MAX-232 este cel mai comun și vom folosi acest convertor de nivele RS-232 în exemplele care urmează.
2. 2. 9. Folosirea formatului serial
Pentru a face ceva folositor cu datele noastre transmise serial, trebuie să le convertim înapoi în format paralel. Acest lucru era făcut înainte cu ajutorul UART-ului. Dar datorită popularității microcontroller-elor care sunt destul de ieftine, acestea pot fi mult mai potrivite în unele aplicații. Vom căuta avantajele și dezavantajele fiecărei metode.
2. 2. 10. 8250 și UART-urile compatibile
Am studiat deja un tip de UART și compatibilitățile găsite în calculatorul nostru. Aceste dispozitive au regiștrii care pot fi configurați prin cuvinte de control și care se află la adrese bine definite pe magistrale de I/O. Acestea trebuie inițializate înainte de a fi folosite, ceeace nu reprezintă o problemă dacă dispozitivul construit folosește un microprocesor. Majoritatea microprocesoarelor, microcontroller-elor în zilele noastre au incorporate Interfețe de Comunicare Serială (SCI). De aceea nu avem nevoie să conectăm un16550 cu 40 de pini deoarece, spre exemplu68HC11 conține un UART încorporat. Dacă sistemul este bazat pe Z-80 sau 8086, atunci un 16550 poate fi o opțiune.
2. 2. 11. CDP 6402, AY-5-1015/D36402R-9, etc. UART
Sunt UART-uri asemanea CDP6402, AY-5-1050/D36402R-9 sau compatibile. Acestea diferă de 8250 (sau compatibile) prin au magistrale de date separate pentru recepție și transmisie și poate fi configurat prin conectarea anumitor pini la nivele logice diferite. Acestea sunt ideale pentru aplicații unde nu este disponibil un microprocesor. Un asemenea exemplu în cazul în care trebuie conectat un ADC0804 (convertor analog-numeric) la UART, sau un dispozitiv de afișaj LCD la o linie serială, care folosesc o magistrală de date paralelă pe 8 biți.
Registrul de control al CDP6402 prezintă facilitatea de inhibare a Controlului Parității (PI), Selectarea Bitului de Stop (SBS), Selecatrea Lungimii Caracterului (CLS1 și 2) și validarea parității impare (EPE). Aceste intrări pot fi blocate folosind (CLR) sau dacă acest pin este pus pe “1”, atunci modificările făcute pe pinii respectivi vor avea efect imediat.
Un avantaj a acestor cipuri, față de 8250, este că aceste UART-uri nu au încorporat un Generator de Viteză Programabil, și nuci o posibilitate de conectare directă a unui cristal de cuarț. Dacă avem integrate precum AY-5-8 o alternativă comună ți mai ieftină este numărătorul și oscilatorul pe 14 biți de tip74HC4060.
74HC4060, fiind un numărător liniar pe 14 biți are iețiri doar pentru unele din etajele sale. Astfel doar Q4 până la Q14 sunt disponibile pentru conexiuni externe. Aceasta ănseamnă că vitezele mai mari nu pot fi obvținute cu cuarțuri obișnuite precum 1,8432MHz și 2,4576MHz, deoareceUART-ul are nevoie de o frecvență de tact de 16 ori mai mare decât viteza de transmisie. De exwemplu o viteză de 9600 BPS impune un tact de 153,6kHz. Cristalul de 1,8432MHz furenizează viteze care nu sunt în mod normal neobișnuite. Cât timp multe dintre acestea nu vor fi acceptate de programele terminale sau unele hardweare-uri, sunt acceptabile însă pentru propriile programe seriale. De exemplu divizorul pentru viteze de transmisie din PC are factorul de divizare 16 pentru 7200 BPS, 32 pentru 3600 BPS, 64 pentru 1800BPS, etc. Dacă este nevoie de viteze mai mari, este posibil să se conecteze UART-ul la pinul OUT2. Această conexiune utilizează oscilatorul dar nu aplică nici un factor de divizare.
UART-ul CMOS CDP6402 poate funcționa până la 5V pe când MAX-232 poate fi limitat la 120kBPS (dar este încă în domeniul vitezelor standard).
CAP. 3. PREZENTAREA STANDARDULUI RS-485
1. Generalități
Standardul EIA RS-485 este foarte utilizat pentru comunicații de date în mediu industrial. Spre deosebire de legătura realizată conform standardului RS-232, standardul RS-485 permite realizarea unor rețele care să conțină mai multe receptoare și mai multe emițătoare. Se pot utiliza și repetoare și în acest caz topologia rețelei poate fi de tip stea sau arbore.
EIA RS-485 folosește semnale diferențiale care sunt transmise pe perechi de fire torsadate. Cele două fire dintr-o pereche nu formează o buclă, fiecare dintre ele sunt mediul de transmitere a unei tensiuni (raportată la un al treilea fir virtual de masă). O exemplificare este prezentată în figura RS-485.1, în care se prezintă semnalele diferențiale transmise pe cele două fire, pentru litera S. Cele două fire sunt denumite în standard ca fiind A și B (unii producători le numesc + și -).
Figura 3.1.1. Reprezentarea în cod ASCII pentru litera S.
Fiecare bit este interpretat prin tensiunea relativă a lui A față de B. Dacă VA < VB atunci bitul are valoarea corespunzătoare lui 1 logic iar dacă VA > VB atunci vom avea 0 logic. Fiecare linie asincronă în repaus (fără date) va fi normal în starea 1 logic.
Imunitatea la perturbații rezultă din însăși natura legăturii diferențiale. Astfel, o tensiune perturbatoare se va induce în ambele fire, în mod identic. Deoarece receptorul RS-485 va interpreta doar semnul diferenței de tensiune dintre cele două fire, chiar și în intervalul de timp în care perturbația este suprapusă peste semnalul util, rezultatul comparației nu este alterat. De exemplu, dacă pe firul A avem 2Vcc și pe B avem 4Vcc, atunci o tensiune suprapusă de 3V va avea ca rezultat tensiuni de 5V, respectiv 7V, dar relația VA < VB rămâne neschimbată.
În figura 485.2 este prezentată o rețea Rs-485 tipică, cu cinci echipamente, având legăturile realizate pe două fire. Se remarcă prezența unui master (M), a patru echipamente slave (SA, SB, SC și SD) și trei convertoare RS-232 la RS-485, izolate galvanic, (CM și CS). Echipamentele SB și SC sunt conectate irect la rețeaua RS-485 cu două fire. De obicei o rețea este construită cu echipamente de același fel dar în acest exemplu s-au luat în considerare mai multe configurații posibile.
Astfel, M este un calculator de tip PC cu port RS-232, legat la masă prin conectarea standard. Masa sa este legată atât la șasiu cât și la masa internă, fapt ce impune o izolare galvanică a echipamentului master de mediul industrial.
Figura 3. 1. 2. Exemplu de rețea RS-485 cu două fire.
Echipamentul SA comunică tot printr-un port RS-232 și folosește un convertor izolat galvanic pentru conectarea la RS-485.
SB are port RS-485 direct, fără izolare galvanică. În acest exemplu, întreaga rețea este pusă la masă direct prin SB, datorită conectării directe la masă a acestuia. SB va trebui să controleze intern sensul transferului, de exemplu printr-un semnal RTS. Exemplul prezintă un rezistor opțional 100 Ohm la 1W. Standardul RS-485 sugerează instalarea acestui rezistor ori de câte ori se formează o buclă de masă. In exemplul din figura 485.2 rezistorul nu este necesar deoarece ambele convertoare CM și CS sunt izolate galvanic, având mase flotante. Dar dacă, în timp se operează modificări și se înlocuiește convertorul izolat CM cu un convertor neizolat, atunci apare o buclă de masă prin cablul de comunicare de date.
SC are un port RS-485 fără izolare galvanică. Spre deosebire de SB, SC nu furnizează o legătură la masă: SC va presupune că masa legăturii RS-485 se referă la propriul său semnal de masă (se acceptă prin standard încă 7Vcc). Dacă valoarea acestui potențial nu este cunoscută, trebuie instalat un izolator galvanic.
SD are un port RS-232 și se conectează la RS-485 la fel ca M. Deoarece CS 2 este, tehnic vorbind, capătul magistralei, va avea instalat și un rezistor terminator de valoare egală cu impedanța caracteristică a cablului utilizat SC2 nu are legătură la masă împreună cu alte echipamente din rețeaua RS-485. Masa sa flotantă este legată la masa locală și deci va considera că masa legăturii RS-485 este raportată față de propriul său semnal de masă 7Vcc. Dacă acesta nu se cunoaște atunci masa echipamentului SC2 trebuie conectată la masa rețelei, adică la masa comună pentru CM, CS 1 și SB.
Un sistem de comunicații de date implică de fapt conectarea mai multor subsisteme împreună și prin urmare trebuie ținut cont de legătura de masă. De fapt RS-485 nu are nevoie doar de 2 fire, ci de cel puțin 3 cabluri: 2 cabluri pentru semnale și unul pentru calea de întoarcere a semnalelor.
Standardul EIA/RS-485 definește:
Funcționarea corectă a circuitelor de emisie și recepție impun prezența unei căi de semnal de întoarcere (masă) între masele circuitelor echipamentelor aflate la fiecare capăt al conexiunii. Circuitul de referință poate fi realizat prin:
intermediul unui al 3-lea conductor care va conecta masele echipamentelor sau,
conectarea fiecărui echipament la o referință de pământare.
În figura 485.2 se observă că CM și SC 1 implementează regula celui de-al treilea conductor, pe când SC și CS 2 sunt conectate conform regulii de legătură la pământare. SB este conform ambelor reguli, în parte pentru a asigura că al treilea conductor este raportat la referința de pământare pentru a putea avea conectate și SC și SC 2.
Dacă alegem regula de pământare atunci este necesară o singură pereche torsadată de fire.
Dacă se alege regula celui de-al treilea cablu (de masă), atunci RS-485 cu două fire va avea nevoie de:
două perechi de fire dintre care se utilizează o pereche pentru masă,
o pereche de cabluri și un fir de masă separat, extern sau
o pereche de cabluri ecranată.
Magistrala RS-485 este de la M la SD. Se remarcă prezența terminatorului de 120 Ohm la fiecare capăt.
Standardul ISO-8482 (versiunea standardizată pentru RS-485) definește lungimea totală a magistralei ca fiind limitată la 500 m pentru viteza de transmisie a datelor de 1Mbps. In exemplul din figura 485.2 avem M și SD care definesc capetele magistralei. SA, SB și SC sunt conectate la magistrală prin legături a căror lungime este limitată la 15m.
Prin natura lor, standardele impun anumite limitări. Astfel, ISO impune distanța maximă de 500m dar există mulți producători care furnizează echipamente cu interfață pentru RS-485 care pot comunica la distanțe cuprinse între 1Km și 13Km. O primă compensație este diferența de viteză, o viteză mai mică pentru transmiterea datelor permițând folosirea unei legături mai lungi. Distanța de 1Km este o lungime uzuală pentru RS-485.
Deoarece RS-485 este semiduplex, datele pot fi trimise doar într-un sens, la un moment dat de timp. Echipamentele trebuie să fie sau pe recepție sau (doar unul) în emisie. Modificarea din emițător în receptor trebuie să fie activată electronic. Cea mai folosită metodă este utilizarea unui semnal, direct de la echipament, care să controleze modul de lucru. Acesta este adesea RTS.
Trebuie avut în vedere ca software-ul de control al echipamentului să fie capabil să comande (sau să invalideze) semnalul RTS atunci când este necesar.
Dacă semnalul RTS nu este disponibil, se vor folosi convertoare RS-485 cu control duplex automat. Acestea detectează un bit de start pe linia de date provenind de la echipament și comută automat din modul de recepție în cel de emisie. Controlul automat al sensului se mai numește și control duplex pasiv.
Când nu se transmite nici un mesaj, magistrala RS-485 cu două fire ar fi flotantă și acest fapt ar conduce la imunitate scăzută la perturbații și chiar solicitări false de întrerupere pentru comunicație. Pentru aceasta se folosesc, în convertoare, rezistoare de polarizare care vor fixa nivele de tensiune cunoscute pentru fiecare din liniile magistralei.
Când nu este folosită magistrala, tensiunea în firul D+ este mai mare decât tensiunea în firul D-. Starea de repaus este deci corespunzătoare lui „1”.
Pornind de la starea de repaus, vom analiza cele două metode de control pentru o rețea RS-485:
1. Controlul duplex pasiv (automat);
2. Controlul duplex activ (cu RTS).
3. 2. Controlul transferului de date și terminații
Deoarece RS-485 este semiduplex, datele pot fi doar transmise într-o singură direcție la un moment dat de timp. Echipamentul trebuie să fie sau pe recepție sau pe emisie în orice moment de timp, dar nu și-și. Modificarea de la emisie la recepție trebuie să fie activată electronic. Cea mai folosită metodă este utilizarea unui semnal direct de la echipament pentru a controla modul de lucru. Acesta este adesea denumit semnal de control RTS (Ready To Send).
Din păcate, softul de control al echipamentului trebuie să fie programat să activeze și să dezactiveze când trebuie RTS (mulți fabricanți proiectează pentru full-duplex RS-232 și pierd din vedere acest aspect).
Totuși, dacă nu avem RTS nu este totul pierdut deoarece există convertoarele RS-485 cu control duplex automat. Acestea detectează un bit de start pe linia de transmisie asincronă de la echipament și comută automat din modul recepție în modul transmisie.
3. 2. 1. Controlul duplex pasiv (automat)
Acesta este un alt exemplu de realizare posibilă a unei rețele RS-485 cu doua fire.
Totuși, echipamentele ce vor fi prezentate în continuare folosesc control duplex pasiv -numit și controlul automat al direcției pe magistrală sau controlul transmisiei. Interfața recepționează în mod normal de la rețea și când detectează date ce au fost trimise de la echipamentul atașat (corespunzător), comută automat și transmite data. Situațiile întâlnite pe o astfel de rețea sunt următoarele:
Nu exista date de transmis – linia este în repaus
Când nu se transmite nici un mesaj, bus-ul RS-485 cu două fire este flotant. Din acest motiv trebuie folosite rezistoare speciale de polarizare care fixează o stare de repaus: „1”.
Fig.3. 2. 1.Linie în repaus
Fiecare slave așteaptă o cere de la Master. Nici o interfață de echipament nu este în emisie, toate echipamentele sunt pe recepție.
Master-ul trimite o cerere
Fig. 3. 2. 2.Linie ăn emisie
Master-ul trimite un mesaj de cerere: interfața sa cu rețeaua (cu bus-ul) detectează primul bit de start și începe automat transferul.
Echipamentele Slave recepționează mesajul. Imediat ce Master-ul încetează emiterea mesajului, sau după un anumit timp de la terminarea mesajului, interfața master-ului revine în modul recepție. Pentru moment, toate echipamentele sunt din nou pe recepție si bus-ul este în repaus.
Echipamentul trimite un răspuns
Să presupunem că echipamentul adresat a fost E07 și nu s-a detectat nici o eroare în cerere, atunci E07 formulează răspunsul și îl trimite.
Fig.3. 2. 3. Linie de recepție
Interfața lui E07 detectează primul bit de start și trece în emisie. Master-ul și celelalte echipamente Slave primesc răspunsul. Interfața echipamentului E07 este în emisie și toate celelalte sunt pe recepție. Imediat ce a terminat de trimis răspunsul, interfața Slave-ului care a emis comută pe recepție și rețeaua este din nou în repaus prin intermediul rezistoarelor de polarizare.
3. 2. 2. Controlul duplex activ (cu RTS)
Echipamentele prezentate mai jos folosesc control duplex activ denumit și control direct sau control soft. Situațiile întâlnite pe o astfel de rețea sunt următoarele:
Nu se transmit date – linia este în repaus.
Fig. 3. 2. 1. Linie în repaus
Când nu se transmite nimic, Master-ul activează semnalul de control RTS forțând astfel bus-ul în starea de repaus echivalent cu “1”. Fiecare echipament Slave își dezactivează RTS și așteaptă o cerere de la master. Interfața Master-ului este în emisie, toate celelalte sunt pe recepție.
Master-ul trimite o cerere.
Fig. 3. 2. 2. Linie de emisie
Master-ul trimite un mesaj. Bitul de start din primul byte al mesajului întrerupe starea de așteptare a celorlalte echipamente și ele încep recepționarea mesajului byte cu byte. Când s-a recepționat complet se verifică posibilele erori. Dacă apare o eroare, echipamentul nu ia în considerare mesajul și nu trimite nici un răspuns. Imediat ce echipamentul Master termină de trimis cererea, el dezactivează semnalul de control RTS. Pentru moment, toate echipamentele sunt pe recepție.
Slave-ul trimite un răspuns.
Fig. 3. 2. 3. Linia de răspuns
Presupunând că E07 a fost cel adresat și nu s-a detectat nici o eroare, atunci E07 formulează răspunsul. E07 activează linia sa de control RTS și transmite iar Master-ul și toate echipamentele Slave recepționează, echipamentele Slave ignorând ce primesc.
Interfața lui E07 este în emisie, toate celelalte sunt pe recepție. Imediat ce E07 a terminat răspunsul își dezactivează linia sa RTS. Imediat ce M recunoaște sfârșitul transmisiei își activează RTS și își pune interfața proprie pe emisie pentru a impune modul în repaus.
3. 2. 3.Terminații specifice rețelei RS-485
Terminația este utilizată pentru a adapta impedanța unui nod din rețea la impedanța cablului utilizat pentru legătură. Când impedanțele nu este egale, semnalul nu este “absorbit” complet de către sarcină și un procent este reflectat înapoi pe linia de transmisie. Dacă impedanța sursei, cea a liniei de transmisie și impedanța de sarcină sunt egale, reflexiile sunt eliminate. Inerent, utilizarea terminației prezintă unele dezavantaje deoarece se mărește astfel sarcina driver-ului (emițătorului), crește complexitatea instalației, se schimbă cerințele de polarizare și fac mai greu de modificat sistemul.
Decizia de a folosi sau nu terminație trebuie să se facă pe baza lungimii cablului și a vitezei de transmitere din sistem. O replică aplicabilă este ca, dacă timpul de propagare pe linia de date este mult mai mic decât durata unui bit, atunci nu este nevoie de terminație. Această regulă presupune că reflexiile se vor atenua în câteva parcurgeri ale legăturii determinând “oscilația” în sus și în jos a nivelelor de tensiune pe linia de date.
Deoarece UART-ul de la recepție va eșantiona linia de date în mijlocul fiecărui bit, este important ca nivelul semnalului să fie ferm în acel moment. De exemplu, într-un sistem cu o linie de date de 500 m, timpul de propagare poate fi calculat înmulțind lungimea cablului cu viteza de propagare prin cablu. Această valoare este tipic între 66% și 75% din viteza luminii și este specificată de către producătorul de cablu.
Pentru exemplu nostru, un transfer de date dus-întors are 1000 m. Folosind o viteză de propagare de 0.66 · c, un tur complet este realizat în 5,05s. Dacă presupunem că reflexiile se anulează în 3 ture, semnalul se va stabiliza dupa 15,15s, calculat din momentul apariției frontului ridicător al primului bit emis. La 9600 bps, un bit are durata de 104s. Deoarece reflexiile s-au atenuat cu mult înainte de centrul bitului, nu este necesară terminația.
Pentru cazurile când este nevoie de terminație, există două metode pentru realizarea adaptării folosind terminații de linii de date.
O metodă este terminația paralelă: se utilizează un rezistor în paralel pe liniile de recepție A și B pentru a egala impedanța caracteristică a liniei, care este specificată de fabricantul cablului. O valoare tipică este de 120 Ω. Această valoare reprezintă impedanța intrinsecă (caracteristică) a liniei de transmisie și nu este funcție de lungimea liniei. Se va folosi deci un rezistor cu o valoare de 120 Ω sau o valoare apropiată, dar nu mai mică de 90 Ω. Terminațiile sub formă de rezistoare trebuie plasate doar la capetele extreme ale liniei de date și nu se folosesc mai mult de 2 terminații în nici un sistem (care nu utilizează repetoare). Acest tip de terminație, în mod evident, este o sarcină, de tip dc (de curent continuu), de valoare destul de mare și poate supraîncărca etajul de ieșire al convertorului de la RS-232 spre RS-485 și care o are ca și sarcină.
Un alt tip de terminație este terminația cuplată în curent alternativ (AC coupled termination) și folosește un condensator în serie cu rezistorul, pentru a elimina efectul de încărcare în curent continu. Deși această metodă elimină încărcarea în curent continu, selecția condensatorului este dependentă în mare măsură de proprietățile sistemului. Figura 3.2.4. prezintă ambele tipuri de terminații (paralelă și în a.c.) pentru o rețea cu 2 fire.
Figura 3. 2. 4. Terminații pentru o rețea RS-485 cu 2 fire.
3. 2. 4. Polarizarea rețelei RS-485
Când RS-485 este în repaus, toate nodurile sunt în mod recepție. În această situație nu există driver-e active în rețea, toate sunt cu ieșirile în impedanță ridicată. Deoarece nu există nici un circuit care să impună un anumit nivel de tensiune pe linie, starea liniei este necunoscută. Dacă nivelul de tensiune la recepție, la intrările A și B, este mai mic de ±200mV, nivelul logic al receptoarelor va fi valoarea ultimului bit recepționat. Pentru a obține starea de tensiune corectă în repaus, trebuie utilizate rezistoare de polarizare pentru a forța, în condiția de repaus, liniile de date la o valoare de tensiune aleasă prin proiectare pentru nivelul logic “1”. Rezistoarele de polarizare nu sunt altceva decat câte un rezistor, de tip “pull-up” pe linia B (tipic legat la 5V) și unul de tip “pull-down” pentru linia A (legat la masă).
Figura 485.4 prezintă plasarea celor două rezistoare pentru un transceiver într-o configurație cu 2 fire.
Figura 3. 2.5. Transceiver cu rezistoare de polarizare.
(De notat că într-o configurație RS-485 cu 4 fire, rezistoarele de polarizare se plasează pe liniile de receptie.) Valoarea rezistenței de polarizare este dependentă de terminație și de numărul de noduri din sistem. Scopul este să generăm suficient curent de polarizare în c.c. în rețea pentru a menține o valoare minimă de tensiune de 200mV între A și B.
Pentru calcularea rezistenței de polarizare vom considera următoarele două exemple:
10 noduri în retea RS-485 cu două rezistoare de câte 120Ω pentru terminații.
Fiecare nod RS-485 are o impedanță de intrare de 12 KΩ. Zece noduri în paralel rezultă o sarcină de 1200 Ω. În plus avem cele două terminații de câte 120 Ω fiecare, rezultă 60 Ω și rezultat final pentru sarcina: 57 Ω. În mod evident, rezistoarele de terminație sunt responsabile, în cea mai mare parte, de încărcarea rețelei (au cea mai mare contribuție la stabilirea sarcinii). Pentru a menține cel puțin 200 mV între liniile B și A, avem nevoie ca un curent de polarizare de 3,5 mA să trecă prin sarcină. Pentru a crea această polarizare, plecând de la o alimentare de 5V, este necesară o sarcină totală maximă de 1428 Ω. Scazând valoarea de 57 Ω care reprezintă sarcina existentă, rămân 1371 Ω. Se pune ½ din această valoare ca rezistență de “pull-up” și ½ spre masă, adică 685 Ω pentru fiecare rezistor de polarizare.
32 de noduri, rețea RS-485 fără terminații.
Fiecare nod RS-485 are o impedanță de intrare de 12 KΩ. Având treizeci și două de noduri în pararel, rezultă o rezistență echivalentă de 375 Ω. Pentru a menține cel puțin 200 mV prin această sarcină de 375 Ω, avem nevoie de un curent de 0,53 mA. Pentru a genera acest curent de la o alimentare de 5V rezultă maxim 9,375 Ω. Deoarece 375 Ω este deja ca și impedanță de intrare a celor 32 de receptore în paralel, rezistența de polarizare trebuie să fie de minim 9 KΩ. De remarcat faptul că este nevoie de un curent foarte mic de polarizare în sistemele fără terminații.
Rezistoarele de polarizare pot fi plasate oriunde în rețea sau pot fi distribuite în mai multe noduri. Contribuția paralelă a tuturor rezistențelor de polarizare din sistem trebuie să fie cel mult egală cu cerințele de polarizare.
Există producători care, o dată cu echipamentul cu interfață RS-485 furnizează și rezistoarele de polarizare. O valoare des întâlnită este cea de 4,7 KΩ. Această valoare este potrivită pentru marea majoritate a sistemelor fără terminații. Proiectantul de sistem este cel care trebuie să calculeze întotdeauna polarizarea necesară pentru rețea. Cosecințele polarizării sub limită au drept consecință scăderea imunității la perturbații (zgomot) sau chiar imposibilitate de funcționare. Polarizarea care determină un curent mai mare are efecte negative mai mici asupra funcționării sistemului. Primul dezavantaj este însă încărcarea draiver-elor. Unele sisteme care folosesc convertoare de la RS-232 la RS-485 pot fi sensibile la suprasarcini (over biasing = polarizare excesivă)
3. 2. 4. Extinderea specificațiilor
Unele sisteme impun distanțe mai mari sau mai multe noduri decât poate suporta RS-485. În mod obișnuit, în aceste cazuri se folosesc repetoarele. Un repetor RS-485 poate fi astfel plasat încât să împartă sarcina în mai multe segmente. Fiecare semnal “repetat” (reîmprospătat) poate fi utilizat pentru o distanță de 1200 m pentru alte 31 de sarcini de tip RS-485.
Altă metodă de a mări numărul de noduri este aceea de a utiliza receptoare RS-485 care prezintă impedanță ridicată de intrare, pentru a diminua sarcinile driver-elor RS-485, putându-se astfel mări numărul total de noduri. În prezent există circuite receptoare care au o impedanță de intrare mai mare și deci care vor încărca (pe jumătate sau chiar pe sfert), numărul de noduri putând astfel crește la 64 sau 128.
3. 3. Prezentarea protocolului de comunicare
Condițiile inițiale în care are loc transmisia au fost stabilite ca fiind următoarele:
viteza la care se face comunicarea este de 9600 BPS ;
comunicarea este validată prin utilizarea liniei de control RTS;
lungimea maximă a oricărui mesaj trnsmis prin rețea să nu depășească o secundă;
după fiecare mesaj va fi o pauză de minim 125 ms;
nu este permis nici unui emițător să înceapă o emisie în timpul primelor 80 ms;
Master-ul, PC-ul (care are cea mai mare prioritate) va putea începe emisia după scurgerea a 85 ms;
stația cu prioritatea imediat următoare va putea începe emisia după 125 ms;
următoarea stație va putea emite după 150 ms;
Master-ul va începe comnicarea prin a emite primul caracter un semn
de întrebare :
“?”
pe care Slave-ul îl recepționează și îl recunoaște. În consecință va trimite un mesaj de răspuns (cu majuscule):
COM“AȘTEPT ANDA!”
care va fi afițat pe ecran de către Master. Dacă Mastre-ul va emite alt caracter, sau nu se va rcepționa corect mesajul, Slave-ul va trmite mesajul:
“EROARE”
care va fi de asemenea recunoscut și afișat pe ecran de către Master, iar apoi se va trimite din nou un semn de întrebare până ce mesajul va fi recepționat corect.
Odată ce s-a stabilit legătura între Master ți Slave, comunicarea continuă cu emiterea de către Master a două cifre, care vor reprezenta adresa unei linii de port. Slave-ul va recunoaște mesajul și va citi, memora și transmite
CAP. 4. PROGRAME PENTRU COMANDA PORTULUI SERIAL
1. Programe de comunicare pe RS-232
Pentru realizarea programului de comunicare am pornit de la o structură de
program simplă, pe care am dezvoltat-o ulterior. Am verificat de asemenea funcționarea în fiecare etapă de realizare. În paragrafele următoare se prezintă fiecare program corespunzător etapelor parcurse, cu explicarea detaliată a liniilor și a programelor.
4. 1. 1. Prezentarea unui program de emsie a unui caracter
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <dos.h>
#define COM 2
#define IER 0x2F9
#define IIR 0x2FA
#define LSR 0x2FD
#define TDR 0x2F8
#define RDR 0x2F8
#define DLR 0x2FB
#define DRL 0x2F8
#define DRH 0x2F9
#define MCR 0x2FC
#define LCR 0x2FB
struct {char lsr,mcr,drl,drh,lcr;}stare_linie;
struct {float lcr,drl,drh,mcr,lsr;}st_li;
char c;
void main (void)
{
clrscr();
stare_linie.lcr=inportb(LCR);/*Salvarea conținutului regiștrilor in*/
/*structura de variabile "stare_linie"*/
stare_linie.drl=inportb(DRL);
stare_linie.mcr=inportb(LSR);
stare_linie.drh=inportb(DRH);
stare_linie.lsr=inportb(LSR);
outportb(LCR,0x80); /*Se încarcă 80h in registrul LCR*/
st_li.lcr=inportb(LCR); /*Se verifică conținutul registrului LCR*/
outportb(DRL,0x0C); /*Se încarcă 0Ch in registrul DRL*/
st_li.drl=inportb(DRL); /*Se verifică conținutul registrului*/
outportb(DRH,0); /*Se incarcă 0h in registrul DRH*/
st_li.drh=inportb(DRH); /*Se verifică conținutul registrului DRH*/
outportb(LCR,3); /*Se incarcă 3h în registrul LCR*/
st_li.lcr=inportb(LCR); /*Se verifică conținutul registrului LCR*/
outportb(MCR,0x20); /*Se încarcă 20h în registrul MCR*/
st_li.mcr=inportb(MCR); /*Se verifică conținutul registrului MCR*/
outportb(IER,1); /*Se încarcă 1h în registrul IER*/
puts ("Acest program asigura emisia unui caracter introdus de la tastatura\n");
puts ("Puteti parasi programul apasand tasta 'ESC'!\n");
printf ("Apasati o tasta: \n");
c=getch(); /*Se afișeaza caracterul dat de la*/
/*tastatură*/
if(c!=27) /*Se testează caracterul dat de la*/
/*tastatură pentru o eventuala */
/*opțiune de a ieși din program*/
{printf("A fost emis caracterul %c\n",c);
outportb(TDR,c); /*Se încarcă caracterul in registrul*/
/*TDR*/
delay(100); /*Întârziere */
c=inportb(RDR); /*Se verifică conținutul registrului
/*RDR*/
printf("S-a receptionat caracterul %c",c);}
outportb(LSR,stare_linie.lsr);/*Se redă conținutul inițial al */
/*regiștrilor, ce a fost salvat în */
/*structura de variabile "stare_linie*/
outportb(DRL,stare_linie.drl);
outportb(DRH,stare_linie.drh);
outportb(LCR,stare_linie.lcr);
outportb(MCR,stare_linie.mcr);
}
4.1.2. Expllicarea programului
În prima fază am conceput un program simplu de emisie a unui caracter, pe care l-am rulat utilizând o conexiune în buclă închisă, adică ceea ce se emite se poate recepționa imediat (pinul DTR este legat cu pinul RDR).
Încărcăm 80h în registrul LCR pentru a putea avea acces la regiștrii DRL și DRH de unde să pute stabili viteza de comunicare dorită. Aceasta am stbilit-o la 9600 BPS, ceea ce înseamnă că registrul DRL trebuie să conțină 0Ch, iar DRH 0h.
Stabilim apoi lungimea caracterului (cuvântului), de 8 biți, încărcând în registrul LCR 3h.
Prin încărcarea în registrul IER a valorii 1h, înseamnă că vom avea o cerere de întrerupere după emisia unui caracter.
Conținutul inițial al regiștrilor este salvat într-o structură de variabile de tip caracter. Din motive didactice folosim structura de variabile “st_li” cu ajutorul căreia urmărim conținutul regiștrilor ai căror conținut se modifică în program.
Se asigură posibilitatea utilizatorului de a părăsi programul prin apăsarea tastei “ESC”, prin folosirea testului:
if(c!=27)
Caracterul ce se dorește a fi transmis se citește de la tastatură și este apoi încărcat în registru TDR, registrul de transmisie.
Pentru a vedea dacă acest caracter a fost transmis se citește conținutul registrului RDR, dar aceasta trebuie să se facă cu o întârziere,
În cele din urmă se reîncarcă regiștrii a căror conținut a fost modificat cu datele inițiale, acestea fiind recuperate din structura de variabile “stare_linie”.
4. 1. 3. Prezentarea subrutinelor “intrerupere” și “emisie”
void intrerupere (void)
{
int contor,ier,iir;
char primire[8];
ier=inportb(IER); /*Citim conținutul registrului IER*/
printf("Stare 'IER':%d\n",ier); /*Afișăm conținutul registrului IER*/
iir=inportb(IIR); /*Citim conținutul registrului IIR*/
printf("Stare 'IIR':%d\n",iir); /*Afișăm conținutul registrului IIR*/
while ((inportb(LSR)&&0x20)==1) /*Cât timp conținutulregistrului*/
/*LSR este 20h se parcurge bucla*/
/* "while"*/
{for(contor=0;contor<=7;contor++) /*Incărcăm in variabila de tip*/
/*sir de caractere conținutul*/
/*conținutul registrului RDR*/
primire[contor]=inportb(RDR);
break;} /*Întreruperea buclei "while"*/
ier=inportb(IER); /*Verificăm conținutul registrului IER*/
printf("Stare 'IER':%d\n",ier); /*Afișăm conținutului registrului IER*/
iir=inportb(IIR); /*Verificăm conținutul registrului IIR*/
printf("Stare 'IIR':%d\n",iir); /*Afișăm conținutul registrului IIR*/
delay (t); /*Întarziere pe perioada t*/
printf("t=%d\n",t); /*Afișăm timpul t*/
}
void receptie (char c)
{
int sts;
outportb (LSR,0x20); /*Încărcăm 20h în registrul LSR*/
c=inportb(RDR); /*Citim caracterul recepționat din */
/*registrul RDR*/
printf ("S-a receptionat caracterul: %c\n",c);/*Afișăm caracterul */
/*recepționat*/
sts=inportb(LSR); /*Verificăm conținutul registrului*/
/*LSR*/
printf("Stare 'LSR':%d\n",sts); /*Afișăm conținutul registrului*/
/*LSR*/
}
4. 1. 4. Explicarea subrutinelor “intrerupere” și “emisie”
În continuare am dezvoltat programul astfel încât fiecărei etape să-I corespundă câte o funcție apelată în programul principal. Am ilustrat funcțiile “intrerupere” și “recepție” deoarece nu au fost cuprinse în programul anterior.
Funcția “intrerupere”, este apelată după emisia unui caracter și realizează o buclă de așteptare, pe o durată stabilită arbitrar (în acest caz pe perioada cât durează emisia).În același timp, dacă se primesc date în registrul RDR, ele sunt stocate (memorate) în variabila de tip șir de caractere “primire”, prin parcurgerea unei bucle “for”.
Durata întârzierii este calculată în programul principal, prin citirea succesivă a timpului de la începutul programului și până la momentul anterior apelării funcției “emisie”,respectiv de la începutul programului și până în momentul terminării funcției”emisie”, și făcând diferența. De menționat că valoarea citită cu ajutorul instrucțiunii:
t=clock();
trebuie împărțită cu tactul sistemului (CLK_TCK), înainte de a fi afișată.
De asemenea pentru a putea folosi această instrucțiune, avem nevoie de funcția “clock_t”, care o conține precum și de librăria time.h.
Din motive didactice este urmărit conținutul regiștrilor de validare a întreruperilor (IER) și de identificare a îtreruperilor (IIR).
Funcția “recepție” asigură recepția unui caracter prin intermediul registrului RDR, și îl afișează. Se urmărește de asemenea conținutul registrului LSR, pentru a se observa eventualele modificări.
4. 1. 5. Prezentarea programului de comunicare pe RS-232
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<dos.h>
#include<time.h>
#include<math.h>
#define COM 2
#define IER 0x2F9
#define IIR 0x2FA
#define LSR 0x2FD
#define TDR 0x2F8
#define RDR 0x2F8
#define DLR 0x2FB
#define DRL 0x2F8
#define DRH 0x2F9
#define MCR 0x2FC
#define LCR 0X2FB
void setari (void);
void emisie (char c);
void intrerupere(void);
void receptie (char c);
void stare_initiala(void);
struct{char lcr,drl,mcr,lsr,drh;}stare_linie;
struct{float lcr,drl,mcr,lsr,drh;}st_li;
int t;
char c;
void setari (void)
{
stare_linie.lcr=inportb (LCR); /*Salvăm conținutul regiștrilor */
/*într-o structură de variabile /*(stare_linie)*/
stare_linie.drl=inportb (DRL);
stare_linie.mcr=inportb (MCR);
stare_linie.lsr=inportb (LSR);
stare_linie.drh=inportb (DRH);
outportb(LCR,0x80); /*Încărcăm 80h în registrul LCR*/
st_li.lcr=inportb(LCR); /*Verificăm conținutul registrului*/
/*LCR*/
outportb(DRL,0x0C); /*Încărcăm 0Ch în registrul DRL*/
st_li.drl=inportb(DRL); /*Verificăm conținutul registrului*/
/*DRL*/
outportb(DRH,0); /*Încărcăm 0h în registrul DRH*/
st_li. drh=inportb(DRH); /*Verificăm conținutul registrului*/
/*DRL*/
outportb(LCR,3); /*Încărcăm 3h în registrul LCR*/
st_li.lcr=inportb(LCR); /*Verificăm conținutul registrului*/
/*LCR*/
outportb(MCR,0x08); /*Încărcăm 8h in registrul MCR*/
st_li.mcr=inportb(MCR); /*Verificăm conținutul registrului*/
/*MCR*/
outportb(IER,1); /*Încărcăm 1h in registrul IER*/
}
void emisie (char c)
{
char r;
int sts;
sts=inportb(LSR); /*Verificăm conținutul registrului LSR*/
printf("Stare 'LSR': %d\n",sts); /*Afișăm conținutul registrului LSR*/
outportb (TDR,c); /*Încărcăm caracterul în registrul de emisie*/
printf("S-a trimis caracterul: %c\n",c); /*Afișăm caracterul emis*/
sts=inportb(LSR); /*Verificăm conținutul registrului LSR*/
printf("Stare 'LSR': %d\n",sts); /*Afișăm conținutul registrului LSR*/
}
void intrerupere (void)
{
int contor,ier,iir;
char primire[8];
ier=inportb(IER); /*Citim conținutul registrului IER*/
printf("Stare 'IER':%d\n",ier); /*Afișăm conținutul registrului IER*/
iir=inportb(IIR); /*Citim conținutul registrului IER*/
printf("Stare 'IIR':%d\n",iir); /*Afișăm conținutul registrului IIR*/
while ((inportb(LSR)&&0x20)==1) /*Cât timp conținutul registrului LSR/*
/* este 20h se parcurge bucla “while”*/
{for(contor=0;contor<=7;contor++) /*Încărcăm în variabila de tip*/
/*șir de caractere continutul */
/*registrului RDR*/
primire[contor]=inportb(RDR);
break;} /*Întreruperea buclei ”while”*/
ier=inportb(IER); /*Verificăm conținutul registrului IER*/
printf("Stare 'IER':%d\n",ier); /*Afișăm conținutul registrului IER*/
iir=inportb(IIR); /*Verificăm conținutul registrului IIR*/
printf("Stare 'IIR':%d\n",iir); /*Afișăm conținutul registrului IIR*/
delay (t); /*Întârziere pe perioada t*/
printf("t=%d\n",t); /*Afișăm timpul t*/
}
void receptie (char c)
{
int sts;
outportb (LSR,0x20 /*Încărcăm 20h în registrul LSR*/
c=inportb(RDR); /*Citim caracterul recepționat din*/
/*registrul RDR*/
printf ("S-a receptionat caracterul: %c\n",c); /*Afișăm caracterul recepționat*/
sts=inportb(LSR); /*Verificăm conținutul registrului*/
/*LSR*/
printf("Stare 'LSR':%d\n",sts); /*Afișăm conținutul registrului*/
/*LSR*/
}
void stare_initiala (void)
{
outportb(LCR,stare_linie.lcr); /*Încărcăm în regiștrii datele inițiale pe care */
/*le-am memorat în structura de date*/
/*”stare_linie”*/
outportb(DRL,stare_linie.drl);
outportb(DRH,stare_linie.drh);
outportb(MCR,stare_linie.mcr);
outportb(IER,0);
}
void main (void)
{
char primire[8];
clrscr();
puts("Acest program realizeaza transmisia unui caracter\n");
setari(); /*Apelăm funcția "setari"*/
printf ("Daca doriti sa parasiti programul tastati 'ESC'!\n");
outportb (LSR,0x20); /*Încărcăm în registrul */
/*LSR 20h*/
printf("Se asteapta trimiterea unui caracter. \n");
if((c=getch())!=27)
{clock_t t1,t2;
t1=clock(); /*Citim timpul parcurs de la începerea*/
/*programului*/
printf("Timpul scurs:%d\n",t1/CLK_TCK);/*Afișăm timpul scurs de*/
/*la începerea programului*/
emisie(c); /*Apelăm funcția "emisie"*/
t2=clock(); /*Citim timpul scurs de la începerea */
/*programului*/
printf("Timpul scurs:%d\n",t2/CLK_TCK); /*Afișăm timpul scurs de la*/
/*începerea programului*/
t=(t2-t1)/CLK_TCK; /*Calculăm timpul de emisie*/
printf("Timpul de emisie este: %d\n",t);/*Afișăm timpul de emisie*/
intrerupere(); /*Apelăm funcția ”intrerupere*/
receptie(c); /*Apelăm funcția "receptie"*/
stare_initiala();} /*Apelăm funcția "stare initiala*/
else
{setari();
puts("Ati parasit programul!");}/*Dacă utilizatorul hotărăște să părăsească*/
/*programul va apare mesajul de atentionare*/
}
4.1. 6. Explicarea programului de comunicare
Programul realizează transmiterea unui caracter pe portul serial (COM2).
Programul principal realizează acest lucru prin apelarea succesivă a unor funcții și afișarea caracterelor emise, respectiv recepționate, precum și a unor mesaje explicative.
În funcția “setari” toate datele existente în regiștrii portului serial în momentul începerii transmisiei sunt salvate într-o structura de variabile, “stare_linie”, pentru a putea fi recuperate la sfârșituln transmisiei. Apoi, se stabilesc condițiile în care va avea loc transmisia, și anume:
-Se stabilește ca transmisia să se facă cu o viteză de 9600 BPS;
-După transmiterea unui caracter va apare o întrerupere;
-Lungimea caracterului de 8 biți;
Pentru stabilirea vitezei, trebuie mai întâi să încărcăm mai întâi în registrul de control al liniei (LCR) 80h și astfel avem acces la regiștrii DRL, DRH. Prin intermediul acestor regiștrii stabilim valoarea dorită pentru viteză; în cazul nostru 9600 BPS, inseamnă că în registrul DRL trebuie să avem 0Ch, iar în registrul DRH 0h. Apoi, prin încărcarea a 3h în registrul de control al liniei (LCR), stabilim lungimea cuvântului (caracterului) la 8 biți. Încărcând 1h în registrul de validare al întreruperilor (IER), ne asigurăm că va apare o cerere de întrerupere după fiecare emisie a unui caracter. Am stabilit astfel condițiile în care se va face transmisia.
Se asigură de asemenea posibilitatea utilizatorului de a parăsi programul prin apăsarea tastei “ESC”.
Se încarcă în registrul de stare a liniei (LSR) 20h, ceea ce înseamnă că avem acces la regiștrii de emisie (TDR) și de recepție a datelor (RDR).
Este apelată apoi funcția “emisie”, care realizează emisia unui caracter și afișează caracterul emis.Este verificat conținutul registrului LSR, pentru a observa eventualele modificări de stare ale acestuia în timpul emisiei.
Urmează parcurgerea funcției “intrerupere”, care realizează o întârziere cu o durată t, timp în care, preia toate caracterele ce pot fi recepționate și le memorează (salvează) într-o variabilă de tip șir de caractere de unde vor fi preluate după terminarea întreruperii.
Funcția “recepție” realizează recepția unui caracter și îl afișează.
În final se reinstalează conținutul inițial al
4.2.Prezentarea programului de comunicare pe interfața RS-485
Programul a fost realizat în mai multe etape. Am realizat mai întâi un program de transmisie în buclă închisă, pe care l-am dezvoltat apoi, urmărind protocolul de comunicare.
4.2.1. Program de transmisie în buclă a unui caracter (șir de caractere)
pe interfața RS-485
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<dos.h>
#include<time.h>
#include<math.h>
#include<string.h>
#define COM 2
#define IER 0x2F9
#define IIR 0x2FA
#define LSR 0x2FD
#define TDR 0x2F8
#define RDR 0x2F8
#define DLR 0x2FB
#define DRL 0x2F8
#define DRH 0x2F9
#define MCR 0x2FC
#define LCR 0X2FB
void setari (void);
void emisie (char ch);
void receptie (char ch);
void stare_initiala(void);
struct{char lcr,drl,mcr,lsr,drh;}stare_linie;
int i;
char ch;
void setari (void)
{
stare_linie.lcr=inportb (LCR);
stare_linie.drl=inportb (DRL);
stare_linie.mcr=inportb (MCR);
stare_linie.lsr=inportb (LSR);
stare_linie.drh=inportb (DRH);
outportb(LCR,0x80);
outportb(DRL,0x0C);
outportb(DRH,0);
outportb(LCR,3);
outportb(MCR,0x08);
outportb(IER,0);
}
void emisie (char ch)
{int i;
ch=getch();
printf("Se trimite caracterul: %c\n",ch);
outportb (TDR,ch);
}
void receptie (char ch)
{ch=inportb(RDR);
printf ("%c",ch);
}
void stare_initiala (void)
{
outportb(LCR,stare_linie.lcr);
outportb(DRL,stare_linie.drl);
outportb(DRH,stare_linie.drh);
outportb(MCR,stare_linie.mcr);
outportb(IER,0);
}
void main (void)
{
clrscr();
puts("Acest program realizeaza transmisia unui sir de caractere\n");
setari();
puts("Dati un caracter\n");
outportb (MCR,0x08);
emisie(ch);
outportb(LSR,0x20);
outportb(MCR,0x0A);
while((inportb(LSR)&&0x01)==1)
{receptie(ch);
break;}
stare_initiala();
}
4.2.2. Explicarea programului
Programul realizează transmisia unui caracter sau a unui șir de careactere în buclă închisă.
Funcția „setări” salvează într-o structură de variabile datele existente pe liniile portului serial. Tot în această funcție se setează portul serial pentru comunicare.
Funcția „emisie” efectuează emisia propriu-zisă.
Este apelată apoi funcția „recepție”, care afectuează „recepția”.
La sfârșitul programului se restaurează conținutul regiștrilor, pentru a nu afecta rulare eventualelor programe care ar putea utiliza portul serial.
4.2.3. Progran de transmisie pe interfața RS-485
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<dos.h>
#include<time.h>
#include<math.h>
#include<string.h>
#define COM 2
#define IER 0x2F9
#define IIR 0x2FA
#define LSR 0x2FD
#define TDR 0x2F8
#define RDR 0x2F8
#define DLR 0x2FB
#define DRL 0x2F8
#define DRH 0x2F9
#define MCR 0x2FC
#define LCR 0X2FB
void setari (void);
void emisie (char c);
void receptie (char c);
void stare_initiala(void);
struct{char lcr,drl,mcr,lsr,drh;}stare_linie;
char c;
int ch;
void setari (void)
{
stare_linie.lcr=inportb (LCR);
stare_linie.drl=inportb (DRL);
stare_linie.mcr=inportb (MCR);
stare_linie.lsr=inportb (LSR);
stare_linie.drh=inportb (DRH);
outportb(LCR,0x80);
outportb(DRL,0x0C);
outportb(DRH,0);
outportb(LCR,3);
outportb(MCR,0x08);
outportb(IER,0);
}
void emisie (char c)
{int i;
c=getch();
if (c!=27)
{printf("Caracterul emis este: %c",c);
outportb(TDR,c);}
else
{puts("Ati parasit programul!");
setari();}
}
void receptie (char c)
{
do
{
ch=inportb(LSR);
if (ch&1){c=inportb(RDR);
printf ("\n%c",c);}}
while(c!=64);
}
void stare_initiala (void)
{
outportb(LCR,stare_linie.lcr);
outportb(DRL,stare_linie.drl);
outportb(DRH,stare_linie.drh);
outportb(MCR,stare_linie.mcr);
}
void main (void)
{ int i;
clrscr();
puts ("Program de comunicare pe portul serial\n");
setari();
puts("Daca doriti sa parasiti programul tastati 'ESC'!\n");
puts("Tastati '?'!\n");
emisie(c);
puts("S-a receptionat mesajul: \n");
outportb(MCR,0x0A);
receptie(c);
outportb(MCR,0x08);
puts("Tastati cifra '1', apoi cifra '6' sau '7'\n");
for(i=0;i<1;i++) /*Se trimite adresa liniei de port de la care se*/
/*asteapta date*/
emisie(c); /*Prin acest ciclu se apeleaza 'emisie' de doua*/
/*ori deoarece se trimt doua caractere*/
puts("Datele cerute sunt: \n");
outportb(MCR,0x0A);
receptie (c);
puts("Tastati 'G' pentru incheierea transmisiei:\n");
outportb (MCR,0x08);
emisie(c); /*Caracterul care semnaleaza incheierea*/
/*transmisiei*/
setari();
}
4.2.4. Explicarea programului
Programul realizeaza comunicarea prin mai multe etape, fiecare etapa fiind ilustratade o functie, apelata în programul principal.
Dupa definirea portului serial COM 2, prin functia "setari" salvam datele de pe fiecare linie a portului serial, într-o structura de variabile, date ce vor fi repuse în registrii la sfîrsitul rularii programului. Acest lucru este nscesar pentru ca sa nu pierdem date necesare altor programe care ar utiliza portul serial.
În aceeasi functie setam registrii portului serial astfel încât sa îndeplinim conditiile impuse de protocolul de comunicare.
Fiecare pas al rularii programului va fi explicat prin mesaje tiparite pe ecran, pentru o utilizare usoara a programului .
Urmeaza emisia unui caracter prin apelarea functiei "emisie". Este indicat prin mesaj caracterul "?" , caracterul cheie al transmisiei, dupa care se trece imediat la functia "receptie" care realizeaza receptia. Daca slave-ul nu identifica corect mesajul "?" sau se tasteaza un alt caracter, slave-ul trimite mesajul "EROARE"- mesaj care va fi afisat pe ecran. Daca slave-ul recepteaza mesajul corect, master-ul va primi si afisa pe ecran mesajul "ASTEPT COMANDA".
Master-ul va trece din noupe emisie si va trimite doua cifre reprezentând adresa unei linii de port. Este obligatoriu ca aceste linii sa fie P1.6 sau P1.7 deoarece se doreste o extensie ulterioara a interfetei spre interfata I2C.
Slave-ul va citi valoarea logica a acestei linii si o va trimite master-ului, care o va afisa.
În acest moment transmisia este considerata încheiata. Master-ul trimite mesajul "G" ce va fi recunoscut de slave si va semnifica încheierea comunicarii.
Programul se încheie cu functia "stare initiala", ce restaureaza datele registrilor portului dinaintea rularii programului.
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Electronica Port Serial Interfață de Comunicare pe Portul Serial (ID: 148891)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
