;***************************************************************************************************
;****               Ovládač LCD displeja typu HD44870 (iba zápis do LCD, 4 bitový mód)          ****
;****                             Procesor PIC16Fxx s kryštálom 4Mhz                            ****
;****                                     LCD max. 80 znakov                                    ****
;****                                       c.NIKI 5/2016                                       ****
;****                                           v.1.0                                           ****
;****                                                                                           ****
;***************************************************************************************************

;Podporované príkazy pre ovládanie displeja.
;LCD_WR_CMD       - Zápis povelu pre display.
;LCD_WR_CHAR      - Zápis znaku na pozíciu kurzora.
;LCD_INIT         - Inicializácia displeja (default hodnoty, kurzor, blikanie, smery, atd. je možné prednastaviť v regisri LCD_FLAGS) 
;LCD_CLR          - Zmaže displej a nastaví kurzor na začiatok prvého riadku.
;LCD_HOME         - Nastaví kurzor na prvý znak na prvom riadku. 
;LCD_DIR_L        - Nastavuje smer posunu kurzora alebo textu vľavo, posun nastáva po zápise znaku.
;LCD_DIR_R        - Nastavuje smer posunu kurzora alebo textu vpravo, posun nastáva po zápise znaku.
;LCD_SHIFT_TEXT   - Nastaví displej na posun textu. Po zápise znaku sa bude posúvať text a kurzor bude stáť na mieste.
;LCD_SHIFT_CUR    - Nastaví displej na posun kurzora. Po zápise znaku sa posunie kurzor text bude stáť.
;LCD_ON           - Zapni displej.
;LCD_OFF          - Vypni displej.          
;LCD_CUR_ON       - Zapni zobrazovanie kurzora.
;LCD_CUR_OFF      - Vypni zobrazovanie kurzora.
;LCD_FLASH_ON     - Zapni blikanie kurzora.
;LCD_FLASH_OFF    - Vypni blikanie kurzora.
;LCD_CUR_INC      - Posunie kurzor o jednu pozíciu do prava.
;LCD_CUR_DEC      - Posunie kurzor o jednu pozíciu do ľava.
;LCD_TEXT_INC     - Posunie text o jednu pozíciu do prava.
;LCD_TEXT_DEC     - Posunie text o jednu pozíciu do ľava.
;LCD_FONT_5X8     - Nastaví font displeja. (default)
;LCD_FONT_5X10    - Nastaví font displeja.
;LCD_1_LINE       - Nastaví displej do jednoriadkového režimu.
;LCD_2_LINE       - Nastaví displej do dvojriadkového režimu.
;LCD_SET_POS      - Nastaví kurzor na daný riadok a stĺpec. Riadok na pozíciu danú registrom LCD_ROW 
;                   a stĺpec na pozíciu danú registrom LCD_COL. Hodnoty v LCD_ROW a LCD_COL sa volaním rutiny nezmenia.
;LCD_NATIONAL     - Zapíše do CGRAM prvých 8 znakov z tabuľky znakov, usporiadaním sa dá vytvoriť potrebná národná sada.       
;LCD_WR_STR       - Zápis reťazca znakov na pozíciu danú LCD_ROW,LCD_COL od adresy EE_ADDR. 
;                   Prenos skončí keď rutina narazí na znak FFH.  

;****************************************************************************************************************
;Nastavenie pripojenia LCD, vývody treba priradiť podľa pripojenia vývodov disleja k mikrokontroléru 
;a podľa typu displeja.
 
 constant  CHARS    =    16             ;<-- Pocet znakov na riadok displeja
 #define   PORT          PORTB          ;<-- Datový port LCD, LCD treba  pripojiť na D0-D3
 #define   RS            PORTB,5        ;<-- Signál RS volba registra dat, 0 - inštrukcia, 1 - data
 #define   E             PORTB,4        ;<-- Výber obvodu, zápis do LCD nastáva pri prechode z úrovne H do L
 
;****************************************************************************************************************
 #define    _N           LCD_FLAGS,0    ;N   počet riadkov displeja, 0 - jednoriadkový, 1 - dvojriadkový
 #define    _F           LCD_FLAGS,1    ;F   typ znaku 0 - 5x7 bodov, 1 - 5x10 bodov   
 #define    _C           LCD_FLAGS,2    ;C   0 - kurzor OFF, 1 - kurzor ON
 #define    _B           LCD_FLAGS,3    ;B   0 - kurzor nebliká, 1 - kurzor bliká
 #define    _S           LCD_FLAGS,4    ;S   0 - rolovanie textu vypnuté, 1 - rolovanie textu zapnuté
 #define   _RL           LCD_FLAGS,5    ;R/L 0 - rolovanie textu doľava , 1 - rolovanie do prava
 #define   _SC           LCD_FLAGS,6    ;S/C 0 - kurzor, 1 -  text, prepína posun kurzor alebo text
 #define   _ID           LCD_FLAGS,7    ;I/D 0 - dekrement pozicie kurzora, 1 - inkrement pozicie kurzora  
 #define   _D            LCD_FLAGS1,0   ;D   0 - displej OFF, 1 - displej ON
 
;Blok používaných registrov
  cblock 23h                                ;<-- treba nastaviť tak aby data nezavadzali v pamäti RAM
  WAIT1                                     ;registre čítača času
  WAIT2 
  LCD_ROW
  LCD_COL
  LCD_TMP
  LCD_TMP1
  LCD_FLAGS
  LCD_FLAGS1
  LCD_REMB
  endc

  org H'350'                               ;<-- treba nastaviť tak aby data nezavadzali v pamäti programu 
 ;********************************************************************************************************
;Inicializácia displeja
LCD_INIT 	   MOVLW	B'10100001'        ;<-- prednastavenie mimo príkazy (môže sa nastaviť ale nemusí)
   		       MOVWF 	LCD_FLAGS          ;<-- nastaví vlastnosti LCD pri inicializácii.
               MOVLW    B'00000001'
               MOVWF    LCD_FLAGS1
          	   MOVLW	1                  ;1 riadok a 1 stĺpec.
          	   MOVWF    LCD_ROW
               MOVWF    LCD_COL
               CALL     WAIT15             ;Najprv počkaj 15mS po zapnutí napájania.
               BCF      RS                 ;RS do log.0, zápis povelu
               CALL     PORT_OUT           ;port ako výstup
               MOVLW    03H                
               CALL     LCD_WR_NIBBLE      ;zapíš iba dolný polbyte 03H do LCD 
               CALL     WAIT4.1            ;Počkaj minimálne 4.1mS  
               MOVLW    03H          
               CALL     LCD_WR_NIBBLE      ;komunikácia 8bit,opäť zapíš 03H do LCD 
               CALL     WAIT40 
               CALL     WAIT40             ;Počkaj minimálne 100uS
               MOVLW    03H          
               CALL     LCD_WR_NIBBLE      ;komunikacia 8bit,opäť zapíš 03H do LCD
               MOVLW    02h                ;navoľ 4 bitovú komunikáciu.
               CALL     LCD_WR_NIBBLE
               MOVLW    20h
               MOVWF    LCD_TMP            ;20h do zalohy  
               BTFSC    _N                 ;test počtu riadkov, ak je _N = 1 , jedná sa o dvojriadkový displej. 
               BSF      LCD_TMP,3          ;nastav N = 1, displej je dvojriadkový
               BTFSC    _F                 ;Test typu znaku,0 - 5x7, 1 - 5x10  
               BSF      LCD_TMP,2          ;nastav F = 1, znak 5x10
               MOVF     LCD_TMP,W          ;Typ znaku a pocet riadkov do LCD           
               CALL     LCD_WR_CMD
               MOVLW    0Ch                ;maska pre zapnutie displeja, kurzor a blikanie kurzora
               MOVWF    LCD_TMP     
               BTFSC    _C                 ;zapnutie kurzora
               BSF      LCD_TMP,1
               BTFSC    _B                 ;blikanie kurzora
               BSF      LCD_TMP,0
               MOVF     LCD_TMP,W           
               CALL     LCD_WR_CMD
               MOVLW    1                  ;zmaž displej          
               CALL     LCD_WR_CMD
               CALL     WAIT1.64
               MOVLW    4                  ;rolovanie textu a smer
               MOVWF    LCD_TMP
               BTFSC    _ID                ;posun kurzora
               BSF      LCD_TMP,1
               BTFSC    _S                 ;smer posunu kurzora
               BSF      LCD_TMP,0
               MOVF     LCD_TMP,W           
               RETURN

;Prenesie data z W na port a generuje zapisovací impulz
LCD_WR_CHAR    BSF      RS
LCD_WR_CMD     MOVWF    LCD_TMP         ;data do zálohy
               SWAPF    LCD_TMP,F       ;prehodi polbajty
               MOVF     PORT,W          ;stav portu do zálohy a vynuluj dolný polbajt.
               ANDLW    B'11110000'
               MOVWF    LCD_TMP1
               MOVF     LCD_TMP,W       ;do W prehodené data zo zálohy
               ANDLW    B'00001111'     ;horný polbyte vynuluj
               IORWF    LCD_TMP1,W      ;zapis dolného polbyte bez ovplyvnenia horného pobyte portu.
               MOVWF    PORT            ;vlož do portu a vysielaj
               BSF      E               ;generuj zapisovací impulz
               NOP
               BCF      E
               CALL     WAIT40          ;počkaj 40uS
               SWAPF    LCD_TMP,F       ;v zálohe znova prehodíme polbajty, dolný bude opä? na svojom mieste
               MOVF     LCD_TMP,W       ;obnova W registra
LCD_WR_NIBBLE  MOVWF    LCD_TMP
               MOVF     PORT,W          
               ANDLW    B'11110000'     ;stav portu opäť do zálohy a vynuluj dolný polbajt.
               MOVWF    LCD_TMP1
               MOVF     LCD_TMP,W       ;data do W
               ANDLW    B'00001111'     ;nuluj horný polbyte dat a vytvor masku
               IORWF    LCD_TMP1,W      ;zápis dolného polbyte bez ovplyvnenia horného pobyte portu.
               MOVWF    PORT            ;data z W do portu a ochod na generovanie zápisu
               BSF      E               ;generuj zapisovací impulz
               NOP
               BCF      E
               CALL     WAIT40          ;počkaj 40uS
               BCF      RS              ;prepni LCD na príjem príkazov.
               RETURN

;Zmaž display
LCD_CLR        MOVLW    1               ;nastav ukazatele na prvý riadok a prvý stĺpec
               MOVWF    LCD_ROW
               MOVWF    LCD_COL
               CALL     LCD_WR_CMD      ;zapíš povel č.1 do LCD - CLR,pri mazaní sa kurzor nastaví na zač. displeja. 
               CALL     WAIT1.64        ;čakaj 1,64mS
               RETURN

;nastav kurzor na HOME
LCD_HOME       MOVLW    B'00000010'
               CALL     LCD_WR_CMD
               RETURN

;nastav smer posunu a typ posunu kurzor/text
LCD_DIR_L      BCF      _ID
               GOTO     LDLJ1
LCD_DIR_R      BSF      _ID
               GOTO     LDLJ1
LCD_SHIFT_CUR  BCF      _S
               GOTO     LDLJ1
LCD_SHIFT_TEXT BSF      _S
LDLJ1          MOVLW    4 
               MOVWF    LCD_TMP
               BTFSC    _ID
               BSF      LCD_TMP,1
               BTFSC    _S
               BSF      LCD_TMP,0
               GOTO     ENDD

;zapni displej,kurzor,blikanie kurzora
LCD_ON         BSF      _D 
               GOTO     LCLJ1
LCD_OFF        BCF      _D
               GOTO     LCLJ1         
LCD_CUR_ON     BSF      _C 
               GOTO     LCLJ1
LCD_CUR_OFF    BCF      _C 
               GOTO     LCLJ1
LCD_FLASH_ON   BSF      _B  
               GOTO     LCLJ1
LCD_FLASH_OFF  BCF      _B
LCLJ1          MOVLW    8
               MOVWF    LCD_TMP
               BTFSC    _D
               BSF      LCD_TMP,2
               BTFSC    _C
               BSF      LCD_TMP,1
               BTFSC    _B
               BSF      LCD_TMP,0
               GOTO     ENDD

;Posun kurzora bez zápisu znaku
LCD_CUR_INC    BCF      _SC
               BSF      _RL
               GOTO     LCSJ1 
LCD_CUR_DEC    BCF      _SC
               BCF      _RL
               GOTO     LCSJ1  
LCD_TEXT_INC   BSF      _SC
               BSF      _RL
               GOTO     LCSJ1
LCD_TEXT_DEC   BSF      _SC
               BCF      _RL
LCSJ1          MOVLW    16
               MOVWF    LCD_TMP
               BTFSC    _SC
               BSF      LCD_TMP,3
               BTFSC    _RL
               BSF      LCD_TMP,2
               GOTO     ENDD

;Nastavenie fontu displeja
LCD_FONT_5X8   BCF      _F
               GOTO     LCFJ1  
LCD_FONT_5X10  BSF      _F
               GOTO     LCFJ1
LCD_1_LINE     BCF      _N
               GOTO     LCFJ1
LCD_2_LINE     BSF      _N
LCFJ1          MOVLW    32
               MOVWF    LCD_TMP
               BTFSC    _F
               BSF      LCD_TMP,2
               BTFSC    _N
               BSF      LCD_TMP,3
ENDD           MOVF     LCD_TMP,W
               CALL     LCD_WR_CMD
               RETURN  

;nastav kurzor na pozíciu riadok / stĺpec 
LCD_SET_POS    DECF     LCD_ROW,W     ;znížime obsah o jedna lebo riadok začína od nuly 
               MOVWF    LCD_TMP       ;číslo riadku do zálohy
               MOVLW    80h           ;prvý riadok,nastav počiatočnú adresu riadku
               BTFSC    LCD_TMP,0
               ADDLW    H'40'
               BSF      LCD_TMP,7     ;príkaz zápis adresy do DDRAM
               BTFSC    LCD_TMP,1
               ADDLW    CHARS
               ADDWF    LCD_COL,W     ;pripočítaj aktuálnu pozíciu kurzora v stĺpci.
               MOVWF    LCD_TMP
               DECF     LCD_TMP,W
               CALL     LCD_WR_CMD    ;vysielaj do LCD
               RETURN

;prenesie reťazec znakov z EEPROM do LCD
;využíva modul EEPROM.inc
LCD_WR_STR     MOVWF    EE_ADR
LWSJ0          CLRWDT
               CALL     RD_EEPROM
               MOVWF    LCD_TMP
               SUBLW    H'FF'
               BTFSC    STATUS,Z
               RETURN
               MOVF     LCD_TMP,W
               CALL     LCD_WR_CHAR
               GOTO     LWSJ0         ;návrat na čítanie z EEPROM
               RETURN

;čakacia slučka 4.1mSec.
WAIT4.1        MOVLW    81            ;<-- 168 pre 2 Mhz       
               MOVWF    WAIT1
               MOVLW    6             ;<-- 3 pre 2 Mhz
               MOVWF    WAIT2
               GOTO     WLOOP

;cakacia slucka 1,64mSec.
WAIT1.64       MOVLW    30            ;<-- 13 pre 2 Mhz        
               MOVWF    WAIT1
               MOVLW    3             ;<-- 2 pre 2Mhz
               MOVWF    WAIT2
               GOTO     WLOOP
          
;čakacia slučka 40 uSec.
WAIT40         CLRWDT
               MOVLW    15            ;<-- 6 pre 2 Mhz
               MOVWF    WAIT1
               DECFSZ   WAIT1,F
               GOTO     $-1
               RETURN

;čakacia slučka 15 mSec.
WAIT15         MOVLW    115           ;<-- 200 pre 2 Mhz       
               MOVWF    WAIT1
               MOVLW    20            ;<-- 10 pre 2 Mhz
               MOVWF    WAIT2
               GOTO     WLOOP
          
;Datový port nastav ako výstupný
PORT_OUT       MOVLW     PORT            ;Adresa portu do ukazateľa
               MOVWF     FSR
               BSF       FSR,7           ;Ukazate3 posuo na tris register daneho portu.
               MOVLW     B'11110000'     ;4 bitová komunikácia, "zmaž  b3-b0 v tris"
               ANDWF     INDF,F
               RETURN       

;Jadro čakacej slučky
WLOOP          CLRWDT
               DECFSZ   WAIT1,F
               GOTO     $-1
               DECFSZ   WAIT2,F
               GOTO     $-4
               RETURN  

;Natiahne prvých 8 znakov národnej znakovej sady podla výberu poprehadzovaním.
LCD_NATIONAL   CALL      WAIT1.64
               MOVLW     40h          ;príkaz "prepni na zápis do CGRAM" 
               CALL      LCD_WR_CMD   ;odošli do LCD
               MOVLW     64           ;počítadlo 8 znakov po 8 bodových riadkov
               MOVWF     LCD_REMB
               CLRF      EE_ADR       ;načítavať sa bude od adresy 00 v EEPROM kde začína sada znakov nár. abecedy
               CALL      RD_EEPROM    ;načítaj data z EEPROM (1 riadok znaku)
               CALL      LCD_WR_CHAR  ;zapíš do CGRAM v LCD
               DECFSZ    LCD_REMB,F   ;posuň počítadlo
               GOTO      $-3          ;ak neboli ešte načítané všetky data pokračuj v načítavaní z EEPROM
               MOVLW     80h          ;koniec načítavania, prepni LCD na zápis do DDRAM.
               CALL      LCD_WR_CMD
               RETURN

 ;výber znakov národnej abecedy.Podľa potreby vybrať max. 8 znakov. (jeden riadok = jeden znak)            
 org 2100h
       de 0Ah,04h,0Fh,10h,0Eh,01h,1Eh,00h ; š
       de 0Ah,04h,0Eh,10h,10h,11h,0Eh,00h ; č
       de 0Ah,04h,1Fh,02h,04h,08h,1Fh,00h ; ž
       de 02h,04h,0Eh,01h,0Fh,11h,0Fh,00h ; á
       de 02h,04h,0Ch,04h,04h,04h,0Eh,00h ; í
       de 1Dh,09h,0Dh,13h,11h,13h,0Dh,00h ; ď
       de 04h,0eh,15h,04h,04h,04h,04h,00h ; ^ šípka hore
       de 04h,04h,04h,04h,15h,0eh,04h,00h ; ˇ šípka dolu
       ;de 02h,04h,11h,11h,0Fh,01h,0Eh,00h ; ý
       ;de 0Ah,04h,16h,19h,10h,10h,10h,00h ; ř
       ;de 02h,04h,0Eh,11h,1Fh,10h,0Eh,00h ; é
       ;de 02h,04h,11h,11h,11h,13h,0Dh,00h ; ú
       ;de 02h,04h,0Eh,11h,11h,11h,0Eh,00h ; ó
       ;de 06h,06h,11h,11h,11h,13h,0Dh,00h ; ů
       ;de 0Ah,04h,16h,19h,11h,11h,11h,00h ; ň
       ;de 0Bh,1Dh,08h,08h,08h,09h,06h,00h ; ť
       









  