Alfanumerični displej, postavljen na ploščico razvojnega sistema Shield-A, daje mikrokontrolerju možnost izpisa smiselnih sporočil tudi brez povezanosti z osebnim računalnikom: če mu zagotovimo ustrezno napajanje, bo komplet Arduino Uno + Shield-A + LCD postal avtonomni komplet, in za komunikacijo z uporabnikom osebni računalnik ni več potreben. Zato je alfanumerični displej zelo koristen dodatek mikrokontrolerskega kompleta. Zato se bomo v tem nadaljevanju bolj podrobno spoznali z njegovimi možnostmi. Poglejmo najprej, katere vse ukaze programska jezika Bascom-AVR in Arduino imata predvidene za delo z LCD-jem (tabeli 1 in 2).
Shield-A, učni pripomoček za programiranje mikrokontrolerjev (8)
ukaz opis
CLS Briše obstoječi izpis na displeju, postavlja kurzor na naslov 1, 1 (začetek prve vrstice)
HOME V Postavlja kurzor na naslov 1, 1 (začetek prve vrstice)
HOME L Postavlja kurzor na naslov 2, 1 (začetek druge vrstice)
HOME T Postavlja kurzor na naslov 3, 1 (začetek tretje vrstice)
HOME F Postavlja kurzor na naslov 4, 1 (začetek četrte vrstice)
LOCATE y , x Postavlja kurzor na naslov y, x (y = vrstica, x = pozicija znotraj vrstice)
CURSOR ON/OFF Vklopi/izklopi prikaz kurzorja
DISPLAY ON/OFF Vklopi/izklopi prikaz na displeju
LCD x Izpiše vsebino konstante ali spremenljivke “x”začenši od trenutne pozicije kurzorja
SHIFTLCD LEFT/RIGHT Premika vsebino displeja eno pozicijo v levo/v desno
ukaz opis
begin()
clear() Briše obstoječi izpis na displeju, postavlja kurzor na naslov 0, 0 (začetek prve vrstice)
home() Postavlja kurzor na naslov 0, 0 (začetek prve vrstice)
setCursor(x,y) Postavlja kurzor na naslov y, x (y = vrstica, x = pozicija znotraj vrstice)
print() Izpiše vsebino na displeju
display() Vklopi prikaz na displeju po izklopu z ukazom noDisplay()
noDisplay() Izklopi prikaz na displeju
cursor() Vklopi prikaz kurzorja
noCursor() Izklopi prikaz kurzorja
scrollDisplayLeft() Premika vsebino displeja eno pozicijo v levo
scrollDispplayRight() Premika vsebino displeja eno pozicijo v desno
Za uspešno rešitev 11. in 12. programske naloge bomo potrebovali alfanumerični displej ter tipki SW1 in SW2 na razvojnem sistemu Shield-A. Shema na sliki 32 prikazuje, kako je vse to povezano s priključki Arduino Uno ploščice, oziroma s priključki mikrokontrolerja ATmega328P.
11. programska naloga: v spominu alfanumeričnega displeja je definiranih 192 znakov. Poleg velikih in malih črk angleške abecede, številk in drugih znakov, katere običajno najdemo na tipkovnici osebnega računalnika. V spominu displeja se nahajajo tudi znaki kitajske abecede in nekaj črk grške abecede. Del teh znakov lahko izpišemo direktno, z uporabo znakov s tipkovnice osebnega računalnika, drugi del pa posredno, z uporabo ustrezne funkcije. Program mora izpisati vse znake, ki so vpisani v spominu alfanumeričnega displeja. Izpisovali jih bomo v blokih po 16 znakov v spodnji vrstici displeja, medtem ko se v zgornji vrstici izpisujejo parametri Bascom-AVR funkcije Chr(), oziroma Arduino funkcije lcd.write(), potrebni za izpis posameznega znaka.
Bascom-AVR rešitev (program Shield-A_11.bas)
V programu moramo najprej definirati kateri tip AN displeja uporabljamo, opisati kako so njegovi priključki povezani s priključki mikrokontrolerja in vključiti osvetlitev ozadja; ta del programa smo opisali v predhodnem članku. Nato bomo konfigurirati priključke PC1 in PC2 kov vhodne, zato, da bi z njimi lahko brali stanja tipk SW1 in SW2:
Config Portc.1 = Input
Portc.1 = 1
Config Portc.2 = Input
Portc.2 = 1
Tipki bomo uporabili za izpis naslednjega oziroma predhodnega bloka znakov. V programu bomo potrebovali te tri spremenljivke:
Dim Znak As Byte
Dim Od_znaka As Byte
Dim Do_znaka As Byte
Spremenljivko Znak bomo uporabili kot kazalo na en znak iz tabele znakov definiranih v spominu displeja. Ti znaki se nahajajo na naslovih 32-127 in 160-255, pri čemer naslovi 32-127 vsebujejo definicije znakov, katere običajno srečujemo na tipkovnici osebnega računalnika in njihov položaj v tabeli ustreza njihovi ASCII kodi. Npr., ASCII koda črke “A” je &B01000001, kar ustreza desetiški številki 65, in zato se bo definicija znaka “A” nahajala na naslovu 65. Zaradi te skladnosti”znake s tipkovnice” lahko izpisujemo na displeju direktno, npr.
Lcd “ABC”
vendar tudi posredno, z uporabo funkcije Chr():
Lcd Chr(65); Chr(66); Chr(67)
Oba primera bi na displeju izpisala tekst ABC. V drugem bloku se nahajajo znaki kitajske abecede, grške abecede in nekateri specialni znaki. Te znake lahko izpišemo samo posredno, z uporabo funkcije Chr(). Npr, znake definirane na naslovih 200 in 201, kar koli bi že bili, bomo izpisali tako:
Lcd Chr(200); Chr(201)
Spremenljivki Od_znaka in Do_znaka bomo uporabili v podprogramu Ispis kot mejne vrednosti bloka znakov, kateri se trenutno prikazujejo. V zgornji vrstici izpisujemo kateri razpon znakov pokrivamo s tem prikazom:
Ispis:
Do_znaka = Od_znaka + 15
Home V
Lcd “Chr(” ; Od_znaka ;
Lcd “-” ; Do_znaka ; “) ”
in nato jih znak po znak, v For-Next zanki, izpisujemo v spodnji vrstici:
Home L
For Znak = Od_znaka To Do_znaka
Lcd Chr(znak)
Next
Return
V glavni zanki preverjamo ali je bila pritisnjena katera od tipk in ko se to dogodi, kličemo podprograme Nazad ali Naprijed:
Do
Debounce Pinc.1 , 0 , Nazad , Sub
Debounce Pinc.2 , 0 , Naprijed , Sub
Loop
V njih se pripravljamo za prikaz predhodnega ali naslednjega bloka znakov:
Nazad:
If Od_znaka > 32 Then
Od_znaka = Od_znaka – 16
End If
Gosub Ispis
Return
Naprijed:
If Od_znaka < 240 Then
Od_znaka = Od_znaka + 16
End If
Gosub Ispis
Return
Fotografije na Sliki 33 prikazujejo, kako to izgleda v praksi. Vsebina gornje vrstice displeja tolmačimo na naslednji način: znaki v spodnji vrstici dobimo z uporabo Chr(48) do Chr(63), oziroma, Chr(224) do Chr(239).
Arduino rešitev (program Shield-A_11.ino)
V programu moramo najprej definirati knjižnico funkcij, ki nam omogoča enostavnejše delo z displejem, nato definiramo kateri tip AN displeja uporabljamo, opišemo kako so njegovi priključki povezani s priključki mikrokontrolerja in vključimo osvetlitev ozadja; ta del programa smo opisali v predhodnem članku. Nato bomo konfigurirali priključke PC1 in PC2 kot vhodne zato, da bi z njimi lahko brali stanje tipk SW1 in SW2:
pinMode(A1, INPUT_PULLUP);
pinMode(A2, INPUT_PULLUP);
Tipki bomo uporabili za izpis naslednjega oziroma predhodnega bloka znakov. V programu bomo potrebovali te tri spremenljivke na nivoju celotnega programa:
byte znak;
byte Od_znaka = 32;
byte Do_znaka;
Spremenljivko znak bomo uporabili kot kazalo na en znak iz tabele znakov definiranih v spominu displeja. Znake lahko izpisujemo na displeju direktno, npr.
Lcd.print(“ABC”);
pa tudi posredno, z uporabo funkcije lcd.write():
lcd.write(65);
lcd.write(66);
lcd.write(67);
Oba primera bi na displeju izpisala tekst ABC. V drugem bloku se nahajajo znaki kitajske abecede, grške abecede in nekateri specialni znaki. Te znake lahko izpisujemo samo posredno, z uporabo funkcije lcd.write(). Npr, znake definirane na naslovih 200 in 201, kar koli so že, izpisat jih bomo tako:
lcd.write(200);
lcd.write(201);
Spremenljivke od_znaka in do_znaka bomo uporabili v funkciji izpis() kot mejne vrednosti bloka znakov, kateri se trenutno prikazujejo. V zgornji vrstici izpisujemo kateri razpon znakov pokrivamo s tem prikazom:
void izpis(){
do_znaka = od_znaka + 32;
lcd.setCursor(0,0);
lcd.print(“Chr(“);
lcd.print(od_znaka);
lcd.print(“-“);
lcd.print(do_znaka);
lcd.print(“) “);
in nato jih znak po znak, v for zanki, izpisujemo v spodnji vrstici:
lcd.setCursor(0,1);
for (znak = od_znaka; znak <= do_znaka; znak++){
lcd.write(znak);
}
}
V funkciji loop() preverjamo ali je bila pritisnjena katera od tipk in ko se to dogodi, kličemo funkciji nazad() ali naprijed(). V primeru Shield-A_6b smo pojasnili kako ta algoritem dela:
void loop() {
if (digitalRead(A1) == 0) {
delay(25);
if (digitalRead(A1) == 0) {
nazad();
while (digitalRead(A1) == 0){
}
}
}
if (digitalRead(A2) == 0) {
delay(25);
if (digitalRead(A2) == 0) {
naprijed();
while (digitalRead(A2) == 0){
}
}
}
}
V njem se pripravljamo za prikaz predhodnega ali naslednjega bloka znakov:
void nazad(){
if ( od_znaka > 32) {
od_znaka = od_znaka – 16;
}
izpis();
}
void naprijed(){
if (od_znaka < 240) {
od_znaka = od_znaka + 16;
}
izpis();
}
***
12. programska naloga: Poleg znakov katerih definicija je trdno vpisana v spomin alfanumeričnega displeja, ima uporabnik možnost definirati osem lastnih znakov. Te znaki se namestijo v RAM displeja na naslovne lokacije 0-7 in se lahko izpišejo s pomočjo funkcij Chr(), oziroma lcd.write (). Naša naloga je definirati posebne znake in napisati sporočilo “Mačak Tom i mišić Jerry”.
Bascom-AVR rešitev (program Shield-A_12.bas)
Za definiranje lastnih znakov v Bascom-AVRu bomo uporabili orodje “LCD designer” iz menija “Tools” (Slika 34).
V mreži, ki jo nariše LCD designer, kliknemo v polja, ki jih želimo počrniti in tako, točko za točko, oblikujemo želeni znak. Ko zaključimo oblikovanje s klikom na gumb “OK”, se bo v programu pojavila vrstica, ki je na sliki 34 izpisana na modri podlagi. Tukaj moramo zamenjati “[x]” s številko med 0 in 7 (0 v primeru na sliki) in ukaz Deflcdchar bo črko “č” shranil v RAM displeja na naslov 0! Na isti način bomo definirali tudi črki “ć” in “š”:
Deflcdchar 0, 10, 4, 14, 16, 16, 17, 14, 32 ‘ č
Deflcdchar 1, 2, 4, 14, 16, 16, 17, 14, 32 ‘ ć
Deflcdchar 2, 10, 4, 14, 16, 14, 1, 30, 32 ‘ š
Cls
Definiranje lastnih znakov obvezno zaključimo z ukazom Cls, nakar nam bodo postali dostopni v programu. V glavni zanki bomo izmenično izpisovali sporočila z lastnimi znaki:
Do
Lcd “ma” ; Chr(0) ; “ak Tom i”
Home L
Lcd “mi” ; Chr(2) ; “i” ; Chr(1) ; ” Jerry”
Wait 2
Cls
in sporočila s “črkami iz tipkovnice”
Lcd “mačak Tom i”
Home L
Lcd “mišić Jerry”
Wait 2
Cls
Loop
zato, da bi poudarili razliko: če uporabljamo črke kot č, ć, đ, š in ž s tipkovnice, se bodo na displeju prikazale kot “čudni znaki” (slika 35).
Arduino rešitev (program Shield-A_12.ino)
Adruino IDE nima LCD designerja, zato bomo uporabili tekstualno vizualizacijo znakov v programski kodi. Glede na to, da se vsaka vključena točka znaka opisuje s številko 1, vsaka izključena pa s številko 0, bomo definirati za vsak znak posebej enodimenzionalno polje vrste byte velikosti 8 bajtov. Za črko č bomo definirati polje imena ch:
byte ch[8] = {
B01010,
B00100,
B01110,
B10000,
B10000,
B10001,
B01110,
B00000}; // č
Opazili boste, da smo za vsakega člana polja vpisali številko v binarni obliki, ki predstavlja eno vrstico “slike” znaka. Ko se navadimo gledati to “matrico” velikosti 8×5 točk, bomo videli, da so obrisi, ki jih tvorijo številke 1 pravzaprav enaki obrisu male črke č.
Polja za črk ć in š definiramo na isti način:
byte cc[8] = {
B00010,
B00100,
B01110,
B10000,
B10000,
B10001,
B01110,
B00000}; // ć
byte sh[8] = {
B01010,
B00100,
B01110,
B10000,
B01110,
B00001,
B11110,
B00000}; // š
Ko smo definirali kako bodo izgledali znaki, je potrebno v funkcijo setup() dodati tudi ukaz lcd.createChar(), s katero definiramo znake za izpis. Ukaz prejema dve informaciji: spominski naslov in polje s definicijo izgleda znaka:
lcd.createChar(0, ch);
lcd.createChar(1, cc);
lcd.createChar(2, sh);
Za izpis definiranega znaka uporabljamo funkcijo lcd.write(), v kateri kot vhodni parameter vpisujemo spominski naslov kot vrsto byte. Primer izpisa znaka č:
lcd.write(byte(0));
V primeru, da smo pozabili definirati, da je številka nič vrste byte, bo prevajalnik javil napako pri prevajanju programa.
V funkciji loop() bomo izmenično izpisovali sporočila z lastnimi znaki
void loop() {
lcd.print(“ma”);
lcd.write(byte(0));
lcd.print(“ak Tom i”);
lcd.setCursor(0,1);
lcd.print(“mi”);
lcd.write(byte(2));
lcd.print(“i”);
lcd.write(byte(1));
lcd.print(” Jerry”);
delay(2000);
lcd.clear();
in sporočila s “črkami s tipkovnice”
lcd.print(“mačak Tom i”);
lcd.setCursor(0,1);
lcd.print(“mišić Jerry”);
delay(2000);
lcd.clear();
}
Opomba: Programi Shield-A_11.bas, Shield-A_12.bas, Shield-A_11.ino in Shield-A_12.ino se lahko brezplačno dobijo od uredništva revije Svet elektronike.
Avtorja: Vladimir Mitrović in Robert Sedak
email: vmitrovic12@gmail.com