; ******************************************************************************
; ******************************************************************************
; ****   Progetto di terminale con LCD e tastiera AT o ATX.                 ****
; ******************************************************************************
; ******************************************************************************
; ****                    Copyright 2004 by Carlo Fusco                     ****
; ******************************************************************************
; ******************************************************************************
; *                                                                            *
; * Note di programmazione:                                                    *
; * -----------------------                                                    *
; *  Tutte le variabili allocate nei file registers sono scritte in minuscolo. *
; *  Tutte le costanti sono scritte in minuscolo.                              *
; *  Tutte le funzioni sono scritte in maiuscolo.                              *
; *                                                                            *
; * Note tecniche:                                                             *
; * --------------                                                             *
; *  Frequenza del quarzo: 4.433 MHz.                                          *
; *  Tipo di LCD: Hitachi HD44780 o compatibile.                               *
; *                                                                            *
; * Note sull' LCD:                                                            *
; * ---------------                                                            *
; *  La comunicazione avviene in un solo senso ovvero senza controllo del busy *
; * flag al fine di risparmiare una linea di I/O del Pic. Al posto di tale con-*
; * trollo si attende un periodo di tempo oppurtuno che consente al controller *
; * dell' LCD di eseguire le operazioni interne.                               *
; *                                                                            *
; * Note sulla tastiera:                                                       *
; * --------------------                                                       *
; *  Il protocollo non è conforme a quello descritto nei datasheets.           *
; *                                                                            *
; * Nota sul bus:                                                              *
; * -------------                                                              *
; *  Nessuna nota.                                                             *
; *                                                                            *
; * Connessioni:                                                               *
; * ------------                                                               *
; *                                                                            *
; *                           .------. .-------.                               *
; *                           |1-RA2 '-' RA1-18|                               *
; *                           |                |                               *
; *        Led di diagnostica-|2-RA3     RA0-17|                               *
; *                           |                |                               *
; *                           |3-RA4    OSC1-16|-------------------------      *
; *                           |                |                   4MHz |      *
; *   +5<-------|--|----------|4-/MCLR  OSC2-15|--------------------[o]-|      *
; *             /  /          |                |                 |      |      *
; *       4.7K  \  \ GND<-----|5-Vss     Vdd-14|----->+5         = 27pF = 27pF *
; *             /  /          |                |                 |      |      *
; *  AT-Clock<--|--|----------|6-RB0     RB7-13|----->D7        GND    GND     *
; *                |          |                |                               *
; *  AT-Data <-----|----------|7-RB1     RB6-12|----->D6                       *
; *                           |                |                               *
; *                   RS<-----|8-RB2     RB5-11|----->D5                       *
; *                           |                |                               *
; *                    E<-----|9-RB3     RB4-10|----->D4                       *
; *                           '----------------'                               *
; *                                                                            *
; ******************************************************************************
; ******************************************************************************
; * Direttive di assemblaggio.                                                 *
; *                                                                            *
	PROCESSOR	16F84A
	RADIX		HEX
	INCLUDE		"P16F84A.inc"
	__CONFIG	H'3FF1'
	ERRORLEVEL	2
; *                                                                            *
; ******************************************************************************
; ******************************************************************************
; * FILE REGISTERS.                                                            *
; *                                                                            *

		ORG	0C
delay_1		RES	1
delay_2		RES	1
rs		RES	1
lcd_byte	RES	1
address		RES	1
address_lcd	RES	1
n_car		RES	1
kb_data		RES	1
aux		RES	1


; ******************************************************************************
; * Main.                                                                      *
; ******************************************************************************
	ORG	0
	goto	main
; *                                                                            *
; * Impostazione delle porte di I/O.                                           *
; *                                                                            *
	ORG	5
main	call	HARD_INI	; Inizializzazione delle porte.
	call	DELAY_50M
	call	LCD_INI		; Inizializzazione del display.

	movlw	d'6'		; Messaggio iniziale.
	movwf	n_car
	movlw	h'2100'
	movwf	address
	movlw	h'45'
	movwf	address_lcd
	call	SEND_ST


	call	KB_INI		; Inizializzazione della keyboard.
	call	KB_INI		; E' chiamata più volte per rendere visibile
	call	KB_INI		; il messaggio iniziale.
	call	KB_INI		; Bisogna implementare una funzione di ritardo
	call	KB_INI		; più lunga.
	call	KB_INI

ciclo	call	LCD_CLR
	clrf	address_lcd
	call	LCD_ADR
	movlw	d'20'
	movwf	aux
primo	call	KB_GET
	movf	kb_data,0
	call	KB_CONV
	movwf	lcd_byte
	call	LCD_CAR
	decfsz	aux,1
	goto	primo
	movlw	h'40'
	movwf	address_lcd
	call	LCD_ADR
	movlw	d'20'
	movwf	aux
secondo	call	KB_GET
	movf	kb_data,0
	call	KB_CONV
	movwf	lcd_byte
	call	LCD_CAR
	decfsz	aux,1
	goto	secondo
	movlw	h'14'
	movwf	address_lcd
	call	LCD_ADR
	movlw	d'20'
	movwf	aux
terzo	call	KB_GET
	movf	kb_data,0
	call	KB_CONV
	movwf	lcd_byte
	call	LCD_CAR
	decfsz	aux,1
	goto	terzo
	movlw	h'54'
	movwf	address_lcd
	call	LCD_ADR
	movlw	d'20'
	movwf	aux
quarto	call	KB_GET
	movf	kb_data,0
	call	KB_CONV
	movwf	lcd_byte
	call	LCD_CAR
	decfsz	aux,1
	goto	quarto
	goto	ciclo
	sleep

; ******************************************************************************
; * Funzioni varie.                                                            *
; ******************************************************************************

; * Funzione che invia una stringa al display.
; * n_car = lunghezza della stringa
; * address = indirizzo del primo carattere della stringa nella eeprom.
; * address_lcd = posizione sul display del primo carattere. (1-80)
; *               se =0 allora non specifica.

SEND_ST	movf	address_lcd,1
	btfss	3,2
	call	LCD_ADR
send	decf	n_car,1
	call	MESS
	movf	n_car,1
	btfss	3,2
	goto	send
	return

MESS	movf	address,0
	movwf	EEADR
	bsf	3,5
	bsf	EECON1,RD
	bcf	83,5
	movf	EEDATA,0
	movwf	lcd_byte
	call	LCD_CAR
	incf	address,1
	return

; * Funzione che converte il byte ricevuto dalla tastiera con quello corretto
; * per il display secondo lo schema nella eeprom.

KB_CONV	addlw	h'20f1'
	movwf	EEADR
	bsf	STATUS,RP0
	bsf	EECON1,RD
	bcf	STATUS,RP0
	movf	EEDATA,0
	return

; ******************************************************************************
; ******************************************************************************
; * Protocollo di comunicazione Hitachi HD44780.                               *
; * --------------------------------------------                               *
; * Si presuppone che le porte RB1->RB6 siano configurate come output.         *
; *                                                                            *
; ******************************************************************************
; * DELAY - Funzione di ritardo temporale di 49uS.                             *
; ******************************************************************************
DELAY_50	movlw	D'18'
		movwf	delay_1
loop		decfsz	delay_1,1
		goto	loop
		return

; ******************************************************************************
; * DELAY_17 - Funzione di ritardo temporale di 2mS.                           *
; ******************************************************************************
DELAY_17	movlw	D'3'
		movwf	delay_2
		movlw	D'223'
		movwf	delay_1
loop1		decfsz	delay_1,1
		goto	loop1
		decfsz	delay_2,1
		goto	loop1
		return

; ******************************************************************************
; * DELAY_50M - Funzione di ritardo temporale di 50mS.                         *
; ******************************************************************************
DELAY_50M	movlw	D'78'
		movwf	delay_2
		movlw	D'245'
		movwf	delay_1
loop2		decfsz	delay_1,1
		goto	loop2
		decfsz	delay_2,1
		goto	loop2
		return

; ******************************************************************************
; * LCD_W - Funzione che manda un byte al display.                             *
; *         La 'rs' deve essere 1 se è un dato                                 *
; *                             0 se è un indirizzo                            *
; *         mentre il byte da inviare è contenuto in 'lcd_byte'.               *
; ******************************************************************************
LCD_W	bcf	06,2		; RS=0
	btfsc	rs,0		; e' 0 veramente?
	bsf	06,2		; no -> RS=1
	call	DELAY_50
	call	LCD_W_
	swapf	lcd_byte
	call	LCD_W_
	return
LCD_W_	bsf	06,3		; E=1
	bcf	06,7		; D7=0
	btfsc	lcd_byte,7	; e' 0 veramente?
	bsf	06,7		; no e' 1
	bcf	06,6		; D6=0
	btfsc	lcd_byte,6	; e' 0 veramente?
	bsf	06,6		; no e' 1
	bcf	06,5		; D5=0
	btfsc	lcd_byte,5	; e' 0 veramente?
	bsf	06,5		; no e' 1

	bcf	05,0		; D4=0
	btfsc	lcd_byte,4	; e' 0 veramente?
	bsf	05,0		; no e' 1

;	bcf	06,4		; D4=0
;	btfsc	lcd_byte,4	; e' 0 veramente?
;	bsf	06,4		; no e' 1

	bcf	06,3		; E=0
	call	DELAY_50
	return

; ******************************************************************************
; * LCD_ADR - Funzione che imposta l'indirizzo del carattere sul display.      *
; *                                                                            *
; *   _____________________________________________________________            *
; *   |00|01|02|03|04|05|06|07|08|09|0A|0B|0C|0D|0E|0F|10|11|12|13| <-Linea 1a *
; *   |40|41|42|43|44|45|46|47|48|49|4A|4B|4C|4D|4E|4F|50|51|52|53| <-Linea 2a *
; *   |14|15|16|17|18|19|1A|1B|1C|1D|1E|1F|20|21|22|23|24|25|26|27| <-Linea 1b *
; *   |54|55|56|57|58|59|5A|5B|5C|5D|5E|5F|60|61|62|63|64|65|66|67| <-Linea 2b *
; *   '-----------------------------------------------------------'            *
; ******************************************************************************
LCD_ADR	clrf	rs
	movf	address_lcd,0
	movwf	lcd_byte
	bsf	lcd_byte,7
	call	LCD_W
	return

; ******************************************************************************
; * LCD_CAR - Funzione che invia un carattere al display.                      *
; ******************************************************************************
LCD_CAR	movlw	1
	movwf	rs
	call	LCD_W
	return

; ******************************************************************************
; * LCD_CLR - Funzione che pulisce il display.                                 *
; ******************************************************************************
LCD_CLR	clrf	rs
	movlw	b'00000001'
	movwf	lcd_byte
	call	LCD_W
	return

; ******************************************************************************
; * LCD_INI - Funzione che inizializza il display.                             *
; ******************************************************************************
LCD_INI	call	DELAY_50M
	call	DELAY_50M
	call	DELAY_50M
	call	DELAY_50M
	bsf	06,3		; E=1		; La prima volta vanno trasmes-*
	bcf	06,2		; RS=0		; si solo 4 bit perchè il di-  *
	bcf	06,7		; D7=0		; splay parte per default col  *
	bcf	06,6		; D6=0		; protocollo a 8 bit. Sempre   *
	bsf	06,5		; D5=1		; per tale motivo bisogna tra- *
	bcf	05,0
;	bcf	06,4		; D4=0		; smettere l'impostazione a 4  *
	bcf	06,3		; E=0		; bit una seconda volta ma con *
	call	DELAY_50			; il protocollo a 4 bit.       *
	clrf	rs
	movlw	b'00101000'	; 4 bit mode + 2 linee + caratteri 5x8.
	movwf	lcd_byte
	call	LCD_W
	movlw	b'00001101'	; Display on + cursore on + cursore lampeggia.
	movwf	lcd_byte
	call	LCD_W
	movlw	b'00000110'	; Incrementa + non shifta.
	movwf	lcd_byte
	call	LCD_W
	return

; *                                                                            *
; * Fine del protocollo HD44780.                                               *
; ******************************************************************************
; ******************************************************************************

; ******************************************************************************
; * Funzioni per l'impostazione dell'hardware e la diagnostica.                *
; ******************************************************************************
HARD_INI	bsf	03,5		; bank1
		movlw	b'00000011'	; Porta B
		movwf	86
		movlw	b'11110000'	; Porta A
		movwf	85
		bcf	83,5		; bank0
		return

DIAGN	bsf	05,3		; Funzione che fa lampeggiare il led sulla RA3.*
	call	DELAY_50M
	bcf	05,3
	call	DELAY_50M
	return

; ******************************************************************************
; ******************************************************************************
; * Protocollo di comunicazione con tastiera AT.                               *
; * --------------------------------------------                               *
; * Si presuppone che le porte RB1->RB6 siano configurate come output.         *
; *                                                                            *
; ******************************************************************************
; * KB_INI - Funzione che inizializza la tastiera.                             *
; ******************************************************************************
KB_INI	call	DELAY_50M	; Aspetta che sia finito il BAT.
	call	DELAY_50M
	call	DELAY_50M
	call	DELAY_50M
	return

; ******************************************************************************
; * KB_STOP - Funzione che inibisce la tastiera.                               *
; ******************************************************************************
KB_STOP	bsf	03,5	; bank1
	bcf	86,0
	bcf	83,5	; bank0
	bcf	6,0
	return

; ******************************************************************************
; * KB_GO - Funzione che disinibisce la tastiera.                              *
; ******************************************************************************
KB_GO	bsf	03,5	; bank1
	bsf	86,1
	bcf	83,5	; bank0
	return

; ******************************************************************************
; * KB_RX - Funzione che riceve un byte dalla tastiera.                        *
; ******************************************************************************
KB_RX		clrf	kb_data
;		call	KB_GO
busy		btfss	06,0		; clock=0?
		goto	busy		; si, aspetta la tastiera è occupata.
start_bit	btfsc	06,0		; clock=1?
		goto	start_bit	; si, aspetta lo start bit.
		btfsc	06,1		; data=1?
		goto	main		; si, c'è un errore, riavvia.
		call	KB_CLOCK	; no, ok aspetta il prossimo bit.
		btfsc	06,1		; data0=1?
		bsf	kb_data,0
		call	KB_CLOCK
		btfsc	06,1		; data1=1?
		bsf	kb_data,1
		call	KB_CLOCK
		btfsc	06,1		; data2=1?
		bsf	kb_data,2
		call	KB_CLOCK
		btfsc	06,1		; data3=1?
		bsf	kb_data,3
		call	KB_CLOCK
		btfsc	06,1		; data4=1?
		bsf	kb_data,4
		call	KB_CLOCK
		btfsc	06,1		; data5=1?
		bsf	kb_data,5
		call	KB_CLOCK
		btfsc	06,1		; data6=1?
		bsf	kb_data,6
		call	KB_CLOCK
		btfsc	06,1		; data7=1?
		bsf	kb_data,7
		call	KB_CLOCK
		call	KB_CLOCK	; Salta il bit di parità
		btfss	06,1		; stop=0?
		goto	main		; si, c'è un errore riavvia.
aa		btfss	06,0		; clock=0?
		goto	aa		; si aspetta
		return


; ******************************************************************************
; * KB_CLOCK - Funzione che aspetta che il clock sia passato alto e poi basso. *
; ******************************************************************************
KB_CLOCK	btfss	06,0		; clock=0?
		goto	KB_CLOCK	; si aspetta
a		btfsc	06,0		; clock=1?
		goto	a		; si aspetta
		return			; ok clock=0.

; ******************************************************************************
; * KB_GET - Funzione che preleva il codice del tasto premuto.                 *
; *          Questa funzione è necessaria perchè la tastiera invia il codice   *
; *          del carattere poi F0 e poi ancora il codice. Senza questa funzione*
; *          a ogni pressione di un tasto si ricevono tre byte invece di uno.  *
; *          Perchè funziona così non lo sò, sui datasheet non è descritto un  *
; *          tale funzionamento.                                               *
; ******************************************************************************
KB_GET	call	KB_RX		; restituisce kb_data
	movf	kb_data,0	; w=kb_data
	sublw	h'f0'		; w=h'f0'-w
	btfss	03,2		; kb_data=h'f0'?
	return			; no puoi passarlo.
	call	KB_RX		; si preleva il doppione
	goto	KB_GET		; e aspetta il prossimo.

; *                                                                            *
; * Fine protocollo di comunicazione con tastiera AT.                          *
; ******************************************************************************
; ******************************************************************************

; ******************************************************************************
; * Contenuto della EEPROM.                                                    *
; ******************************************************************************
	ORG	H'2100'
;DE	"TerminaleLCD",0	; 2100 - 12
;DE	"Copyright2004",0	; 210d - 13
DE	"CFusco"		; 211a - 11 (2100 - 11)
				; 2124

; La formula per la corrispondenza è: codice+h'20f1'.

DE	"q1   zsaw2  cxde43   vftr5  nbhgy6   mju78  ,kio09  ./l;p",0

END
