; Control de temperatura con LM35 y pantalla de LCD
; Una salida se activa ante una temp. baja y se desactiva ante una alta ambas seteables
; Guarda los parámetros en la EEPROM
; Micro: PIC16F870 a 4MHz XT

pcl	equ	0x02		;Contador de programa (Parte baja)
estado	equ	0x03		;Registro de estados
ptoa	equ	0x05		;Puertos de E/S
ptob	equ	0x06
ptoc	equ	0x07
intcon	equ	0x0B		;Controlador de interrupciones
eedata	equ	0x0C		;Registro de datos de la EEPROM
eeaddr	equ	0x0D		;Registro de direccion de la EEPROM
adres	equ	0x1E		;Resultado de la conversión A/D (HIGH / LOW)
adcon	equ	0x1F		;Configuración del conversor A/D
uni	equ	0x20		;Usados para manejar los datos a mostrar en display
dec	equ	0x21
cen	equ	0x22
tiempo1	equ	0x23		;Usados para temporizar
tiempo2	equ	0x24
letra	equ	0x25		;Usado para apuntar la letra a colocar en el LCD
menor	equ	0x26		;Temperatura de activación
mayor	equ	0x27		;Temperatura de desactivación
buffer	equ	0x28		;Usado como registro temporal

#define	CARRY	estado, 0	;Bit de acarreo
#define	CERO	estado, 2	;Flag indicador de resultado cero
#define	RP0	estado, 5	;Bit 0 selector de página de memoria
#define	RP1	estado, 6	;Bit 1 selector de página de memoria
#define	ADGO	adcon, 2	;Bit que inicia la conversión (1) / Indica finalización (0)
#define	EEREAD	eedata, 0	;Bit que inicia la lectura de la EEPROM
#define	EEWRITE	eedata, 1	;Bit que inicia la escritura de la EEPROM - Indica finalización
#define	EEWREN	eedata, 2	;Bit que habilita la escritura en la EEPROM
#define	EEAREA	eedata, 7	;Bit que selecciona el área de EEPROM a utilizar (0=AREA DE DATOS)
#define	MINS	ptoa, 1		;Sube el punto mínimo
#define	MINB	ptoa, 2		;Baja el punto mínimo
#define	MAXS	ptoa, 3		;Sube el punto máximo
#define	MAXB	ptoa, 4		;Baja el punto máximo
#define	BUZZER	ptoc, 3		;Salida al aviso acústico
#define	RELE	ptoc, 4		;Relé que maneja la carga (calefactor / enfriador)
#define	LCDE	ptoc, 6		;Habilitación del LCD
#define	LCDRS	ptoc, 7		;Selección de modo del LCD

	bsf	RP0		;Pasa a página 1
	bcf	RP1
	movlw	b'00011111'	;Configura puerto A
	movwf	ptoa
	clrf	ptob		;Puerto B completo como salidas (bus del LCD)
	clrf	ptoc		;Puerto B completo como salidas
	movlw	b'10001110'	;Configura los pines del Puerto A
	movwf	adcon		;AN0 como única entrada análoga
	bsf	RP1		;Pasa a página 3
	bcf	EEAREA		;Selecciona el banco de EEPROM de datos
	bcf	RP1		;Pasa a página 0
	bcf	RP0
	movlw	b'01000001'	;Enciende y configura el convertidor A/D - Selecciona AN0 como entrada
	movwf	adcon
	
	clrf	ptoa		;Apaga todo
	clrf	ptob
	clrf	ptoc
	
	bsf	RP1		;Pasa a la página 2 de memoria
	clrf	eeaddr		;Direcciona la primera posición de la EEPROM
	bsf	RP0		;Pasa a la página 3 de memoria
	bsf	EEREAD		;Inicia la lectura de la EEPROM
	bcf	RP0		;Vuelve a la página 3 de memoria
	movf	eedata, 0	;Dato Leído de la EEPROM -> W
	movwf	menor		;Guarda el dato leído de la EEPROM en MENOR (punto de activación del relé)
	incf	eeaddr		;Direcciona a la segunda posición de la EEPROM
	bsf	RP0		;Pasa a la página 3 de memoria
	bsf	EEREAD		;Inicia la lectura de la EEPROM
	bcf	RP0		;Vuelve a la página 3 de memoria
	movf	eedata, 0	;Dato Leído de la EEPROM -> W
	movwf	mayor		;Guarda el dato leído de la EEPROM en MAYOR (punto de desactivación del relé)
	bcf	RP1		;Pasa a la página 0 de memoria

	movlw	b'00111000'	;Comunicación con el LCD a ocho bits - Dos líneas de texto
	call	CONTROL
	movlw	d'2'
	call	DEMORA		;Demora 2ms
	movlw	b'00000110'	;Mensaje estático, se desplaza el cursor hacia la derecha
	call	CONTROL
	movlw	d'2'
	call	DEMORA		;Demora 2ms
	movlw	b'00001100'	;Enciende el display - Oculta el cursor - Caracter fijo
	call	CONTROL
	movlw	d'2'
	call	DEMORA		;Demora 2ms
	movlw	b'00000001'	;Limpia la pantalla y pone cursor en posición inicial
	call	CONTROL
	movlw	d'2'
	call	DEMORA		;Demora 2ms

	clrf	letra		;Coloca el título en el LCD
OTRA	movf	letra, 0	;Letra actual -> W
	call	LINEA1		;Obtiene el caracter a colocar desde la tabla
	call	DATO		;Envía el caracter al LCD
	incf	letra, 1

	movf	letra, 0	;Comprueba si ya envió los 16 caracteres del título
	sublw	d'16'
	btfss	CERO
	goto	OTRA		;Si no llego a la letra 16 sigue enviando

	movlw	0xC0		;Posiciona el cursor en la 2da. linea
	call	CONTROL
	movlw	d'1'
	call	DEMORA		;Demora 1ms

	clrf	letra		;Coloca el título en el LCD
OTRA2	movf	letra, 0	;Letra actual -> W
	call	LINEA2		;Obtiene el caracter a colocar desde la tabla
	call	DATO		;Envía el caracter al LCD
	incf	letra, 1

	movf	letra, 0	;Comprueba si ya envió los 16 caracteres del título
	sublw	d'16'
	btfss	CERO
	goto	OTRA2		;Si no llego a la letra 16 sigue enviando

	call	VERINF		;Coloca en el LCD la temp. inferior (de activación)
	call	VERSUP		;Coloca en el LCD la temp. superior (de desactivación)

CICLO	bsf	ADGO		;Inicia la conversión A/D
	btfsc	ADGO		;Espera que termine de convertir
	goto	$ -1
	
	bsf	RP0		;Pasa a página 1 (para acceder a los ocho bits bajos del resultado)
	movf	adres, 0	;Resultado de conversión -> W
	bcf	RP0		;Pasa a página 1

	movwf	buffer		;Guarda el dato obtenido de ADRESL en el buffer temporal
	bcf	CARRY		;Limpia el CARRY
	btfsc	adres, 0	;Mira el bit menos significativo de ADRESH (Bit 8)
	bsf	CARRY		;Si está en 1 pone en uno el carry
	rrf	buffer, 1	;Hace desaparecer el bit 0 de ADRESL, mete el bit 0 de ADRESH por el 7 de ADRESL

	movf	menor, 0	;Punto de activación -> W
	addlw	d'1'		;Suma 1 a W
	subwf	buffer, 0	;W = Temp. Actual - (Menor + 1)
	btfss	CARRY		;Si dio negativo es porque la temp. medida es igual o menor al punto de activación
	bsf	RELE		;Si dio negativo (si carry = 0) acciona el relé
	
	movf	mayor, 0	;Punto de desactivación -> W
	subwf	buffer, 0	;W = Temp. Actual - (Mayor)
	btfsc	CARRY		;Si dio negativo es porque aún no alcanzó la temp. de desactivación
	bcf	RELE		;Si dio positivo (si carry = 1) desactiva el relé

	movf	buffer, 0	;Dato digitalizado -> W
	call	DECIMAL		;Obtiene UNI, DEC y CEN con el agregado de 30h para la tabla ASCII
	
	movlw	0x8D		;Coloca el cursor en la posición 0Dh de la pantalla.
	call	CONTROL

	movf	cen, 0		;Coloca en el LCD las centenas
	call	DATO
	movf	dec, 0		;Coloca las decenas
	call	DATO
	movf	uni, 0		;Coloca las unidades
	call	DATO

	btfss	MINS		;Mira el pulsador de incremento en temp. de activación
	call	SUBEMIN
	btfss	MINB		;Mira el pulsador de decremento en temp. de activación
	call	BAJAMIN
	btfss	MAXS		;Mira el pulsador de incremento en temp. de desactivación
	call	SUBEMAX
	btfss	MAXB		;Mira el pulsador de decremento en temp. de desactivación
	call	BAJAMAX
	
	goto	CICLO		;Vuelve a medir y mostrar

LINEA1	addwf	pcl, 1		;Suma el contenido de W al contador de programa (para explorar la tabla)
	retlw	"T"
	retlw	"E"
	retlw	"M"
	retlw	"P"
	retlw	"E"
	retlw	"R"
	retlw	"A"
	retlw	"T"
	retlw	"U"
	retlw	"R"
	retlw	"A"
	retlw	":"
	retlw	" "
	retlw	" "
	retlw	" "
	retlw	" "

LINEA2	addwf	pcl, 1		;Suma el contenido de W al contador de programa (para explorar la tabla)
	retlw	" "
	retlw	" "
	retlw	" "
	retlw	" "
	retlw	" "
	retlw	" "
	retlw	b'01111111'	;Flecha izquierda
	retlw	"-"
	retlw	"-"
	retlw	b'01111110'	;Flecha derecha
	retlw	" "
	retlw	" "
	retlw	" "
	retlw	" "
	retlw	" "
	retlw	" "

SUBEMIN	incf	menor, 1	;Suma 1 a la temp. de activación
	call	VERINF		;Actualiza la información en el LCD
	btfss	MINS		;Espera que suelte el pulsador
	goto	$ -1
	goto	SAVEMIN		;Una vez que suelta la tecla va a guardar el parámetro
	
BAJAMIN	decf	menor, 1	;Resta 1 a la temp. de activación
	call	VERINF		;Actualiza la información en el LCD
	btfss	MINB		;Espera que suelte el pulsador
	goto	$ -1
	
SAVEMIN	bsf	RP1		;Pasa a página 2
	clrf	eeaddr		;Direcciona el primer byte de la EEPROM
	movf	menor, 0
	movwf	eedata		;Temp. Activación -> EEPROM
	call	EESAVE		;Ejecuta la rutina de grabación
	bcf	RP1		;Pasa a página 0
	goto	TIC		;Va a hacer el TIC de teclado

SUBEMAX	incf	mayor, 1	;Suma 1 a la temp. de desactivación
	call	VERSUP		;Actualiza la información en el LCD
	btfss	MAXS		;Espera que suelte el pulsador
	goto	$ -1
	goto	SAVEMAX		;Una vez que suelta la tecla va a guardar el parámetro
	
BAJAMAX	decf	mayor, 1	;Resta 1 a la temp. de desactivación
	call	VERSUP		;Actualiza la información en el LCD
	btfss	MAXB		;Espera que suelte el pulsador
	goto	$ -1
	
SAVEMAX	bsf	RP1		;Pasa a página 2
	movlw	d'1'
	movwf	eeaddr		;Direcciona el 2do. byte de la EEPROM
	movf	mayor, 0
	movwf	eedata		;Temp. Activación -> EEPROM
	call	EESAVE		;Ejecuta la rutina de grabación
	bcf	RP1		;Pasa a página 0
	goto	TIC		;Va a hacer el TIC de teclado
	
EESAVE	bsf	RP0		;Pasa a página 3
	bsf	EEWREN		;Habilita la escritura en la EEPROM
	movlw	0x55		;Secuencia de seguridad
	movwf	eeaddr
	movlw	0xAA
	movwf	eeaddr
	bsf	EEWRITE		;Inicia la grabación
	bcf	EEWREN		;Deshabilita la escritura
	btfsc	EEWRITE		;Espera que termine de grabar
	goto	$ -1
	bcf	RP0		;Pasa a página 2
	return

TIC	bsf	BUZZER		;Acciona el buzzer
	movlw	d'100'
	call	DEMORA		;Deja sonar el buzzer durante 100ms
	bcf	BUZZER
	return
	
CONTROL	bcf	LCDRS		;Pone en bajo la línea de modo del LCD (Control)
	goto	ENVIAR		;Se saltea la sig. línea
DATO	bsf	LCDRS		;Pone en alto la línea de modo del LCD (Dato)
ENVIAR	movwf	ptob		;Coloca el dato o control a enviar en el bus del LCD
	movlw	d'1'
	call	DEMORA		;Demora 1ms
	bsf	LCDE		;Habilita el LCD
	movlw	d'1'
	call	DEMORA		;Demora 1ms
	bcf	LCDE		;Deshabilita el LCD
	movlw	d'1'
	call	DEMORA		;Demora 1ms
	return

DECIMAL	movwf	uni		;Convierte el dato presente en W en UNI, DEC y CEN
	clrf	dec
	clrf	cen
	movlw	d'100'		;Determina la cant. de centenas
CENTENA	subwf	uni, 1
	btfss	CARRY
	goto	CIEN
	incf	cen, 1
	goto	CENTENA
CIEN	addwf	uni, 1
	movlw	d'10'		;Determina la cant. de decenas
DECENA	subwf	uni, 1
	btfss	CARRY
	goto	DIEZ
	incf	dec, 1
	goto	DECENA
DIEZ	addwf	uni, 1		;Uni queda con la cant. de unidades (sin decenas ni centenas)

	movlw	0x30		;Le suma 30h a los valores de UNI, DEC y CEN para que queden en ASCII
	addwf	uni, 1
	addwf	dec, 1
	addwf	cen, 1
	return
	
DEMORA	movwf	tiempo2		;Demora tantos milisegundos como valor en w
TOP2	movlw	d'110'
	movwf	tiempo1
TOP1	nop
	nop
	nop
	nop
	nop
	nop
	decfsz	tiempo1, 1
	goto	TOP1
	decfsz	tiempo2, 1
	goto	TOP2
	return

VERINF	movf	menor, 0	;Temperatura de activación -> W
	call	DECIMAL		;Obtiene UNI, DEC y CEN en formato ASCII
	movlw	0xC2		;Posiciona el cursor en el tercer caracter de la 2da. línea
	call	CONTROL		;para escribir el punto de activación
	movlw	d'1'
	call	DEMORA		;Demora 1ms
	movf	cen, 0		;Coloca en el LCD las centenas
	call	DATO
	movf	dec, 0		;Coloca las decenas
	call	DATO
	movf	uni, 0		;Coloca las unidades
	call	DATO
	return

VERSUP	movf	mayor, 0	;Temperatura de desactivación -> W
	call	DECIMAL		;Obtiene UNI, DEC y CEN en formato ASCII
	movlw	0xCB		;Posiciona el cursor en el caracter 12 de la 2da. línea
	call	CONTROL		;para escribir el punto de desactivación
	movlw	d'1'
	call	DEMORA		;Demora 1ms
	movf	cen, 0		;Coloca en el LCD las centenas
	call	DATO
	movf	dec, 0		;Coloca las decenas
	call	DATO
	movf	uni, 0		;Coloca las unidades
	call	DATO
	return
	
	org	0x2100		;Guarda los parámetros por default en la EEPROM
	data	0x28		;Punto de activación: 40 grados
	data	0x32		;Punto de desactivación: 50 grados

	end
