;	4MHz-es clock-ra íródott LCD vezérlő program (időzítő rutin)
;	Az LCD-t 2soros 4bites üzemmódban működtetjük
; 	Az LCD alsó 4 bitje a "levegőben lóg" de teljesen mindegy, 
;	hogy mit olvas be alul az LCD, mikor 8 bites módban van.
; 	Amikor már átálltunk a 4 bites üzemre, a portára küldött adatból, 
;	csak a felső négy bit (nibble) érvényes az LCD-n. 
; 	A nyocbites adatokat, most már kétszer 4 bitben küldjük ki.
;	Előszőr a felső 4 bitet, majd az alsó 4-et. 
;       A program nem túl elegáns, de jól követhető, hogy mit kell tenni.

; LCD bekötése:	
;	LCDpin	Funkció		Porta			Állapot v. jelleg       Demo IDC pin
;	1	VSS		-Tápfesz		GND			1
;	2	VDD		+Tápfesz		+5V			2		
;	3	VEE(Vo)		Kontraszt poti közepe	0..+5V			---
;	4	RS		PORTD.0			H=Data/L=Command	3
;	5	R/W		PORTD.1			H=Read/W=Write		4
;	6	E		PORTD.2			Enable(Felfutó élre)	5	
;	7	D0		-----			(Nem használt)		---
;	8	D1		-----			(Nem használt)		---
;	9	D2		-----			(Nem használt)		---
;	10	D3	        PORTD.3			(Nem hastnált)		6
;	11	D4		PORTD.4			Data D4 majd D0		7
;	12	D5		PORTD.5			Data D5 majd D1		8
;	13	D6		PORTD.6			Data D6 majd D2		9
;	14	D7		PORTD.7			Data D7 majd D3(& Busy)	10
;	15	Led Anód	-------			Háttér világítás	---
;	16	Led Katód	-------			Háttér világítás	---


	Errorlevel	0,-302,-309,-216,-308 ; hibaüzenetek letiltása	
	Title	LCD_4_biten     ; Fejléc az lst file-ban
	list	X=on            ; Listafile bekapcsolása
	List	c=132           ; 132 karakteres sorok
	List	N=94            ; 94 sor

	processor  16F877
	radix hex               ; alap számrendszer HEXA
	
	include p16f877.inc     ; A proci regisztereinek deklarációja
;------------------------------------------------------
;RAM regiszterek deklarációja
;------------------------------------------------------
	CBLOCK	0x20
flags,flag1		;jelzőbitek
timer1,timer2		;időzítő számlálók
cnt0,cnt1,cnt2		;számláló regiszterek
cnthi,cntlo		;16 bites számláló (Counter Hi-Lo)
count0,count1		;bin_hex rutiné
temp0,temp1,temp2	;átmeneti regiszterek
wtreg0,wtreg1,wtreg2	;várakozó hurok regiszterei
lcdaddr			;karakter címe az LCD-n (első sor 00h..ffh-ig, második 40h..4ffh-ig)
lcddata			;karakter kódja az LCD-n (LCD-nek átadott adat)
lcdpos			;karakter aktuális pozíciója az LCD-n (átmeneti tároló)
chr1,chr2               ; kiírandó aktuális karakter
	endc

opcioreg	equ	b'11001111'	;RPBU=dis. INT=rise, RTCC=int.
					;PRESC.=wdt, PRES.=111 (1:128)
iranyb		equ	b'00000000'     ; PortaB iránya
iranyd		equ	b'00000000'     ; PortaD iránya

;---------------------------------------------------------
;	BITEK
;---------------------------------------------------------
#define	lcdbusy		flags,0			;flags regiszterben a busy bit
#define	carry		status,c                ; Átvitelibit
#define	zero		status,z                ; Zéro bit
#define	lcdport		PORTD			; LCD a Dportán
#define	lcdtris		TRISD                   ; Dporta írányregisztere
#define	enabl		lcdport,2		; LCD "enable" vezérlő lába PD2	
#define	busy		lcdport,7		; busy bit az LCD felől
#define	lcdcmd		bcf	lcdport,0	; RS parancs küldése    PD0=1
#define	lcddat		bsf	lcdport,0	; RS adat küldése       PD0=0
#define	lcdrd		bsf	lcdport,1	; Read LCD              PD1=1
#define	lcdwr		bcf	lcdport,1	; Write LCD             PD1=0


enable	macro			; LCD Enable (Strobe) makro impulzus előállítása
	bsf	enabl           ; E=1
;        nop                     ; Vár
	bcf	enabl           ; E=0
	endm
;---------------------------------------------------------
	ORG	0000            ; Reset után induló cím
	nop                     ; Csak a debugger miatt, ha használod
	goto	INIMAIN         ; Ugrás az inicializáló részre

;---- INTERRUPT RUTIN ------------------------------------
	ORG	0x004
		 		;ide kellene írni az INT rutint, ha lenne
	retfie			;Interrupt rutin vége
;---------------------------------------------------------

;---- LCD inicializálása és 4bites üzemmódra állítása----------------------------

LCDSET
	banksel	lcdport		; Bank0
	movlw	b'00110000'	; LCD funkcio set (Most még 8bites az átvite)
	movwf	lcdport		; parancs az LCD portára
	lcdcmd			; vezérlő RS bit beállítása
	lcdwr			; vezérlő RW bit beállítása
	enable			; enable impulzus (felfutó élére beolvassa a parancsot)

	movlw	.5		; 5mS várakozás
	call	WAIT
	enable			; Ismételt parancs kiírás
	movlw	.10		; 100uS várakozás
	call 	DELAY10
	enable			; harmadszor is kiírom (nem kellene, de hátha nem érti még)
	movlw	.4		; 40uS várakozás
	call 	DELAY10
	
	MOVLW	b'00100000'	; LCD funkció Set (DL=0 azaz 4bites módra állítás)
	movwf	lcdport
	enable
	movlw	.4		; 40uS várakozás
	call 	DELAY10
				; Innentől már csak a felső 4bit számít a porton!
	MOVLW	b'00100000'	; Felső nibble: 
	movwf	lcdport		; Function Set: DL=0 azaz 4 bites mód
	enable
	MOVLW	b'10000000'	; Alsó nibble:
	movwf	lcdport		; N=1 azaz 2 soros üzemmód, 5x8 pontos CHR formátum
	enable
	movlw	.4		; 40us várakozás
	call 	DELAY10
	

	MOVLW	b'00000000'	; Felső nibble:
	movwf	lcdport		;
	enable
	MOVLW	b'10000000'	; Alsó nibble:
	movwf	lcdport		; Display off, Cursor off, Blinking off
	enable
	movlw	.4              ; 40us várakozás
	call 	DELAY10

	MOVLW	b'00000000'	; Felső nibble:
	movwf	lcdport
	enable
	MOVLW	b'11100000'	; Alsó nibble:
	movwf	lcdport		; Display on, Cursor on, Blinking off 
	enable
	movlw	.4
	call 	DELAY10

	MOVLW	b'00000000'	; Felső nibble:
	movwf	lcdport
	enable
	MOVLW	b'01100000'	; Alsó nibble:
	movwf	lcdport		; Entry mode, Kiírás ballról jobbra, Shift (léptetés) nincs
	enable
	movlw	.4
	call 	DELAY10

	MOVLW	b'00000000'	; Felső nibble:
	movwf	lcdport
	enable
	MOVLW	b'00100000'	; Alsó nibble:
	movwf	lcdport		; Return Home (kurzor az első sor elejére)
	enable
	movlw	.2
	call 	WAIT

	MOVLW	b'00000000'	; Felső nibble:
	movwf	lcdport
	enable
	MOVLW	b'00010000'	; Alsó nibble:
	movwf	lcdport		; Display Cleaar (kijelző letörlése)
        enable
	movlw	.2		; (ez a parancs csak 2mS alatt hajtódik csak végre)
	call 	WAIT
	
	return

;----- LCD ADDRES RUTIN -----------------------------------
;	Ez a rutin az lcdaddr-ben lévő adatot küldi az LCD-re
;	mint karakter memória címet (DD ADDR azaz karakter pozíció)
LCD_addr
	banksel	lcdport         ; Bank0
	movf	lcdaddr,w	; Áttesszük a címet, a LCD-pozíció RAM-ba
	movwf	lcdpos
	bsf	lcdpos,7	; Set DDRAM = 1 (bit7=1 : address set + 6bites DDRAM cím)

	movlw	0xf0		; Felső nibble kiválasztása
	andwf	lcdpos,w	; Maszkoljuk a felső nibble-t
	movwf	lcdport		; LCD portra kitesszük,
	lcdwr			; írás lesz (RW vezérlőbit),
	lcdcmd			; parancs, nem adat (RS vezérlő bit),
	enable			; kiírjuk.

	swapf	lcdpos,f	; alsó-felső nibble csere
	movlw	0xf0		; maszk (ez már az alsó nibble lesz, csak felül)
	andwf	lcdpos,w	; Maszkoljuk a felső nibble-t
	movwf	lcdport		; LCD portra kitesszük,
	lcdwr			; írás lesz (RW),
	lcdcmd			; parancs, nem adat (RS),
	enable			; kiírjuk.

	movlw	.4		; 40usec várakozás
	call 	DELAY10
	return

;----- LCD DATA rutin -------------------------------
;	Ez a rutin az LCDDATA-ban lévő adatot kiírja az LCD-re,
;	az aktuális kursor pozícióba
LCD_data
	banksel	lcdtris		; Bank1
	clrf	lcdtris		; PortD mind out
	banksel	lcdport		; Bank0
	movlw	0xf0		; Maszk felső nibble
	andwf	lcddata,w	; Adat byte maszkolása
	movwf	lcdport		; Kivitel a portra
	lcdwr			; Adat kiírás (Write)
	lcddat			; Adatot írok ki
	enable			; Enable bit impulzus
	swapf 	lcddata,f	; Alsó-felső nibble csere
	movlw	0xf0		; Maszk, máraz alsó nibble
	andwf	lcddata,w	; Adat byte maszk
	movwf	lcdport		; Kivitel a portra
	lcdwr			; Adat kiírás (Write)
	lcddat			; Adatot írok ki
	enable			; Enable bit impulzus
	
	movlw	.4		; 40usec várakozás
	call 	DELAY10
	return

;----- WAIT rutin (Órajel 4MHz) -----------------------------------
;	Ez a rutin N msec-ot vár, ahol az N száma a W regiszterben van,
;	Közben törli a watchdogot. 4MHz-re íródott
WAIT
	movwf	wtreg1          ; Külső ciklus számláló feltöltése
	movlw	.248            
	movwf	wtreg0          ; Belső ciklus számláló feltöltése (248-al)
WT1	clrwdt			; WDT törlése (nop helyett)
	decfsz	wtreg0,f        ; Belső számláló csökkentése
	goto	WT1             ; Új belső ciklusra
	movlw	.249
	movwf	wtreg0          ; Belső  ciklus száméláló újratöltése
	decfsz	wtreg1,f        ; Külső ciklus számláló csökkentése
	goto	WT1             ; Új külső ciklusra
	return                  ; Kész

;----- DELAY rutin ----------------------------------
;	A rutin késleltetése 10xN mikrosec, ahol az N a W regiszterben van.
DELAY10
	movwf	wtreg0          ; Ciklus számláló feltöltése (1usec de csak egyszer)
DLY1	goto	$+1             ; késleltetés 2usec (fosc/4 * 2ütem)
	goto	$+1             ; Megint 2usec        
	nop                     ; 1usec
	decfsz	wtreg0,f        ; Ciklus számláló csökkentése (2usec)
	goto	DLY1            ; Ugrás vissza, ha még nem telt le (2usec)
	RETURN                  ; Kész (2usec de csak egyszer)

;===================================================
INIMAIN                         ; Főprogram kezdete
	banksel	PORTA		; Bank0
	clrf	PORTB		; Porták előtörlése (B&D)
	clrf	PORTD

	banksel	OPTION_REG	; Bank1	
	movlw	opcioreg	; PullUp= no, INT=on falling, RTCC=internal
	movwf	OPTION_REG	; Presc. to watchdog, divide by 1:128
	movlw	iranyd		; Dporta iránybeállítása
	movwf	TRISD
	movlw	iranyb		; Bporta iránybeállítása
	movwf	TRISB

	banksel TMR1L		; Bank0
	goto 	START		; Ugrás a program kezdetére (de hát ott is vagyunk :))
                                ; A porták beállításán kívül erre a részre, nincs igazásn szükség, 
                                ; mert a RESET úgy is beállította ezeket.  

;----- Itt kezdődik a program -----------------------
START
	movlw	.15		; Bekapcsolás után 3sec várakozás (15*200ms),
	movwf	count1		; hogy az LCD tuti elinduljon.
STRT	movlw	.200		; 200msec várakozás
	call	WAIT		; Várakozás LCD RESET miatt
	decfsz	count1,f        ; 15*200ms=3sec
	goto 	STRT		

	call	LCDSET		; LCD setup rutine (LCD Inicializálás)
	banksel	lcdport		; Bank0
	movlw	0x00		; Pozícionálás a 0. karakterpozícióra
	movwf	lcdaddr         ; LCD-ADDR feltöltése
NEXT
        movf    lcdaddr,w       ; Megadom, melyik karaktert kell beolvasni az 1. sorban
        call    TXT1            ; Karakter beolvasása az 1. táblából
        movwf   chr1            ; 1. sor aktuális kiírandó karaktere
        movf    lcdaddr,w       ; Megadom, melyik karaktert kell beolvasni a 2.sorban
        call    TXT2            ; Karakter beolvasása a 2. táblából
        movwf   chr2            ; 2. sor aktuális kiírandó karaktere

	call	LCD_addr	; DDRAM (karakter pozíció 1,sorra)
        movf    chr1,w          ; Első sor karakterét a w-be
	movwf	lcddata		; a karaktert a kimeneti regiszterbe teszem
	call	LCD_data	; kiírom az LCD-1. sorába

        bsf     lcdaddr,6       ; Cím átállítása a 2. sorra
        call    LCD_addr        ; DDRAM (karakter pozíció 2. sorra)
        movf    chr2,w          ; Második sor karakterét a w-be
        movwf	lcddata		; a karaktert a kimeneti regiszterbe teszem     
        call    LCD_data        ; kiírom az LCD 2. sorába
        bcf     lcdaddr,6       ; Cím visszaállítása az 1. sorra

	banksel lcdport		; Bank0
	movf	lcdaddr,w       ; Kiírási pozíció a W-be
	movwf	PORTB		; Kijelezzük a Bportán hol állunk (csak a móka kedvéért)

	movlw	.200		; 200msec várakozás, hogy látható legyen a kiírás
	call	WAIT	
	incf	lcdaddr,f	; Következő karakter pozíció
	movlw	0x0f		; Maszk	alsó nibble (megakadályozzuk, hogy 16-nál több legyen.
	andwf	lcdaddr,f	; Cím byte maszk (Csak az első sorba írunk)       
	goto	NEXT		; Újra kezdjük!


;------ Szöveg táblázat olvasása ------------------------------------------------------
TXT1    addwf	PCL,f           ; Ugrás a táblázat címbéli elemére, majd "RETLW"    
        DT      "****VARISZAB****"      ; 1. sor kiírandó szting fűzére

TXT2    addwf   PCL,f
        DT      "== 2008.09.28 =="      ; 2. sor sztring füzére
; Ha a szövegek már más lapon lennének, akkor lapozni kell, hogy a táblázat elérhető legyen.
	END

	
	

