CURSUL 08

Comunicația Serială Asincronă

Durată: 119 min de predare Nivel: licență, anul II - recomandat după Cursul 07 Disciplină: Microcontrollere și Microprocesoare Laborator asociat: Laboratorul 06 PDF: descarcă suportul EN English version

Un microcontroler care lucrează singur este o excepție. Aproape orice sistem încorporat e format din mai multe circuite care trebuie să schimbe informație între ele, iar cele două capete ale unei legături sunt întotdeauna independente: ceasuri diferite, alimentări diferite, fără nicio memorie comună. Informația trebuie deci codificată ca o variație de tensiune pe un fir, transmisă în timp, apoi decodificată la celălalt capăt. Cursul de față răspunde la două întrebări: cum se codifică biții în timp, și cum știe receptorul unde începe și unde se termină fiecare bit, fără să existe vreun fir de ceas care să i-o spună.

1Obiectul și structura cursului6 min

Vom urmări logica de fond a comunicației seriale asincrone: de ce a înlocuit comunicația paralelă aproape peste tot, cum arată un cadru UART, cum reușește un receptor fără fir de ceas să găsească mijlocul fiecărui bit, ce limitează practic rata de transfer, și cum se traduce toată această teorie în registrele concrete ale modulului USART al ATmega328P.

Recapitulare din cursurile anterioare
  • O rutină de întrerupere trebuie scurtă, comunică prin variabile volatile (Cursul 05)
  • Formulele de prescalare - frecvență, divizor, valoare de comparare - revin identic, aplicate acum divizorului ratei de transfer (Cursul 06)
  • Să explicați de ce comunicația serială a înlocuit-o pe cea paralelă și ce înseamnă sincron față de asincron
  • Să descrieți structura unui cadru UART și rolul fiecărui bit
  • Să explicați mecanismul de supraeșantionare de 16 ori și de ce ultimul bit al cadrului e cel mai vulnerabil la eroarea de ceas
  • Să calculați valoarea registrului UBRR și eroarea rezultată pentru o rată de transfer dată
  • Să scrieți inițializarea, transmisia și recepția UART, atât prin interogare cât și prin întrerupere cu tampon circular
  • Să distingeți TTL, RS-232 și RS-485 după nivelurile electrice și domeniul de aplicare

2Sisteme și tipuri de comunicație12 min

Toate schimburile de date presupun un mecanism prin care o informație dintr-un registru al unui circuit ajunge, nealterată, într-un registru al altui circuit - un sistem de comunicație. Nevoia apare din interfațarea cu periferice externe (senzori, afișaje), din comunicația între mai multe microcontrolere, din legătura cu un calculator, și din integrarea în rețele IoT.

Serial față de paralel

În comunicația paralelă, opt biți circulă simultan pe opt fire; în cea serială, unul după altul, pe un singur fir. Intuiția spune că paralelul e de opt ori mai rapid - realitatea a mers exact invers.

De ce aproape toate interfețele moderne sunt seriale Numărul de pini: o magistrală paralelă de 8 biți consumă jumătate din pinii unui ATmega328P pentru un singur periferic; o interfață serială consumă doi. Decalajul de propagare (skew): firele unei magistrale paralele nu au exact aceeași lungime electrică - la frecvențe mari, acest decalaj devine comparabil cu durata unui bit, iar receptorul citește bitul n de pe un fir și bitul n+1 de pe altul. O legătură serială, cu un singur fir de date, nu are față de ce să se decaleze. Diafonia: fire alăturate care comută simultan se influențează reciproc prin cuplaj; un singur fir se comportă mult mai bine. Rezultatul: o legătură serială bine făcută funcționează la frecvențe cu două-trei ordine de mărime mai mari decât una paralelă de aceeași lungime.

Sincron față de asincron

Sincron: emițătorul trimite, pe un fir separat, un semnal de ceas care marchează fiecare bit - sincronizare perfectă prin construcție (SPI, I2C). Asincron: nu există fir de ceas - receptorul deduce singur momentele de eșantionare, cu propriul oscilator, pornind de la un reper transmis chiar în flux (tranziția care marchează începutul cadrului). Costul: cele două capete trebuie să fi convenit dinainte asupra vitezei, iar oscilatoarele trebuie suficient de apropiate ca frecvență. Câștigul: un fir mai puțin, și independență completă între cele două dispozitive.

Simplex, semiduplex, duplex integral

Simplex: un singur sens, permanent. Semiduplex: ambele sensuri, dar nu simultan - cele două capete își împart același mediu, pe rând. Duplex integral: simultan în ambele sensuri, prin fire sau canale distincte. UART-ul, cu RxD și TxD separate, e duplex integral.

Punct la punct față de magistrală

Punct la punct: exact două capete, fără adresare - tot ce se transmite e pentru celălalt. O magistrală (multipunct) leagă mai multe dispozitive la aceleași fire și cere adresare plus arbitrare. UART-ul e, în forma de bază, punct la punct; RS-485 (secțiunea finală) îl extinde la o magistrală de până la 32 de dispozitive.

Un modul radio se prezintă microcontrolerului tot ca UART Un modul Bluetooth primește octeți prin UART de la microcontroler și se ocupă singur de radiofrecvență. Stăpânirea comunicației seriale asincrone deschide astfel accesul la o categorie foarte largă de periferice, dincolo de cablul propriu-zis.

3Modulul UART și formatul cadrului13 min

UART-ul (Universal Asynchronous Receiver Transmitter) traduce bidirecțional între lumea paralelă din interiorul microcontrolerului și lumea serială de pe fir. Linia TxD e ieșirea, RxD e intrarea; la conectarea a două dispozitive, cele două linii se încrucișează (TxD la RxD), plus o legătură de masă comună obligatorie. Pe ATmega328P: PD0 (RxD), PD1 (TxD).

Greșeala clasică: TxD la TxD

Nu se transmite nimic și nu se arde nimic - eroarea e greu de depistat tocmai pentru că nu produce niciun simptom vizibil imediat, doar tăcere pe ambele canale.

Patru parametri trebuie identici la ambele capete: numărul de biți de date (de regulă 8, LSB primul), bitul de paritate (absent, par sau impar), rata de transfer (9600, 19200, 38400, 57600, 115200 fiind valorile uzuale) și numărul de biți de stop (1 sau 2). Notația 8N1 (opt biți de date, fără paritate, un bit de stop) e configurația implicită a aproape tuturor terminalelor.

Formatul cadrului

Codificarea e NRZ (Non Return to Zero): fiecare bit e un nivel constant menținut pe toată durata lui, fără revenire la repaus între biți - consecință: un șir lung de biți identici nu produce nicio tranziție, de aceea receptorul nu poate recupera ceasul din semnal și rata trebuie convenită dinainte. În repaus, linia stă în 1 logic.

Structura cadrului, în ordinea transmiterii
Bit de start (întotdeauna 0): produce frontul descrescător folosit ca origine a timpului - nu transportă informație utilă.
Biții de date (5-9, LSB primul).
Bit de paritate (opțional).
Bit(i) de stop (întotdeauna 1): garantează revenirea liniei în repaus înainte de următorul cadru, ca frontul de start următor să fie detectabil.
Randamentul codificării Pentru 8 biți utili, formatul 8N1 pune 10 biți pe fir, 8E1 pune 11 - se pierd 20-27% pe sincronizare și control. La 9600 bauzi, 8N1: un cadru durează 10/9600 ≈ 1,04 ms, deci maximum ~960 caractere/s. La 115200 bauzi: ~86,8 µs/cadru, ~11 520 caractere/s.

Bitul de paritate detectează un număr impar de erori de bit, dar nu le corectează și nu detectează un număr par de erori - pe legături scurte e de obicei dezactivat; pe cabluri lungi, o sumă de control pe mesajul întreg e oricum de preferat.

Transmisia unui octet pe UART: puneti evenimentele in ordine

4Sincronizarea între emițător și receptor12 min

Marginile unui bit sunt zona cea mai nesigură - acolo se produce tranziția, cu timp de creștere, posibile oscilații și jitter. La mijlocul bitului, nivelul e stabil și cât mai departe de ambele tranziții vecine. Receptorul eșantionează deci la mijlocul bitului, nu la margine.

Potriviti fiecare element al cadrului cu rolul lui
Cadrul UART si deriva de esantionare

Supraeșantionarea de 16 ori

Receptorul lucrează cu un ceas de 16 ori mai rapid decât rata de transfer, eșantionând linia RxD de 16 ori pe durata fiecărui bit. La un front descrescător din repaus, presupune început de bit de start și pornește un numărător; eșantioanele 8, 9, 10 cad, prin construcție, în jurul mijlocului bitului - receptorul le citește pe toate trei și decide prin vot majoritar. Dacă majoritatea confirmă 0, bitul de start e validat; altfel, frontul a fost un impuls parazit, și receptorul revine în așteptare. Aceeași procedură se repetă, fără nicio tranziție necesară, pentru fiecare bit următor.

De ce vot majoritar pe trei eșantioane, nu unul singur Votul majoritar oferă imunitate la un singur impuls parazit care ar afecta un eșantion izolat. La 115200 bauzi, ceasul intern de eșantionare lucrează la 16×115200 = 1,8432 MHz - oscilatorul trebuie să poată furniza această frecvență prin divizare întreagă, ceea ce e sursa principalei limitări practice (secțiunea următoare).

De ce eroarea de ceas se acumulează

Receptorul se resincronizează o singură dată pe cadru, pe frontul de start. Dacă ceasul lui are o eroare relativă e față de emițător, intervalul considerat un bit e T_b(1+e) - eroarea nu se anulează, se adună: după n biți, deplasarea e n·e·T_b.

Ultimul bit al cadrului, nu primul, e cel mai vulnerabil

Într-un cadru 8N1, mijlocul bitului de stop e la 9,5 durate de bit după frontul de start. Ca eșantionul să cadă încă în bit, deplasarea acumulată trebuie sub jumătate de bit: 9,5·|e| < 0,5 ⇒ |e| < 5,3% - limita geometrică ideală. În practică, incertitudinea de detecție a frontului de start (1/16 dintr-un bit) și faptul că toate trei eșantioanele 8, 9, 10 trebuie să cadă în bit restrâng marja reală la aproximativ ±4,6% - împărțită între cele două capete, regula practică e ca eroarea fiecărui capăt să nu depășească ±2,5%. Simptomul unei erori de ceas prea mari, la un terminal serial: un flux de caractere aparent aleatoare în locul textului așteptat.

5Calculul ratei de transfer13 min

Rata de transfer se obține prin divizarea întreagă a frecvenței oscilatorului, printr-un numărător programabil - registrul UBRR (USART Baud Rate Register).

Formula registrului UBRR
UBRR = f_osc/(16·B) - 1, unde B e rata dorită.
Rata efectivă: B_ef = f_osc / (16·(UBRR+1)).
Eroarea relativă: ε = (B_ef/B - 1)×100%.

Rezultatul primei formule rareori e întreg - rotunjirea introduce o eroare. Cu cât divizorul e mai mic (rată cerută mare față de frecvența oscilatorului), cu atât o unitate de rotunjire înseamnă o fracțiune mai mare din divizor - de aceea ratele mari sunt mult mai greu de generat exact.

Exercițiu rezolvat - UBRR0 și eroarea la 9600 și la 115200 bauzi, oscilator 16 MHz
Vezi rezolvarea

9600 bauzi: UBRR = 16×10⁶/(16×9600) - 1 = 104,17-1 = 103,17 → 103. B_ef = 16×10⁶/(16×104) = 9615,4. ε = +0,16% - complet neglijabilă.

115200 bauzi: UBRR = 16×10⁶/(16×115200) - 1 = 8,68-1 = 7,68 → 8. B_ef = 16×10⁶/(16×9) = 111 111. ε = -3,55% - peste limita practică de ±2,5%; dacă și celălalt capăt are eroare de același semn, recepția devine nesigură.

Modul de viteză dublă

Bitul U2X0 din UCSR0A coboară factorul de supraeșantionare la 8: UBRR = f_osc/(8·B) - 1. Divizorul se dublează, rotunjirea are un efect relativ mai mic. La 115200 bauzi, 16 MHz: UBRR = 16,36 → 16, B_ef = 16×10⁶/(8×17) = 117 647, ε = +2,1% - mult mai bun decât -3,55%, exact ce face biblioteca Arduino la 115200. Prețul: cu opt eșantioane pe bit în loc de șaisprezece, votul se face pe eșantioanele 4, 5, 6, fereastra utilă se îngustează, iar imunitatea la zgomot scade aproximativ la jumătate.

De ce există cristale de 14,7456 MHz 14 745 600 = 115200×128 = 9600×1536 - multiplu întreg al tuturor ratelor standard. La 115200 bauzi: UBRR = 14 745 600/(16×115200) - 1 = 8-1 = 7, exact întreg, eroare zero. Arduino preferă 16 MHz, mai comod pentru temporizări zecimale, cu prețul erorii discutate mai sus - un exemplu clar de compromis de proiectare: nu există o frecvență simultan convenabilă pentru temporizări și pentru rate standard exacte.
Valoarea UBRR depinde de frecvența oscilatorului, nu doar de rata dorită

Un program corect la 16 MHz, mutat fără modificări pe o placă la 8 MHz, transmite la jumătate din rata dorită - la 8 MHz, 9600 bauzi cere UBRR=51, nu 103. În cod portabil, valoarea nu se scrie niciodată ca o constantă numerică, ci se calculează la compilare, din macroul F_CPU.

Calculator UBRR: ce eroare are rata de transfer aleasa?

6Registrele modulului USART al ATmega328P8 min

Modulul USART0 are trei categorii de registre: un registru de date, registre de control și stare, și registrul ratei de transfer.

UDR0 e două registre fizice distincte sub o singură adresă

O scriere în UDR0 încarcă tamponul de emisie; o citire returnează tamponul de recepție - nu se poate citi înapoi ce s-a scris. La recepție, tamponul are două niveluri, formând un mic FIFO.

RegistruBitRol
UCSR0ARXC0recepție completă (se șterge la citirea UDR0)
UCSR0AUDRE0tamponul de emisie e gol, poate primi un octet nou
UCSR0AFE0 / DOR0 / UPE0eroare de cadru / depășire / paritate
UCSR0BRXCIE0 / RXEN0 / TXEN0întrerupere la recepție / activare receptor / emițător
UCSR0CUPM01:00 / USBS0 / UCSZ01:00paritate / biți de stop / dimensiune cadru
Activarea RXEN0/TXEN0 preia automat controlul pinilor Indiferent de ce s-a configurat în DDRD, modulul serial are prioritate față de portul GPIO obișnuit - scutește programatorul de configurarea direcției, dar explică de ce pinii 0 și 1 ai Unoului nu mai pot fi folosiți ca pini obișnuiți odată ce interfața serială a fost pornită.

Trei indicatori de eroare, toți referitori la octetul din vârful tamponului: FE0 (frame error) - în poziția bitului de stop s-a citit 0, semn tipic al unei rate de transfer nepotrivite între capete; DOR0 (data overrun) - un cadru nou a sosit complet cât timp tamponul era plin, date pierdute prin eroare de arhitectură software, nu electrică; UPE0 (parity error) - bitul de paritate nu corespunde, semn de zgomot electric sau configurare diferită.

UCSR0A se citește obligatoriu înainte de UDR0

Citirea registrului de date avansează tamponul - dacă indicatorii de eroare sunt citiți după, se referă deja la următorul octet, nu la cel tocmai extras.

7Aplicație: transmisia și recepția unui caracter11 min

Inițializarea cere trei operații: divizorul în UBRR0, activarea emițătorului/receptorului în UCSR0B, formatul cadrului în UCSR0C. UBRR0 e de 12 biți, împărțit în UBRR0H și UBRR0L - partea superioară se scrie prima.

#define F_CPU 16000000UL
#define BAUD 9600UL
#define UBRR_VAL ((F_CPU + 8UL*BAUD) / (16UL*BAUD) - 1UL)   /* rotunjire corecta */

void usart_init(void) {
    UBRR0H = (uint8_t)(UBRR_VAL >> 8);
    UBRR0L = (uint8_t)(UBRR_VAL & 0xFF);
    UCSR0B = (1<<RXEN0) | (1<<TXEN0);
    UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);   /* 8N1 */
}
De ce se adaugă 8·BAUD la numărător Împărțirea întreagă în C trunchiază, introducând o eroare sistematică într-un singur sens. Adăugarea a jumătate din numitor transformă trunchierea în rotunjire la cel mai apropiat întreg, înjumătățind eroarea maximă - artificiu standard, folosit și în bibliotecile Arduino.

Transmisia și recepția prin interogare

void usart_transmite(uint8_t data) {
    while (!(UCSR0A & (1<<UDRE0))) { ; }   /* asteapta golirea tamponului de emisie */
    UDR0 = data;
}
uint8_t usart_date_disponibile(void) {
    return (UCSR0A & (1<<RXC0)) != 0;
}
Recepția blocantă poate opri programul la nesfârșit

La emisie, așteptarea e limitată la durata unui cadru (~1 ms la 9600 bauzi). La recepție, dacă celălalt capăt nu transmite nimic, o funcție blocantă oprește întregul program pe termen nedefinit. Varianta corectă: testați doar disponibilitatea (usart_date_disponibile()) și citiți numai dacă există date, cu registrul de stare citit înaintea lui UDR0 pentru ca indicatorii de eroare să se refere la octetul care urmează a fi extras.

Echivalentul cu clasa Serial din Arduino

void setup() { Serial.begin(9600); }
void loop() {
    Serial.write('G');
    if (Serial.available() > 0) { char c = Serial.read(); Serial.write(c); }
    delay(500);
}

Serial.available() nu citește RXC0, ci numărul de octeți dintr-un tampon circular de 64 de octeți întreținut de rutina de întrerupere de recepție. Serial.write() depune octetul într-un tampon software și revine imediat - transmisia se face în fundal, prin întreruperi. Aceasta e exact arhitectura discutată în secțiunea următoare.

8Recepția cu întrerupere și tamponul circular11 min

Interogarea e simplă, dar are un defect structural: programul trebuie să treacă prin punctul de verificare mai des decât sosesc caracterele. La 115200 bauzi, un cadru durează ~87 µs, adică ~1400 cicluri la 16 MHz între două caractere - orice funcție mai lentă (o conversie ADC cu așteptare, un delay()) face ca al doilea caracter sosit între timp să suprascrie tamponul hardware, ridicând DOR0, iar datele se pierd fără ca programul să observe, dacă nu testează explicit indicatorul.

Soluția: separarea completă a sosirii de prelucrare Sosirea se tratează într-o rutină de întrerupere, care doar mută octetul din UDR0 într-o zonă de memorie. Prelucrarea rămâne în bucla principală, care extrage din acea zonă când are timp. Structura care mediază: un tampon circular (buffer circular, coadă FIFO) - un tablou de dimensiune fixă cu doi indici, cap (unde se scrie) și coadă (de unde se citește), fiecare avansând ciclic. Gol când cei doi indici sunt egali, plin când avansarea capului ar egala coada. Fără deplasare de date, fără alocare dinamică, timp constant - esențial într-o rutină de întrerupere.
#define BUF_SIZE 64                    /* obligatoriu o putere a lui doi */
#define BUF_MASK (BUF_SIZE - 1)
static volatile uint8_t buf[BUF_SIZE];
static volatile uint8_t cap = 0, coada = 0;

ISR(USART_RX_vect) {
    uint8_t stare = UCSR0A;            /* stare INAINTE de citirea datelor */
    uint8_t data = UDR0;
    if (stare & ((1<<FE0)|(1<<DOR0)|(1<<UPE0))) return;   /* cadru eronat, se arunca */
    uint8_t cap_urmator = (cap + 1) & BUF_MASK;
    if (cap_urmator != coada) { buf[cap] = data; cap = cap_urmator; }
    /* altfel tamponul e plin, octetul se pierde controlat */
}

uint8_t buffer_citeste(void) {
    uint8_t data = buf[coada];
    coada = (coada + 1) & BUF_MASK;
    return data;
}

Activarea cere doar UCSR0B |= (1<<RXCIE0) plus sei().

Trei detalii esențiale ale acestui cod O dimensiune putere a lui doi transformă operația de modulo, costisitoare pe un procesor de 8 biți fără divizor hardware, într-o simplă mascare binară. Separarea rolurilor - întreruperea scrie doar cap, programul principal scrie doar coadă - face scrierile atomice pe variabile de un octet, fără nevoie de secțiune critică (dacă tamponul ar depăși 256 de poziții, indicii ar deveni de 16 biți și accesul din bucla principală ar trebui protejat). La umplere, codul verifică loc înainte de a scrie și aruncă octetul controlat - alternativa, suprascrierea celui mai vechi octet, ar strica ordinea mesajelor.
Rutina de întrerupere trebuie să facă doar atât - goli UDR0

Nu interpretează mesajul, nu afișează nimic, nu apelează funcții de temporizare, nu transmite. Orice prelucrare introdusă în rutină reduce marja disponibilă și readuce, pe altă cale, exact problema pe care întreruperea trebuia să o rezolve.

9De la UART la USART5 min

USART (Universal Synchronous and Asynchronous Receiver Transmitter) adaugă, peste modul asincron descris până acum, un mod sincron, cu o linie suplimentară de ceas (XCK, pe PD4 la ATmega328P). Unul din parteneri generează ceasul (master), celălalt îl primește (slave); biții sunt validați de fronturile lui, iar receptorul nu mai are nevoie nici de supraeșantionare, nici de vot majoritar, nici de un ceas propriu precis.

De ce modul sincron e rar folosit în practică Avantajele sunt reale - riscul de eroare de sincronizare dispare, nu mai există limitarea de rotunjire a divizorului, iar cadrul poate renunța la biții de start și stop. Dezavantajul: un fir în plus, care trebuie tras pe toată lungimea legăturii și care, dacă culege zgomot, produce biți inexistenți - mai grav decât o deplasare de fază. Acolo unde se dorește comunicație sincronă se preferă protocoale dedicate, SPI și I2C (cursul următor). Pe ATmega328P, în modul asincron scriem „UART" și citim „USART în mod asincron" - același bloc hardware, doar configurare diferită.

10Standardele RS-232 și RS-48510 min

UART-ul spune totul despre logica transmisiei, dar nimic despre electrica ei - ce tensiune reprezintă un 1 logic, cât de lung poate fi cablul. Acestea fac obiectul standardelor RS-232 și RS-485.

Nivelurile TTL nu sunt RS-232

Pinii ATmega328P lucrează cu niveluri TTL/CMOS: ~0 V pentru 0, tensiunea de alimentare pentru 1. RS-232 folosește tensiuni negative pentru 1 logic (mark, -3 până la -15 V) și pozitive pentru 0 (space, +3 până la +15 V) - o zonă moartă între -3 și +3 V dă imunitate la zgomot.

Un pin TxD de microcontroler nu poate fi legat direct la un port RS-232

Două motive independente, fiecare suficient: semnalul ar fi inversat (polaritatea RS-232 e opusă convenției TTL), iar tensiunea de -12 V aplicată unui pin de microcontroler îl distruge aproape sigur. Un convertor de nivel (MAX232) face traducerea în ambele sensuri, generând singur tensiunile negative dintr-o singură alimentare de 5 V, printr-o pompă de sarcină.

Un cablu USB-serial nu e un adaptor RS-232 Cablurile folosite la programarea plăcilor moderne lucrează direct în TTL de 5 V sau 3,3 V, deci sunt compatibile cu pinii microcontrolerului. Verificați tensiunea la pinul de emisie, în repaus: ~+5 V înseamnă TTL, ~-9 sau -12 V înseamnă RS-232 adevărat - confuzia dintre cele două e o cauză frecventă de circuite arse.

RS-485 și semnalul diferențial

RS-232 rezolvă amplitudinea, dar rămâne asimetric (fața de masă) - pe distanțe mari, diferența de potențial dintre mase și perturbațiile electromagnetice induse se adaugă direct semnalului. RS-485 elimină ambele probleme: informația e purtată de diferența de tensiune dintre două fire torsadate, A și B, comandate în antifază. Receptorul citește doar U_A - U_B.

De ce semnalul diferențial merge mult mai departe Fiind torsadate, cele două fire parcurg același traseu, expuse aceluiași câmp perturbator - orice tensiune indusă apare aproape identic pe amândouă (mod comun) și se anulează la diferență. La fel se anulează diferența de potențial dintre mase, atât timp cât rămâne în domeniul de mod comun admis (-7 până la +12 V). Rezultat: RS-485 permite legături de până la ~1200 m, cu până la 32 de dispozitive pe aceeași pereche.
RS-232RS-485
Topologiepunct la punctmultipunct
Tip de semnalasimetricdiferențial, pereche torsadată
Distanță maximă~15 m~1200 m
Dispozitive2până la 32
Mod de lucruduplex integralsemiduplex (2 fire)
Terminarea liniei nu e opțională la lungimile de lucru ale RS-485

Cablul e o linie de transmisie cu impedanță caracteristică (~120 Ω); un front care ajunge la un capăt neadaptat se reflectă și se suprapune peste semnal, producând false tranziții. Remediul: câte un rezistor de 120 Ω la fiecare din cele două capete fizice ale magistralei - nu la dispozitivele intermediare. O magistrală neterminată poate funcționa aparent corect la viteză mică și se defectează brusc la creșterea vitezei, când durata frontului devine comparabilă cu timpul de propagare dus-întors.

Important: ambele standarde descriu doar stratul fizic - formatul cadrului rămâne cel al UART-ului (start, date, paritate, stop). Un microcontroler care transmite prin RS-485 folosește exact același modul USART; se schimbă doar circuitul de interfață și un pin suplimentar care comandă activarea emițătorului.

11Erori frecvente4 min

  • „Am legat TxD la TxD - dacă nu merge, măcar n-am ars nimic." Corect că nu se arde nimic, dar eroarea trece adesea neobservată multă vreme, tocmai pentru că lipsa oricărui simptom evident nu îndreaptă atenția spre cablaj. TxD se leagă întotdeauna la RxD al celuilalt capăt, niciodată la propriul lui omolog.
  • „Am citit UDR0 și abia apoi am verificat bitul de eroare - dar nu găsesc niciodată o eroare de cadru." Fals pozitiv structural - citirea UDR0 avansează tamponul, deci indicatorii citiți după se referă deja la următorul octet, nu la cel tocmai extras. UCSR0A se citește întotdeauna înaintea lui UDR0.
  • „Interogarea (polling) e suficientă pentru orice aplicație cu UART." Fals la rate mari sau bucle principale lente - orice funcție care durează mai mult decât intervalul dintre două cadre (87 µs la 115200 bauzi) face ca datele să se piardă prin depășirea tamponului hardware, fără niciun avertisment dacă indicatorul DOR0 nu e testat explicit. Pentru fluxuri rapide, folosiți o rutină de întrerupere scurtă plus un tampon circular, separând sosirea de prelucrare.

12Rezumat și glosar5 min

Comunicația serială asincronă rezolvă transferul de informație între circuite independente cu minimum de resurse hardware, renunțând la firul de ceas în schimbul unei convenții prealabile asupra vitezei și al unei resincronizări la fiecare cadru, pe bitul de start. Receptorul supraeșantionează de 16 ori pe bit și decide prin vot majoritar în jurul mijlocului fiecărui bit, tolerând o eroare de ceas de câteva procente, cu condiția ca ea să nu se acumuleze peste jumătate de bit până la ultimul bit al cadrului - cel mai vulnerabil. Divizorul întreg impus de registrul UBRR face ca unele combinații de frecvență și rată să fie exacte, altele nu; de aici cristalele de 14,7456 MHz și modul de viteză dublă. La nivel de programare, modulul USART se reduce la un registru de date, trei registre de control și stare, și un registru de divizor - recepția prin interogare e suficientă pentru programe simple, dar arhitectura corectă pentru fluxuri rapide combină o întrerupere scurtă cu un tampon circular. Protocolul și nivelul electric sunt lucruri distincte: aceleași cadre circulă la niveluri TTL pe câțiva centimetri, prin RS-232 pe cincisprezece metri, sau prin RS-485 diferențial pe peste un kilometru.

NRZ
Non Return to Zero - codificare în care fiecare bit e un nivel constant, fără revenire la repaus.
UBRR
USART Baud Rate Register - divizorul care fixează rata de transfer.
Frame error (FE0)
bit de stop citit ca 0, semn tipic al unei rate de transfer nepotrivite.
Tampon circular
coadă FIFO cu doi indici (cap, coadă) care mediază între o rutină de întrerupere și programul principal.
Semnal diferențial
informație purtată de diferența de tensiune dintre două fire, imună la perturbațiile de mod comun.

13Întrebări de verificare7 min

  1. Explicați de ce comunicația serială a înlocuit-o pe cea paralelă în aproape toate aplicațiile moderne. Ce e decalajul de propagare, și de ce efectul lui se agravează la frecvențe mari?
  2. Ce trebuie să cunoască dinainte receptorul într-o legătură asincronă, și de ce nu poate fi dedus din semnalul primit, pornind de la codificarea NRZ?
  3. Descrieți mecanismul de supraeșantionare de 16 ori. De ce se folosesc eșantioanele 8, 9, 10 și de ce prin vot majoritar?
  4. Un cadru e 8E2. La câte durate de bit după frontul de start se află mijlocul ultimului bit de stop? Deduceți eroarea relativă maximă de ceas tolerată, geometric.
  5. Un ATmega328P la 16 MHz trebuie să comunice la 57600 bauzi. Calculați UBRR0, rata efectivă și eroarea, atât normal cât și cu U2X0 activat.
  6. Distingeți indicatorii FE0, DOR0 și UPE0. Pentru fiecare, indicați cauza probabilă.
  7. Argumentați de ce dimensiunea unui tampon circular se alege ca putere a lui doi, și de ce indicii trebuie declarați volatile.

14Direcții de aprofundare2 min

Cursul următor rămâne în familia comunicației seriale, dar trece la protocoalele sincrone - SPI și I2C - unde firul de ceas readus în schemă elimină problema ratei de transfer discutată aici, în schimbul unui fir suplimentar și al unei topologii diferite.

Configurarea UART-ului, calculul UBRR și tamponul circular din acest curs devin montaj real în Laboratorul 06.