2013-02-24

USART Atmega mikrokontroleriuose

Komunikacijai tarp elektronikos įrenginių naudojami įvairiausi protokolai - I2C/TWI, SPI, PCI, USB ir t.t. Vienas iš populiariausių ir labiausiai paplitusių mikrokontrolerių tarpe - USART (angl. universal synchronous-asynchronous receiver/transmitter) arba UART. Apie jį jau daug visur prirašyta ir nesunku rasti pavyzdžių internete. Jo paplitimą ir pripažinimą lėmė tai, jog jis nesudėtingas, puikiai leidžia emuliuoti terminalo funkcijas, palaiko pilnavertę dvipusę (angl. full duplex) komunikaciją vienu metu, o signalizacija vykdoma naudojant dvi ryšio linijas-laidus. RS-232 (arba COM) modemuose ir senuose spausdintuvuose yra puikus jo panaudojimo pavyzdys. Šiame straipsnelyje pabandysime išmokti (o gal pakartoti), kaip taikyti jį praktiškai Atmega mikrokontroleriams, apžvelgsime svarbiausius taikymo niuansus.


I. Intro

USART - nuoseklaus perdavimo (angl. serial) protokolas, t.y. viena linija paeiliui (vienas po kito) perduodami siunčiami(ar priimami) duomenų paketo bitai. Duomenis galima siųsti sinchroniniu ir asinchroniniu būdu (UART - palaikomas asinchroninis, USART - palaikomi abu variantai). Naudojant sinchroninį metodą reikalinga trečia - taktų sinchronizavimo signalo linija CLOCK, siekiant to išvengti, labiausiai paplito asinchroninis metodas. Jame komunikuojantys įrenginiai turi būti suderinę siuntimo parametrus ir greičius iš anksto, kadangi nėra bendro sinchronizavimo.

Fiziniame lygyje siunčiama duomenų porcija (angl. frame) yra standartizuota ir turi savo formatą. Siųsti galima 5, 6, 7, 8 ar 9 bitus informacijos viename pakete. Kiekvieną paketą sudaro kelios dalys - pradžioje yra siunčiamas START bitas (čia gavėjas ir siuntėjas sinchronizuoja savo laikrodžius), po kurio seka duomenų bitai ir pabaigoje vienas ar du STOP bitai. Papildomai galima siųsti lygiškumo (angl. parity) bitą, kuriuo galima nustatyti, ar duomenų paketas nebuvo pakeistas/sugadintas, bet šis dažniausiai tiesiog nenaudojamas. Kiekvienas bitas yra siunčiamas (t.y. nustatoma reikiama LOW/HIGH įtampa) fiksuotą laiko tarpą linijoje. Visa tai - kiek bitų informacijos siųsti vienu metu, kiek naudoti STOP bitų bei kokiu greičiu siųsti - turi būti konfigūruojama prieš pradedant naudotis USART.


Toliau vienas iš svarbiausių parametrų - siuntimo greitis BAUD (angl. baud rate). Jis matuojamas bitais per sekundę (angl. bps - bits per second). Čia reikia atkreipti dėmesį, jog į BAUD greitį yra įskaičiuojami VISI paketo bitai, t.y. tiek START, tiek STOP ir pan. Standartiškai naudojama 9600bps, 115200bps ir t.t. Šiuolaikiniais kompiuterių komunikacijos protokolais - tai iš ties labai lėtai. Palyginimui - USB 2.0 greitis siekia 480Mbps (~60MB/s), tačiau reikia nepamiršti, jog čia duomenis apdoroja žymiai greitesnis procesorius, o mikrokontroleriuose CPU dažniausiai dirba tik ~20MHz ar mažesniu dažniu. Siunčiama, žinoma, turi būti lėčiau, nei dirba pats mikrokontroleris dėl keletos priežasčių - turi būti palikta laiko apdoroti duomenims bei svarbiausia - reikia pastoviai tikrinti linijos įtampos lygį, kadangi gavėjas neturi taktų sinchronizavimo su siuntėju, t.y. nėra CLOCK linijos ir priimančioji pusė nežino, kada bus siunčiama informacija iš siuntėjo. Linijos tikrinimas atliekamas bent 2x greičiau nei siunčiama informacija (dažniausiai 16x) ir keletą kartų nuskaityta įtampos reikšmė priimama kaip vieno bito 0 arba 1.

Siuntimo greitis taip pat nustatomas atitinkamai pakoregavus reikiamus mikrokontrolerio registrus prieš komunikavimą, be to, jis priklauso nuo naudojamo taktinio dažnio (t.y. kvarcinio generatoriaus dažnio). Akivaizdu, jog kuo didesnis dažnis, tuo greičiau galima siųsti duomenis. Vis gi reikia nepamiršti, jog didinant greitį, taip pat didėja ir rizika sugadinti daugiau duomenų, didėja nestabilumas. USART turi gerą savybę - retransliuoti paketą (angl. retransmission), jeigu įvyksta klaida (angl. framing error). Duomenų praradimas ar jų sugadinimas nėra dažnas reiškinys, tačiau tikrai pasitaikantis praktikoje - todėl tam reikia pasirengti ir niekada nesitikėti 100% korektiškumo. Kaip pamatysime vėliau - tam tikri kvarco dažniai yra specialiai "subalansuoti" naudoti USART komunikacijoms.

Akivaizdžiai siuntimo ir gavimo procese dalyvauja dvi pusės - siuntėjas ir gavėjas. Komunikacijai naudojamos dvi linijos - viena priėmimui, kitai - siuntimui. Kaip parodyta schemoje viršuje - kiekvienas įrenginys turi dvi jam priskirtas išvestis TX ir RX, t.y. siuntimo ir priėmimo (angl. transmit/receive). Šie linijų pavadinimai rašomi pagal kiekvieną įrenginį, todėl jungiant du įrenginius tarpusavyje reikia jungti ne TX į TX, o sukryžiavus - TX į RX. Reikia nepamiršti, kad įrenginių GND turi būti sujungti į bendrą, kad būtų suvienodinamas bendras 0V lygis. Taip pat svarbu suvokti, kad USART pritaikytas dviejų įrenginių komunikacijai, tačiau labai norint galima prie tų pačių linijų jungti ir daugiau įrenginių, tačiau tada reikia užtikrinti, kad vienu metu bendraus tik du įrenginiai, o kiti tuo metu nieko nesiųs į liniją. Tai gana komplikuota, todėl tokiu atveju naudojamas USART Multi-processor Communication metodas (MPCM) arba kitas - I2C protokolas. Daugiau informacijos - oficialiuose Atmega datasheet dokumentuose.

II. Pajungimas prie Atmega


Mikrokontroleriuose, pavyzdžiui Atmega, USART jau standartiškai realizuojamas loginių schemų lygyje (angl. hardware), todėl reikia tik žinoti kur, kada ir kokius registrus reikia valdyti bei panaudoti. Siuntimui ir gavimui prieinamas visas USART įrenginys, kuris turi TX ir RX atskirus FIFO duomenų buferius. Jungiant du Atmega mikrokontrolerius tarpusavyje nereikia atlikti lygių suderinimo, kadangi naudojama 0-5V įtampa. Jungiant prie kompiuterio RS-232 (t.y. COM) jungties reikia atlikti lygių (-15...+15) suderinimą/keitimą į TTL (0..+5V) naudojant MAX232 mikroschemą ar pan. kaip pateikta paveiksle žemiau. MAX232 reikia papildomo išorinio įtampos šaltinio. 
Neturint COM jungties ar norint komunikuoti per USB galimas ir kitas sprendimas - nusipirkti iš ebay.com ar pan. USB-TTL USART pritaikytą modulį/konverterį (foto žemiau). Žinoma, galima ir pasigaminti naudojant V-USB biblioteką ar panaudoti specialią FTDI mikroschemą (schema žemiau) - tiesiog žiūrint kas greičiau, patogiau ar priimtiniau ir pan. Turint konverterį telieka sujungti atitinkamus TX su RX ir galima bandyti komunikuoti.

 

III. Basics - Inicializacija

Dabar pasiaiškinsime kaip pradėti darbą su USART ir kokius registrus reikia valdyti/keisti, jog gautume tai, ko norime - siųsti ir gauti duomenis. USART inicializuojamas nustatant BAUD siuntimo greitį,  STOP bitų skaičių bei PARITY. Toliau lieka tik įjungti patį įrenginį. Visa tai atliekama kaip parodyta žemiau.




BAUD greitis nustatomas keičiant UBBR registrą, kadangi jis yra 16bitų, tai nustatoma žemesnioji L ir aukštesnioji H dalis atskirai. UBBR reikšmę galima paskaičiuoti pagal formulę duotą oficialiame Atmega datasheet.

Kaip minėjau anksčiau - priklausomai nuo kvarcinio rezonatoriaus dažnio ir parinkto BAUD greičio priklauso ir persiuntimo klaidų tikimybė. Su specialaus dažnio kvarciniais rezonatoriais šis klaidų procentas praktiškai artimas 0%.


USBS bitu nustatomas STOP bitų skaičius, jis pavyzdyje praleistas - todėl bus naudojamas 1 STOP bitas. UCSZx nustato duomenų bitų skaičių, kadangi siųsime po vieną baitą, todėl reikia 8 bitų. Taip pat UMSEL bitas nenurodytas (t.y. 0) reiškia, jog USART dirbs asinchroniniu režimu. URSEL - leidimas redaguoti UCSRC registrą. Siuntimo ir gavimo įrenginys įjungiamas nustačius TXEN ir RXEN bitus. Inicializacijai kaip ir viskas.


IV. Basics - Siuntimas ir priėmimas

Toliau duomenų siuntimo ir gavimo funkcijos labai paprastos. Priimant duomenis yra laukiama, kol priėmimo buferyje atsiras duomenų (tikrinamas RXC bitas UCSRA registre - t.y. receive complete) ir grąžinama nuskaityta baito reikšmė iš UDR registro.

Siuntimo atveju viskas vyksta analogiškai - laukiama, kol prieš tai siųsti duomenys bus išsiųsti (UDRE bitas - data register empty), o tada į UDR registrą įrašoma siunčiama reikšmė. Kiekvieno bito siuntimu/gavimu pasirūpina pats Atmega mikrokontroleris. Manau pakankamai paprasta.

V. Basics - Naudojimas

USART patikrinimui galima realizuoti labai paprastą pavyzdį (žr.žemiau) - Echo serverį, t.y. kokius duomenis išsiųsime, tokius gausime atgal - tiesiog atkartosime. Visos programos projektas - straipsnio pabaigoje. Žinoma programos pradžioje reikia inicializuoti USART - tą jau išmokome padaryti. Toliau seka programos veiksmai while cikle - priimame ir siunčiame baitus. Papildomai prie vieno laisvo Atmega PB išvado prijungiau LED, kad būtų matoma, jog siunčiami duomenys.


Toliau programą įrašome į mikrokontrolerį ir galime patestuoti. Tai galima padaryti naudojant terminalo emuliatorių kaip RealTerm. Sukonfiguruojame jį su tokiais pat parametrais kaip ir patį mikrokontrolerį - tokį patį BAUD greitį, STOP ir PARITY bitų skaičių. Pasirenkame tą COM portą, per kurį vyks komunikacija ir spaudžiame "Change" mygtuką. Jeigu viskas sėkmingai, neturėtumėte gauti jokių klaidų ir dešiniajame apatiniame kampe matyti nustatytus parametrus "Port: X 9600 8N1 None". Toliau siuntimą vykdome kitame skirtuke - įrašome siunčiamą tekstą ir spaudžiama "Send ASCII", jeigu viskas gerai - rezultatą turėtume matyti ekrane.


Štai tiek to paprasto USART komunikavimo naudojant Atmega. Norint programos neblokuojančio sprendimo, siūlau skaityti toliau.

VI. Advanced USART

Galbūt pastebėjote, jog ankstesnio metodo pagrindinis trūkumas - blokuojamas programos vykdymas while cikle, kol duomenys nebus išsiųst ar gauti, t.y. mikroprocesorius eikvoja bereikalingus taktus vis tikrindamas milijoną(ar daugiau) kartų per sekundę ar duomenys išsiųsti/gauti. Tokia situacija labai paprastose programose yra priimtina, tačiau norint vykdyti kitus darbus ar atlikti naudingus skaičiavimus - reikia tai likviduoti. Tam naudojami pertraukimai (angl. interrupts). Pertraukimas šiuo atveju - įvykis Atmega sistemoje, kai gaunami USART duomenys. Jo metu trumpam sustabdoma Atmega vykdoma programa ir pereinama vykdyti aprašyto pertraukimo kodo. Jį įvykdžius - programa toliau tęsiama nuo ankstesnio sustojimo taško. Pertraukimui aprašomas specialus vektorius - USART_RXC_vect. Tai specialus kodo fragmentas,  kuris bus vykdomas tik tuo metu, kai gausime duomenis iš siuntėjo. Analogiškas yra ir USART_TXC_vect, kuris kviečiamas kiekvienąkart sėkmingai išsiuntus duomenis (šiuo atveju - praleista, nes nenaudojama). Visus aprašytus pertraukimus galima rasti čia.


Naujame kodo pavyzdyje gautus duomenis iš UDR registro vėl įrašome į jį siuntimui atgal, tačiau tai atliekame vektoriaus viduje. USART inicializavimo metode reikia papildomai įjungti RXCIE bitą, kad aprašytas vektorius būtų aktyvuotas. Ir galiausiai reikia įjungti pertraukimų sistemą su sei() metodu. Pastebėkime, jog dabar pagrindiniame programos metode main() nebeliko jokių siuntimo/gavimo metodų, t.y. nebus blokuojama - galime vykdyti kitus darbus.


VII. Pabaiga

Suprasti USART veikimo principus galbūt nėra iškart paprasta, bet manau panaudojimas yra vienas paprasčiausių iš visų komunikacijos tarp įrenginių metodų. Pabaigai reiktų paminėti keletą svarbių dalykų toliau naudojant USART - papildomai reikėtų pagalvoti apie informacijos buferizavimą programoje - naudoti žiedinį sąrašą (angl. circular buffer) ar pan. jeigu duomenys apdorojami iškart ir yra galimybė nespėti to padaryti. Tam galima naudoti jau esamus sprendimus - pavyzdžiui Peter Fleury USART biblioteką. Taip pat - atkreipti dėmesį į klaidų tikrinimą ir apdorojimą (kas jeigu suklibės kontaktas, ar užstrigs komunikavimo mechanizmas?) - tam skirti Frame Error (FE), Data OverRun (DOR) bitai. Taip pat reikėtų turėti galimybę patikrinti gautų duomenų korektiškumą - panaudoti Parity Error(PE) bitą ar net skaičiuoti kitas kontrolines sumas - CRC16/32. Nepamiršti, jog laukiami duomenys gali taip niekad ir neateiti, t.y. viršyti leistiną priėmimo laiką (angl. timeout). Tokie ir kitokie realizacijos klausimai aktualūs naudojantis USART komunikacijoms priklausomai nuo projekto sudėtingumo. Paprastiems dalykams geriau dėl to tiesiog nesukti sau galvos, o realizuojant sudėtingesnį ir patikimesnį variantą - verta apmąstyti.  Manau jau laikas atsikvėpti - iki kitų susitikimų.

Project download - USART basic
Project download - USART advanced

Komentarų nėra:

Rašyti komentarą