Alfanumerikus LCD modulok programozása
Ha már megismertük az I/O portok használatát, akkor nyitva áll az út ahhoz is, hogy alfanumerikus (szöveges információ megjelenítésére alkalmas) LCD kijelző modulok vezérlésével foglalkozzunk. Folyadékkristályos kijelzőkkel (LCD = Liquid Crystal Display) a mindennapi életben számos területén találkozunk, hiszen elterjedten alkalmazzák különféle készülékek (pl. zsebszámológépek, lézernyomtatók, digitális mérlegek, digitális karórák, kenyérsütők, telefonok, italautomaták, digitális lázmérők stb.) kijelzőjeként
A címben is említett "kijelző modul" kifejezés arra utal, hogy mi nem közvetlenül az LCD kijelző szegmenseit vezéreljük, hanem olyan LCD-t használunk, ami egybe van építve az ipari szabványnak tekinthető HD44780, vagy azzal kompatibilis IC-re épülő vezérlő áramkörrel is, ami az LCD kijelzőhöz erősített nyomtatott áramköri lapon helyezkedik el.
Az alfanumerikus LCD modulok bekötése
A háttérvilágítással rendelkező kijelzőknek összesen 16 kivezetése van, a reflexiós típusúaknak pedig csak 14. Előfordul azonban, hogy a nem használt 15. és 16. kivezetést is elkészítik, hogy a panel csatlakozója kompatibilis legyen a háttérvilágítással rendelkező kijelzőkével. Az alábbi képen egy tipikus 16x2 karakteres (két sorban, soronként 16 karakter megjelenítésére képes) kijelző lábkiosztását mutatjuk be.
6_1. ábra: Egy tipikus 16x2 LCD modul lábkiosztása
Az LCD modul kivezetéseinek funkcióit az alábbi táblázatban foglalhatjuk össze:
6_1. táblázat: Az LCD modul kivezetései
Sorszám | Jel | Funkció |
1. |
VSS |
A tápegység negatív sarka, GND |
2. |
VCC |
Tápfeszültség (többnyire +5 V) |
3. |
VEE |
Kontraszt szabályozó jel (többnyire 0,5 V körül) |
4. |
RS |
Parancs/adat választó (Register Select |
5. |
R/W |
Olvasás/írás (adatáramlási irány választása) |
6. |
E |
Enegedélyező jel (Enable) |
7. |
D0 |
Adatbusz 0.bit |
8. |
D1 |
Adatbusz 1.bit |
9. |
D2 |
Adatbusz 2.bit |
10. |
D3 |
Adatbusz 3.bit |
11. |
D4 |
Adatbusz 4.bit |
12. |
D5 |
Adatbusz 5.bit |
13. |
D6 |
Adatbusz 6.bit |
14. |
D7 |
Adatbusz 7.bit |
15. |
A |
A háttérvilágítás pozitív sarka (LED anód) |
16. |
K |
A háttérvilágítás negatív sarka (LED katód) |
A D7-D0 lábak a kétirányú adatvonalak, amelyeken keresztül a mikrovezérlő és az LCD modul adatokat cserél. Lehetőség van a modul 8-bites, párhuzamos porton történő vezérlésére, de azt is megtehetjük, hogy takarékosságból csak négy adatvonalat használunk (hogy pl. kis lábszámú mikrovezérlő minél kevesebb kivezetést foglaljunk le az LCD vezérlésére). Mi ezt az utóbbi, 4-bites módot fogjuk használni.
A HD44780 vezérlőnek kívülről két regiszterét érhetjük el. A parancsregiszterbe a vezérlő utasításokat tölthetjük bele (pl.képernyőtörlés, kurzor mozgatása, üzemmód beállítása, stb). Az adatregiszterbe a kiírandó karakterek kódját, vagy a felhasználó által definiálható karakterek bitképét írhatjuk be. A regiszterek közötti választás az RS vonal (RS = Register Select) beállításával történhet: ha az RS lábra magas szintet kapcsolunk (logikai '1'), akkor az adatregisztert, ha pedig alacsony szintet (logikai '0') kapcsolunk, akkor a parancsregisztert választjuk ki.
Az R/W vonalon az adatáramlás irányát állíthatjuk be: R/W = 0 írást, R/W = 1 olvasást jelent. Az E (Enable) vonal alaphelyzetben alacsony (logikai '0') szinten van. Az adatvonalak és az RS, R/W vezérlő vonalak beállítása után rövid időre az E vonalat magas szintre, majd újra alacsony szintre állítjuk (pulzálás). A tényleges adatátvitel ekkor, az E jel magas szintre váltásakor történik.
Az LCD modul és az MSP430 Launchpad kártya összekapcsolása
A Launchpad kártya és az LCD modul összekapcsolásánál az alábbi szempontokat kell figyelembe venni:
- A Launchpad kártya 3,5 V-os tápfeszültséggel működik, az LCD modulok döntő többsége pedig 5 V-os. Gondolnunk kell tehát a két rendszer illesztésére. Szerencsére az LCD modul TTL kompatibilis jelszintekkel dolgozik, így a mikrovezérlő által kiadott magas jelszinten magas szintként érzékeli. A fordított irányban azonban nem kompatibilis a két rendszer, mivel az MSP430G2xx mikrovezérlők nem tolerálják az 5 V-os jelszintet. Ez azt jelenti, hogy nem használhatjuk az LCD modul foglaltságának figyelését (lásd: Read Busy Flag parancs), s hogy véletlenül se kapcsolhassunk vételre, az LCD modul R/W kivezetését fixen lekötjük a földre.
- Ahogy fentebb már írtuk, az LCD modul 5 V-os tápfeszültséget igényel. Honnan vegyük ezt a feszültséget? Legegyszerűbben onnan, ahol van, illetve bejön: az USB csatlakozóról! Szerencsére ez már ki is van vezetve a TP1 forrasztási pontra, így ide könnyen csatlakozhatunk.
- Az LCD modul VEE kivezetésére olyan feszültséget kell kötni, ami kb. 4,5 V-tal alacsonyabb az LCC modul tápfeszültségénél. Ennek a feszültségnek a beállítása azért fontos, mert ez szabályozza a kijelző kontrasztját. Az optimális érték a hőmérséklettől is függ. Ezt a feszültséget többnyire egy, az 5 V és a föld közé kötött 10 kohmos értékű potenciométerrel szokták beállítani. Az esetek többségében azonban tökéletesen megfelel az is, ha a VEE lábat vagy közvetlenül, vagy egy 500 ohm - 1 k ohm közötti értékű ellenálláson keresztül a földre kötjük.
- A mikrovezérlőn kevés kivezetésére való tekintettel mi az LCD modult négybites módban vezéreljük, tehát az adatvonalak közül csak 4 db-ot, a D7...D4 kivezetéseket használjuk. Ezen kívül az RS és az E vezérlő bemeneteket kell meghajtanunk, így összesen 6 db I/O kivezetést foglalunk le. Az adatvonalakat mi a P1 port P1.7...P1.4 lábaira, Az RS (regiszter választás) vonalat a mikrovezérlő P2.6/Xin lábára, az E (engedélyező) vonalat pedig a mikrovezérlő P2.7/Xout lábára kötöttük. Természetes az utóbbi két vonalat köthetjük máshová is, csak a program elején a definíciókat módosítani kell.
6_2. ábra: Az MSP430 Launchpad kártya és az LCD modul összekötésének vázlata
Az alfanumerikus LCD modulok parancskészlete
A programozáshoz tudnunk kell, hogy az LCD modul milyen parancsokat fogad. A HD44780 vezérlő által elfogadott parancsokat az alábbi táblázatban foglaltuk össze, ahol a nyolc adatbiten kívül az RS és az R/W vezérlő jelek állapotát is feltüntettük. Vegyük észre, hogy a parancsokat a legmagasabb helyiértéken található 1-es azonosítja (lásd az alábbi táblázat átlóját!). A parancs esetleges paraméterei az alacsonyabb helyiértékeken helyezkednek el. A "*" jellel megjelölt pozíciók értéke közömbös (don't care bit).
6_2. táblázat: A HD44780 vezérlő parancskészlete
R/W | RS | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | Funkció |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
Clear display: Törli a képernyőt és alaphelyzetbe helyezi a mutatót (0 cím) |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
* |
Cursor home: Alaphelyzetbe állítja a mutatót és a képernyő eltolást. |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
I/D |
S |
Entry mode set: Beírási mód (I/D = mutató léptetés, S= képernyő eltolás) beállítása. |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
D |
C |
B |
Display control: Display ki/be (D), mutató ki/be (C), villogó kurzor ki/be (B) |
0 |
0 |
0 |
0 |
0 |
1 |
S/C |
R/L |
* |
* |
Shift cursor/screen: Mutató vagy a képernyő (S/C) eltolása jobbra/balra (R/L) |
0 |
0 |
0 |
0 |
1 |
DL |
N |
F |
* |
* |
Function set: adatút-szélesség (DL), sorok száma (N) és fontméret (F) beállítása |
0 |
0 |
0 |
1 |
A5 |
A4 |
A3 |
A2 |
A1 |
A0 |
CGRAM cím beállítása |
0 |
0 |
1 |
A6 |
A5 |
A4 |
A3 |
A2 |
A1 |
A0 |
DDRAM cím beállítása |
1 |
0 |
BF |
A6 |
A5 |
A4 |
A3 |
A2 |
A1 |
A0 |
Read busy flag: foglaltság figyelése |
0 |
1 |
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
Write data: adat írása a korábban megcímzett CGRAM vagy DDRAM területre |
1 |
1 |
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
Read data: adat olvasása a korábban megcímzett CGRAM vayg DDRAM területről |
A paraméterek jelentése az alábbi táblázatból olvasható ki:
6_3. táblázat: A fenti parancsok paramétereinek jelentése
I/D |
0: csökkent a kurzor pozícióját |
1: növeli a kurzor pozícióját |
S |
0: nincs képernyő eltolás |
1: van képernyő eltolás |
D |
0: megjelenítés letiltása |
1: megjelenítésengedélyezése |
C |
0: kurzor megjelenítés letiltása |
1: kurzor megjelenítés engedélyezése |
B |
0: kurzorvillogás letiltása |
1: kurzorvillogás bekapcsolása |
S/C |
0: kurzor mozgatása |
1: képernyő eltolása |
R/L |
0: balra mozgatás |
1: jobbra mozgatás |
DL |
0: 4 bites adatáramlás |
1: 8 bites adatáramlás |
N |
0: egysoros megjelenítés |
1: kétsoros megjelenítés |
F |
0: 5x7 font |
1: 5x10 font |
BF |
0: parancsfogadásra kész |
1: foglalt, belső művelet végrehajtása zajlik |
Az LCD vezérlő utasításai kicsit részletesebben
A Clear Display utasítás szóközzel tölti fel az adatmemóriát (DDRAM). Utána nullára állítja a címregiszter és alaphelyzetbe állítja a képernyőeltolást. Más szavakkal: törli a képernyőt és a kurzor a bal felső sarokban jelenikmeg (ha láthatónak van beállítva). Az I/D bitet pedig növekményes módba állítja (a kurzor pozíció eggyel nő minden beíráskor).
A Cursor Home utasítás nullára állítja a címregisztert és a képernyő eltolást. A DDRAM tartalma nem változik. a kurzor a bal felső sarokba kerül.
Az Entry mode Set utasítás a beviteli módot állítja be. Az I/D bit értéke szabja meg, hogy karakter beíráskor a kurzor jobbra lépjen (I/D=1) vagy balra lépjen (ennek megfelelően a következő karakter kórja a DDRAM következő, eggyel nagyobb vagy kisebb című rekeszébe kerüljön). A beállított kurzorléptetési irány vonatkozika CGRAM-ba történő írásra is. Az S bit a képernyő eltolását szabályozza. A képernyő eltolását az S = 1 beállítás engedélyezi. Egyébként a képernyő nemtolódik el. Ha a képernyő eltolást engedélyezzük, úgy látjuk, mintha a kurzor nem mozdulna el beíráskor, a képernyő viszont igen. A képernyő nem tolódik el, amikor olvasunk a DDRAM memóriából. Nem tolódik el aképernyő a CGRAM írása vagy olvasása esetén sem.
A Display Control utasításnak három paramétere van: D, C és B, amelyekel a megjelenítést (D=display), a kurzort (C=cursor) és a kurzor villogását (B=blink) kapcsolhatjuk ki (0) vagy be (1).
A Shift Cursor/Screen utasítással a kurzort vagy a képernyőt tolhatjuk jobbra vagy balra, anélkül, hogy az adatmemóriár (DDRAM) írnánk vagy olvasnánk. Az S/C paraméter '0' értéke a kurzot, '1' értéke a képernyőt választja ki, az R/L bit pedig a léptetés irányát szabja meg (0: balra, 1: jobbra). Eltoláskor a címregiszter (a következő beírás helye a memóriában) nem változik meg.
A Function Set utasításnak nagyon fontos szerepe van: az LCD üzemmódját állítja be a vezérlő inicializálásakor.
Fontos tudni, hogy az üzemmód inicializálásonként csak egyszer állítható be! DL az adatút szélességét állítja be (0: 4 bites, 1: 8 bites). Ha 4 bites üzemmódot állítunk be, akkor a D7, D6, D5, D4 adatvonalakat kell használni, s a kiírandó adatnak először a magasabb helyiértékű felét írjuk ki, ezt követően pedig az alacsonyabb helyiértékű felét. Az N paraméter a sorok számát szabja meg: N=0 egysoros mód, N=1 kétsoros mód. Az F paraméter '0' értéke az 5x7-s fontot, az '1' értéke pedig az 5x10-es fontot választja ki.
A CGRAM cím beállításására akor van szükség, ha a felhasználó által definálható karakterek bitképét akarjuk feltölteni. A 0. címre írjuk az első karakter legfelső pontsorát (csak az alsó 5 helyiérték bitje számít), az 1.címre az első karakter felülről második pontsorát, és így tovább.
A DDRAM cím beállítását a kurzor pozicionálására használhatjuk. Például kétsoros megjelenítőnél a 0x40 címen kezdődik a második sor. Egy lcd_gotoxy(sor,oszlop) kurzorpozicionáló függvény pedig a sor*0x40+oszlop címre kell, hogy állítsa a DDRAM címet. (A példáknál feltétleztük, hogy nincs eltolva a képernyő, s az lcd_gotoxy() függvény paramétereinél a sorok és oszlopok számozását 0-tól kezdjük.
Az LCD modul inicializálása
Az LCD modul vezérlője a tápfeszültség megjelenésekor inicializálja magát (Power on Reset), de ha bekapcsoláskor túl lassú a tápfeszültség felfutása, vagy bekapcsolt állapotban van szükségünk újrainicializálásra ("meleg" RESET), akkor szoftveres parancsokkal is kikényszeríthetjük, hogy az LCD modul alaphelyzetbe kerüljön. Ennek pontos módját a HD44780 vezérlő adatlapja írja le, s van néhány apró különbség a nyolc-, illetve négybites üzemmódban végzett inicializálás között. Az LCD használatának talán ez a legkritikusabb része, mivel helytelen inicializálás után nem fog működni a modul, vagy zagyvaságok jelennek meg a képernyőn. Mi a kijelzőt 4-bites módban fogjuk vezérelni, ezért annak beállítását ismertetjük.
Inicializálás 4 bites üzemmódban
- Várunk legalább 15 ms-ot azután, hogy a tápfeszültség elérte a 4,5 V-ot, majd RS=0, R/W=0 valamint D7...D4 = 0b0011 mellett (D3..D0 beállítása itt közömbös) pulzáljuk az E vezérlőjelet (E-t előbb magas szintre, majd alacsony szintre kapcsoljuk). Magyarul ez azt jelenti, hogy az LCD-nek kiadjuk a Function set parancsot DL=1 beállítással. A foglaltságot (BF bit) most nem vizsgálhatjuk! Megjegyzés:az LCD itt még 8 bites módban van.
- Várunk legalább 4,1 ms-ot, majd ismét kiadjuk a fenti módon a Function set parancsot. A foglaltságot (BF bit) most nem vizsgálhatjuk! Megjegyzés:az LCD itt még 8 bites módban van.
- Várunk legalább 100 µs-ot, és harmadszor is kiadjuk az 1. pontban leírt módon a Function set parancsot. A foglaltságot (BF bit) most sem vizsgálhatjuk! Megjegyzés:az LCD itt még mindig 8 bites módban van.
- Újabb 100 µs-os várakozás után negyedszer is kiadjuk a Function set parancsot, ezúttal azonban D4 = 0 legyen (DL = 0)! A D3..D0 bitek állapota még mindig közömbös. Amikor ezt a parancsot kiadjuk, az LCD még 8 bites módban van. Ennek a parancsnak a hatására kapcsol át 4 bites módba. A következő ponttól kezdődően tehát a parancsokat két részletben (előbb a magas helyiértékű félbájt, majd az alacsonyabb) kell kiküldeni.
- Újabb 100 µs-os várakozás után ötödször is kiadjuk a Function set parancsot, ezúttal azonban a D3 és D2 adatbitek tartalma is számít (N és F paraméterek, lásd 2.és 3. táblázat!). A 4 bites üzemmódra való tekintettel DL =0, kétsoros kijelzőnél pedig N=1 és F=0 (kétsoros kijelzőnél csak 5x7 pontos karakterek használhatók). Végeredményben tehát esetünkben az adatvonalakra 0x28-at kell küldeni, két részletben. Ezután a parancs után volna figyelhető a foglaltság, ha nem akadályozna bennünket az, hogy a mikrovezérlőnk bemenetei nem tolerálják az 5 V-os jelszintet. A sorok száma és a fontméret csak újrainicializálás után változtatható meg!
- Ideiglenesen letiltjuk a megjelenítést egy Display control paranccsal, D=0 beállítással.
- Töröljük a képernyőt egy Clear Display paranccsal.
- Újraengedélyezzük a megjelenítést egy Display control paranccsal, D=1 beállítással. A kurzor villogását és megjelenítését is ugyanitt engedélyezhetjük.
Első kísérlet: 2x16 karakteres LCD modul vezérlése
Az alábbi program 4-bites módba konfigurálja a 2x16 karakteres kijelzőt, kiír egy kétsoros üzenetet, majd végtelen ciklusban a piros LED-et (LED1) villogtatja. Ez a program terjedelmesebb a korábbiaknál, ezért csak nagy vonalakban ismertetem a működését és főbb részeit. A becsatolt header állományok közé felvettük a standard változótípusokat deklaráló stdint.h állományt is. Az LCD vezérlésére használt lábakhoz szimbolikus neveket rendeltünk. Így egy esetleges átszervezés után csak a program elején kell a definíciókat módosítani. Arra azonban ügyeljünk, hogy az adatvonalak kezelésénél messzemenően kihasználtuk, hogy azok a P1 port 7...4 bitjeire vannak kötve! Ezt nem változtathatjuk meg a program átnézése és áttervezése nélkül! Meg lehetett volna írni általánosabb formában is az adatbitek kezelését, de akkor a CPU futás közbeni terhelése több volna, tehát az elegancia ára az erőforrások pazarlása.
#include "io430.h"
#include "stdint.h"
/* LCD port és vezérlő bitek megadása */
#define LCD_PORT P1OUT
#define LCD_PORT_DIR P1DIR
#define LCD_MASK BIT7+BIT6+BIT5+BIT4
#define LCD_RS P2OUT_bit.P6
#define LCD_RS_DIR P2DIR_bit.P6
#define LCD_E P2OUT_bit.P7
#define LCD_E_DIR P2DIR_bit.P7
/**-----------------------------------------------
* Inline függvény, amely egy regiszter valamelyik
* bitcsoportját atomi művelettel módosítja
*-----------------------------------------------
* \param reg a módosítandó regiszter neve
* \param val a beírandó érték (helyiérték-helyesen!)
* \param mask a módosítandó bitcsoportot kijelölő maszk
*/
#define ChangeBits(reg,val,mask) reg^=((reg^val)&mask)
/**----------------------------------------------
* Késleltető eljárás (1 - 65535 ms)
*-----------------------------------------------
* \param delay a késleltetés ms egységben megadva
*/
void delay_ms(uint16_t delay) {
uint16_t i;
for(i=0; i
__delay_cycles(1000);
}
}
/**----------------------------------------------
* LCD Enable bemenet pulzálása
*-----------------------------------------------
*/
void lcd_toggle_E() {
LCD_E = 1;
__delay_cycles(500);
LCD_E = 0;
__delay_cycles(500);
}
/**----------------------------------------------
* Egy bájt kiküldése az LCD vezérlőjének
*-----------------------------------------------
* \param val a kiírandó érték
* \param cmd regiszterválasztó bit (0: parancs, 1: adat)
*/
void lcd_write(uint8_t val, uint8_t cmd) {
LCD_RS = cmd;
ChangeBits(LCD_PORT,(val&0xF0),LCD_MASK);
lcd_toggle_E();
ChangeBits(LCD_PORT,((val&0x0F)<<4),LCD_MASK);
lcd_toggle_E();
__delay_cycles(1000);
}
/*-----------------------------------------------
* LCD kijelző inicializálása
*-----------------------------------------------
*/
void lcd_init (void){
//-- Az LCD port inicializálása
ChangeBits(LCD_PORT,0x00,LCD_MASK);
ChangeBits(LCD_PORT_DIR,LCD_MASK,LCD_MASK);
P2SEL = 0;
LCD_RS = 0;
LCD_RS_DIR = 1;
LCD_E = 0;
LCD_E_DIR = 1;
delay_ms(100); //40ms várakozás bekapcsolás után
//-- Az LCD vezérlőjének inicializálása:
//-- 1. szoftveres LCD reset: 0x30 (8-bites mód) kiírása háromszor
//-- 2. 4-bites üzemmód beállítása
//-- 3. Képernyőtörlés, kurzor kikapcsolása
ChangeBits(LCD_PORT,0x30,LCD_MASK);
lcd_toggle_E ();
delay_ms(5); //várjunk legalább 4.1ms-ot
lcd_toggle_E ();
__delay_cycles(100); //várjunk legalább 100us-ot
lcd_toggle_E ();
__delay_cycles(40); //várjunk legalább 37us-ot
ChangeBits(LCD_PORT,0x20,LCD_MASK); //0x20 = 4-bites üzemmód
lcd_toggle_E ();
delay_ms(5); //várjunk legalább 4.1ms-ot
//-- Innen kezdve minden bájtot két félbájtként kell kiírni! ------
lcd_write(0x28,0); // display mód beállítás
delay_ms(5); //várjunk legalább 4.1ms-ot
lcd_write(0x08,0); // display letiltás
lcd_write(0x01,0); // képernyőtörlés
lcd_write(0x0C,0); // display be, cursor, és villogás ki
}
/**----------------------------------------------
* Karakterfüzér kiírása az LCD-re
*-----------------------------------------------
* \param p_str karakterfüzér mutató (nullával lezárt stringre mutat)
*/
void lcd_puts(char* p_str) {
char c;
while ((c=*p_str)) {
lcd_write(c,1);
p_str++;
}
}
int main(void) {
WDTCTL = WDTPW + WDTHOLD; //watchdog letiltása
P1DIR |= 0x01;
lcd_init();
lcd_puts("");
lcd_write(0xC0,0); //A második sor elejére lép
lcd_puts("Now in 4bit mode");
while(1) {
P1OUT ^= 0x01; //LED1 villogtatása
__delay_cycles(250000);
}
}
A programban definiált függvényeket előfordulásuk sorrendjében ismertetjük:
A ChangeBits() függvényt inline függvényként definiáltuk, ami azt jeleni, hogy fordításkor minden hivatkozás helyére beépül. Ez azt jelenti, hogy elmarad a CALL/RETURN hívással járó többletteher és a veremtár használatával is takarékoskodunk. A függvény egyébként a reg paraméterben megadott regiszterben módosítja a mask paraméter által kijelölt bitcsoportot, a val paraméterben megadott értékre. Ugyanaz a hatása, mintha ezt írtuk volna:
reg &= ~mask; //Töröljük a bitcsoportot
reg |= val; //Beállítjuk a bitcsoportot
A fenti műveletsor azonban kétszer is módosítja a reg regiszter értékét, s nem "atomi" művelettel történik a változtatás. Ennek majd akkor lesz jelentősége, ha programmegszakításokkal vagy több szálon futó programokkal foglalkozunk.
A delay_ms() függvény arra szolgál, hogy 1 ms egységekben megadott késleltetéseket írhassunk elő. Kihasználva, hogy alapértelmezetten kb. 1 MHz frekvenciájú órajellel fut a CPU, egy for ciklus szerveztünk, ami a ciklusmagban 1000 gépi ciklus, azaz 1 ms idejű késleltetést végez. Ha a for ciklus 10-szer ismétli a ciklusmagot, akkor az nagyjából 10 ms késleltetést jelent, és így tovább...
Az lcd_toggle_E() függvény az LCD modul engedélyező jelének pulzálását végzi. Ennek az impulzusnak a hatására íródik be az adatvonalakra kitett adat az RS vonal által kiválasztott regiszterbe. Ezért ügyeljünk rá, hogy először az adatvonalakat és az RS vonalat állítsuk be, s csak utána hívjuk meg az lcd_toggle_E() függvényt!
Az lcd_write(val,cmd) függvény egy bájt kiküldését végzi el - a 4-bites módnak megfelelően két lépésben. A bemeneő paramáterk közül val a kiküldendő adat, cmd pedig az RS vonal vezérlésre szolgál (0: parancs, 1: adat).
Az lcd_init() függvény az LCD modul inicializálására (az üzemmód beállítására) szolgál. Itt gondoskodunk a P1 és P2 portok LCD-hez kapcsolódó lábainak alaphelyzetbe állításáról, majd szoftveresen alaphelyzetbe állítjuk az LCD modul vezérlőjét is, s beállítjuk a 4-bites üzemmódba, a fenti leírás szerint. Vegyük észre, hogy a 4-bites üzemmód beállításáig az LCD modul 8-bites módban van, s csak a felső négy adatbit számít. Így ezeknél a lépéseknél a ChangeBits() függvényt használjuk a parancsok kiküldésére. A 4-bites mód beállítása után pedig át kell térnünk az lcd_write() függvény használatára, mert itt már két félbájtot vár az LCD vezérlője. A 4-bites üzemmód beálíttása után töröljük a képernyőt, a kurzort alaphelyzetbe (a bal felső sarokba) állítjuk, s a kurzor megjelenítését és a kurzor villogtatást kikapcsoljuk.
Az lcd_puts() függvény egy nullával lezárt karaktersorozat kiírására használható, paramétere egy ilyen, nullával lezárt karakterfüzérre kell, hogy mutasson. Mi az egyszerűbb megoldást választjuk: a kiírandó szöveget közvetlenül, szövegkonstanként adjuk meg. Például:
lcd_puts("Helló világ!");
Ilyenkor a szöveg elhelyezéséről (beleértve a lezáró nullát is) és a szövegkonstansra mutató pointer átadásáról a fordító automatikusan gondoskodik.
A főprogramban kikapcsoljuk a Watchdog időzítőjét, s kimenetre állítjuk a LED1-hez tartozó P1.0 kiemenetet. A mikrovezérlő LCD-hez kötött lábainak beállításáról és az LCD modul inicializálásáról az lcd_init() függvény gondoskodik. Ezután kiírunk két szövegsort, majd a végtelen ciklusban LED1-et villogtatjuk a korábban tanult módon. Külön magyarázatot csak az alábbi sor igényel:
lcd_write(0xC0,0); //A második sor elejére lép
A második paraméter nulla, tehát parancsot küldünk az LCD modulnak. Az első paraméter legfelső bitje '1', ez jelzi, hogy DDRAM cím beállításáról, azaz a kiírás címének beállításáról van szó, ahol az első paraméter további bitjei a kiírás címét (a kurzor pozícióját) adják meg. 0x40 a második sor kezdőcíme, tehát a fenti paranccsal a második sor elejére állunk be. Célszerű a 0xC0 paraméter bináris alakját (0b11000000) összevetni a 6_2. táblázat DDRAM cím beállítása c. sorával!
Sikeres futtatás esetén az alábbi képen látható eredményt kell kapnunk.
6_3. ábra: Az lcd_2x16 demó eredménye
Második kísérlet: 4x20 karakteres LCD modul vezérlése
Második kísérletünkhöz egy EW20400YLY típusú, négysoros, soronként 20 karakteres LCD modult használtunk bekötése ugyanaz, mint a 2x16-os modulé. A program is nagyon hasonló az előzőhöz, gyakorlatilag csak a főprogramot kellett módosítani. Ezen kívül kényelmi okokból a kurzor pozicionálásához (a megadott sor elejére történő beálláshoz) makrókat definiáltunk, de az előző programhoz hasonlóan használhattuk volna az lcd_write(0xC0,0) függvényhívást (természetesen 0xC0 helyére minden sorhoz más-más értéket írva).
A főprogramban csupán annyi a változás, hogy most négy sornyi szöveget írunk ki, s a sorok egy picit hosszabbak lehetnek (soronként 16 helyett 20 karaktert írhatunk). Ebből könnyen levonható a konklúzió: ilyen kijelzőt ott érdemes használni, ahol több adatot vagy szöveget kell egyidejűleg megjeleníteni.
-
#define GOTO_LINE1() lcd_write(0x80,0)
-
#define GOTO_LINE2() lcd_write(0xC0,0)
-
#define GOTO_LINE3() lcd_write(0x94,0)
-
#define GOTO_LINE4() lcd_write(0xD4,0)
-
-
int main(void) {
-
WDTCTL = WDTPW + WDTHOLD; //watchdog letiltása
-
P1DIR |= BIT0;
-
lcd_init();
-
lcd_puts("");
-
GOTO_LINE2(); //A második sor elejére lép
-
lcd_puts("--Now in 4bit mode--");
-
GOTO_LINE4(); //A negyedik sor elejére lép
-
lcd_puts("MCU: TI MSP430G2231 ");
-
GOTO_LINE3(); //A harmadik sor elejére lép
-
lcd_puts("Launchpad demo board");
-
while(1) {
-
P1OUT ^= BIT0; //LED1 villogtatása
-
__delay_cycles(250000);
-
}
-
}
A program eredménye az alábbi képen látható. Megjegyezzük, hogy ez az LCD modul háttérvilágítással is rendelkezik, de ehhez a kísérlethez nem kötöttük be azt. A VEE lábat pedig egy 1 k ohm-os ellenálláson keresztül kötöttük a földre, így szép tiszta képet kaptunk. Ha az ellenállást elhagytuk, akkor az elvileg kioltott képpontok is látszottak halványan, ami némileg rontotta az olvashatóságot.
6_4. ábra: az lcd_4x20 demóprogram eredménye
A cikk még nem ért véget, lapozz!