; Ejemplo de uso de macro
PROCESSOR P16F84
#include "p16f84.inc"
_CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
; Macro para extraer info para mostrar en el Display
; Dig1 = MSD (centenas) Dig2= decenas Dig3= LSB (unidades)
; par0 = variable a ser mostrada LSB 8-bits (0-255)
digibyte macro par0
local Loop_C
local Loop_D
local Pozitiv
clrf Dig1 ; Limpiamos contadores que contienen lo
clrf Dig2 ; que se va a mostrar en el display
clrf Dig3 ; En este caso 3 digitos (0 a 255)
Pozitiv
movf par0,w ; Guarda el número a ser separado
movwf Digtemp ; en forma temporal
;
; Convierte a BCD
; La técnica consiste en dividir el parámetro entre una mascara
; (100,10,1). para obtener asi el digito en decimal.
; Se implementa la división - subtrayendo al parametro la
; mascara contando cuantas veces lo hemos hecho, hasta que el
; resultado de la resta sea menor a la mascara.
; como empesamos con el contador en 1 debemos substraer 1 antes de
; salir. Para tener en el contador con el resultado correcto
;
; Empesamos con las centenas
movlw .100 ; mascara para las centenas
Loop_C
incf Dig1,f ; Centenas = Centenas + 1
subwf Digtemp,f ; Parametro = Parametro - .100
btfsc STATUS,C ; Si es menor a zero (c=0) salta 1 linea
goto Loop_C ; Si no regresa hasta que ocurra
decf Dig1,f ; Resta 1 alcontador antes de salir
; Digtemp contiene el cosiente de la division
; Seguimos con las decenas
movlw .10 ; Ajustamos la mascara para decenas
Loop_D
incf Dig2,f ; Decenas = Decenas + 1
subwf Digtemp,f
btfsc STATUS,C
goto Loop_D
decf Dig2,f ; Dig2 contiene las Decenas y
; Digtemp contiene ahora las unidades
; y finalizamos con las unidades
movf Digitemp,w ; Mueve las unidades a su contador
movwf Dig3
endm
org 0x00
goto main ; Inicio del programa
org 0x04
goto ISR ; Inicio del vextor de interrupción
Cblock 0x0C
Dig1 ; Centenas del numero binario D
Dig2 ; Decenas del numero binario D
Dig3 ; Unidades del numero binario D
Digtemp ; auxiliar en conversion bin-.Dec
D ; numero a desplegar
One ; auxiliar para el multiplexado del Display
W_temp ; copia de W en interrupciones
endc
Main
; banksel TRISA
bsf STATUS,5 ;se pone un 1 en el bit 5 del status para
; elegir el banco 1
movlw b'11111100' ; RA0 & RA1 son salida para multiplexado
movwf TRISA
clrf TRISB ; Puerto B son las salidas de los segmentos
movlw b'10000100' ; Prescaler = 32-> TMR0 incrementa cada 32ms
movwf OPTION_REG ; Asumimos que se usa un cristal de 4 MHz4
; banksel PORTA
bcf STATUS,5 n ; cambiamos al banco 0 poniendo un 0 en el
; bit 5 del Status
movf PORTA,0nn ; leemos el puerto A y cargamos en W
movlw ,96 ; TMR0 inicia en 96
; de manera que una interrupcion ocurre
; cada (255-97)* 32 ms = 5.088 ms
movwf TMR0
movlw b'10100000' ; Habilita interrupcion del timer 0
novwf INTCON
movlw .21 ; Despliega el numero 21
movwf D
clrf One
clrf PORTA ; Apaga ambos digitos al inicio
Loop
goto Loop ; Loop principal -> salimos con una interrupcion
ISR ; Rutina de interrupcion
movwf W_temp ; Salva W
movlw .96 ; Inicializa TMR0 para que tenga la siguiente
movwf TMR0 ; interrupcion en aprox 5ms
bcf INTCON, T0IF ;Limpia bandera de Overflow del TMR0
; para ser capaz de reaccionar a la siguiente
; interupcion
bcf PORTA, 0 ; Digito en A0, apagado
bcf PORTA, 1 ; Digito en A1, encendido
movf One, f ; Ajusta banderas
btfsc STATUS,Z ; Cual display debe prenderse?
goto Msd_on
Lsd_on ; Si el MSD estaba anteriormente ON
bcf One,0 ; indica que LSD esta ON
movlw High Bcdto7seg ; Antes de usar el macro tenemos que ir
; a la tabla de conversion, PCLATH
movwf PCLATH ; W debe sr inizializado con la direccion
; mas alta de la tabla
; para prever errores de direccionamiento
digibyte D ; llama a la macro para separar digitos de D
movf Dig3, w ; W = Unidades
call Bcdto7seg ; llama la tabla de conversion para 7-seg
; para displays que son catodo común
; regresa W con el codigo correspondiente
movwf PORTB ; y prepara los segmentos
bsf PORTA, 1 ; Enciende el Digito de las Unidades
; por ~ 5ms, hasta que la siguiente
; interrución ocurra
movf W_temp,w ; Recupera W alvalor que tenia antes de
; entrar a la rutina de interrupción.
retie
Msd_On
bsf One, 0 ; Indica que el MSD esta encendido
movlw High Bcdto7seg ; Antes de usar el macro tenemos que ir
; a la tabla de conversion, PCLATH
movwf PCLATH ; W debe sr inizializado con la direccion
; mas alta de la tabla
; para prever errores de direccionamiento
digibyte D ; llama a la macro para separar digitos de D
movf Dig2, w ; W = Unidades
call Bcdto7seg ; llama la tabla de conversion para 7-seg
; para displays que son catodo común
; regresa W con el codigo correspondiente
movwf PORTB ; y prepara los segmentos
bsf PORTA, 0 ; Enciende el Digito de las Decenas
; por ~ 5ms, hasta que la siguiente
; interrución ocurra
movf W_temp,w ; Recupera W alvalor que tenia antes de
; entrar a la rutina de interrupción.
retie
org 0x300 ; Inicio de la tabla de conversion
; puesta al inicio de la tercer banco de RAM4
; Otras paginas son posibles pero la tabla
;debe estar en una sola pagina (banco) de RAM
Bcdto7seg ; Tabla de conversion para 7-seg
addwf PCL,f ; Ajusta W al valor de tabla + offset
dt 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f
; retlw 0x3f ; número 0
; retlw 0x06 ; número 1
; retlw 0x5b ; número 2
; retlw 0x4f ; número 3
; retlw 0x66 ; número 4
; retlw 0x6d ; número 5
; retlw 0x7d ; número 6
; retlw 0x07 ; número 7
; retlw 0x7f ; número 8
; retlw 0x6f ; número 9