Hola quiero crear un temporizador con el PIC P16F886, de 0,5 segundos de pulso osea con una frecuencia de 1Hzy no se como programarlo , tengo la idea pero no se plasmarlo en emsalblador. Os explico:
Voy a usar el oscilador interno del PICde 4MHz lo que es lo mismo con un periodo de 0,25us si una instruccion tarda 4 ciclos de reloj, cada instrucción tarda en ejegutarse 1us.
Tengo que conseguir que oscile a 0,5s--> 500.000us para ello quiero poner el TMR0 inicialmente a 250 y el preescale a 8 con lo que el TMR0 se desborda cada 2000us (250*8=2000). Si con un contador cuento 250 vecesda 0,5 s (2000us*250=500.000us=0.5s).
Lo que no se hacer o que no entiendo como se le da la orden de que empie a contar otra cosa que no entiendo es que al ir comparando el valor del contador cuenta como un tiempo de instrucción por tanto ya se retrasaria, no se tengo un cacao muy grande,
se que tengo cuando se supere el desbordamiento del TMR0 cada 2000us tengo que poner el bit TI0IF del registro INTCON mediante programa a 0.
Aqui os dejo un diagrama de como creo que funciona:
(http://s2.subirimagenes.com/otros/previo/thump_8365894untitledu.jpg)
Gracias
Hola:
Si le interesa usar retardos, aquí hay información.
http://electronica-pic.blogspot.com.es/2012/02/retardos-para-pic12f-16f-y-18f.html
Saludo.
Gracias Meta por la ayuda, umm lo único que he sabido hacer es configurar los puertos:
;***** CONFIGURACIÓN ******************************************************
List p=16F886 ;Tipo de procesador
include "P16F886.INC" ;Definiciones de registros internos
;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades
__config _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF ;Palabra 1 de configuración
__config _CONFIG2, _WRT_OFF&_BOR40V
; _MCLRE_ON: Reset externo ACTIVADO.
; _CP_OFF: Protección del código DESACTIVADO.
; _WDT_OFF: Watchdog DESACTIVADO.
; _IntRC_OSC: Oscilador interno de 4MHz.
;***** DEFINICIÓN DE VARIABLES
; Definimos las posiciones de memoria de los datos
CONTADOR equ 0x10
;**************************************************************************
; Inicialización del programa:
; Origen
Org 0x00
goto Inicio ;Vector de reset
org 0x05
; Configuración de los puertos como entradas y salidas
Inicio clrf PORTB ; Borrado de los biestables de salida
bsf STATUS,RP0 ; Selecciona banco 3 (RP0=RP1='1')
bsf STATUS,RP1
clrf ANSEL ; El puerto A de tipo digital
clrf ANSELH ; El puerto B de tipo digital
bcf STATUS,RP1 ; Selecciona banco 1 (RP1='0' RP0='1')
clrf TRISB ; RB7:RB0 se configuran como salidas
movlw b'00111111'
movwf TRISA ; RA5:RA0 se configuran como entrada
movlw b'00000110' ;movemos el valor de la opción del preescale al registro W
movwf OPTION_REG ;pasamos el valor de w al registro
bcf STATUS,RP0 ; Se vuelve al banco 0
movlw b'00000111' ;movemos el valor de la opción del preescale al registro W
movwf INTCON ;
ya más no se estoy bastante perdido :S
Gracias[/size]
Hola:
Aquí encontré un ejemplo sencillo.
;El Timer 0 TMR0.
;
;Se trata de comprobar el funcionamiento básico del Timer 0. Cuando se detecta un flanco
;decendente en RA0 (conectada con un pulsador), se activa la salida RB0 durante un tiempo
;y luego se desconecta. El TMR0 realiza una temporización de 50mS que se repite tantas veces
;como se indique en la variable "Temp". Así pues la temporización total será de 50mS*Temp.
;
;Suponiendo una frecuencia de trabajo de 4MHz, 4Tosc=1uS. Trabajando con un prescaler de 256,
;al TMR0 hay que cargarlo con 195 para temporizar 50mS (Temporización=1uS*195*256)
List p=16F886 ;Tipo de procesador
include "P16F886.INC" ;Definiciones de registros internos
;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades
__config _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF ;Palabra 1 de configuración
__config _CONFIG2, _WRT_OFF&_BOR40V ;Palabra 2 de configuración
Valor equ .20 ;Constante para temporizar 1 seg (50mS*20)
Temp equ 0x020 ;Variable para la temporización
org 0x00 ;Vector de RESET
goto Inicio
org 0x05
;*********************************************************************************************
;Delay: El Timer 0 realiza un retardo de 50mS que se repite tantas veces como se indica en la
;constante valor
Delay movlw Valor
movwf Temp ;Nº de veces a temporizar 50 mS
Delay_1 movlw ~.195
movwf TMR0 ;Inicia el Timer 0 con 195 (195*256=49.9mS)
bcf INTCON,T0IF ;Repone flag del TMR0
Delay_2 btfss INTCON,T0IF ;Fin de los 50mS ??
goto Delay_2 ;No, el TMR0 no ha terminado
decfsz Temp,F ;Decrementa el contador. Fin de temporización ??
goto Delay_1 ;No, el TMR0 temporiza otros 50 mS
return ;Si, final de la temporización
;Programa principal
Inicio clrf PORTB ;Borra los latch de salida
bsf STATUS,RP0
bsf STATUS,RP1 ;Selecciona banco 3
clrf ANSEL ;Puerta A digital
clrf ANSELH ;Puerta B digital
bcf STATUS,RP1 ;Selecciona banco 1
movlw b'11111110'
movwf TRISB ;RB0 se configura como salida
movlw b'00111111'
movwf TRISA ;RA5:RA0 se configuran como entrada
movlw b'00000111'
movwf OPTION_REG ;TMR0 con reloj interno y preescaler de 256
bcf STATUS,RP0 ;Selecciona banco 0
;Este es el cuerpo principal del programa. Espera a que en RA0 se detecte un flanco descendente
Loop btfsc PORTA,0 ;RA0=0 ??
goto Loop ;No, esperar
bsf PORTB,0 ;Si activar RB0
call Delay ;Temporizar
bcf PORTB,0 ;Desactivar RB0
goto Loop ;Repetir el proceso
end
Otro más por aquí.
;La interrupción del TMR0.
;
;Se trata de comprobar la interrupción provocada por el TMR0. El programa
;lee el estado de los interruptores conectados a RA0 y RA1 para reflejarlo en
;los leds conectados a RB0 y RB1 respectivamente. Al mismo tiempo el TMR0
;genera una interrupción cada 0.01 seg. (10 mS) que se repetirá 50 veces con objeto
;de hacer intermitencia de 500 mS sobre el led conectado a RB3.
List p=16F886 ;Tipo de procesador
include "P16F886.INC" ;Definiciones de registros internos
;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades
__config _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF ;Palabra 1 de configuración
__config _CONFIG2, _WRT_OFF&_BOR40V ;Palabra 2 de configuración
Contador equ 0x020 ;Variable para la temporización
org 0x00 ;Vector de RESET
goto Inicio
org 0x04 ;Vector de interrupción
goto Interrupcion
org 0x05
Interrupcion bcf INTCON,T0IF ;Repone flag del TMR0
decfsz Contador,F ;Decrementa el contador. Ha habido 50 interrupciones ??
goto Seguir ;No, no han pasado los 500 mS
Con_si_0 movlw .50
movwf Contador ;Repone el contador nuevamente para contar 50 interrupciones
movlw b'00001000'
xorwf PORTB,F ;RB3 cambia de estado
Seguir movlw ~.39
movwf TMR0 ;Repone el TMR0 con 39
retfie ;Retorno de interrupción
Inicio clrf PORTB ;Borra los latch de salida
bsf STATUS,RP0
bsf STATUS,RP1 ;Selecciona banco 3
clrf ANSEL ;Puerta A digital
clrf ANSELH ;Puerta B digital
bcf STATUS,RP1 ;Selecciona banco 1
clrf TRISB ;RB7:RB0 se configuran como salida
movlw b'00111111'
movwf TRISA ;RA5:RA0 se configuran como entrada
movlw b'00000111'
movwf OPTION_REG ;Preescaler de 256 para el TMR0
bcf STATUS,RP0 ;Selecciona banco 0
;El TMR0 se carga con 39. Con un preescaler de 256 y a una frecuencia de 4MHz se obtiene una interrupción
;cada 10mS. Se habilita la interrupción del TMR0.
movlw ~.39
movwf TMR0 ;Carga el TMR0 con 39
movlw .50
movwf Contador ;Nº de veces a repetir la interrupción
movlw b'10100000'
movwf INTCON ;Activa la interrupción del TMR0
;Este es el cuerpo principal del programa. Consiste en leer constantemente el estado de RA0 y RA1 para visualizar
;sobre RB0 y RB1 sin que cambie el estado actual de RB7
Loop btfsc PORTA,0 ;Testea el estado de RA0
goto RA0_ES_1
bcf PORTB,0 ;Desactiva RB0
goto TEST_RB1
RA0_ES_1 bsf PORTB,0 ;Activa RB0
TEST_RB1 btfsc PORTA,1 ;Testea el estado de RA1
goto RA1_ES_1
bcf PORTB,1 ;Desactiva RB1
goto Loop
RA1_ES_1 bsf PORTB,1 ;Activa RB1
goto Loop
end ;Fin del programa fuente
Saludo.
Muchas garcias Meta por la ayuda creo que estoy avanzando hasta ahora llevo lo siguiente, me falta poner que cuando el contador de usuario llegue a 0 se active la salida:
;**************************************************************************
;***** CONFIGURACIÓN ******************************************************
List p=16F886 ;Tipo de procesador
include "P16F886.INC" ;Definiciones de registros internos
;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades
__config _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF ;Palabra 1 de configuración
__config _CONFIG2, _WRT_OFF&_BOR40V
; _MCLRE_ON: Reset externo ACTIVADO.
; _CP_OFF: Protección del código DESACTIVADO.
; _WDT_OFF: Watchdog DESACTIVADO.
; _IntRC_OSC: Oscilador interno de 4MHz.
;***** DEFINICIÓN DE VARIABLES
; Definimos las posiciones de memoria de los datos
CONTADOR equ 0x20
;**************************************************************************
; Inicialización del programa:
; Origen
Org 0x00
goto Inicio ;Vector de reset
org 0x05
; Configuración de los puertos como entradas y salidas
Inicio clrf PORTB ; Borrado de los biestables de salida
bsf STATUS,RP0 ; Selecciona banco 3 (RP0=RP1='1')
bsf STATUS,RP1
clrf ANSEL ; El puerto A de tipo digital
clrf ANSELH ; El puerto B de tipo digital
bcf STATUS,RP1 ; Selecciona banco 1 (RP1='0' RP0='1')
clrf TRISB ; RB7:RB0 se configuran como salidas
movlw b'00111111'
movwf TRISA ; RA5:RA0 se configuran como entrada
movlw b'00000010' ;movemos el valor de la opción del preescale al registro W EN ESTE CASO A 8
movwf OPTION_REG ;pasamos el valor de w al registro
bcf STATUS,RP0 ; Se vuelve al banco 0
movlw b'00000111' ;movemos el valor de la opción del preescale al registro W
movwf INTCON
; Fin de la inicialización del programa.
empezar MOVLW .250 ;INICIALIZAR CONTADOR
MOVWF CONTADOR
esperar BTFSS PORTA,0 ;comprobamos si en interuptor esta en ON
GOTO esperar
MOVLW d'5' ;INICIALIZAR TMR0 A 5 PARA QUE CUENTE HASTA 250 YA QUE DESBORDA A 256 para simular x ejemplo poner 252
MOVWF TMR0 ;CARGA EL VALOR DE 5 EN TMR0
CLRF INTCON ;POR SI MIENTRAS SE ESPERABA A QUE SE ACTIVARA EL INTERRUPTOR SE HA DESBORDADO
esperardes BTFSS INTCON,T0IF ;VERIFICAMOS CUANDO LLEGA A 256 MEDIANTE EL BIT 2 DEL REGISTRO INTCON
GOTO esperardes ;SI NO ES UNO HAY QUE ESPERAR
CLRF INTCON ;SE HA ALCANZADO DESBORDAMIENTO HAN PASADO 2000us SE BORRA EL DESBORDAMIENTO
DECFSZ CONTADOR,1 ;COMPROBAR QUE EL CONTADOR HA LLEGADO A 0 CUANDO OCURRE SALTA UNA INSTRUCCION
GOTO esperar
GOTO empezar ;EL CONTADOR ESTA A 0 , YA HAN PASADO 0,5 SEGUNDOS
end
¿Como lo veis de momento? :)
Gracias por la ayuda.[/size]
Bueno por fin lo he conseguido me ha costado lo suyo pero lo he conseguido ;D
aqui esta:
;***** CONFIGURACIÓN ******************************************************
List p=16F886 ;Tipo de procesador
include "P16F886.INC" ;Definiciones de registros internos
;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades
__config _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF ;Palabra 1 de configuración
__config _CONFIG2, _WRT_OFF&_BOR40V
; _MCLRE_ON: Reset externo ACTIVADO.
; _CP_OFF: Protección del código DESACTIVADO.
; _WDT_OFF: Watchdog DESACTIVADO.
; _IntRC_OSC: Oscilador interno de 4MHz.
;***** DEFINICIÓN DE VARIABLES
; Definimos las posiciones de memoria de los datos
CONTADOR equ 0x20
AUX equ 0x21
;**************************************************************************
; Inicialización del programa:
; Origen
Org 0x00
goto Inicio ;Vector de reset
org 0x05
; Configuración de los puertos como entradas y salidas
Inicio clrf PORTB ; Borrado de los biestables de salida
bsf STATUS,RP0 ; Selecciona banco 3 (RP0=RP1='1')
bsf STATUS,RP1
clrf ANSEL ; El puerto A de tipo digital
clrf ANSELH ; El puerto B de tipo digital
bcf STATUS,RP1 ; Selecciona banco 1 (RP1='0' RP0='1')
clrf TRISB ; RB7:RB0 se configuran como salidas
movlw b'00111111'
movwf TRISA ; RA5:RA0 se configuran como entrada
movlw b'00000010' ;movemos el valor de la opción del preescale al registro W EN ESTE CASO A 8
movwf OPTION_REG ;pasamos el valor de w al registro
bcf STATUS,RP0 ; Se vuelve al banco 0
movlw b'00000111' ;movemos el valor de la opción del preescale al registro W
movwf INTCON
; Fin de la inicialización del programa.
;______________________________ACTIVACIÓN INICIAL DE LA SALIDA_________________________________________________________
ESPERAR BTFSS PORTA,0 ;PRIMERA VEZ QUE SE VA A VER SI ESTA ACTIVADO EL INTERUPTOR
GOTO ESPERAR
MOVLW b'0000001' ;SE ACTIVA LA SALIDALA PRIMERA VEZ QUE SE PONE EL INTERRUPTOR
MOVWF PORTB
MOVLW 0X01 ;INICIALIZO EL REGISTRO AUX PARA INDICAR QUE SE HA ACTIVADO EL INTERRUPTOR
MOVWF AUX
;__________________________________________________________________________________________________________
empezar
MOVLW .2 ;INICIALIZAR CONTADOR A 250 PARA SIMULAR PONER EL CONTADOR A 2
MOVWF CONTADOR
esperar2
CALL COMP_ENTRADA ;COMPRUEBA EL ESTADO DE LA ENTRADA
BTFSS AUX,0 ;SI EL RESULTADO DE LA LLAMADA HA DADO 0 NO SE SALTA UNA INSTRUCCIÓN POR TANTO TIENE QUE REINICIARSE EL PROGRAMA
GOTO ESPERAR
MOVLW d'252' ;INICIALIZAR TMR0 A 5 PARA QUE CUENTE HASTA 250 YA QUE DESBORDA A 256 para simular x ejemplo poner 252
MOVWF TMR0 ;CARGA EL VALOR DE 5 EN TMR0
CLRF INTCON ;POR SI MIENTRAS SE ESPERABA A QUE SE ACTIVARA EL INTERRUPTOR SE HA DESBORDADO
esperardes BTFSS INTCON,T0IF ;VERIFICAMOS CUANDO LLEGA A 256 MEDIANTE EL BIT 2 DEL REGISTRO INTCON CUANDO LLEGA SE DESBORADA DANDO UN 1
GOTO esperardes ;SI NO ES 1 HAY QUE ESPERAR
CLRF INTCON ;SE HA ALCANZADO DESBORDAMIENTO HAN PASADO 2000us SE BORRA EL DESBORDAMIENTO
DECFSZ CONTADOR,1 ;COMPROBAR QUE EL CONTADOR HA LLEGADO A 0 CUANDO OCURRE SALTA UNA INSTRUCCION
GOTO esperar2
GOTO activarsal ;EL CONTADOR ESTA A 0 , YA HAN PASADO 0,5 SEGUNDOS
activarsal
MOVLW b'0000001'
XORWF PORTB,F ;INVIERTE EL VALOR DE LA SALIDA
GOTO empezar
;_______________________SUBRUTINAS________________________________________________
COMP_ENTRADA NOP
esperar3 BTFSS PORTA,0
GOTO SALIDA0
RETURN
SALIDA0 CLRF PORTB
CLRF AUX ;AL APAGAR EL INTERUPTOR EN MITAD DEL PROCESO ENTRA AQUI Y SEÑALO CON UN 0 QUE SE HA APAGADO EN INTERRUPTOR ES COMO EN C PONER EL RESULTADO DE UNA FUNCIÓN
GOTO esperar3
end
Gracias por la ayuda, si veis algo que se puede mejorar o reducir el programa me gustaría saberlo o si veis algún fallo.
Salu2
Hola:
Puedes comprobarlo con un simulador de PIC como el Proteus 7.10.
Saludo.
Si ya has conseguido que funcione ahora podrías perfeccionarlo.
Cuando comprobamos si un interruptor está a "1" o a "0" hay que eliminar rebotes.
Es decir, cualquier modo de contacto piezoeléctrico al hacer que conecten sus dos "bornes" hay ahí un "ruido" que en ocasiones puede ser que realmente el interruptor no esté a "1" o que en cuanto le des el contador automáticamente se detenga (en caso de que cuando detecte cero se pare).
Por esto mismo te recomiendo que hagas una cosa. Hazte una subrutina de retardos, como la que tienes de 0,5 segundos en este mismo hilo pero con muchas otras de 20 milisegundos, 50 milisegundos, 100 milisegundos, etc, etc.
Para hacer la comprobación de un pulsador es tan fácil como poner:
bucle btfss PORTA,1 ; Comprueba pulsador conectado en RA1.
goto bucle
call R20MS ; Haz una subrutina y solo tendras que poner esto en el código, sin tener que escribirla tu cada dos por tres.
btfss PORTA,1; Comprueba de nuevo, eliminando los rebotes
goto bucle
TU CODIGO -> Y aqui sigues con tu codigo.
En breves te pongo otro enlace con un ejemplo de una subrutina
Gracias Firos por responder siempre me gustan tus respuestas y aprendo bastante. A ver si lo he entendido, te refieres que se compruebe el estado de la entrada cada cierto tiempo ¿no?
Cita de: Fox_Neo en 29 Marzo 2013, 00:20 AM
Gracias Firos por responder siempre me gustan tus respuestas y aprendo bastante. A ver si lo he entendido, te refieres que se compruebe el estado de la entrada cada cierto tiempo ¿no?
No...
Mira esta imagen:
(http://hyperphysics.phy-astr.gsu.edu/hbasees/electronic/ietron/debounce.gif)
Bien, en la parte de arriba, vemos una señal que va desde 0 a 5 V pero... al ser un interruptor mecánico, el contacto que hacen los dos bornes metálicos para dejar pasar la corriente no es perfecto y rebota un poco, dando ese efecto que aparece en la parte de arriba a la izquierda de la imagen, una señal que hace "ziczac".
Esos rebotes no los percibimos porque transcurren en microsegundos. El problema es que los microprocesadores trabajan mucho más rápido. Por ejemplo, un microprocesador trabajando a 4Mhz realiza una instrucción en cada microsegundo.
Eso que ves a la derecha es una forma de eliminar esos rebotes sin usar ningun programa, haciéndolo mediante Hardware pero eso no nos interesa aquí (aunque no está mal saberlo). Como ves, la señal de la derecha va desde "0" lógico a "1" lógico sin ningún problema.
Ahora bien, ¿como eliminamos esto mediante un programa? Con el código que te he puesto.
Tendríamos que comprobarlo un par de veces en un tiempo mínimo, mayor que el de los rebotes y menor de el que una persona pudiera cerrar y abrir el interruptor.
Por esto mismo puedes hacer un retardo de 20 milisegundos (20000 microsegundos) para que no tenga interferencias e implementarlo en el código.
Lo que se suele hacer cuando programamos para simplificar el código son "subrutinas" o "funciones" que son partes de código que se repiten y que con ponerlas una vez en una parte de el código y llamarlas desde donde las queremos ejecutar nos basta.
Por ejemplo: Si el PIC lo tenemos trabajando a 4Mhz con lo que tenemos 1 instrucción por segundo, podemos usar un par de contadores para tal efecto (sin usar los TIMERS para no mantenerlos ocupados y poder usarlos para hacer retardos de otro tipo como PWM, capturas de señal, retardos de tiempo para encender y apagar LEDS, etc, etc).
Imagina que tenemos 2 contadores. Con uno, podemos contar hasta 256, ¿verdad? Y como tenemos trabajando el microprocesador a 4Mhz sabemos que cada vez que ejecutemos una instrucción para incrementarlo (como INCF) tardaremos 1uS (microsegundo).
¿Y si usamos otro contador? Podríamos contar 256 veces el otro contador. Por lo tanto:
256 * 256 = 65536
Podríamos contar trabajando a 4Mhz con dos contadores hasta 65536 uS (65536 milisegundos). Pues bien, ahora solo nos hace falta despejar la formula.
XXX * 200 = 20000 <- Pongo 200 por poner algo, también podríamos ponerle 256 y solo tendríamos que borrar el contador con "CLRF" para que empiece a contar.
20000 / 200 = 100 <- Pues ya sabemos lo que tenemos que cargar en cada contador.
Esto es una manera rápida y cutre de hacerlo. Lo que tendríamos que hacer es un diagrama de flujo (un esquema) con los pasos que hacemos en el contador y sumarle los pasos que tarda en cada acción en cada bucle porque con estos cálculos que te he puesto para que lo entendamos todos en realidad va a tardar bastante mas de 20000 uS (aunque no lo percibirá el ojo humano y podríamos despreciarlo si la finalidad es únicamente comprobar el interruptor).Esta es la que uso yo, que tiene un desfase de 1uS (que 1/20000 es un fallo mínimo):
;********************************************************************
; "R20MS"
;tsubrutina R20MS = (4.RET1.RET2 + 4.RET2 + 1) micseg.
;Rutina de temporización 20 milisegundos.
;********************************************************************
R20MS movlw .25 ;Carga RET2.
movwf RET2 ; "
R20MS1: movlw .199 ;Carga RET1.
movwf RET1 ; "
R20MS2: clrwdt ;Inicializa WDT.
decfsz RET1,F ;Decrementa RET1 hasta cero.
goto R20MS2 ;Si RET1 no es cero repite decremento.
decfsz RET2,F ;Si RET1=0 decrementa RET2.
goto R20MS1 ;Si RET2 no es 0 repite el bucle.
return
Y la tengo metida dentro de un fichero al que llamo "retardos.inc". Los contadores están en las posiciones altas 0x63, por ahí, para que si programo no me equivoque y ponga otro registro en el mismo sitio.
Luego, en el programa principal, en la parte de abajo ponemos:
include "retardos.inc"
end
Y con eso nos incluirá al compilar el programa la subrutina en nuestro programa. Ahora, desde cualquier otra parte de el programa podemos llamarla con:
call R20MS
Con lo que si miras el programa del POST anterior lo podrás ver mejor:
Cita de: Firos en 26 Marzo 2013, 21:32 PM
Si ya has conseguido que funcione ahora podrías perfeccionarlo.
Cuando comprobamos si un interruptor está a "1" o a "0" hay que eliminar rebotes.
Es decir, cualquier modo de contacto piezoeléctrico al hacer que conecten sus dos "bornes" hay ahí un "ruido" que en ocasiones puede ser que realmente el interruptor no esté a "1" o que en cuanto le des el contador automáticamente se detenga (en caso de que cuando detecte cero se pare).
Por esto mismo te recomiendo que hagas una cosa. Hazte una subrutina de retardos, como la que tienes de 0,5 segundos en este mismo hilo pero con muchas otras de 20 milisegundos, 50 milisegundos, 100 milisegundos, etc, etc.
Para hacer la comprobación de un pulsador es tan fácil como poner:
bucle btfss PORTA,1 ; Comprueba pulsador conectado en RA1.
goto bucle
call R20MS ; Haz una subrutina y solo tendras que poner esto en el código, sin tener que escribirla tu cada dos por tres.
btfss PORTA,1; Comprueba de nuevo, eliminando los rebotes
goto bucle
TU CODIGO -> Y aqui sigues con tu codigo.
En breves te pongo otro enlace con un ejemplo de una subrutina
Espero que haya quedado claro :)
Un saludo.
Estaba revisando el hilo un poco... y se me ha ocurrido otra cosa.
Veo que en tu código para cambiar de bancos tocas los registros RP0 y RP1.
Lo que voy a proponerte ahora es otra cosa para que no tengas que estar escribiendo eso también. Imagínate que cada vez que quieras cambiar de banco no tuvieras que pensar... mmm en cual había que poner un "1" en RP0 o en RP1?...
Pues bien. Puedes hacer lo siguiente:
Banco0 macro
bcf STATUS,RP0
bcf STATUS,RP1
endm
Banco1 macro
bsf STATUS,RP0
bcf STATUS,RP1
endm
Banco2 macro
bcf STATUS,RP0
bsf STATUS,RP1
endm
Banco3 macro
bsf STATUS,RP0
bsf STATUS,RP1
endm
padigital macro ;Para el correcto funcionamiento de esta macro es
movlw 06 ;necesario que antes se esté posicionado en el banco 1.
movwf ADCON1
endm
Con esto, estas creando unas macros y te servirán para no tener que escribir tanto en el código cada vez que quieras cambiar de banco. Será menos tedioso programar en ASM.
Estas macros lo que hacen es sustituir en el código donde pongas "Banco0" por lo que pone ahí. No es como una subrutina o función a la cual llamas y realizas un salto de PC para ejecutarla. Con esto directamente le mandas a el compilador que sustituya "Banco 0" por "bcf STATUS,RP0 / bcf STATUS,RP1".
Esto puedes guardarlo en la misma carpeta donde vayas a compilar tu programa y llámalo "macros.inc" por ejemplo. Luego, para incluirlo en tu programa, en vez de ponerlo abajo, ponlo arriba, encima de la declaración de variables, debajo de la configuración del PIC.
list p=16f876, f=INHX8M, r=hex
include "p16f876.inc"
include "macros.inc"
CONDIR equ 20
CONCAR equ 21
org 0
Pruébalo. Espero que te sirva.
Un saludo.
Gracias Firos como siempre me gusta mucho tus respuestas, despúes de las vacaciones me lo miraré con más detenimiento. Si veo que no entiendo algo ya lo diré ;D Salu2
Cita de: Firos en 26 Marzo 2013, 21:32 PM
Cuando comprobamos si un interruptor está a "1" o a "0" hay que eliminar rebotes.
Ejemplo de antirebores de un pulsador. Este antirebores es por software y funciona de maravilla, es para ahorrar más electrónica.
; Cada vez que presiona el pulsador conectado a la línea RA4 conmutará el estado de
; un LED conectado a la línea RB1.
;
; ZONA DE DATOS **********************************************************************
LIST P=16F84A
INCLUDE <P16F84A.INC>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
CBLOCK 0x0C
ENDC
#DEFINE Pulsador PORTA,4 ; Pulsador conectado a RA4.
#DEFINE LED PORTB,1 ; Línea donde se conecta el diodo LED.
; ZONA DE CÓDIGOS ********************************************************************
ORG 0 ; El programa comienza en la dirección 0.
Inicio
bsf STATUS,RP0 ; Acceso al Banco 1.
bsf Pulsador ; La línea RA4 se configura como entrada.
bcf LED ; Se configura como salida.
bcf STATUS,RP0 ; Acceso al Banco 0.
bcf LED ; En principio diodo LED apagado.
Principal
btfsc Pulsador ; ¿Pulsador presionado?, ¿(Pulsador)=0?
goto Fin ; No. Vuelve a leerlo.
call Retardo_20ms ; Espera que se estabilicen los niveles de tensión.
btfsc Pulsador ; Comprueba si es un rebote.
goto Fin ; Era un rebote y sale fuera.
btfsc LED ; Testea el último estado del LED.
goto EstabaEncendido
EstabaApagado
bsf LED ; Estaba apagado y lo enciende.
goto EsperaDejePulsar
EstabaEncendido
bcf LED ; Estaba encendido y lo apaga.
EsperaDejePulsar
btfss Pulsador ; ¿Dejó de pulsar?. ¿(Pulsador)=1?
goto EsperaDejePulsar ; No. Espera que deje de pulsar.
Fin
goto Principal
INCLUDE <RETARDOS.INC>
END
Saludo.