Mikrokontroler PIC16f628a in LCD prikazovalnik

LCD prikazovalniki (Liquid cristal display – prikazovalniki na tekoče kristale) omogočajo izpisovanje črk, številk in ostalih znakov. Uporabljamo jih kot vmesnike med uporabnikom in elektronsko napravo. V vajah bomo uporabili dvovrstične LCD prikazovalnike z lastno osvetlitvijo, ki imajo v vsaki vrstici po 16 znakov (DEM 16216 SYH-PY).

Slika 1: LCD prikazovalnik 2x16

Vsebujejo lasten kontroler (KS0070B-00 proizvajalca Samsung oziroma HD44780U proizvajalca Hitachi), ki skrbi za vklapljanje ustreznih pik na zaslonu. Vsak znak je sestavljen iz 5 x 8 pik. LCD kontroler ima 80 bajtov zaslonskega pomnilnika RAM, imenovanega DDRAM (Display data RAM). Vsebuje še znakovni pomnilnik ROM s podatki o simbolih (imenovanega CGROM) in 64 bajtov zaslonskega pomnilnika RAM (imenovanega CGRAM), namenjenega izdelavi lastnih simbolov. CGROM je pomnilnik, ki ga ne moremo spreminjati. Vsebuje podatke o tem, kako so sestavljeni znaki, ki jih LCD pozna: vse črke angleške abecede, številke, ločila in še ostale znake, ki so odvisni od proizvajalca, osnoven nabor znakov ASCII pa je vedno enak.

Slika 2: LCD 2x16, naslovi DDRAM - šestnajstiške vrednosti

Vsak znak na LCD prikazovalniku ima svoj naslov (slika 26) v DDRAM-u. Začetni naslov skrajnega levega znaka v prvi vrstici je 0x00, skrajnega levega znaka v drugi vrstici pa 0x40. Vsaka vrstica je navidezno dolga po 40 znakov, kar znaša skupaj 80 znakov. Vsak znak zavzame 1 bajt pomnilnika DDRAM. Od vseh 40 znakov v vsaki vrstici jih trenutno vidimo na zaslonu le 16. Tega lahko poljubno premikamo po celotnem prikazovalniku in tako določimo, kaj bo v določenem trenutku prikazano na zaslonu.

Slika 3: Kar v resnici vidimo na LCD zaslonu je le del celotnega DDRAM-a

CGRAM ima enako vlogo kot CGROM, le da lahko vanj sami vpisujemo podatke oziroma jih iz njega beremo. Če delamo z znaki velikosti 5 x 8 pik, lahko ustvarimo do 8 novih znakov, ki imajo kode od 0x00 do 0x07. Vsak znak vsebuje 8 naslovov, vrednosti znaka pa so odvisne od novega simbola oziroma znaka, ki smo ga ustvarili.

Priklop LCD prikazovalnika na mikrokontroler:

LCD prikazovalniki brez možnosti osvetlitve zaslona imajo 14 priključkov, taki z možnostjo osvetlitve zaslona pa imajo 2 priključka več, torej 16 priključkov. Funkcija posameznega priključka je standardna, vedeti moramo le, kje se nahaja prvi priključek. Če priključki za določen tip LCD-ja niso označeni, poiščemo podatke na spletu.

Slika 4: Priklop LCD prikazovalnika na mikrokontroler

Priključki od 7 do 14 LCD prikazovalnika so namenjeni podatkovnim linijam (od D0 do D7). Preko njih se prenašajo podatki od mikrokontrolerja do LCD-ja, če pišemo v LCD, in od LCD-ja do mikrokontrolerja, če beremo iz LCD-ja. LCD prikazovalniki lahko delujejo v 8 ali v 4-bitnem načinu. Mi bomo izbrali 4-bitni način delovanja, saj s tem privarčujemo pri priključkih mikrokontrolerja. Ker iz LCD-ja ne bomo ničesar brali, bomo priključek 5 (R/W) povezali z maso in s tem pridobili dodaten prost priključek na mikrokontrolerju. Podatki se pri 4-bitnem načinu delovanja prenašajo po 4 bite hkrati, zato moramo poslati obe polovici bajta posebej, pošiljamo pa jih po podatkovnih linijah od D4 do D7.

Tretji priključek LCD-ja služi nastavitvi kontrasta. Kontrast reguliramo z napetostjo na tem priključku. V ta namen uporabimo potenciometer kot delilnik napetosti.

LCD-prikazovalnik krmilimo tako, da mu pošiljamo ukaze ali podatke. Če postavimo priključek 4 (RS) v stanje logične 0, bo LCD sprejel podatek kot ukaz, če pa ga postavimo na nivo logične 1, bo LCD sprejel navaden podatek. Priključek 6 (E) je namenjen vklopu prikazovalnikove logike. Ko pošiljamo neki podatek na LCD, ga moramo nekako obvestiti, da je na podatkovnih linijah nov podatek. To storimo tako, da ta priključek vklopimo (postavimo na 1) in izklopimo (postavimo na 0). Ob tem prehodu bo LCD sprejel nov podatek. Pri 4-bitnem načinu delovanja pošljemo najprej zgornje 4 bite podatka na priključke 11–14 (D4–D7), vmes vklopimo in izklopimo priključek 6 (E) in nato na iste priključke pošljemo še spodnje 4 bite podatka. Zatem zopet vklopimo in izklopimo priključek 6 (E). Vsak vpis ukaza ali podatka vzame LCD-ju nekaj časa, da ga obdela. V tem času, podajajo ga proizvajalci LCD-jev, mu ne smemo pošiljati naslednjega ukaza ali podatka, zato uporabimo metodo zakasnitve, ki bo v našem primeru ca. 5 ms. Časa zakasnitve ni treba točno nastaviti, le manjši od predpisanega ne sme biti.

                                                                                       Tabela 1: Funkcije priključkov LCD prikazovalnika 2x16


LCD prikazovalnik moramo pred uporabo inicializirati. To pomeni, da moramo izvesti določeno zaporedje operacij, da ga postavimo v želeni način delovanja. Uporabili bomo inicializacijo za delo v 4-bitnem načinu. Opis korakov, potrebnih pri inicializaciji, si poglejmo v programu, ki bo v prvi vrstici LCD-ja zapisal "Mikrokontroler", v drugi vrstici pa "in LCD zaslon", kot kaže slika 5.

Slika 5: Prikaz napisa na LCD zaslonu

Program v zbirnem jeziku:

 ;-------------------------------------------------------------------------------------------------------------

 ; Prikaz napisa na LCD zaslonu.

 ; Okolje MPLAB IDE v8.92, prevajalnik MPASM Assembler V5.51, oscilator 4 MHz.

 ; Avtor: Milan Ivič, nov 2017

 ;-------------------------------------------------------------------------------------------------------------

    list p=16f628a                           ;Tip mikrokontrolerja

    #include <p16f628a.inc>          ;Vključi v program datoteko p16f628a.inc.

    __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _MCLRE_ON & _LVP_OFF & _XT_OSC

;********************* Deklaracija spremenljivk *********************

    Cblock 0x20                             ;Blok konstant in začasnih spremenljivk

    Temp1

    Temp2                                      ;Začasni spremenljivki

    Naslov                                      ;Nov naslov DDRAM-a

    Stevec                                      ;Števec za izpis niza v prvi vrstici

    Stevec1                                    ;Števec za izpis niza v drugi vrstici

    endc

 ;******************* Definiranje novih oznak **********************

    #define RS PORTB,1               ;RS-linija LCD-ja

    #define RW PORTB,2              ;RW-linija LCD-ja

    #define E PORTB,3                  ;E-linija LCD-ja

 ;************** Definiranje konstant za LCD ukaze ***************

DDRAM equ 0x80                    ;Maska za vpis v DDRAM

Kurzor equ 0x0C                      ;Izklop kazalčka (kurzorja)

 ;************** Začetek ***************

    org 0x000

    goto Glavni_zacetek

    org 0x004

 ;********************* Glavni program *********************

Glavni_zacetek

    bsf STATUS,5                       ;Banka 1

    clrf TRISA

    clrf TRISB                             ;Vsi pini PORTA in PORTB so izhodni.

    movlw b'10000001'

    movwf OPTION_REG          ;Preddelilnik dodeljen časovniku TMR0, preddelitev 1 : 4.

    bcf STATUS,5                       ;Banka 0

    clrf PORTB                           ;Inicializacija PORTB

    clrf INTCON                          ;Onemogočimo odzivanje mikrokontrolerja na prekinitve

    call LCD_Init                         ;Klicanja podprograma za inicializacijo LCD-ja

    bsf RS                                   ;Podatkovni način, pisanje znakov

    call LCD_Niz1                       ;Klicanje podprograma za izpis niza na LCD (prva vrstica)

    clrf Stevec                             ;Spremenljivka Stevec = 0

    movlw 0x40

    call DDRAM_n                      ;Pišemo na začetek druge vrstice LCD (naslov 0x40)

    bsf RS                                   ;Podatkovni način, pisanje znakov

    call LCD_Niz2                       ;Klicanje podprograma za izpis niza na LCD (druga vrstica)

    clrf Stevec1                           ;Spremenljivka Stevec1 = 0

Delaj goto Delaj                       ;Neskončna zanka

 ;********************* Podprogrami *************************

 ;******* Izpis na LCD v 4-bitnem načinu ********************

LCD_pisi

    movwf Temp1                       ;Podatek iz W v Temp1

    movlw 0x0F                          ;b'00001111' v register W

    andwf PORTB,f                    ;Zgornje 4 bite registra PORTB izbrišemo

    movf Temp1,w                      ;Registru W povrnemo podatek iz Temp1

    andlw 0xF0                          ;Izbrišemo spodnje štiri bite

    iorwf PORTB,f                      ;Pošljemo zgornje štiri bite podatka

    bsf E

    bcf E                               ;Obvestimo LCD o novem podatku

    swapf Temp1,f                      ;Zamenjamo polbajte v Temp1

    movlw 0xF0                          ;b'11110000' v register W

    andwf Temp1,f                      ;Spodnje 4 bite v Temp1 izbrišemo

    movlw 0x0F                          ;b'00001111' v register W

    andwf PORTB,f                    ;Zgornje 4 bite v registru PORTB izbrišemo

    movf Temp1,w                      ;Podatek iz Temp1 v register W

    iorwf PORTB,f                      ;Pošljemo spodnje štiri bite podatka

    bsf E

    bcf E                               ;Obvestimo LCD o novem podatku

    call Cakaj_155_us                ;Zakasnitev 155 µs

    return

 ;****************** Inicializacija LCD-ja ********************

LCD_Init

    bcf RW

    bcf RS                            ;Ukazni način, vpisovanje podatkov v LCD

    movlw .34

    call Cakaj_ms                       ;ca. 35 ms pavze

    movlw 0x30

    movwf PORTB                      ;Na D7–D4 pošljemo 0x30

    bsf E

    bcf E                              ;Obvestimo LCD o novem podatku

    movlw .5

    call Cakaj_ms                       ;ca. 5 ms pavze

    movlw 0x30

    movwf PORTB                      ;Na D7–D4 pošljemo 0x30

    bsf E

    bcf E                             ;Obvestimo LCD o novem podatku

    call Cakaj_155_us                ;Zakasnitev 155 µs

    movlw 0x30

    movwf PORTB                      ;Na D7–D4 pošljemo 0x30

    bsf E

    bcf E                               ;Obvestimo LCD o novem podatku

    movlw .5

    call Cakaj_ms                       ;ca. 5 ms pavze

    movlw 0x20

    movwf PORTB                      ;Na D7–D4 pošljemo 0x20

    bsf E

    bcf E                               ;Obvestimo LCD o novem podatku

    call Cakaj_155_us                 ;Zakasnitev 155 µs

                                        ;Sedaj smo v 4-bitnem načinu

    movlw 0x28                          ;LCD 2x16, 4-bitni način, velikost znakov 5 x 8 pik

    call LCD_pisi                       ;Pošljemo 0x28 na LCD

    movlw 0x08                          ;Izklop zaslona

    call LCD_pisi                       ;Pošljemo 0x08 na LCD

    movlw 0x01                          ;Brisanje DDRAM-a

    call LCD_pisi                       ;Pošljemo 0x01 na LCD, izbrišemo zaslon

    movlw .2

    call Cakaj_ms                       ;Zahtevana zakasnitev, večja od 2 ms

    movlw 0x06                          ;Pisanje v desno brez pomikanja zaslona

    call LCD_pisi                       ;Pošljemo 0x06 na LCD

    movlw 0x0F                          ;Vklop zaslona, veliki kazalček (kurzor)

    call LCD_pisi                       ;Pošljemo 0x0F na LCD

    return

 ;****************** Nastavitev trenutnega naslova DDRAM-a ********************

 ;Naslov DDRAM-a vpišemo v register W pred klicem podprograma.

DDRAM_n

    bcf RS                              ;Ukazni način

    iorlw DDRAM                        ;Z OR-operacijo ustvarimo ukaz

    call LCD_pisi                       ;Vpis ukaza v LCD

    bsf RS                              ;Podatkovni način

    return

 ;****************** Zakasnitev 155 µs ********************

Cakaj_155_us

    movlw .50                           ;Število ponovitev zanke prestavimo v register W

    movwf Temp2                        ;Vrednost registra W v Temp2

Se decfsz Temp2,f                  ;Temp2 = Temp2 - 1. Temp2 = 0?

    goto Se                             ;Temp2 še ni enak 0. Še zmanjšuj Temp2

    return                              ;Temp2 = 0. Vrni se iz podprograma

 ;********* Zakasnitev ca. 1 ms krat vrednost registra W *********

Cakaj_ms

    movwf Temp2                        ;W v Temp2 (iz LCD_Init je vrednost W enaka 34 oziroma 5)

    clrf TMR0                           ;Inicializacija registra TMR0

Cak1 btfss INTCON,T0IF         ;Ali je TMR0 prekoračil svojo vrednost (255)?

    goto Cak1                           ;Ne še

    bcf INTCON,T0IF                  ;Da, postavi zastavico T0IF na 0

    decfsz Temp2,f                      ;Temp2 = Temp2 - 1

    goto Cak1                           ;Temp2 še ni enak 0

    return                              ;Temp2 = 0. Vrni se iz podprograma

 ;*************** Naša niza, napisana sta v tabelah ***************

Tabela1

    addwf PCL,f

    DT "Mikrokontroler"              ;Tabela1 z nizom

Tabela2

    addwf PCL,f

    DT "in LCD zaslon"              ;Tabela2 z nizom

 ;*************** Niz1 za izpis v prvi vrstici LCD-ja ***************

LCD_Niz1

    clrf Naslov                         ;Naslov = 0

    bsf RS                              ;Podatkovni način

    movlw .14

    movwf Stevec                      ;Niz 1 ima 14 znakov (14 črk: Mikrokontroler)

Delaj1

    movf Naslov,w                     ;Odmik = 0, začnemo s prvim znakom niza iz tabele 1

    call Tabela1

    call LCD_pisi                       ;Podatek iz tabele 1 v LCD

    incf Naslov,f                       ;Naslednji podatek iz tabele 1

    decfsz Stevec,f                    ;Ali se vpisani vsi podatki iz tabele 1 v LCD?

    goto Delaj1                         ;Ne še

    bcf RS                              ;Da, preklopi na ukazni način

    return

 ;*************** Niz2 za izpis v drugi vrstici LCD-ja ***************

LCD_Niz2

    clrf Naslov                         ;Naslov = 0

    bsf RS                              ;Podatkovni način

    movlw .13

    movwf Stevec1                   ;Niz 2 ima 13 znakov (11 črk in 2 presledka: in LCD zaslon)

Delaj2

    movf Naslov,w                    ;Odmik = 0, začnemo s prvim znakom niza iz tabele 1

    call Tabela2

    call LCD_pisi                      ;Podatek iz tabele 1 v LCD

    incf Naslov,f                       ;Naslednji podatek iz tabele 1

    decfsz Stevec1,f                 ;Ali se vpisani vsi podatki iz tabele 1 v LCD?

    goto Delaj2                         ;Ne še

    bcf RS                              ;Da, preklopi na ukazni način

    movlw Kurzor                     ;Izklopimo kazalček - kurzor (koda ukaza 0x0C v register W)

    call LCD_pisi

    return

    end

Na začetku programa najdemo novo direktivo Cblock. Ta direktiva počne isto kot equ, le da nam nekoliko olajša delo. Z njo damo besedam vrednosti, ki so lahko naslovi spremenljivk. Prvi parameter poleg direktive (0x20) pomeni vrednost, ki jo bo imela prva oznaka na seznamu, ki tej direktivi sledi. V našem primeru je prva oznaka na seznamu Temp1, ki ima torej vrednost 0x20. To vrednost smo določili zato, ker se na tem naslovu prične podatkovni pomnilnik RAM, namenjen splošni uporabi pri mikrokontrolerju PIC16f628a. Vsaka naslednja oznaka na seznamu bo dobila vrednost, za 1 večjo od vrednosti predhodne oznake v seznamu.

Naslednja nova direktiva v programu je #define. Ta direktiva tekst v prvem parametru zamenja s tekstom v drugem parametru. Kadarkoli se npr. v programu pojavi beseda E, jo prevajalnik zamenja s tekstom PORTB,3, kamor tudi povežemo priključek 6 LCD-ja (E) na mikrokontroler (priključek RB3).

V podprogramu za inicializacijo LCD-ja najprej poskrbimo za zakasnitev 35 ms, da se lahko LCD-jeva elektronika stabilizira. Nato sledi natančno določeno zaporedje korakov, ki so potrebni za inicializacijo in delo v 4-bitnem načinu. Ti koraki so zapisani in komentirani v podprogramu LCD_Init.

V glavnem programu smo časovniku TMR0 dodelili preddelilnik 1 : 4, zato preseže svojo vrednost 255 v času ca. 1 ms pri 4 MHz oscilatorju. S TMR0 v podprogramu Cakaj_ms odmerimo zakasnitev, ki je odvisna od vrednosti delovnega registra W, preden se začne podprogram izvajati. Prvič je vrednost W enaka 34, drugič pa 5. V prvem primeru TMR0 34-krat preseže vrednost 255, v drugem primeru pa 5-krat, preden mikrokontroler zapusti podprogram. Da se pri prekoračenju TMR0 ne sproži prekinitev, smo registru INTCON izklopili njegov sedmi bit GIE. Zakasnitev 155 μs smo dosegli z vrtenjem programa v zanki v podprogramu Cakaj_155_us.

Poglejmo vlogo podprograma LCD_pisi bolj natančno. Podatek za vpis na LCD podprogram prebere iz registra W. Register W se namreč iz obeh tabel vsakič vrne z vrednostjo odmika, ki je v našem primeru črka ali presledek, in ga začasno shrani v Temp1. Kakšen bo odmik, je odvisno od vrednosti spremenljivke Naslov. Če je njegova trenutna vrednost 5, se bo register W iz tabele vrnil z vrednostjo šestega znaka v nizu. Spremenljivki Stevec in Stevec1 štejeta odmike v nizih, ki sta zapisana v obeh tabelah in skrbita, da tabele ne prekoračimo. Preden smo začeli iz posamezne tabele brati, smo postavili vrednost spremenljivke Naslov na 0, spremenljivkama Stevec in Stevec1 pa smo določili vrednost 14 oziroma 13, saj je v prvi tabeli 14 znakov (šteje tudi presledek), v drugi pa 13. V tem podprogramu smo uporabili nove instrukcije. Instrukcija andlw napravi logično operacijo AND med posameznimi enakoležečimi biti registra W in konstanto, podano v parametru, ki je v našem primeru 0xF0. Rezultat operacije se vpiše nazaj v register W. Ker imajo zgornji štirje biti vrednost 1 (F0 šestnajstiško je 11110000 dvojiško), instrukcija andlw pobriše priključke RB4–RB7, da se lahko nanje vpiše nov podatek, hkrati pa ohrani vrednosti priključkov RB0 – RB3, kamor so povezani RS, R/W in E priključki LCD-ja. Instrukcija andwf napravi v našem programu logično operacijo AND med registroma W in PORTB, rezultat operacije pa shrani nazaj v register PORTB. Instrukcija iorwf pa napravi logično operacijo OR med registrom W in registrom, zapisanim v prvem parametru, v našem primeru je to PORTB. Rezultat operacije shrani v register PORTB. Instrukcijo swapf že poznamo, v programu pa jo uporabimo zato, da v začasni spremenljivki Temp1, kjer je shranjena trenutna koda znaka iz tabele, zamenja spodnje 4 bite z zgornjimi 4 biti. To storimo zato, da pošljemo na LCD enkrat zgornje 4 bite podatka in drugič spodnje 4 bite, saj delamo v 4-bitnem načinu.

Poglejmo, kakšen je postopek vpisa črke M, ki je prvi znak v tabeli 1. ASCII koda znaka M v CGROM-u je 01001101(2). S to vrednostjo se iz tabele 1 vrne register W in jo shrani v Temp1. Nato registru W določimo vrednost 00001111(2) (0Fh), da lahko z instrukcijo andwf pobrišemo zgornje 4 bite registra PORTB. Zatem registru W povrnemo kodo znaka M, ki je bila shranjena v Temp1. Z masko 11110000(2) (F0h) in instrukcijo andlw pobrišemo spodnje 4 bite kode znaka M, ki ima sedaj vrednost 01000000(2). Da pri prenosu tega podatka na PORTB ne spremenimo spodnjih 4 bitov registra PORTB, uporabimo instrukcijo iorwf. Na podatkovnih linijah od D4 do D7 LCD-ja (povezani so na RB4 do RB7) so sedaj pripravljeni zgornji štirje biti kode znaka M. LCD moramo samo še obvestiti, da je pripravljen nov podatek, zato vklopimo in izklopimo njegov priključek E. Po tem prehodu je LCD podatek prejel. Poslati mu moramo še spodnje 4 bite kode znaka M. Z instrukcijo swapf zamenjamo polbajta v Temp1. Ta ima sedaj vrednost 11010100(2). Spodnji 4 biti kode znaka M so zamenjali mesto z zgornjimi 4 biti. Postopek enako kot prej ponovimo in po prehodu priključka E z 1 na 0 prejme LCD drugo polovico kode znaka M. Pred pošiljanjem drugega znaka iz tabele na LCD počakamo ca. 155 μs. Zakasnitve, ki jih moramo upoštevati, so za posamezne tipe LCD-jev različne. Najdemo jih v proizvajalčevih katalogih (priložena spodaj). 

V katalogu so opisani tudi ukazi LCD prikazovalnika in potrebne zakasnitve, ki jih posamezni ukaz potrebuje, da ga LCD obdela. Vseh je namreč preveč, da bi jih obravnavali v tem gradivu. Vsak ukaz je koda dolžine enega bajta, ki jo pošljemo LCD-ju. Mednje sodijo:

V katalogu najdemo tudi naslove vseh znakov DDRAM-a, ki jih je LCD zmožen prikazati. Poleg teh pa lahko sami izdelamo do osem svojih znakov. Katere vrednosti in naslove CGRAM-a imajo, je prikazano v katalogu.

Nekateri ukazi, ki jih moramo poslati LCD prikazovalniku za posamezne naloge:

                                         Tabela 2: Ukazi za LCD zaslon


Program za prikaz enakega napisa na LCD zaslonu v programskem jeziku c:

V program bomo vključili zaglavno datoteko, header file. Za programiranje mikrokontrolerja je splošen pristop ta, da deklariramo in definiramo funkcije v isti datoteki, v datoteki kjer je zapisana glavna funkcija void main(). Ta pristop je splošno sprejet, saj je programerju enostavno razumeti celoten program, napisan v eni datoteki. Zna pa povzročati probleme pri razumevanju programa, če je vključenih več zunanjih enot. Predstavljajmo si aplikacijo, ki vključuje LCD zaslon, matrično tipkovnico, GSM in RFID modul, ki so povezani z mikrokontrolerjem. Vse navedene enote potrebujejo posebne funkcije za delovanje in komunikacijo z mikrokontrolerjem. Če bi napisali vse te funkcije v isti datoteki, bi bil takšen program težko razumljiv in bi programerju povzročal težave pri njegovem razumevanju. Zato lahko ugotovimo, da moramo za večje aplikacije nekaj storiti, uporabiti modularno programiranje. To je pristop, v katerem so funkcije zapisane v drugi datoteki, kličemo pa jih iz glavnega programa z vpisom #include"ustrezna_datoteka.h". Če uporabljamo vse zgoraj opisane zunanje enote in uporabo zaglavnih datotek, bi namesto velikega števila vrstic in funkcij v glavni datoteki, iz nje le vključili klic posameznih:

#include"lcd.h"

#include"gsm.h"

#include"keypad.h"

#include"rfid.h"

Takšen pristop vsekakor zmanjša zapletenost programa, posamezne zaglavne datoteke pa lahko uporabljamo v kateremkoli programu.

Enako kot datoteko v kateri je zapisana glavna funkcija void main(), v projekt vstavimo tudi zaglavno (Header File) File >> New, jo poimenujemo in dodamo končnico .h. Shranjena mora biti v mapi projekta. V našem primeru jo bomo poimenovali lcd.h:

Slika 6: Projekt z vključeno zaglavno datoteko lcd.h

Program za prikaz napisa na LCD zaslonu v c jeziku:

 /*

  Prikaz napisa na LCD zaslonu.

  Okolje MPLAB IDE v8.92, HI_TECH compiler for PIC10/12/16 MCUs V9.82, oscilator 4 MHz.

  Avtor: Milan Ivič, nov. 2017.

*/

    #include <htc.h>

    #include <pic.h>

 //Definiranje priključnih pinov za LCD:

    #define RS RB1

    #define EN RB3

    #define D4 RB4

    #define D5 RB5

    #define D6 RB6

    #define D7 RB7

    #define _XTAL_FREQ 4000000

    __CONFIG (0x2129);

    #include "lcd.h"                          //Vključitev header (zaglavne) datoteke lcd.h

 void main()

 {

    int i;

    TRISB = 0x00;                             //Pini RB0 - RB7 so izhodni

    LCD4bitni_Init();                         //Klicanje funkcije za inicializacijo LCD-ja

    while(1)

    {

        LCD4bitni_Set_Cursor(1,0);                  //Prva vrstica prvi znak (znak 0)

        LCD4bitni_Pisi_niz("Mikrokontroler");

        LCD4bitni_Set_Cursor(2,0);                  //Druga vrstica prvi znak (znak 0)

        LCD4bitni_Pisi_niz("in LCD zaslon");

    }

 }

Zaglavna datoteka (Header File) lcd.h:

 //LCD 4-bitni način delovanja

 void LCD4bitni_Port(char a)     //Nastavitev bitov podatkovnih linij

 {

    if(a & 1)                           //& => IN operacija nad biti (1 dec = 0001 dvojiško)

        D4 = 1;                         //Podatkovna linija D4

    else

        D4 = 0;

    if(a & 2)                           //2 dec = 0010 dvojiško

        D5 = 1;

    else

        D5 = 0;

    if(a & 4)                           //4 dec = 0100 dvojiško

        D6 = 1;

    else

        D6 = 0;

    if(a & 8)                           //8 dec = 1000 dvojiško

        D7 = 1;

    else

        D7 = 0;

 }

 void LCD4bitni_Cmd(char a)

 {

    RS = 0;                           //RS = 0, Ukazni način, vpisovanje podatkov v LCD

    LCD4bitni_Port(a);

    EN  = 1;                         //E = 1, na pin RB3 pošlje 1

    __delay_ms(4);

    EN  = 0;                          //E = 0, na pin RB3 po 4 ms pošlje 0. Obvestimo LCD o novem podatku

 }

 LCD4bitni_Clear()

 {

    LCD4bitni_Cmd(0x00);        //Počisti zaslon LCD-ja

    LCD4bitni_Cmd(0x01);        //Postavi kurzor na prvo pozicijo

 }

 void LCD4bitni_Set_Cursor(char a, char b)

 {

    char temp,z,y;

    if(a == 1)                      //Prva vrstica LCD-ja

    {

        temp = 0x80 + b;

        z = temp>>4;                  //Spodnji štirje biti 8-bitnega podatka

        y = (0x80+b) & 0x0F;      //Zgornji štirje biti, IN operacija nad ustreznimi biti

        LCD4bitni_Cmd(z);         //Nastavitev vrstice

        LCD4bitni_Cmd(y);         //Nastavitev kolone

    }

    else if(a == 2)                     //Druga vrstica LCD-ja

    {

        temp = 0xC0 + b;

        z = temp>>4;

        y = (0xC0+b) & 0x0F;

        LCD4bitni_Cmd(z);

        LCD4bitni_Cmd(y);

    }

 }

 void LCD4bitni_Init()         //Inicializacija LCD-ja

 {

    LCD4bitni_Port(0x00);

    __delay_ms(20);

    LCD4bitni_Cmd(0x03);       //4-bitni način

    __delay_ms(5);

    LCD4bitni_Cmd(0x03);

    __delay_ms(11);

    LCD4bitni_Cmd(0x03);

    LCD4bitni_Cmd(0x02);       //Vrne se domov (zaslon pomakne v prvotni položaj)

    LCD4bitni_Cmd(0x02);

    LCD4bitni_Cmd(0x08);       //Izbira prve vrstice

    LCD4bitni_Cmd(0x00);       //Počisti prvo vrstico

    LCD4bitni_Cmd(0x0C);       //Izbira druge vrstice

    LCD4bitni_Cmd(0x00);       //Počisti drugo vrstico

    LCD4bitni_Cmd(0x06);       //Nastavi kazalček (kurzor) za premikanje v desno

 }

  void LCD4bitni_Pisi_znak(char a)         //Funkcija za pisanje znakov (pošiljanje 8-bitnega podatka v 4-bitnem načinu)

 {

    char temp,y;

    temp = a&0x0F;                       //Spodnji 4 biti

    y = a&0xF0;                             //Zgornji 4 biti

    RS = 1;                                     //RS = 1 => Podatkovni način, pisanje znakov

    LCD4bitni_Port(y>>4);             //Pošiljanje podatkov

    EN = 1;

    __delay_ms(5);

    EN = 0;

    LCD4bitni_Port(temp);

    EN = 1;

    __delay_ms(5);

    EN = 0;

 }

 void LCD4bitni_Pisi_niz(char *a)            //Funkcija za pisanje nizov

 {

    int i;

    for(i=0; a[i]!='\0'; i++)

        LCD4bitni_Pisi_znak(a[i]);

 }

 void LCD4bitni_Pomakni_Desno()                 //Funkcija za pomikanje v desno

 {

    LCD4bitni_Cmd(0x01);

    LCD4bitni_Cmd(0x0C);

 }

 void LCD4bitni_Pomakni_Levo()                  //Funkcija za pomikanje napisa levo

 {

    LCD4bitni_Cmd(0x01);

    LCD4bitni_Cmd(0x08);

 }

 void LCD4bitni_Pisi_Znake(char a)              //Pošiljanje 8-bitov po 4-bitnem načinu

 {

    char Spodnji_biti,Zgornji_biti;

    Spodnji_biti = a&0x0F;

    Zgornji_biti = a&0xF0;

    RS = 1;

    LCD4bitni_Port(Zgornji_biti>>4);            //Pošiljanje zgornjih 4 bitov

    EN = 1;

    for(int j=2130483; j<=0; j--)  NOP();

    EN = 0;

    LCD4bitni_Port(Spodnji_biti);               //Pošiljanje spodnjih 4 bitov

    EN = 1;

    for(int j=2130483; j<=0; j--)  NOP();

    EN = 0;

 }

 void LCD4bitni_Pisi_Niz(char *a)

 {

    int j;

    for(j=0;a[j]!='\0';j++)

        LCD4bitni_Pisi_Znake(a[j]);

 }

Izdelajmo sedaj program, ki bo uporabljal različne načine prikazovanja napisa na LCD zaslonu, pomikanje zapisa v levo in v desno ter prikazal osem znakov, ki smo jih sami ustvarili. Zaglavna datoteka lcd.h je enaka, napisali bomo le novi glavni program. Izpisi na LCD-ju naj bodo takšni, kot prikazuje spodnji posnetek:

V zaslonski pomnilnik CGRAM lahko podatke zapisujemo in iz njega podatke beremo. Njegova velikost je 64 bajtov, namenjen pa je izdelavi lastnih znakov oziroma simbolov. Če delamo z znaki velikosti 5 x 8 pik, lahko ustvarimo do 8 novih znakov. Vsak znak vsebuje 8 naslovov, vrednosti znaka pa so odvisne od simbola oziroma znaka, ki smo ga ustvarili. Mi smo ustvarili 8 znakov:

Slika 7: Kreiranje lastnih znakov in njihove vrednosti

Program v c jeziku:

 /*

  Prikaz napisa na LCD zaslonu. Pomikanje napisa, napisi znakov in lastno izdelanih znakov.

  Okolje MPLAB IDE v8.92, HI_TECH compiler for PIC10/12/16 MCUs V9.82, oscilator 4 MHz.

  Avtor: Milan Ivič, nov. 2017.

*/

    #include <htc.h>

    #include <pic.h>

 //Definiranje priključnih pinov za LCD:

    #define RS RB1

    #define EN RB3

    #define D4 RB4

    #define D5 RB5

    #define D6 RB6

    #define D7 RB7

    #define _XTAL_FREQ 4000000

    __CONFIG (0x2129);

    #include "lcd.h"                             //Vključitev header (zaglavne) datoteke lcd.h

    const unsigned short Posebni_znaki5x8[] = {

    0b01110,0b01110,0b00100,0b01110,0b10101,0b00100,0b01010,0b01010,            //Koda za CGRAM, posebni znak 1

    0b00000,0b00000,0b01010,0b00100,0b00100,0b10001,0b01110,0b00000,           //Koda za CGRAM, posebni znak 2

    0b01010,0b10101,0b01010,0b10101,0b01010,0b10101,0b01010,0b10101,          //Koda za CGRAM, posebni znak 3

    0b00000,0b00100,0b00010,0b11111,0b00010,0b00100,0b00000,0b00000,           //Koda za CGRAM, posebni znak 4

    0b00000,0b01010,0b10101,0b10001,0b10001,0b01010,0b00100,0b00000,          //Koda za CGRAM, posebni znak 5

    0b11011,0b00000,0b01010,0b00000,0b10101,0b10001,0b01110,0b00000,           //Koda za CGRAM, posebni znak 6

    0b00100,0b01110,0b00100,0b00100,0b00100,0b01110,0b11111,0b11111,            //Koda za CGRAM, posebni znak 7

    0b01110,0b10001,0b01110,0b00100,0b11111,0b00100,0b01010,0b10001             //Koda za CGRAM, posebni znak 8

    };

 void main()

 {

    int i;

    unsigned int j; char a;

    TRISB = 0x00;                               //Pini RB0 - RB7 so izhodni

    LCD4bitni_Init();                           //Klicanje funkcije za inicializacijo LCD-ja

    LCD4bitni_Cmd(0x04);                 //Naslov CGRAM

    LCD4bitni_Cmd(0x00);

    for (j = 0; j <= 63 ; j++)

    {

        LCD4bitni_Pisi_Znake(Posebni_znaki5x8[j]);

    }

    LCD4bitni_Cmd(0x00);                 //Počisti zaslon LCD-ja

    LCD4bitni_Cmd(0x02);                 //Pomakni zaslon na začetek

  while(1)

  {

    LCD4bitni_Set_Cursor(1,0);                             //Prva vrstica prvi znak (znak 0)

    LCD4bitni_Pisi_niz("Mikrokontroler in LCD zaslon");

    for(i=0; i<12; i++)

    {

        __delay_ms(400);

        LCD4bitni_Pomakni_Levo();

     }

    __delay_ms(1000);

    for(i=0; i<12; i++)

    {

        __delay_ms(600);

        LCD4bitni_Pomakni_Desno();

     }

    __delay_ms(800);

    LCD4bitni_Clear();

    LCD4bitni_Set_Cursor(2,6);

    LCD4bitni_Pisi_znak('M');

    __delay_ms(500);

    LCD4bitni_Set_Cursor(2,8);

    LCD4bitni_Pisi_Znake(0b00100110);             //Binarna vrednost za znak & (katalog)

    __delay_ms(500);

    LCD4bitni_Set_Cursor(2,10);

    LCD4bitni_Pisi_znak('I');

    __delay_ms(2000);

    LCD4bitni_Clear();

    __delay_ms(1000);

    //Izpis posebnih znakov:

    LCD4bitni_Set_Cursor(1,0);

    LCD4bitni_Pisi_znak(0);

    LCD4bitni_Set_Cursor(1,2);

    LCD4bitni_Pisi_znak(1);

    LCD4bitni_Set_Cursor(1,4);

    LCD4bitni_Pisi_znak(2);

    LCD4bitni_Set_Cursor(1,6);

    LCD4bitni_Pisi_znak(3);

    LCD4bitni_Set_Cursor(1,8);

    LCD4bitni_Pisi_znak(4);

    LCD4bitni_Set_Cursor(1,10);

    LCD4bitni_Pisi_znak(5);

    LCD4bitni_Set_Cursor(1,12);

    LCD4bitni_Pisi_znak(6);

    LCD4bitni_Set_Cursor(1,14);

    LCD4bitni_Pisi_znak(7);

    __delay_ms(2500);

    LCD4bitni_Clear();

  }

 }