TODOPIC
Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: Enigma en 14 de Septiembre de 2009, 04:39:03
-
Hola muchachos, estaba recordando y leyendo algunas cosas de los timer como contadores con instrucciones en ASM y me topo con este programita.... Pero no logro captar un pedacito del programa, en especifico es la parte que está en rojo:
El programa es de los ejemplos de la MICROCHIP, y es el siguiente:
PRACTICA 10
;
; Autor: Mikel Etxebarria
; (c) Microsystems Engineering (Bilbao)
;
;El TMR1 en el modo contador. Frecuencímetro
;
;Mediante el generador de onda cuadrada del entrenador, se aplican pulsos por la línea RC0/T1CKI.
;
;El TMR1 cuenta los pulsos durante un intervalo de 0.250 s. Al resultado de la cuenta se
;multiplica por 4 y se obtiene el número de pulsos por segundo o herzios.
;
;Dicha frecuencia se visualiza por la pantalla LCD de la tarjeta Micro'PIC Trainer.
List p=16F873 ;Tipo de procesador
include "P16F873.INC" ;Definiciones de registros internos
Lcd_var equ 0x20 ;Inicio de variables de las rutinas LCD
Byte_L equ 0x22 ;Parte baja del byte a convertir
Byte_H equ 0x23 ;Parte alta del byte a convertir
BCD_2 equ 0x24 ;Byte 2 de conversión a BCD
BCD_1 equ 0x25 ;Byte 1 de conversión a BCD
BCD_0 equ 0x26 ;Byte 0 de conversión a BCD
Contador equ 0x27 ;Variable de contaje
Temporal equ 0x28 ;Variable temporal
Delay equ 0x29 ;Variable para la temporización
DATO_A equ 0x30
DATO_B equ 0x31
org 0x00 ;Vector de Reset
goto Inicio
org 0x04 ;Vector de interrupción
goto Inter
;******************************************************************************************
;Visualizar: Visualiza sobre la pantalla LCD los cinco dígitos situados en las variables
;BCD_0, BC_1 y BCD_2
Visualizar movlw 0x80
call LCD_REG ;Posiciona el cursor
movlw 3
movwf Contador ;Inicia contador de bytes a convertir
movlw BCD_0
movwf FSR ;Inicia puntero índice
Visual_loop swapf INDF,W
andlw 0x0f
iorlw 0x30 ;Convierte a ASCII el nible de más peso
call LCD_DATOS ;Lo visualiza
movf INDF,W
andlw 0x0f
iorlw 0x30 ;Convierte a ASCII el nible de menos peso
call LCD_DATOS ;Lo visualiza
decf FSR,F ;Siguiente byte
decfsz Contador,F
goto Visual_loop
movlw ' '
call LCD_DATOS
movlw 'P'
call LCD_DATOS
movlw 'P'
call LCD_DATOS
movlw 'M'
call LCD_DATOS
return
;****************************************************************************************
;Bits16_BCD: Esta rutina convierte un número binario de 16 bits situado en Cont_H y
;Cont_L y lo convierte 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.
;Esta rutina se presenta en la nota de aplicación AN544 de MICROCHIP y está 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 del resultado
Loop_16 rlf Byte_L,F
rlf Byte_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 de tratamiento de la interrupción que se provoca cuando el TMR0 temporice 50mS.
;Trabajando a 4MHz el TMR0 evoluciona cada 1 uS. Con un preescaler de 256, hay que cargar
;el valor 195 para provocar una interrupción cada 50 mS. Esta temporización se repite 5 veces
;para conseguir un delay de 250 mS, al final de los cuales se captura el contenido del TMR1.
Inter decfsz Delay,F ;Han pasado 250 mS ??
goto No_250_mS ;No
Si_250_mS bcf T1CON,0 ;Si, TMR1 en Off, cuenta detenida
bcf STATUS,C
rlf TMR1L,F
rlf TMR1H,F
rlf TMR1L,F
rlf TMR1H,F ;Multiplica por 4 el valor del TMR1
movf TMR1L,W
movwf Byte_L ;Salva parte baja del contador
movf TMR1H,W
movwf Byte_H ;Salva parta alta del contador
call Bits16_BCD ;Convierte a BCD el resultado de la cuenta
call Visualizar ;Visualiza el resultado
movlw ~.195
movwf TMR0
movlw .20
movwf Delay ;Repone para temporizar cada 250mS
bcf INTCON,2 ;Repone flag del TMR0
clrf TMR1L
clrf TMR1H ;Borra el TMR1
bsf T1CON,0 ;TMR1 en On, se inicia la cuenta
retfie
No_250_mS movlw ~.195
movwf TMR0 ;Repone para temporizar otros 50mS
bcf INTCON,2 ;Repone el flag del TMR0
retfie
;Programa principal
Inicio clrf PORTB ;Borra los latch de salida
clrf PORTA ;Borra los latch de salida
bsf STATUS,RP0 ;Selecciona banco 1
movlw b'00000110'
movwf ADCON1 ;Puerta A E/S digitales
clrf TRISB ;Puerta B se configura como salida
clrf TRISA ;Puerta A se configura como salida
movlw b'11000111'
movwf OPTION_REG ;Preescaler de 256 asociado al TMR0
movlw 0xff
movwf TRISC ;Puerta C como entrada
bcf STATUS,RP0 ;Selecciona banco 0
;El TMR1 actúa como contador externo asíncrono y con un preescaler de 1:1
movlw b'00000010'
movwf T1CON ;TMR1 Off
clrf TMR1L
clrf TMR1H ;Puesta a 0 del TMR1
call UP_LCD ;Configura puerto para el LCD
call LCD_INI ;Inicia el LCD
movlw b'00001100'
call LCD_REG ;LCD On, cursor y blink Off
movlw ~.195
movwf TMR0
bsf T1CON,0 ;TMR1 en On, comienza la cuenta de pulsos externos
movlw .5
movwf Delay ;Prepara temporización de 250mS
movlw b'10100000'
movwf INTCON ;Habilita interrupción del TMR0
Loop clrwdt ;Refresca el WDT
nop
goto Loop ;Bucle infinito
;--------------------------rutina para encender la PANTALLA LCD------------------------
UP_LCD nop
bsf STATUS,5 ;Banco 1
bcf STATUS,6 ;seleccion del BANCO1
movlw 0x8E ;cargo en W el dato 0x06
movwf ADCON1 ;configuro el Puerto A como E/S Digitales
clrf TRISA ;Puerta A salida
clrf TRISB ;Puerta B salida
bcf STATUS,5 ;Banco 0
bcf STATUS,6 ;Banco 0
clrf PORTA ;reset puerta A
clrf PORTB ;reset puerta B
clrf INTCON ;Desactivar interrupciones.
bcf PORTA,3 ;RS=0
bcf PORTA,2 ;E=0 Desactiva LCD
return
;-----------------------------RUTINA LCD-------------------------------------------
;LCD_BUSY: Lectura del Flag busy & direcci¢n.
;
LCD_BUSY bsf PORTA,1 ;Pone el LCD en modo lectura
bsf STATUS,5 ;Selecciona el banco 1
bcf STATUS,6
movlw 0xff
movwf TRISB ;Puerta B como entrada
bcf STATUS,5 ;Selecciona el banco 0
bcf STATUS,6
bsf PORTA,2 ;Activa el LCD
nop
L_BUSY btfsc PORTB,7 ;Chequea bit de Busy
goto L_BUSY
bcf PORTA,2 ;Desactiva LCD
bsf STATUS,5 ;Selecciona banco 1
clrf TRISB ;Puerta B salida
bcf STATUS,5 ;Selecciona el banco 0
bcf PORTA,1 ;Pone LCD en modo WR
return
;-------------------------------------------------------------------------
;LCD_E: Pulso de Enable
;
LCD_E bsf PORTA,2 ;Activa se¤al E
nop ;Espera 1 uS
bcf PORTA,2 ;Desactiva se¤al E
return
;
;-------------------------------------------------------------------------
;LCD_DATO: Escritura de datos en DDRAM o CGRAM
;
LCD_DATOS bcf PORTA,3 ;Desactiva RS (modo comando)
movwf PORTB ;Valor ASCII a sacar por RB
call LCD_BUSY ;Espera a que se libere el LCD
bsf PORTA,3 ;Activa RS (modo dato).
goto LCD_E ;Genera pulso en la se¤al E
;------------------------------------------------------------------------
;LCD_REG: Escritura de comandos en el LCD
;
LCD_REG bcf PORTA,3 ;Desactiva RS (modo comando)
movwf PORTB ;Saca el c¢digo de la instrucci¢n
call LCD_BUSY ;Espera se libere el LCD
goto LCD_E ;Genera pulso en la se¤al E
;
;------------------------------------------------------------------------
;LCD_INI: Inicializaci¢n del LCD
;
LCD_INI movlw b'00111000' ;Caracteres 5-7,datos de 8 bits.
call LCD_REG ;C¢digo de instrucci¢n
call DELAY_5MS ;5ms.(Especificaci¢n de Fabricante)
movlw b'00111000'
call LCD_REG ;C¢digo de instrucci¢n
call DELAY_5MS ;5ms.(Especificaci¢n de Fabricante)
movlw b'00111000'
call LCD_REG ;C¢digo de instrucci¢n
call DELAY_5MS ;5ms.(Especificaci¢n de Fabricante)
return
;--------------------------FIN RUTINA LCD--------------------------------
;------------------------------------------------------------------------
;DELAY_5MS: Genera una temporizaci¢n de 5 mS
;
DELAY_5MS movlw 0x1a
movwf DATO_B ;Carga la variable DATO_B
clrf DATO_A ;Carga la variable DATO_A
DELAY_1 decfsz DATO_A,1 ;Decrementa la variable DATO_A
goto DELAY_1
decfsz DATO_B,1 ;Decrementa la variable DATO_B
goto DELAY_1
return
;------------------------------------------------------------------------
;-----------------------------RUTINA DE TEMPORIZACION--------------------
DELAY call DELAY_5MS ;demora de 25_ms.
call DELAY_5MS
call DELAY_5MS
call DELAY_5MS
call DELAY_5MS
return
DELAY1 call DELAY ;demora de 100_ms.
call DELAY
call DELAY
call DELAY
return
DELAY2 call DELAY1 ;demora de 500_ms.
call DELAY1
call DELAY1
call DELAY1
call DELAY1
return
end ;Fin del programa fuente
Esa parte roja, me dice que al desplazar los registros del timer 1 a la derecha me está multiplicando por 4 el contenido del timer 1, ahora esa es mi duda, como me multiplica por 4 rotando los bits de dichos registros...????
Si alguien pudiera explicarme se lo agradeceria, porque me he quedado con esta duda de este programa!!!! Gracias de antemano!
Atte: Enigma... La llanerita de Guayana ;-)
-
Multiplicar por 2,4,8,16 es sencillo porque solo haces la rotación. Debes asociarlo a la base del sistema de numeración, en este caso binario.
Por ejemplo:
1101*10=11010
1101*100=110100
1101*1000=1101000
Como ves rotando se obtiene el resultado.
-
con cada rotacion a la izquierda se multiplica por 2 y por cada rotacion a la derecha se divide por 2.asi de sencillo
-
Ahhh o.k, o.k..... osea, osea por eso es que rotan dos veces, porque cada una es vale dos como dice groundman, ahhh ya entiendo... aja, pero otra cosita, pero para multiplicar en binario no vale también la regla en decimales, la cual se suma tantas veces el número más si mismo para lograr el resultado es decir, por ejemplo: 2*2=4 o lo que es lo mismo 2+2=4 o por ejemplo tambien 6*4=24 o lo que es lo mismo 6+6+6+6+=24....
Rayos hoy aprendi algo n uevo jejejeje con la rotación de bits! :mrgreen:
Atte: Enigma... La llanerita de Guayana ;-)
-
la rotacion es para pequeñas multiplicaciones y divisiones.siempre que no nos pasemos del valor 255.aunque tambien podriamos sumar los acarreos.
pero la mejor forma es la que comentas al final.
para multiplicar lo mejor es sumar un numero tantas veces como queramos realizar esa multiplicacion.y cuando nos pasemos de 255,tener encuenta el acarreo.
-
Si yo lo veo más facil así sumando y sumando hasta que pase del tamaño de 8bits.... :D
Bueno estaba analizando un poco más el programa y les ruego me disculpen si soy muy molestona con esto no, pero es que lo he revisado, escrito y pues todavia se me hace dificil ver el porque de algunas acciones... A veces es un poco dificil interpretar el programa de otra persona y el saber porque usa agunas instrucciones.... Bueno ojala puedan sacarme de mi duda, esta es la forma que he interpretado el programa hasta ahora:
El programa empieza como todos cargando registros, inicializando puertos, carga el TMR0 y mientras este se desborda pues se queda encerrado en el lazo loop, o.k todo bien hasta aquí en el principal, es decir aquí:
;Programa principal
Inicio clrf PORTB ;Borra los latch de salida
clrf PORTA ;Borra los latch de salida
bsf STATUS,RP0 ;Selecciona banco 1
movlw b'00000110'
movwf ADCON1 ;Puerta A E/S digitales
clrf TRISB ;Puerta B se configura como salida
clrf TRISA ;Puerta A se configura como salida
movlw b'11000111'
movwf OPTION_REG ;Preescaler de 256 asociado al TMR0
movlw 0xff
movwf TRISC ;Puerta C como entrada
bcf STATUS,RP0 ;Selecciona banco 0
;El TMR1 actúa como contador externo asíncrono y con un preescaler de 1:1
movlw b'00000010'
movwf T1CON ;TMR1 Off
clrf TMR1L
clrf TMR1H ;Puesta a 0 del TMR1
call UP_LCD ;Configura puerto para el LCD
call LCD_INI ;Inicia el LCD
movlw b'00001100'
call LCD_REG ;LCD On, cursor y blink Off
movlw ~.195
movwf TMR0
bsf T1CON,0 ;TMR1 en On, comienza la cuenta de pulsos externos
movlw .5
movwf Delay ;Prepara temporización de 250mS
movlw b'10100000'
movwf INTCON ;Habilita interrupción del TMR0
Loop clrwdt ;Refresca el WDT
nop
goto Loop ;Bucle infinito
Bien una vez que se desborda el timer, pues pasa a la interrupción, pero como no se han cumplido los 250ms pues repone el timer0 hasta que la variable delay pase a cero... Bien una vez que la variable delay es cero pues multiplica por cuatro la parte alta y la parte baja del registro del timer1 y salva esto en otras variables llamadas byte_l y byte_h, luegollama a la función que se encarga de convertir los los registros de 16bits que se generaron por multiplicar por 4 para pasarlos a bcd y poderlos visualizar en la lcd a través de tres variables llamadas BCD_0, BCD_1 y BCD2... luego llama a visualizar a la LCD se regresa a la interrupción y repone el TMR0 y las otras variables.... es decir esto:
Inter decfsz Delay,F ;Han pasado 250 mS ??
goto No_250_mS ;No
Si_250_mS bcf T1CON,0 ;Si, TMR1 en Off, cuenta detenida
bcf STATUS,C
rlf TMR1L,F
rlf TMR1H,F
rlf TMR1L,F
rlf TMR1H,F ;Multiplica por 4 el valor del TMR1
movf TMR1L,W
movwf Byte_L ;Salva parte baja del contador
movf TMR1H,W
movwf Byte_H ;Salva parta alta del contador
call Bits16_BCD ;Convierte a BCD el resultado de la cuenta
call Visualizar ;Visualiza el resultado
movlw ~.195
movwf TMR0
movlw .20
movwf Delay ;Repone para temporizar cada 250mS
bcf INTCON,2 ;Repone flag del TMR0
clrf TMR1L
clrf TMR1H ;Borra el TMR1
bsf T1CON,0 ;TMR1 en On, se inicia la cuenta
retfie
No_250_mS movlw ~.195
movwf TMR0 ;Repone para temporizar otros 50mS
bcf INTCON,2 ;Repone el flag del TMR0
retfie;
Pero mi dificultad o mi falta de entendimiento empieza aquí, en la rutina de conversión de 16 bits a BCD....
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 del resultado
Loop_16 rlf Byte_L,F
rlf Byte_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
Ustedes me disculpan pero no entiendo unas cositas aquí, y ya me he reventado el coco… :?
1.) ¿Porqué colocan el bit de acarreo C en cero?
2.) ¿Porqué inicializan contador con 16, con que finalidad?
3.) ¿Porqué multiplican las variables:
rlf Byte_L,F
rlf Byte_H,F
rlf BCD_2,F
rlf BCD_1,F
rlf BCD_0,F por dos y en especial a las variables donde están guardados lo que midio el TMR1?
4.) Está subrutina:
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
Porque direccionan con el FSR??? Rayos aquí me termine de volver un 8…
5.) En la subrutina de viasualizar…
Visualizar movlw 0x80
call LCD_REG ;Posiciona el cursor
movlw 3
movwf Contador ;Inicia contador de bytes a convertir
movlw BCD_0
movwf FSR ;Inicia puntero índice
Visual_loop swapf INDF,W
andlw 0x0f
iorlw 0x30 ;Convierte a ASCII el nible de más peso
call LCD_DATOS ;Lo visualiza
movf INDF,W
andlw 0x0f
iorlw 0x30 ;Convierte a ASCII el nible de menos peso
call LCD_DATOS ;Lo visualiza
decf FSR,F ;Siguiente byte
decfsz Contador,F
goto Visual_loop
movlw ' '
call LCD_DATOS
movlw 'P'
call LCD_DATOS
movlw 'P'
call LCD_DATOS
movlw 'M'
call LCD_DATOS
return
Porque solamente me trabajan con la variable BCD_0, no se supone que en las tres iba guardado el dato?????? :?
Rayos…. Bueno si pueden ayudarme a aclarar mis lagunas se los ruego y disculpen la molestia pero deberas que he tratado de entender pero nada que lo consigo!!!!! De Antemano muchas gracias y nuevamente disculpen la molestia….
Atte: Enigma... La llanerita de Guayana ;-)
-
como tu dices.es bastante dificil interpretar un programa hecho por otra persona.ya es complicado entender uno hecho por nosotros mismos.cuando llevamos mucho tiempo sin estudiarlo.
de todas formas.que es lo que quieres realizar? una multiplicacion entre dos bytes? dos palabras?
quizas sera mejor realizarlo de cero.
-
Si vale, porque es que le he echado cabeza y no logro entender algunas de las acciones que toma!!! Bueno en realidad lo que quiero hacer es tomar los valores que me mide el TMR1 como contador, multiplicarlos por cuatro y el resultado mandarlo a la LCD.... toy enredada!!!
Atte: Enigma... La llanerita de Guayana ;-)
-
para multiplicarlo por 4 ya vistes en el programa anterior que lo hace rotando a la izquierda dos veces los registros alto y bajo del TMR1 ya que son 16bits los que quieres multiplicar.a todo esto tienes que tener en cuenta el acarreo del rejistro alto del TMR1.y guardarlo en un registro.
no es dificil.pero supongo que tu problema es pasar este dato a bcd para visualizarlo en la lcd.es asi?
-
Eso es correcto, esees mi gran problema y dolor de cabeza!!!
Atte: Enigma... La llanerita de Guayana ;-)