Soros port használata

Ha szeretnéd megérteni, pontosan hogyan működik a soros adatátvitel, akkor itt találsz egy kicsit részletesebb leírást. Az alábbi funkciók használatához ez nem szükséges, de ha van időd, nem árt elolvasni!

A soros port tulajdonképen az Arduino és az ember közötti kommunikáció legolcsóbb módja. A program futásakor keletkező adatokat egyszerűen továbbítjuk a PC-re, és megjelenítjük a képernyőn. A bonyolultabb programok fejlesztésekor, hibakereséskor is ez a legegyszerűbb eszköz a működés nyomon követésére. Kiírhatjuk hol jár a program, mik az aktuális változó értékek. Mindkét fejlesztési környezeteben rendelkezésünkre áll a soros port kezelésére néhány egyszerű program utasítás. Annyi hiányossága van a soros portnak, hogy a magyar ékezetes betűket nem szereti. Legalább is én eddig nem láttam olyan megoldást, ami ne kriksz-kraksz karaktereket jelenített volna meg a képernyőn. Így az egyszerűség kedvéért én egyenlőre lemondtam a magyar ékezetes betűk használatáról.
Most pedig mutatok is egy egyszerű példát, hogyan lehet adatokat kinyerni az Arduino-ból, és egyben arra is, hogyan lehet betuszkolni adatokat az Arduino-ba.

A példa program a következőket csinálja:

  1. Megnyitja a kommunikáció számára a soros portot 9600 baud (bit/sec) sebességgel. A sebesség mértékegysége a soros port esetében a baud, ami a másodpercenként átvitt bitek száma. Mivel egy byte átviteléhez kell egy start, egy stop bit, sőt néha még egy paritás bit is, valamint az egyes byte-ok átvitele között idő is telik el, a tényleges átviteli sebesség 600 byte körül adódik másodpercenként. Mérési eredmények átviteléhez ez bőven sok. Ha videót akarnánk továbbítani, akkor pedig reménytelenül kevés.
  2. A program az Arduino 12-es kivezetését definiálja bemenetnek, a 13-as kivezetést pedig kimenetnek. Értelem szerűen a 12-es lábra nyomógombot kell kötni felhúzó ellenállással, míg a 13-as lábra egy led-et soros ellenállással. Az alábbi ábrát a tavir.hu weboldalról vettem kölcsön:

Sajnos a programot nem ugyanazokra a kivezetésekre írtam meg mint amit az ábrán
látni, de remélem ez nem zavaró túlságosan.

  • A program egy végtelen ciklusában másodpercenként megnézi a 12-es kivezetés állapotát (nyomógomb), és az eredményt kiírja a soros portra.
  • A program másodpercenként beolvas egy karaktert a soros portról a PC felől, és megnézi a beolvasott karakter kódját. Ha ez 49, ami a billentyűzeten az „1”-es szám lenyomásának felel meg, akkor fel vagy lekapcsolja a 13-as kivezetésre kötött LED-et. Először megnézi a kimenet állapotát, és ha az 0, akkor beállítja a kimenetet 1-re, ha pedig a kimenet állapota 1-volt, akkor beállítja 0-ra.
  • Ha egy kiválasztott billentyű kódját kapja meg, akkor lezárja a soros kommunikációt. Az Arduino C programban erre a „2”-es billentyűt használtam, aminek a kódja 50. A BASCOM programban az ESC billentyűt figyelem, aminek a kódja 27. A két program nem teljesen azonos megoldást tartalmaz, mivel a beépített soros kommunikációs programoknak más a működése. A példa programok után erről még írok pár sort.

A kommunikáció lezárására nem lenne igazán szükség, mégis beépítettem a programba, mert egy számomra érthetetlen jelenséget tapasztaltam a BASCOM környezetben. Az történt, hogy miután beégettem a programot a BASCOM-al az Arduino Uno R3-ba, többé nem tudtam új programot beégetni. Kommunikációs hibát jelzett a BASCOM. Nyilván összefügg a dolog azzal, hogy a program ugyanazt a soros portot használja, amin keresztül a program beégetés is folyna. A problémát kétféle módon sikerült megoldani. Először is kipróbáltam, hogy amikor a BASCOM-al már nem tudok programot égetni, akkor mit csinál az Arduino C program. Meglepő módon minden hiba nélkül beégetett bármilyen programot. Vettem hát a klasszikus „Blink” programot és beégettem az Arduino Uno-ra, így már a BASCOM is tudott újra kommunikálni. A másik megoldás már inkább megelőző jellegű. Beépítettem az említett soros port bezáró programrészt a „2”-es illetve BASCOM-ban a „ESC” billentyűre. Így már nem tapasztaltam a jelenséget.

byte test=0;                      //deklarálunk egy test nevű változót, kezdő értéke 0
void setup() {
  Serial.begin(9600);     //soros kommunikáció indul 9600boud sebességgel
  pinMode(13, OUTPUT);     //Arduino 13-as kivezetés kimenet lesz
  pinMode(12, INPUT);         //Arduino 12-es kivezetés bemenet lesz
}
void loop() {
  Serial.print("Bemenet allapota:");   //kiírjuk a soros portra a szöveget
  Serial.println(digitalRead(12));     //kiírjuk a soros portra a szöveg mögé a 12-es kivezetés állapotát, és sort emelünk 
  test=Serial.read();                  //beolvasunk a soros portról egy byte-ot a test nevű változóba                                                          
  if (test==49){                       //ha test változó értéke 49 ("1"-es billentyű), akkor                                                   
    if (digitalRead(13)==LOW) {        //ha a 13-as kivezetés alacsony szinten van (led nem világít)                                                 
      digitalWrite(13,HIGH);           //akkor magasra kapcsoljuk a 13-as kivezetést (led világít)                                                 
      Serial.println("LED vilagit");   //soros portra kiírjuk a szöveget
    }
    else {                             //ha a 13-as kivezetés magas volt akkor (led éppen világított)                                                  
      digitalWrite(13,LOW);            //a 13-as kivezetést alacsony szintre állítjuk (led nem világít)                                               
      Serial.println("LED nem vilagit");  //a soros portra kiírjuk a szöveget
    }
  }
  if (test==50){                       //ha a test változó értéke 50 ("2"-es billentyű) akkor a soros portra kiírjuk a szöveget                                                
    Serial.println("Soros kommunikacio lezarva!");  
    Serial.end();                                      //soros kommunikáció lezárása
  }
  delay(1000);                                         //időzítünk 1 másodpercet
}



Arduino C

A program beégetése után el kell indítani a soros monitort. Ezt az eszközök menüpontban találjuk:

Miután a menüpontok kiválasztottuk azonnal megjelenik a soros monitor. Ekkor az Arduino Uno kap egy reset jelet és a program újraindul. Másodpercenként megjelenik a „Bemenet allapota:1” felirat, hiszen a programot így írtuk meg. Ha nem jelenne meg ez a sor, akkor ellenőrizzük a soros monitor képernyője alján a portsebességet, és ha nem 9600, akkor állítsuk be.

Ha karaktert akarunk küldeni a soros porton keresztül, akkor az ablak tetején lévő beviteli mezőbe írhatjuk be, és meg kell nyomnunk a küldés gombot, vagy leütni ez entert. Egyszerre akár több karaktert is beírhatunk.

BASCOM

$regfile = “m328pdef.dat”            ’ATmega3218P chipet használunk
$crystal = 16000000                     ’órajel 16Mhz
$baud = 9600                                  ’sorosport sebességet 9600boud-ra állítjuk

Config Portb.5 = Output                ’13-as arduino láb kivezetés
Config Portb.4 = Input                  ’12-es arduino láb bemenet
Dim Test As Byte                            ’Deklarálunk egy test nevű változót, ebbe
                                                            ’olvassuk be a lenyomott billentyű kódját,
‘amit a soros porton keresztül kap meg
‘az arduino
Test = 0                                             ’test változó kezdő értéke 0
Do
   Print “Bemenet allapota:” ; Pinb.4     ’Kiírjuk a soros portra a 12-es arduino
‘kivezetés (bemenet) jelszintjét
   Test = Inkey()                                         ’az inkey() beolvassa a soros portról
‘az utoljára lenyomott billentyű kódját
    If Test = 49 Then                  ’ha az utoljára lenyomott billentyű
‘kódja 49 (ezt az “1”-es számjegy), akkor
      If Portb.5 = 0 Then            ’megnézzük a kimenet állapotát és ha 0, akkor
         Portb.5 = 1                        ’kimenetet 1-re kapcsoljuk, led világit
         Print “LED vilagit”
      Else                                        ’egyébként
         Portb.5 = 0                        ’kimenetet 0-ra kapcsoljuk, led elalszik
         Print “LED nem vilagit”
      End If
   End If
   Waitms 1000                ’várunk 1000ms-ot, és újra lefut a ciklust
Loop Until Test = 27      ’ha esc gombot nyomunk, akkor kilépünk a ciklusból
End

A terminal programnak futni kell, különben hiába nyomkodjuk a gombokat!

Most, hogy láttunk gyakorlati példát a soros port kezelésére és használatára, itt az ideje, hogy megismerkedjünk egy nagyon kényelmes kommunikációs megoldással az I2C busszal. Kattints ide, ha szeretnéd megismerni!

Kommunikáció a külvilággal

Intelligens eszközöknek (moduloknak) nevezem azokat, melyek önállóan végeznek el feladatokat, és a begyűjtött adatokat valamilyen módon továbbítják Arduino felé, illetve az Arduino-tól kapott adatokat valamilyen módon feldolgozzák. Ilyen eszközök a hőmérséklet, páratartalom és légnyomásmérők, és még rengeteg érzékelő, és nyilván intelligens eszköznek tekinthető az én önkénes meghatározásomban egy LCD karakteres vagy grafikus kijelző is. Ezeknek az eszközöknek ismertető jele, hogy összetett adatokat közvetítenek vagy várnak működésük során, és nem egy vagy több kivezetés állapotát kapcsolgatják vagy figyelik bambán, mint egy kapcsoló, vagy egy led. Az összetettebb adatok átvitele már bonyolultabb folyamat. Az adatcsere kommunikációt kíván!

Lássunk hát példát a kommunikációs lehetőségekre. Sokféle megoldást találtak ki az informatika néhány évtizedes történetében. Ezekből három félét hardveresen is beleépítettek ATmega328P chipbe. A hardveres beépítés azt jelenti, hogy programunkból csak az adatot kell küldeni, vagy éppen várni kell az adat megérkezésére, de nem kell azzal foglalkozni, hogyan is történik a továbbítás. A használathoz egyetlen megkötés, hogy előre meghatározott kivezetéseket kell használnunk.

A legegyszerűbb kommunikációs megoldás a soros port. Szakirodalomban UART-nak szokták becézni. Azért is egy alap kommunikációs forma, mert pl. az Arduino-ba a programot is ezzel a soros porttal töltjük fel a PC-ről. A PC-n található USB csatlakozó is egy soros port, csak egy fokkal modernebb és összetettebb, mint az, amit az Arduino-ban találunk. Az Arduino Uno-ra ráépítették az USB-soros átalakítót, azért is tudunk közvetlenül programokat tölteni rá, illetve adatokat is tudunk továbbítani a PC és az Arduino kártya között. Az ATmega328 chip használata esetében nekünk magunknak kell egy USB-soros átalakítót építenünk, ha a PC-re akarunk adatokat továbbítani, vagy a PC-ben található “mezei” soros portot kellene használnunk. Már nem minden PC-ben van soros port, időközben elavult, így marad az USB port.

A soros kommunikációról egyenlőre elég annyit tudni, hogy két vezetékkel kötjük össze a beszélgető partnereket, egyiken adás, a másikon vétel zajlik. Kell még egy föld vezeték is az eszközök között, ami egy harmadik vezeték, de ezt nem szokták külön számolni, mert általában a tápfeszültség két vezetékének egyike a földvezeték, és automatikusan rendelkezésre áll. Távoli berendezések esetén azonban ez is kelleni fog. Tehát a kettő, az valójában három.
Az átvitelre szánt adatokat egy start, és egy stop jelzéssel látjuk el, a kettő között találhatók az értékes adatok. A részletek most nem érdekesek. Nem kell tudni, hogy miként működik, elég ha használni tudod. Itt találsz konkrét példákat a soros port használatára. Ha részletesebben is szeretnéd megismerni a soros kommunikációt, akkor kattints ide!

Az egyszerű soros kapcsolat igen buta, csak egy-egy eszköz tud egyszerre beszélgetni a két vezeték felhasználásával. Ha az Arduino-nak több különböző külső modullal is beszélgetnie kell, hamar elfogynak a kivezetések, ráadásul csak egy hardveresen beépített soros portunk van. Erre a problémára jelent megoldást az I2C kapcsolat. Ebben már az egyes eszközök címmel rendelkeznek, és ugyanazon a két vezetéken többen is kommunikálhatnak. Nyilván ennek a megoldásnak a hátránya, hogy az értékes adatok mellett egy csomó adminisztráció is áramlik (címek, parancsok stb.), és ezért a kommunikáció sokkal lassúbb, de valamit valamiért! Igen elterjedt az I2C, már szinte minden eszközbe beépítik. Használtam már hőmérőt, LCD kijelzőt, eeprom-ot is ezzel a kommunikációval. Itt láthatsz egy példát a használatára és a fontosabb tulajdonságaira, részletesebben pedig itt ismerheted meg a működését. Az I2C busz természetesen arra is alkalmas, hogy két Arduino alaplap és program cseréljen adatokat. Gyakorlati példát találsz itt!

A soros kommunikáció azért lassú, mert egy vezetéken zajlik az információ átvitele. Az I2C előnye, hogy akár 127 eszközt is felfűzhetsz párhuzamosan egy vezetékpárra, de még a soros portnál is lassúbb lehet a rengeteg adminisztratív adatcsere miatt. Ha valamilyen okból nagy sebességre van szükség, akkor egyik sem az igazi. Erre az eshetőségre találták ki az SPI kommunikációt. Ez az adatátviteli megoldás minimum 3 vezetékkel működik. Van egy oda-vissza adatvezeték pár, és egy órajel vezeték. Az órajel vezeték megmondja, mikor van értékes adat a jelvezetéken. Ettől az átvitel sokkal gyorsabb. Nem kell start és stop bit, az egyes átvitt byte-ok között nem kell szünet, sőt teljesen folyamatos lehet az adatáramlás. Ha több eszközzel is kell egyszerre kommunikálni, akkor minden egyes eszközhöz kell még egy olyan vezeték, ami jelzi, hogy vele akarunk dolgozni. Vagyis eszközönként kell még egy-egy kiválasztó vezeték. Láthatóan szaporodik az összeköttetések száma, de cserébe nagyobb sebességet kapunk. Ennek eredménye, hogy a grafikus kijelzőkön akár animációkat is megjeleníthetünk, vagy az SD kártyáról zenét tudunk lejátszani. Mindez átlagos soros porton vagy I2C-n keresztül nem menne. Már el is árultam melyek azok a modulok, melyeknél várhatóan SPI kommunikációt használunk. Ha ide kattintasz, akkor láthatsz példát arra, hogyan is lehet használni egy SPI kapcsolattal működő eszközt, az SD kártyát. Ha többet szeretnél megtudni az SPI működéséről, akkor kattints ide!

Van azonban még egy fontos felhasználás, ez pedig az ATmega328 programozása. Nem kell feltétlenül soros portot használni a program betöltésre. A soros porton keresztül történő programozás egyébként is feltételezi, hogy a chip-be úgynevezett bootloader programot töltöttek, ami nagyon kényelmessé teszi az esetleges programbetöltési igényeinket. A chip-be épített SPI arra is jó, hogy betöltsük a programot akár úgy is, hogy a chip már be is lett forrasztva egy konkrét áramkörbe. Mindössze néhány vezetéket kell valamilyen módon csatlakoztatni a chip megfelelő kivezetései, és egy programozó közé. Ezeket a csatlakozásokat a gyártók előre elő is készítik. Magán az Arduino-n is megtaláljuk ezeket a kivezetéseket. A programozók ugyanezzel a csatlakozóval rendelkeznek, és ha kell összedugjuk a kettőt, már mehet is a program közvetlenül a chip-be. Nem kell semmi más, még tápfeszültséget is a programozó ad a chip-nek.

Ha az is érdekel, hogyan lehet az Arduino-t ISP buszon keresztül programozni, akkor kattints ide!

Még közel sem értünk a végére! Az Arduino alaplapoknak még nagyon sok tulajdonságát érdemes megismerni. Itt olvashatsz a megszakításokról, amivel ritkán előforduló eseményeket érdemes figyelni és hatásukra beavatkozni a folyamatokba.

Ha elemes kapcsolásokat szeretnél készíteni, akkor az Arduino elalvási funkcióit kell megismerned.

Ha programod túl összetett, és időnként lefagy, de nem találod a megoldást, nem szabad elkeseredni. A watchdog funkció segíteni fog!

Soros adatátvitel működése

Az Arduino mikrovezérlőjén van két olyan kivezetés (D0 és D1), amelyeknek megkülönböztetett funkciójuk van. A két kivezetést együtt soros portnak hívjuk. Az egyik kivezetés az adatokat fogadja (Rx – receiver), a másik pedig küldi (Tx – transmitter). A soros átvitel bitenként zajlik, vagyis egy időben egyetlen bit halad át a vezetéken. Ennek megfelelően a kommunikáció sebességét a másodpercenként átvitt bitek számával mérjük. Az Arduino maximális átviteli sebessége 115200 bit másodpercenként.

Az adatok ugyan bitenként, de egymástól jól elhatárolható csomagokban közlekednek. Ezek az adat csomagok START jelből, 8 bit adatból (1 byte) és két STOP jelből állnak, melyeket az adatvezetéken megjelenő feszültség jelképez.
Adó egység működése: Nyugalmi állapotban az adó egység magas jelszintet tart a jelvezetéken. Ez kb 5V feszültséget jelent. Amikor adatokat akar átadni, meghatározott időre 0V-ot kapcsol a jelvezetékre. Ez a start jelzés. Ezt követően meghatározott időközönként 0V és 5V feszültségeket kapcsol a jelvezetékre attól függően, hogy az átadni kívánt byte-nak melyik bitje 0 és melyik 1. Az átvitel a legkisebb helyi értékű bittel kezdődik. Ha az adó végzett mind a nyolc bittel, akkor két időegységnyi stop jelzés következik, hogy a vevő alaphelyzetbe tudjon állni, és ezzel vége a az adott byte átvitelének.

Vevő egység működése: Mivel a vevő egység nem tudja, hogy mikor következik adatok küldése, folyamatosan figyeli az adatvezeték feszültségét. Mindaddig amig 5V-ot talál, addig várakozik. A start bit értelem szerűen egy 0V-os feszültség érték. A vevő ekkor a start bit megjelenését követően meghatározott időközönként megnézi a jelvezeték feszültségét. Ha éppen 0V-ot talál, akkor az LOW, ha 5V körüli értéket, akkor az HIGH. Mivel 8 bitet akarunk átvinni, 8 alkalommal néz a vonalra. Az időpillanatokat a vevő saját maga időzíti, ezért nem árt, ha az adó és a vevő áramkör órája ugyanolyan gyorsan ketyeg. Nagyon fontos, hogy az adás és a vétel sebessége azonos legyen. A nyolc bit vétele után a vevő még egy alkalommal ránéz a vonalra, és ellenőrzi a két időegységnyi stop jelzés meglétét. Ha ekkor alacsony feszültséget talál a vonalon, akkor hiba van. Mivel a jelvezetékek hossza és a környezet zavarjel impulzusai megzavarhatják az adatátvitelt, különböző sebességeket lehet beállítani. Zavarjelekkel terhelt nagyon hosszú jelvezetékeken az átviteli sebesség legyen kicsi (pl. 9600 bit/sec vagy még kisebb), míg rövid vezetékeken lehet a maximum.

Az univerzális aszinkron soros adatküldés és fogadás története a géptávírók koráig nyúlik vissza. Akkoriban nagyon kicsi sebességekkel dolgoztak, úgy emlékszem 110 bit/sec volt a jellemző sebesség. Egy villanymotor által forgatott mechanikus tengelyen elhelyezett érintkezők állították elő a jelsorozatot a leütött billentyű alapján. Az adó és a vevő egység sebességét össze kellett hangolni. Ehhez a forgó tengelyre szerelt korong nyújtott segítséget. A korongra csíkokat festettek, és ha azt egy rezgésbe hozott hangvilla által nyíló és záródó résen át nézték, akkor megfelelő sebességnél a csíkokat állni látták. A villanymotor fordulatszámát addig változtatták, amíg a csíkok álltak. Már csak a vevő és adó egységnél használt hangvilláknak kellett azonosnak lenniük, hogy szinkronban legyenek a szerkezetek. No meg sokat kellett ellenőrizni a villanymotor sebességét. Akkoriban a kicsi átviteli sebesség miatt nem nagyon kellett átviteli hibákkal foglalkozni. Ahogyan nőtt a sebesség, már előfordult, hogy az átvitel során egy-egy bit megsérült, pl. 0 helyett a vevő 1-et olvasott egy zavarimpulzus miatt. Ezért idővel a soros kommunikációban megjelentek az átvitel helyességét ellenőrző megoldások. A nyolc értékes bit mellett még egy 9. bitet is átvittek, ez a paritás bit. Az elv egyszerű, összeadták a nyolc bit értékét, és az eredmény maradéka lett a paritás bit értéke. Vételkor is megismételték a nyolc bit összeadását, és kiszámolták a paritás értékét. Ha ez megegyezett az átküldött paritás értékével, akkor valószínűleg nem sérült az adat.
A paritás bit használta opció, kikapcsolható a használata, mert ez növeli a sebességet.

Az soros átvitel gyűjtőneve UART kommunikáció. Eredetileg bipoláris jelszintekkel történt az átvitel. Pl. az RS-232 szabvány szerint az ‘1’ -12 V és -5 V közötti, a ‘0’ pedig +12 V és +5 V közötti jelszint. A mikrovezérlők és a logikai IC-k világában azonban természetesebb megoldás az unipoláris jelszint alkalmazása: ‘1’ a digitális rendszer logikai  magas jelszintje (+5 V, az egyes eszközöknél +3,3 V), a ‘0’ pedig az alacsony logikai szint (0 V). Tétlen állapotban, amikor nincs adatküldés, az adás vonalat (TX) mindig magas szint.

Egy bit időtartama az adatküldés sebességétől függ. A szabványos adatsebességek: 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 bit/s. Pl. A 9600 bit/s azt jelenti, hogy egy bitre 1 s/9600  = 0,00010416667 s, azaz 104,1667 µs idő jut. A start és stop (esetleg paritás) bitek miatt a hasznos adatok továbbítási sebessége kisebb, mint az aktuális adatküldési sebesség. Mivel a mikrovezérlők konkrét és kerek órajel frekvenciákkal dolgoznak (pl. az Arduino Uno 16Mhz), nem feltétlenül egyszerű feladat a pontos bitidők előállítása.

Ha megismerted az UART kommunikáció részletes működését, esetleg érdekelhet az I2C kommunikáció is. Kattints ide, ha igen!

Ha szeretnél gyakorlati példát látni arra, hogyan használhatod a soros portot Arduino programban, akkor kattints ide!