Fórum témák

» Több friss téma
Cikkek » Soros LCD vezérlőpanel használata AVR-rel
Soros LCD vezérlőpanel használata AVR-rel
Szerző: Fizikus, idő: Jún 20, 2010, Olvasva: 35273, Oldal olvasási idő: kb. 4 perc
Lapozás: OK   3 / 6

Szoftveres adatküldő UART rutin

Az aszinkron soros kommunikáció az információt egymás után, bitről-bitre továbbítja. Az AVR hardveres UART-ja automatikusan küldi es fogadja a kimenő és bejövő adatokat, beállítja a mintavételezést az Rx lábon, az időzítést pedig a TX lábon és magától visszajelzést küld a folyamatok állapotáról.

Mint azt már korábban említettem, az ATMega8 hardveres UART-ját a robot és a PC közötti kommunikációra akarom majd használni, ezért a mikrovezérlő és az LCD panel közötti soros kommunikációt egy szoftveres UART rutinnal oldottam meg. Ennek használata nehézkesebb mint a hardveres UART-é. A soros kommunikáció lépéseit nekünk kell szoftveresen időzíteni és végrehajtani a programunkban. Nagyon oda kell figyelni a programszervezésre, hogy a szoftveres UART stabil maradjon. Az esetleges megszakítások nehogy felborítsák az adatküldés időzítését.

Szerencsére az LCD és az AVR között csak egyirányú a kommunikáció (csak a kiírandó adatot küldjük az LCD-re), ez nagymértékben leegyszerűsíti a feladatot, mert nem kell megírni a szoftveres UART adatfogadó algoritmusait. (akinek kétirányú szoftveres UART rutin kell, az nézzen körül a neten)

Nézzük meg a soros adatküldés lépéseit a soros LCD vezérlőpanel által használt 9600bps kommunikációs sebesség esetén (a szoftveres UART programunk is pontosan ezt fogja tenni):

  •  Logikai 1 jelet adunk a kiválasztott I/O lábra (Stop bit, várakozó állapot)
  •  Ha adatot akarunk küldeni, akkor Logikai 0-t kapcsolunk a kiválasztott I/O lábra (Start bit)
  •  A Timer0 használatával beállítjuk, hogy pontosan 104us-ig legyen a lábon a Start bit.
  •  Megadunk egy ciklust, ami először az adatbit legkisebb helyiértékű bitjet adja 104us-ig az I/O lábra, majd egymás után az egyre magasabb helyiértékű biteket is az I/O lábra küldi, pontosan 104us-os időintervallumokban.
  •  Az utolsó adatbit után az adatküldést egy Stop bit-tel fejezzük be (Logikai 1 jelet adunk a kiválasztott I/O lábra, várakozó állapot)


A Timer0 8 bites számlálója 0-tól kezdve számol felfelé egyesével folyamatosan, amíg el nem éri a 255-öt, 255 után a számláló túlcsordul és lenullázódik, majd 0-tól ismét újrakezdi a számolást. A periódusidő az előosztás értékétől függ. Ezzel a Timerrel kell majd egy 104 us-os késleltető rutint előállítani.

Mivel a Timert időzítésre akarom használni (pontosabban csak egy adott ideig akarok csak késleltetni), és nem egy adott időközönként folyamatosan ismétlődő periodikus jelet akarok előállítani, ezért nem kell használni a Timer0 túlcsordulásához tartozó megszakítást. Elég lesz a túlcsordulást jelző TOV0 bitet figyelni (mivel a megszakítás ninncs bekapcsolva, ezért ezt a jelzőbitet nekünk kell majd a programunkonn belül törölni).

A soros LCD panel 9600 bps sebességgel kommunikál, ezért egy bit 104us-ig tart. Ha a Timer előosztása 1, akkor ez alatt az idő alatt a számláló 768-ig számolna el ( 7.372800/9600 = 768 órajelütem/bit ). Ez túl sok, mert a Timer0 számlálója 0-tól csak MAX 255-ig tud számolni. De szerencsére a 768-at az előosztással csökkenteni tudjuk.
A Timer0 esetén a következő lehetséges előosztás érték a 8. Ekkor a Timer0 96 ütemet számlál 104us alatt (7.372800/(8*9600) = 96 órajelütem) Ez már jó lesz, mert kisebb mint 255.
Mivel a Timer0 csak felfelé tud számolni, és a hozzá tartozó MAX érték nem változtatható, fixen 255, ezért nem tununk 0-tól 96-ig elszámolni. A TCNT0 regiszterrel a számláló kezdeti értéke viszont szabadon változtatható. Ezért 255-96=159-től 255-ig éppen 96 ütemet számol el a Timer, pontosan 104 us alatt , utána túlcsordul és újrakezdi a számolást, de előtte átállítja a TOV0 jelzőbit értékét a TIFR regiszterben.  Ezért a számlálót 159-től indítva, és a TOV0 jelzőbit értékét figyelve megadhatunk egy 104us-ig tartó szoftveres késleltető rutint.

Az alábbi kóddal létrehozok egy függvényt, ami meghívása esetén a paraméterként megadott értékre állítja a TCNT0 regiszter értékét, bekapcsolja a Timer0-t, majd a számláló túlcsordulása után nullázza a TOV0 jelzőbitet és kikapcsolja a Timert.

  1. void kesleltetes(unsigned int _tick) // Szoftveres UART beallitasa
  2. {
  3.           TCNT0 = _tick;  // a szamlalo beallitasa a fuggvenyben szereplo ertekre
  4.           TCCR0 = (1<<CS01);  // Start Timer0, CLK/8
  5.           while (!(TIFR & (1<<TOV0)));  // varakozas amig a szamlalo eleri maximalis erteket
  6.           TIFR |= (1<<TOV0);  // Tulcsordulas jelzobit torlese
  7.           TCCR0 = 0;  // Stop Timer0
  8. }

A szoftveres adatküldő UART rutinnal bármelyik I/O lábat használhatjuk kimenetnek. Ezért érdemes az egyes portok kezelését leegyszerűsítő függvényeket használni. Az alábbi ki_c(x,y) függvénnyel pl. PORTC lábainak állapotát tudjuk nagyon egyszerűen változtatni. Az utasítás a PORTC x.-ik lábára 0V-ot vagy 5V-ot ad, attól függően hogy y értéke 0 vagy 1. Először a lábat kimenetnek adjuk meg, majd ha y = 1, akkor a lábra 5V-ot adunk. Ha y = 0, akkor pedig 0V-ot adunk. Például a ki_c(5,1) utasítás a PORTC 5. lábára 5V-ot ad, a ki_c(0,0) utasítás pedig a PORTC 0. lábára 0V-ot.

  1. void ki_c(char _bit,char _dat) /* ki_c(x,y) fuggveny definialasa PORTC-re. PORTC x. labara 0V-ot vagy 5V-ot adunk, attol fuggoen hogy y erteke 0 vagy 1 */
  2. {
  3.            DDRC |= _BV(_bit); // PORTC x. lab kimenet
  4.            if(_dat)
  5.                PORTC |= _BV(_bit); // ha y=1, az x. labra 5V-ot ad
  6.            else
  7.                PORTC &= ~_BV(_bit); // ha y=0, az x. labra 5V-ot ad
  8. }

A fenti függvények felhasználásával létrehozhatjuk magát a szoftveres adatküldő UART függvényt, ami először a Start bitet, majd egy 8-szor ismétlődő cikluson belül a küldendő adatbájt bitjeit egymás után, végül pedig a Stop bitjeit kapcsolja  egyenként 104 us-ig a megadott I/O lábra.

  1. void SzoftUARTKuld(char tx, unsigned char adat) //
  2. {
  3.           int i;
  4.           ki_c(tx,0);  // Start bit
  5.           kesleltetes(159);  // kesleltetes 104us-ig
  6.           for (i=0;i<8;i++)   // 8 szor ismetlodo ciklus
  7.           {
  8.              ki_c(tx,adat & 0x01);  // adatbit kuldese
  9.              kesleltetes(159);  // kesleltetes 104us-ig
  10.              adat = adat>>1;  // eltolas a kovetkezo bitre
  11.           }
  12.           ki_c(tx,1);  // Stop bit
  13.           kesleltetes(159);  // kesleltetes 104us-ig
  14. }


Ezzel elméletben már el is készült a szoftveres adatküldő UART rutin de még módosítanunk  kell rajta egy kicsit hogy működőképes legyen. Ugyanis a programban használt ki_c(a,b) függvény végrehajtása is időbe telik (kb. 20us), ezért a Timer0-t egy változtatható mértékű offszet érték közbeiktatásával úgy állítjuk be, hogy ne pontosan 104us után csorduljon túl, hanem kb. 20 us-al korábban (ne 159-től kezdje a Timer a számlálást hanem 177-től). Ennek az offszetnek az értékét kísérletezgetéssel állapítottam meg.

Az adatküldő függvényre alapozva létrehozunk egy SzoftUARTKuldSzoveg() függvényt is, amivel már nemcsak karaktereket, hanem szöveget is küldhetünk.

A szoftveres adatküldő UART rutinunk végső formájában így néz ki:

  1. #define offset 18
  2. unsigned int idoalap;
  3.  
  4. void KonfigSzoftUART(char tx) // Szoftveres UART beallitasa
  5. {
  6.            ki_c(tx,1);  // kezdetkent egy Stop bit-et adunk meg
  7.            TCCR0 = 0;  // Stop Timer0
  8.            TIFR |= (1<<TOV0);  // Tulcsordulas jelzobit torlese
  9.            idoalap = 255-(96 - offset);
  10. }
  11.  
  12. void kesleltetes(unsigned int _tick) // Szoftveres UART beallitasa
  13. {
  14.           TCNT0 = _tick;  //
  15.           TCCR0 = (1<<CS01);  // Start Timer0, CLK/8
  16.           while (!(TIFR & (1<<TOV0))); // varakozas amig a szamlalo eleri a kivant erteket
  17.           TIFR |= (1<<TOV0);  // Tulcsordulas jelzobit torlese
  18.           TCCR0 = 0;  // Stop Timer0
  19. }
  20.  
  21. void SzoftUARTKuld(char tx, unsigned char adat) //
  22. {
  23.           int i;
  24.           ki_c(tx,0);  // Start bit
  25.           kesleltetes(idoalap);  // kesleltetes a megadott idoalap-ig
  26.           for (i=0;i<8;i++)
  27.           {
  28.              ki_c(tx,adat & 0x01);  // adatbit kuldese
  29.              kesleltetes(idoalap); //kesleltetes a megadott idoalap-ig
  30.              adat = adat>>1;  // eltolas a kovetkezo bitre
  31.           }
  32.           ki_c(tx,1);  // Stop bit
  33.           kesleltetes(idoalap); // kesleltetes a megadott idoalap-ig
  34. }
  35.  
  36. void SzoftUARTKuldSzoveg(unsigned char tx, char *p)    // Szovegkuldo fuggveny definialasa
  37. {
  38.            while(*p)
  39.            {
  40.              SzoftUARTKuld(tx, *p++);
  41.            }
  42. }

Már csak az LCD-t kell vezérelni a megfelelő parancsokkal.


A cikk még nem ért véget, lapozz!
Következő: »»   3 / 6
Értékeléshez bejelentkezés szükséges!
Bejelentkezés

Belépés

Hirdetés
XDT.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem