;
;					EJEMPLO 40
;
;				Autor: Mikel Etxebarria
;			(c) Microsystems Engineering (Bilbao)
;
;Ejemplo para MicroPIC Trainer y Micro'PIC Trainer Plus
;
;El módulo USART. Transmisión asíncrona. 
;
;El módulo USART de los dispositivos PIC16F87X incorpora el hardware necesario para implemen-
;tar comunicación serie asíncrona full-duplex o sincrona half-duplex. En este último caso el
;USART se puede comportar como Master o Slave.
;
;En los ejemplos siguientes se propone utilizar un PC para que, con el software TERMINAL.EXE,
;actúe como un simple terminal de comunicaciones. EL usuario deberá preparar los cables de
;comunicación entre la Trainer PLUS y el PC, teniendo en cuenta de cruzar las señal de
;transmisión (TxD) con la de recepción (RxD) y viceversa.
;
;Ejemplo de monitorización. Se trata de enviar vía serie el resultado de los canales analógi-
;cos AN0-AN3 previa conversión de los mismos. Dicho resultado se representa en forma decimal.

		List	p=16F873	;Tipo de procesador
		include	"P16F873.INC"	;Definiciones de registros internos

DatoA_H		equ	0x20
DatoA_L		equ	0x21		;Multiplicando de 16 bits
DatoB_H		equ	0x22
DatoB_L		equ	0x23		;Multiplicador de 16 bits
DatoD_H		equ	0x24
DatoD_L		equ	0x25
DatoC_H		equ	0x26
DatoC_L		equ	0x27		;Resultado de 32 bits
Contador	equ	0x28		;Contador temporal
BCD_2		equ	0x29
BCD_1		equ	0x2a
BCD_0		equ	0x2b		;Variables BCD
Temporal	equ	0x2c
Temporal_1	equ	0x2d
Temporal_2	equ	0x2e		;Variables temporales

		org	0x00		;Vector de Reset
		goto	Inicio

		org	0x05		;Salva vector de interrupción
	
;******************************************************************************************
;Según el valor contenido en el registro W, se devuelve el carácter a visualizar

Tabla_Mensajes	movwf	PCL		;Calcula el desplazamiento sobre la tabla

;***********************************************************************************
;La directiva dt genera tantas intsrucciones retlw como bytes o caracteres contenga

Mens_0		equ	$		;Mens_0 apunta al primer carácter del mensaje 0
		dt	"Canal0  Canal1  Canal2  Canal3",0x0d,0x0a,0x00

Mens_1		equ	$		;Mens_1 apunta al primer carácter del mensaje 1
		dt	"------  ------  ------  ------",0x0d,0x0a,0x0a,0x00

;******************************************************************************************
;Visualiza: Transmite vía serie el valor contenido en las variables BCD_0, BCD_1 y BCD_2
;que contienen el resultado decimal de la tensión analógica de entrada de un canal.
;
Visualiza	movf	BCD_0,W
		iorlw	0x30		;Convierte a ASCCI dígito de más peso
		call	Tx_Dato		;Lo transmite
		movlw	'.'
		call	Tx_Dato		;Transmite punto decimal
		movf	BCD_1,W
		call	BCD_ASCII	;Convierte BCD_1 a ASCII y transmite
		movf	BCD_2,W
		call	BCD_ASCII	;Convierte BCD_2 a ASCII y transmite
		movlw	' '
		call	Tx_Dato
		call	Tx_Dato		;Transmite dos espacios en blanco
		return

;******************************************************************************************
;BCD_ASCII: Convierte el byte presente en W en dos caracteres ASCII y los transmite vía
;RS232
;
BCD_ASCII	movwf	Temporal	;Salva el byte
		swapf	Temporal,W
		andlw	0x0f
		iorlw	0x30		;Convierte a ASCII el nible de más peso
		call	Tx_Dato		;Lo transmite
		movf	Temporal,W
		andlw	0x0f
		iorlw	0x30		;Convierte a ASCII el nible de menos peso
		call	Tx_Dato		;Lo transmite
		return

;******************************************************************************************
;Lectura: Con una Vref. de 5V, la resolución es de 4.8 mV . Esta rutina lee el valor
;del conversor y lo multiplica por la constante 48. El resultado se convierte a BCD. El
;dígito de más peso expresa unidades de voltio y los cuatro restantes fracciones de voltio.

Lectura		bsf	STATUS,RP0
		movf	ADRESL,W
		bcf	STATUS,RP0	;Lee parte de menos peso de la conversión
		movwf	DatoB_L		;Almacena como multiplicando_L
		movf	ADRESH,W	;Lee parte de más peso de la conversión
		movwf	DatoB_H		;Almacena como multiplicando_H
		movlw	.48
		movwf	DatoA_L		;Almacena multiplicador_L
		clrf	DatoA_H		;Almacena multiplicador_H
		call	Mul16x16	;Multiplica valor del conversor por 48
		call	Bits16_BCD	;Convierte a BCD
		return

;******************************************************************************************
;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

;****************************************************************************************
;Bits16_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

;*************************************************************************************
;Mensaje: Esta rutina envía vía serie RS232 el mensaje cuyo inicio está  indicado en
;el acumulador. El fin de un mensaje se determina mediante el código 0x00

Mensaje         movwf   Temporal_1      ;Salva posición de la tabla
Mensaje_1       movf    Temporal_1,W    ;Recupera posición de la tabla
                call    Tabla_Mensajes  ;Busca caracter de salida
                movwf   Temporal_2      ;Guarda el caracter
                movf    Temporal_2,F
                btfss   STATUS,Z        ;Mira si es el último
                goto    No_es_ultimo
                return
No_es_ultimo   	call    Tx_Dato		;Transmite el carácter
                incf    Temporal_1,F    ;Siguiente caracter
                goto    Mensaje_1

;********************************************************************************************
;Tx_Dato: Transmite vía serie el dato presente en el reg. W

Tx_Dato		bcf	PIR1,TXIF	;Restaura el flag del transmisor
		movwf	TXREG		;Almacena el byte a transmitir
		bsf	STATUS,RP0
Tx_Dato_Wait	btfss	TXSTA,TRMT	;Byte transmitido ??
		goto	Tx_Dato_Wait	;No, esperar
		bcf	STATUS,RP0
		return			;Si

;*******************************************************************************************
;Programa principal

Inicio	     	clrwdt
		clrf	PORTC		
		bsf	STATUS,RP0	;Selecciona banco 1
		movlw	b'10000000'
		movwf	ADCON1		;RA0-RA3 analógicas, Vref=Vcc, alineación Dha.
		movlw	b'11111111'
		movwf	TRISA		;Puerta A entrada
		movlw	b'10111111'
		movwf	TRISC		;RC7/Rx entrada, RC6/Tx salida
		movlw	b'11001111'
		movwf	OPTION_REG	;Preescaler de 128 asociado al WDT

		movlw	b'00100100'	
		movwf	TXSTA		;TX en On, modo asíncrono con 8 bits y alta velocidad
		movlw	.25
		movwf	SPBRG		;9600 baudios con Fosc=4MHz

		bcf	STATUS,RP0	;Selecciona banco 0
		bsf	RCSTA,SPEN	;USART en On

;El ADC trabaja a Fosc/8

		movlw	b'01000001'
		movwf	ADCON0		;ADC en On

		movlw	Mens_0
		call	Mensaje
		movlw	Mens_1
		call	Mensaje		;Envía vía RS232 mensajes de cabecera

Loop		clrwdt
		bcf	PIR1,ADIF	;Restaura el flag del conversor
		movlw	b'01000001'
		movwf	ADCON0		
		nop
		bsf	ADCON0,GO	;Inicia conversión del canal 0
ADC0_Wait	btfss	PIR1,ADIF	;Fin de conversión ??
		goto	ADC0_Wait	;No, esperar
		call	Lectura		;Lee el valor de la conversión
		call	Visualiza	;Salida por RS232
		
		bcf	PIR1,ADIF	;Restaura el flag del conversor
		movlw	b'01001001'
		movwf	ADCON0		
		nop
		bsf	ADCON0,GO	;Inicia conversión del canal 1
ADC1_Wait	btfss	PIR1,ADIF	;Fin de conversión ??
		goto	ADC1_Wait	;No, esperar
		call	Lectura		;Lee el valor de la conversión
		call	Visualiza	;Salida por RS232

		bcf	PIR1,ADIF	;Restaura el flag del conversor
		movlw	b'01010001'
		movwf	ADCON0		
		nop
		bsf	ADCON0,GO	;Inicia conversión del canal 2
ADC2_Wait	btfss	PIR1,ADIF	;Fin de conversión ??
		goto	ADC2_Wait	;No, esperar
		call	Lectura		;Lee el valor de la conversión
		call	Visualiza	;Salida por RS232

		bcf	PIR1,ADIF	;Restaura el flag del conversor
		movlw	b'01011001'
		movwf	ADCON0		
		nop
		bsf	ADCON0,GO	;Inicia conversión del canal 3
ADC3_Wait	btfss	PIR1,ADIF	;Fin de conversión ??
		goto	ADC3_Wait	;No, esperar
		call	Lectura		;Lee el valor de la conversión
		call	Visualiza	;Salida por RS232
		
		movlw	0x0d
		call	Tx_Dato		;Transmite CR

		goto	Loop

		end			;Fin del programa fuente
