;
;					EJEMPLO 26
;
;				Autor: Mikel Etxebarria
;			(c) Microsystems Engineering (Bilbao)
;
;Ejemplo MicroPIC Trainer y Micro'PIC I/O
;
;El módulo conversor ADC. Medida de temperatura ambiente. Termostato
;
;Los dispositivos PIC16F87X disponen de un convertidor A/D de 10 bits de resolución y 5 u 8 
;canales de entrada analógica. La tensión de referencia determina la resolución por bit:
;(Res. = Vref/1024). Con 5 Vref=4.86 mV/Bit; con 2.5 Vref=2.43 mV/Bit
;
;El sensor de tª de la tarjeta Micro'PIC I/O proporciona una tensión analógica de 10mV/ºC,
;que se aplica al canal ADC RA5/AN4. El ADC trabaja con una tensión de referencia externa de
;2.5V que se obtiene desde la tarjeta Micro'PIC I/O y se aplica en RA3/Vref. Aproximadamente
;se toma una muestra de la temperatura actúal cada segundo
;
;La pantalla LCD visualiza la temperatura. El relé 1 conectado a RC0 se activa, a modo de 
;calefactor, si la temperatura baja por debajo de la mínima establecida. El motor conectado
;a RC1 y RC2, se activa a modo de ventilador si se supera la máxima establecida.

		List	p=16F873	;Tipo de procesador
		include	"P16F873.INC"	;Definiciones de registros internos

T_Min		equ	0x25		;Temperatura mínima
T_Max		equ	0x35		;Temperatura máxima

Lcd_var		equ	0x20		;Variables para las rutinas del LCD
Duty_H		equ	0x22
Duty_L		equ	0x23		;Variable para la anchura de pulso
DatoA_H		equ	0x24
DatoA_L		equ	0x25		;Multiplicando de 16 bits
DatoB_H		equ	0x26
DatoB_L		equ	0x27		;Multiplicador de 16 bits
DatoD_H		equ	0x28
DatoD_L		equ	0x29
DatoC_H		equ	0x2A
DatoC_L		equ	0x2B		;Resultado de 32 bits
Contador	equ	0x2c		;Variable contadora
BCD_2		equ	0x2d
BCD_1		equ	0x2e
BCD_0		equ	0x2f		;Variables BCD
Temporal	equ	0x30		;Variable temporal
Delay		equ	0x31		;Variable de temporización

		org	0x00		;Vector de Reset
		goto	Inicio

		org	0x05		;Salva el vector de interrupción
		
		include "LCD_CXX.INC"	;Incluye rutinas de manejo del LCD

;Mul16x16: Esta rutina multiplica sin signo dos números de 16 bits (DatoB_H:DatoB_L * 
;DatoA_H:DatoA_L) el resultado de 32 bits se deposita en (DatoD_H:DatoD_L y DatoC_H:DatoC_L)

Mul16x16	movlw	.16
		movwf	Contador	;Inicia contador
		clrf	DatoD_H
		clrf	DatoD_L		;Borra parte alta del resultado

Mul_Loop	rrf	DatoB_H,F
		rrf	DatoB_L,F
		btfss	STATUS,C	;El bit LSB es "1" ?
		goto	No_suma		;No
		movf	DatoA_L,W
		addwf	DatoD_L,F	;Suma octeto de menos peso
		btfsc	STATUS,C
		incf	DatoD_H,F
		movf	DatoA_H,W
		addwf	DatoD_H,F	;Suma octeto de más peso
No_suma		rrf	DatoD_H,F
		rrf	DatoD_L,F
		rrf	DatoC_H,F
		rrf	DatoC_L,F
		decfsz	Contador,F
		goto	Mul_Loop
		return

;16Bits_BCD: Esta rutina convierte un número binario de 16 bits situado en DatoC_H y
;DatoC_L en 5 dígitos BCD que se depositan en las variables BCD_0, BCD_1 y BCD_2, siendo 
;esta última la de menos peso. Está presentada en la nota de aplicación AN544 de MICROCHIP 
;y adaptada por Microsystems Engineering

Bits16_BCD	bcf	STATUS,C
		clrf	Contador	
		bsf	Contador,4	;Carga el contador con 16		
		clrf	BCD_0
		clrf	BCD_1
		clrf	BCD_2		;Puesta a 0 inicial

Loop_16		rlf	DatoC_L,F
		rlf	DatoC_H,F
		rlf	BCD_2,F
		rlf	BCD_1,F
		rlf	BCD_0,F		;Desplaza a izda. (multiplica por 2)
		decfsz	Contador,F
		goto	Ajuste
		return

Ajuste		movlw	BCD_2
		movwf	FSR		;Inicia el índice
		call	Ajuste_BCD	;Ajusta el primer byte
		incf	FSR,F
		call	Ajuste_BCD	;Ajusta el segundo byte
		incf	FSR,F
		call	Ajuste_BCD
		goto	Loop_16

Ajuste_BCD	movf	INDF,W		
		addlw	0x03
		movwf	Temporal	
		btfsc	Temporal,3	;Mayor de 7 el nibble de menos peso ??
		movwf	INDF		;Si, lo acumula
		movf	INDF,W		
		addlw	0x30
		movwf	Temporal
		btfsc	Temporal,7	;Mayor de 7 el nibble de menos peso ??
		movwf	INDF		;Si, lo acumula
		return

;Programa principal

Inicio	        clrf	PORTA
		clrf	PORTB
		clrf	PORTC		;Desconecta salidas
		bsf	STATUS,RP0	;Selecciona banco 1
		movlw	b'00000110'
		movwf	ADCON1		;Puerta A digital
		clrf	TRISB		;Puerta B se configura como salida
		clrf	TRISA		;RA4-RA0 salidas
		clrf	TRISC		;Puerta C salida
		movlw	b'11000111'
		movwf	OPTION_REG	;Preescaler de 128 asociado al TMR0
		bcf	STATUS,RP0	;Selecciona banco 0

		call	UP_LCD		;Configuración de E/S para el LCD
		call	LCD_INI		;Inicialización del LCD
		movlw	b'00001100'
		call	LCD_REG		;LCD On, cursor y Blink Off

Loop		bsf	STATUS,RP0	;Selecciona página 1
		movlw	b'00101000'
		movwf	TRISA		;RA3 y RA5 entradas
		movlw	b'10000001'	;Justificación dcha. RA5/AN4 entrada analógica
		movwf	ADCON1		;RA3/Vref entrada de tensión de referencia
		bcf	STATUS,RP0	;Selecciona página 0

;ADC en On con frecuencia de Fosc/32 y seleción del canal RA5/AN4

		movlw	b'10100001'
		movwf	ADCON0

;Temporizar 1 segundo mediante el TMR0. Este, con un preescaler de 256, evoluciona cada
;256uS. Se carga con 195 para realizar una temporización de 50mS. Los 50 mS se repiten 20 
;veces para conseguir un segundo. Seguidamente se toma una muestra de la temperatura.

		movlw	.20
		movwf	Delay
Delay_1		movlw	~.195
		movwf	TMR0		;Inicia el TMR0
		bcf	INTCON,T0IF	;Restaura el flag del TMR0
Delay_2		clrwdt
		btfss	INTCON,T0IF	;Han pasado 50 mS ??
		goto	Delay_2		;Todavía no
		decfsz	Delay,F		;Se ha repetido 20 veces ??
		goto	Delay_1		;No

		bcf	PIR1,ADIF	;Restaurar el flag del ADC
		bsf	ADCON0,GO	;Inicio de conversión
ADC_Wait	btfss	PIR1,ADIF	;Fin de conversión ??
		goto	ADC_Wait	;Todavía no, esperar

;Al resultado de la conversión se le multiplica por 243 (2.43) que es la resolución por bit.
;P.Ej. La Tª es de 25.6º, como el sensor proporciona 10mV/ºC la tensión a convertir será de
;256 mV. Siendo la resolución de 2.43mV/bit el resultado de la conversión dará 0x69 (105)
;que, multiplicado por 0xf3 (243) queda un resultado de 0x63ab (25515). Se desplaza la coma 
;tres posiciones a la izda. y queda finalmente 25.5º (un error de +/- 1 bit)

		bsf	STATUS,RP0	;Banco 1
		movf	ADRESL,W
		bcf	STATUS,RP0
		movwf	DatoB_L
		movf	ADRESH,W
		movwf	DatoB_H		;Carga el multiplicando (valor de conversión)
		movlw	.243
		movwf	DatoA_L
		clrf	DatoA_H		;Carga el multiplicador (243)

		call	Mul16x16	;Multiplica
		call	Bits16_BCD	;Convierte a BCD
		
;Visualiza el resultado sobre la pantalla LCD. La pantalla LCD se actualiza por tanto a cada
;segundo
		
		bsf	STATUS,RP0	;Selecciona banco 1
		movlw	b'00000110'
		movwf	ADCON1		;Puerta A digital
		bcf	STATUS,RP0	;Selecciona banco 0
		call	UP_LCD		;Reconfigura puertos para el LCD
		movlw	0x80
		call	LCD_REG		;Posiciona el cursor
		movf	BCD_0,W
		andlw	0x0f
		iorlw	0x30
		call	LCD_DATO	;Visualiza decenas de grado
		swapf	BCD_1,W
		andlw	0x0f
		iorlw	0x30
		call	LCD_DATO	;Visualiza unidades de grado
		movlw	'.'
		call	LCD_DATO	;Visualiza punto decimal
		movf	BCD_1,W
		andlw	0x0f
		iorlw	0x30
		call	LCD_DATO	;Visualiza décimas de grado
		movlw	' '
		call	LCD_DATO	;Visualiza un ' '
		movlw	0xdf
		call	LCD_DATO	;Visualiza símbolo º
		movlw	'C'
		call	LCD_DATO	;Visualiza C
		
;Se concatena el nibble bajo de BCD_0 que contiene las decenas de grados, con el nible alto
;de BCD_1 que contiene las unidades de grado. De esta forma se obtiene un byte con la tem-
;peratura actúal medida.
		
		swapf	BCD_0,W
		andlw	0xf0
		movwf	Temporal
		swapf	BCD_1,W
		andlw	0x0f
		iorwf	Temporal,F

;Compara la temperatura con los máximos y minimos establecidos

		movlw	T_Max
		subwf	Temporal,W
		btfsc	STATUS,C	;Mayor que la máxima ??
		goto	Sup_Max		;Si
		bcf	PORTC,2		;No. Motor (ventilador) en Off

		movlw	T_Min
		subwf	Temporal,W
		btfss	STATUS,C	;Es inferior que la mínima ??
		goto	Inf_Min		;Si
		bcf	PORTC,0		;Relé 1 en Off (desconecta calefactor)
		goto	Loop

Sup_Max		bsf	PORTC,2		;Activa motor (ventilador)
		goto	Loop

Inf_Min		bsf	PORTC,0		;Aciva relé 1 (calefactor)
		goto	Loop

		end			;Fin del programa fuente
