;
;					EJEMPLO 3.23
;
;				Autor: Mikel Etxebarria
;			(c) Microsystems Engineering (Bilbao)
;
;Ejemplo para MicroPIC Trainer y Trainer PLUS. Interface I2C gestionado por software.
;
;Haciendo uso de las rutinas incluidas en el fichero I2CLOW.INC, se trata de controlar
;el funcionamiento de los distintos dispositivos I2C, existentes en la tarjeta 
;Trainer PLUS. Estos dispositivos están conectados entre sí al bus I2C común. Se recomienda
;leer las especificaciones técnicas de los mismos, para tener un mayor conocimiento de las
;posibilidades de los mismos. Igualmente es importante desconectar los leds de la uPIC Trainer
;mediante el jumper J7 pues de lo contrario actuarían como carga adicional en las líneas RB6
;y RB7 que, en estos ejemplos, forman el bus I2C.
;
;El dispositivo I2C PCF8583. Reloj/calendario en tiempo real más RAM
;
;Se trata de realizar un cronómetro utilizando el dispositivo I2C PCF8583P. Sobre el módulo 
;LCD se irá presentando la hora, minutos, segundos y centésimas. Cuando se pone en marcha
;el programa, en pantalla aparecerá la hora en curso que contiene el dispositivo.
;Este, al estar alimentado por batería, seguirá trabajando aún a habiendo desconectado
;todo el sistema uPIC Trainer Plus. Pulsando la tecla 0 el cronómetro indicará 
;00:00:00:00 e iniciará la cuenta. Mediante la tecla A se detiene la visualización 
;aunque el reloj siga en marcha hasta una nueva pulsación de A. De esta forma se
;puede medir el lapsus de tiempo transcurrido entre ambas pulsaciones. 

		List	p=16F84		;Tipo de procesador
		include	"P16F84.INC"	;Definiciones de registros internos

CLKIN		equ	.4000000	;Frecuencia de trabajo
                 
I2c_var		equ	0x0c		;Inicio de las variables de I2CLOW.ASM
Lcd_var		equ	0x12		;Inicio de las variables de LCD_CXX.ASM
Key_var		equ	0x14		;Inicio de las variables de TECLADO.ASM

		cblock	0x19		;Variables de la aplicación
		Centesimas		;Variable de centésimas de segundos
		Segundos		;Variable de segundos
		Minutos			;Variable de minutos
		Horas			;Variable para las horas
		ASCII_H			;Carácter ASCII de más peso
		ASCII_L			;Caracter ASCII de menos peso
		Temp_1			;Variable temporal
		N_Bytes			;Nº de bytes a recibir
		Dir_Ini			;Dirección inicial del dispositivo PCF8583
		Flags			;Variable de estado		
		endc

		org	0x00		;Vector de reset
		goto	Inicio
		org	0x05		;Salvar el vector de interrupción	

		include	"I2CLOW.INC"	;Incluye las rutinas de manejo del bus I2C
		include "teclado.inc"	;Incluye rutinas de manejo del teclado
		include "LCD_CXX.inc"	;Incluye rutinas de manejo del LCD.

;**************************************************************************************
;ASCII:	Esta rutina convierte el octeto contenido en el acumulador, en dos caracteres
;de código ASCII y los visualiza en el módulo LCD

ASCII:		movwf	Temp_1		;Guarda octeto
		swapf	Temp_1,W
		andlw	b'00000111'
		iorlw	b'00110000'	;Convierte el primer nible
		call	LCD_DATO	;Lo visualiza
		movf	Temp_1,W
		andlw	b'00001111'
		iorlw	b'00110000'	;Convierte el segundo nible
		call	LCD_DATO	;Lo visualiza
		return

;*******************************************************************************************
;Lectura: Esta rutina lee desde el dispositivo PCF8583 tantos byte como indique la variable
;N_Bytes a partir de la dirección indicada por la variable Dir_Ini. Los bytes leidos se depo-
;sitan a partir del inicio del buffer (posición 0x30).

Lectura		call	Inicia_Bus	;Inicia líneas del bus I2C
		call	Txt_Start_Bit	;Transmite secuencia de Inicio
		movlw	b'10100000'
		movwf	DataByte		
		call	Txt_Byte	;Transmite dirección del dispositivo (escritura)
		movf	Dir_Ini,W
		movwf	DataByte
		call	Txt_Byte	;Transmite dirección inicial a leer
		call	Txt_Start_Bit	;Transmite secuencia de inicio
		movlw	b'10100001'
		movwf	DataByte
		call	Txt_Byte	;Transmite dirección del dispositivo (lectura)
Lectura_1	decfsz	N_Bytes,F
		goto	Lec_no_fin
		goto	Lec_fin

Lec_no_fin	bcf	_Ultimo_Byte	;Indica que no es el último byte a leer
		call	RcvByte		;Recibe un byte
		movf	DataByte,W
		movwf	INDF		;Lo almacena en el buffer
		incf	FSR,F		;Apunta a la siguiente dirección del buffer
		goto	Lectura_1	;Siguiente byte a leer

Lec_fin		bsf	_Ultimo_Byte	;Indica que es el último byte a leer
		call	RcvByte		;Recibe el último byte
		movf	DataByte,W
		movwf	INDF		;Lo guarda en el buffer
		call	Txt_Stop_Bit	;Envía secuencia de stop
		return
		
Inicio:		clrf	PORTA
		clrf	PORTB
		bsf	STATUS,RP0	;Selecciona página 1 de datos
		movlw	b'00011111'
		movwf	TRISA		;RA0-RA4 entradas
		clrf	TRISB		;Puerta B salidas
		movlw	b'10000110'	;Preescaler de 128 para el TMR0. Pull_Up Off
		movwf	OPTION_REG				
		bcf	STATUS,RP0	;Selecciona página 0 de datos	
		clrf	Flags		;Borra el flag de estado

		call	UP_LCD		;Configura puertos para el control del LCD
		call	LCD_INI		;Inicia el módulo LCD
		movlw	b'00001100'
		call	LCD_REG		;LCD en ON, cursor y blink en OFF
		movlw	b'00000001'
		call	LCD_REG		;Borra LCD y home

		call	Inicia_Bus	;Inicia el bus I2C
	
;******************************************************************************************
;Bucle principal del programa. Si la variable Flag está a "0" se visualiza el tiempo sobre
;el LCD. Si está a "1" no se visualiza, situación de lapsus.
	
Loop:		clrwdt			;Refresca el WDT
		btfsc	Flags,0		;Está el flag a "0" ??
		goto	TECLADO		;No, no se visualiza el tiempo
		movlw	Centesimas
		movwf	FSR		;Inicia el buffer de recepción
		movlw	.4
		movwf	N_Bytes		;Nº de bytes a recibir (4)
		movlw	.1
		movwf	Dir_Ini		;Dirección inicial del PCF8583 (1)
		call	Lectura		;Lectura del dispositivo

;Visualiza el buffer de las horas, minutos, segundos y centésimas sobre el LCD

VISUALIZA:	call	UP_LCD		;Configura puertos para el LCD
		movlw	b'00000010'
		call	LCD_REG		;Cursor HOME
		movf	Horas,W
		call	ASCII		;Convierte las horas a ASCII y visualiza
		movlw	':'
		call	LCD_DATO	;Visualiza separadores ":"
		movf	Minutos,W
		call	ASCII		;Convierte los minutos a ASCII y visualiza
		movlw	':'
		call	LCD_DATO	;Visualiza separadores ":"
		movf	Segundos,W
		call	ASCII		;Convierte segundos en ASCII y visualiza
		movlw	':'
		call	LCD_DATO	;Visualiza separadores ":"
		movf	Centesimas,W
		call	ASCII		;Convierte centésimas en ASCII y visualiza

;Exploración del teclado. Si se pulsa 0 el cronómetro se pone a 00:00:00:00 y comienza
;la cuenta. Se se pulsa A la cuenta se detiene hasta pulsarla nuevamente. Se mide el 
;lapsus de tiempo entre ambas pulsaciones.

TECLADO:	call	Key_Scan	;Explora el teclado
		movlw	0x80
		subwf	Tecla,W
		btfsc	STATUS,Z	;Se ha pulsado alguna ??
		goto	Loop		;No.
		movlw	0x7d
		subwf	Tecla,W
		btfsc	STATUS,Z	;Se ha pulsado la 0 ??
		goto	CRONO_A_0	;Si, puesta a 0 del cronómetro
		movlw	0x7e
		subwf	Tecla,W
		btfss	STATUS,Z	;Se ha pulsado la A ??
		goto	Loop		;No
				
		comf	Flags,F		;Complementa señalizador
		goto	Loop

;Puesta a 0 del cronómetro e inicio de una nueva cuenta

CRONO_A_0	clrf	Flags
		call	Inicia_Bus	;Inicia las líneas del bus I2C
		call	Txt_Start_Bit	;Envía secuencia de inicio
		movlw	b'10100000'
		movwf	DataByte
		call	Txt_Byte	;Transmite dirección del dispositivo (escritura)
		clrf	DataByte
		movlw	.6
		movwf	Temp_1		;Nº de bytes a enviar al dispositivo
Next_Byte_tx	call	Txt_Byte        ;Transmite un byte
		decfsz	Temp_1,F        ;Decrementa el nº de bytes a transmitir
		goto	Next_Byte_tx				
		
		goto	Loop

		end			;Fin del programa fuente

