;
;****************************************************************
;Programa DSP232.ASM - Márcio Soares
;04/10/2001
;
;Recebe dado do canal serial e insere no display...
;Se dado alt+254, aguarda próximo dado... interpreta comando valido
;comando 1 - apaga display
;comando 2 - muda para começo da 2 coluna
;
;Comunicação: 9600,N,8,1
;Sem buffer...
;
;Controle de display 2 linhas 16 colunas
;Cursor ligado, incrementa cursor a esquerda
;
;Clocks e velocidade
;
;Clock de 8MHz - 9600 bps com PIC16C5X
;Clock de 4MHz - 4800 bps com PIC16C5X
;Clock de 2MHZ - 2400 bps com PIC16C5X
;
;ultima alteração em 04/10/2001
;uso para testes da pic16C54A
;****************************************************************

		list p=16C54		;listagem
		radix dec		;padrao->valores decimal se nao informado outro
		include <P16C5X.INC>	;inclue arquivo

;
;Constantes
;

picram		equ	0x08
picres		equ	0x1FF
Same		equ	1

MSB		equ	7
LCD_CNTL	equ	PORTA			;port de controle para display
LCD_DATA	equ	PORTB			;port de dados para o display

E		equ	1			;controles do display
RW		equ	2
RS		equ	3

DR		equ	0		;RX principal (bit 0 do port A)

;Tabela para calculo de time out para 9600 com clock de 8MHz
;
BAUD_1		equ	.68		;3+3X = CLKOUT/BAUD
BAUD_2		equ	.67		;6+3X = CLKOUT/BAUD
BAUD_3		equ	.34		;3+3X = 0.5*CLKOUT/BAUD
BAUD_4		equ	.86		;3+3X = 1.25*CLKOUT/BAUD
BAUD_X		equ	.66		;11+3X= CLKOUT/BAUD
BAUD_Y		equ	.66		;9+3X = CLKOUT/BAUD

;
;variaveis
;
		org	picram			;endereço do banco RAM

RcvReg	res	1		;dado recebido
Count	res	1		;contador para bits transmitidos
DlyCnt	res	1		;delay para baud rate
DtCnt	res	1		;flag para comando do display recebido
CHAR	res	1		;variavel para caracter
TEMP	res	1		;variavel de uso geral
T1	res	1		;variavel para temporizador
T2	res	1		;variavel para temporizador
			

	org	0x00			;inicio da ROM

;
;**************************************************************
;inicio do programa
;**************************************************************
;Rotinas de recepcao e verificacao de caracter recebido
;**************************************************************
;
talk:
	clrf	RcvReg			;limpa registro
	btfsc	PORTA, DR		;verifica start bit
	goto	User			;espera 104/2 us
	call	Delay4			;espera 104+104/4

;
;***************************
;recebe caracter
;
rcvr:
	movlw	8			;8 bits
	movwf	Count			;guarda no contador
r_next: 
	bcf	STATUS,C
	rrf	RcvReg,Same		;LSB primeiro
	btfsc	PORTA,DR		
	bsf	RcvReg,MSB	
	call	DelayY
	decfsz	Count,Same
	goto	r_next

;verifica dado recebido
;
r_over:
	movf	RcvReg,0		;prepara registro para teste
	xorlw	0xFE			;testa para ver se é comando
	btfsc	STATUS,Z		;verifica resultado
	goto	gravaCMD		;é comando, grava e aguarda próximo
	goto	gravaCHAR		;nao eh comando... envia caracter para display

gravaCMD:
	bsf	DtCnt,0			;seta bit para avisar do flag recebido
	goto	talk			;aguarda comando

gravaCHAR:
	btfsc	DtCnt,0			;testa para ver se anterior nao era comando
	goto	wrtCMD			;eh comando... escreve comando
	movf	RcvReg,0
	call	SEND_CHAR		;nao eh comando, escreve caracter
	goto	talk			;retorna

wrtCMD:
	bcf	DtCnt,0			;limpa registro...
	movf	RcvReg,0		;prepara para testar registro
	xorlw	0x31			;testa para ver se apaga display
	btfsc	STATUS,Z		;
	goto	clrdisp			;apaga display
	movf	RcvReg,0		;prepara para testar novamente
	xorlw	0x32			;testa para ver se troca de linha
	btfsc	STATUS,Z		;
	goto	swpline			;troca de linha
	goto	talk			;volta e aguarda novo caracter

;*****************************************************
; Rotinas para baud rate
;*****************************************************

DelayY:
	movlw	BAUD_Y
	goto	save
DelayX:
	movlw	BAUD_X
	goto	save
Delay4:
	movlw	BAUD_4
	goto	save
Delay1:
	movlw	BAUD_1
	goto	save
Delay2:
	movlw	BAUD_2
save:
	movwf	DlyCnt
redo_1:
	decfsz	DlyCnt,Same
	goto	redo_1
	retlw	0x00

;
;*****************************************************
; Rotina de inicializacao dos ports e variaveis
;*****************************************************

inicio:
	movlw	0x00			;ajuste para os bits INTCON
	movwf	DtCnt			;zera contador de bits

	movlw	0x01			;ajusta os bits em A como saida
	tris	PORTA
	bsf	PORTA,DR		;levanta porta para receber start bit

	movlw	0x00			;ajusta os bits em B como saida
	tris	PORTB

	bcf	LCD_CNTL,E		; port de controle em Low.
	bcf	LCD_CNTL,RW
	bcf	LCD_CNTL,RS

	
;
;***************************************************************
;rotina principal
;***************************************************************
;
principal:
	call	tp2			;aguarda display inicializar
	goto	DISPLAY_INIT		;inicializa display
						;e envia mensagem de saudação
parada:
	goto	talk			;após inicializar display
						;prepara para receber dado
User:
	movlw	BAUD_3
	movwf	DlyCnt
redo_2:
	decfsz	DlyCnt,Same
	goto	redo_2
	goto	talk

;
;*******************************************************************
;* Subrotinas do display                                           *
;*******************************************************************

;
;*******************************************************************
; Apaga display
;*******************************************************************
;
clrdisp:
	movlw	0x01
	call	SEND_CMD
	goto	talk

;
;*******************************************************************
; Troca linha - linha valida 2
;*******************************************************************
;
swpline:
	movlw	0xC0
	call	SEND_CMD
	goto	talk


;*******************************************************************
; Inicializa o display
; caracter 5x7, 2 linhas, cursor ligado, mensagem fixa
;*******************************************************************
;
DISPLAY_INIT:
        movlw   0x38            ; Comando para interface 8-bits
        call    SEND_CMD

        movlw   0x0E	    ; liga display
        call    SEND_CMD        ;

        movlw   0x06            ; incrementa display
        call    SEND_CMD        ;

      	movlw   0x01            ; apaga display
        call    SEND_CMD        ;

	goto    parada	    ;fim da inicialização

;*****************************************************************
;* SEND_CHAR - envia caracter que esta no registro W para o LCD  *
;* Esta rotina envia todo caracter pelo port                     *
;* O dado eh trasmitido pelo PORTB<7:0> pins                     *
;*****************************************************************
;
SEND_CHAR:
        movwf   CHAR            ; salva caracter em CHAR
	movlw   0x01	    ; prepara TEMP para marcar retorno
	movwf   TEMP            ; de BUSY_CHECK. 	
        goto    BUSY_CHECK      ; espere ate que o display esteje pronto
snd_char:
        bcf     LCD_CNTL, RW    ; seta o LCD em modelo leitura
        bsf     LCD_CNTL, RS    ; seta o LCD em modo dados
        bsf     LCD_CNTL, E     ; inverte E para o LCD
        movf    CHAR, w          
        movwf   LCD_DATA        ; envie o dado para o LCD
        bcf     LCD_CNTL, E
        retlw   0x00

;
;**************************************************************
;* SEND_CND - envia comando contido no registro W para LCD    *
;* esta rotina insere o dados completo no PORT                *
;* o dado eh transmitido pelo pinos do PORT<7:0>              *
;**************************************************************

SEND_CMD:
        movwf   CHAR            ; Comando a enviar em W
        movlw   0x00	    ; prepara TEMP para marcar retorno
	movwf   TEMP            ; de BUSY_CHECK. 	
	goto    BUSY_CHECK      ; aguarde ate que o display esteje pronto
snd_cmd:
	bcf     LCD_CNTL, RW    ; seta o LCD em modo leitura
        bcf     LCD_CNTL, RS    ; seta o LCD em modo comando
	bsf     LCD_CNTL, E     ; inverte E para LCD
        movf    CHAR, w          
        movwf   LCD_DATA        ; envie o dado para o LCD
        bcf     LCD_CNTL, E
        retlw   0x00

;
;**************************************************************
;* Esta rotina checa o busy flag, retorna quando livre        *
;*  Afeta:                                                    *
;*      TEMP - retorna com endereco busy                      *
;**************************************************************
;
BUSY_CHECK:
        movlw   0xFF            ; Seta port B para entrada
        tris    PORTB
        bcf     LCD_CNTL, RS    ; Seta LCD para modo comando
        bsf     LCD_CNTL, RW    ; Setup para ler busy flag
        bsf     LCD_CNTL, E     ; Seta E high
        movf    LCD_DATA, w     ; le o busy flag, endereco DDram 
        bcf     LCD_CNTL, E     ; Seta E low
        andlw   0x80
	btfss   STATUS, Z
        goto    BUSY_CHECK
lcdnobusy:
        bcf     LCD_CNTL, RW        
        movlw   0x00		; seta novamente port B como saida
        tris    PORTB		; Seta port_B para saida
        btfss   TEMP,0		; testa bit 0 de TEMP, se set volta
	goto    snd_cmd	    	; para SEND_CHAR, se nao pata SEND_CMD
        goto    snd_char

;*******************************************************************
; Rotina de temporizacao para aguardar display acordar
;*******************************************************************

tp2:					;rotina para uso com cristal de 8MHz
	movlw	0x02			;executa 2 vezes tempo... 250us
	movwf	TEMP

tempo:
	movlw	0xFF			;carrega W com 255
	movwf	T1			;carrega T1 com W
car_1:
	movlw	0xFF			;carrega W com 255
	movwf	T2			;carrega T2 com 255
dec_1:
	decfsz T2,1			;decrementa T2
	goto	dec_1			;255 x T1 vezes
	decfsz T1,1			;decrementa T1
	goto car_1			;volta a carregar T2
	decfsz	TEMP,1			;decrementa TEMP
	goto	tempo			;nao zero, faz novamente
	retlw	0x00

;********************************************************************
; Reset e endereco para Watch Dog Time
;********************************************************************

erro_aqui:
	org	picres
	goto	inicio
	end
