TODOPIC
Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: Fulguitron en 06 de Mayo de 2018, 06:52:00
-
Buenos días. Tengo un problema con el pic16F628. Cuando quemo el pic o se me acaba la pila de botón nunca empieza el programa a la primera correctamente. En ocasiones no funciona, en otros se queda bloqueado y debo estar metiendo y sacando el pic hasta que por casualidad todo funciona. Os paso el programa completo aunque supongo que el problema residirá al principio.
Alguna sugerencia??
; =====================================================================
; Funciones:
; Hora
; runing mode
; linterna
; ajuste de hora y minutos
; Version: Bonwatch_1_3
; ======================================================================
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT & _DATA_CP_OFF & _LVP_OFF & _MCLRE_OFF
LIST P=16F628A
INCLUDE <P16F628A.INC>
CBLOCK 0x20
Status_temp
W_temp
boton_0
segundos
minutos
horas
running
contador
Ajuste
Ajuste_1
Ajuste_2
dosleds
max_boton_0
; R_ContA ; Contadores para los retardos.
ENDC
; ====================================================================
; Zona donde se guardan los valores invariables.
; ====================================================================
Max_horas EQU d'13' ; Hora máxima para poner a 1 horas después de las 12 horas.
Max_minutos EQU d'60'
Max_segundos EQU d'60'
Max_ajuste_hora EQU d'12'
Max_ajuste_minutos EQU d'60'
uno EQU d'1'
; =========================================================
; Configuración de la interrupción, entradas, salidas, timer.
; ==============================================================
ORG 0x0000 ; Vector de reset
goto Inicio
ORG 0X0004 ; Vector de interrupcion
goto Interrupcion
Inicio
bsf STATUS,RP0
clrf TRISA
movlw b'00000011' ; Configurado como salidas excepto los dos primeros.
movwf TRISB
movlw b'00000000' ; Configurado como salidas
movwf TRISA
bcf STATUS,RP0
movlw 0x07
movwf CMCON
movlw b'10010000'
movwf INTCON
movlw b'00111100' ; ('00111100')Se selecciona TMR1, preescaler de 1/8, modo temporizador.-
movwf T1CON
movlw b'00001011' ; Se configura CCP modo captura cada flanco de subida.-
movwf CCP1CON
movlw b'11111100' ; 0xF4 244
movwf CCPR1H
movlw b'00110111' ; 0x24 36
movwf CCPR1L
CLRF TMR1H
CLRF TMR1L
bsf T1CON,TMR1ON ; Uso del timer interior a 38khz.
BCF PCON, OSCF
clrf segundos
; =================================================================
; Activamos la interrupción
; =================================================================
BCF INTCON,INTF ; Activo interrupcion de RB0/Flanco descendente
BSF INTCON,INTE
BSF INTCON,GIE ; Habilitamos interrupciones globales
;===================================================================
; Zona del banco de memorias de los diferentes registros.
; ====================================================================
movlw d'2'
movwf max_boton_0
movlw d'2'
movwf contador
; movlw d'5'
; movwf Ajuste
; movlw d'125'
; movwf Ajuste_1
movlw d'15'
movwf running
movlw d'51'
movwf dosleds
; =============================================================
; Ponemos en hora el reloj.
; ==============================================================
movlw d'10' ; Aquí se ajusta la hora
movwf horas
movlw d'49' ; Aquí se ajustan los minutos
movwf minutos
; =======================================================================
; Una vez el boton_0 está a 1 mostramos la hora y los minutos
; =======================================================================
Principal
movf boton_0,w
sublw uno
btfsc STATUS,Z
call Tabla
call Contar_hora
goto Principal
; ================================================================
; Comienza el programa principal.
; ================================================================
Tabla
movf boton_0,W
addwf PCL,F
call Principal
call Mostrar_hora
call running_mode
call linterna
call ajustar_hora
call ajustar_minutos
goto Tabla
; ==============================================================
; Se encienden los seis leds de forma intermitente
; ==============================================================
running_mode
movf running,W
movwf PORTA
movwf PORTB
call Contar_hora
clrf PORTA
clrf PORTB
call Contar_hora
btfss PORTB,1
goto clear_running_mode
goto running_mode
clear_running_mode
clrf PORTA
clrf PORTB
clrf boton_0
call Principal
; ==============================================================
; Se encienden los dos leds RGB
; ==============================================================
linterna
movf dosleds,W
movwf PORTA
movwf PORTB
call Contar_hora
btfss PORTB,1
goto clear_linterna
goto Tabla
clear_linterna
clrf PORTA
clrf PORTB
clrf boton_0
call Principal
; ============================================================
; Muestra la hora y los minutos
; ============================================================
Mostrar_hora
movf horas,W ; mostramos las horas por el display de leds.
movwf PORTA
movwf PORTB
call Contar_hora ; tiempo en que los leds permanecen encendidos mostrando la hora
clrf PORTA
clrf PORTB
call Contar_hora ; tiempo en que los leds permanecen apagadosd'6'
movf minutos,W ; mostramos lOS minutos por el display de leds.
movwf PORTA
movwf PORTB
call Contar_hora
clrf PORTA
clrf PORTB
call Contar_hora
; Revisa si boton_0 esta pulsado, sino es así, se apagan los leds, si es así se va a tabla.
movf boton_0,w
sublw uno
btfsc STATUS,Z
call clear_boton_0
call Tabla ;tabla
clear_boton_0
clrf boton_0
call Principal
; ==========================================================================
; Conteo de las horas del reloj y su puesta a cero cuando llega a las 12 horas
; =============================================================================
Contar_hora
inc_segundos
btfss PIR1,CCP1IF
goto inc_segundos
bcf PIR1,CCP1IF
clrf TMR1H
Ajuste_fino
decfsz Ajuste,F ; Se crea esta línea para ajustar aún más el tiempo, se predefine en los valores invariables a principio del código
goto Ajuste_fino
movlw d'10'
movwf Ajuste
decfsz Ajuste_1,F
goto Ajuste_fino
movlw d'240'
movwf Ajuste_1
decfsz Ajuste_2,F
goto Ajuste_fino
movlw d'125'
movwf Ajuste_2
decfsz contador,F
goto inc_segundos
comp
movlw d'1'
movwf contador
incf segundos,F
movf segundos,W ;revisa si ha llegado a 60 segundos.
sublw Max_segundos
btfss STATUS,Z ; si ha llegado a 60 segundos, se va a inc_minutos, sino return
return
; ================================================================================
; En el momento que los segundos llegan a 60, se incrementa 1 a minutos,
; se revisa si se ha llegado a 60 minutos y se pone a 0 los segundos
; ================================================================================
inc_minutos ; Ponemos a cero los segundos para que empiece el conteo.
clrf segundos
incf minutos ; incrementamos en 1 los minutos.
movf minutos,W
sublw Max_minutos ; revisa si ha llegado a 60 minutos.
btfsc STATUS,Z
goto inc_horas ; si ha llegado a 60 minutos se va a inc_horas.
return
; =================================================================================
; En el momento que los minutos llegan a 60,
; se incrementa 1 en horas y se ponen a 0 los minutos y los segundos.
; ==============================================================================
inc_horas
clrf minutos
incf horas
movf horas,W
sublw Max_horas ; revisa si ha llegado a 60 minutos.
btfsc STATUS,Z
call doce_horas
return
; ========================================================================
; Se ponen a inicio las horas, minutos y segundos
; =======================================================================
doce_horas
movlw d'1'
movwf horas
clrf segundos
clrf minutos
return
; =============================================================
; Ajustar hora
; =============================================================
ajustar_hora
btfss PORTB,0
goto ajustar_minutos
call Retardo_200ms
movf horas,W
movwf PORTA
movwf PORTB
btfsc PORTB,1
goto ajustar_hora
incf horas
call Retardo_500ms
movf horas,W
sublw Max_ajuste_hora
btfsc STATUS,Z
clrf horas
goto ajustar_hora
; =============================================================
; Ajustar minutos
; =============================================================
ajustar_minutos
btfss PORTB,0
goto ajustar_minutos
call Retardo_200ms
btfss PORTB,0
goto Poneracero
movf minutos,W
movwf PORTA
movwf PORTB
btfsc PORTB,1
goto ajustar_minutos
incf minutos
call Retardo_500ms
movf minutos,W
sublw Max_ajuste_minutos
btfsc STATUS,Z
clrf minutos
goto ajustar_minutos
Poneracero
clrf PORTA
clrf PORTB
movlw d'0'
movwf boton_0
goto Principal
; ===========================================================
; Comienzo de la interrupcion
; =============================================================
Interrupcion
; Guardo Contexto
MOVWF W_temp
SWAPF STATUS,W
MOVWF Status_temp
; Comienza el codigo de mi interrupcion
BANKSEL PIR1
BTFSC INTCON,INTF
CALL Int_Rb0
; Fin de codigo de interrupcion
; Devuelvo el contexto
;Fin_interrupcion:
SWAPF Status_temp,W
MOVWF STATUS
SWAPF W_temp,F
SWAPF W_temp,W
RETFIE
Int_Rb0
btfss PORTB,0
goto Int_Rb0
call Retardo_2ms
; call Retardo_pulsador
btfss PORTB,0
goto Int_Rb0
incf boton_0,1
movf max_boton_0
btfss STATUS,Z
BCF INTCON,INTF
RETURN
;Retardo_pulsador ; La llamada "call" aporta 2 ciclos máquina.
; nop ; Aporta 1 ciclo máquina.
; movlw d'255' ; Aporta 1 ciclo máquina. Este es el valor de "K".
; movwf R_ContA ; Aporta 1 ciclo máquina.
;Rmicros_Bucle
; decfsz R_ContA,F ; (K-1)x1 cm (cuando no salta) + 2 cm (al saltar).
; goto Rmicros_Bucle ; Aporta (K-1)x2 ciclos máquina.
; return ; El salto del retorno aporta 2 ciclos máquina.
;
INCLUDE <RETARDOS.INC>
END
-
En ocasiones no funciona, en otros se queda bloqueado y debo estar metiendo y sacando el pic hasta que por casualidad todo funciona. Os paso el programa completo aunque supongo que el problema residirá al principio.
Sin mirar el programa. Si funciona correctamente cada tanto quiere decir que el programa esta bien. Y mas seguramente el problema sea de Hardware, proba poniendo el MCLR en ON, tambien agregando capacidades de desacoplo.
EDIT:
Mirando un poco el codigo me encuentro con algunas cosas...
- boton_0 nunca es inicializado a un valor. Mas cuando es usado como indice en una tabla
Int_Rb0
btfss PORTB,0
goto Int_Rb0
call Retardo_2ms
; call Retardo_pulsador
btfss PORTB,0
goto Int_Rb0
incf boton_0,1
movf max_boton_0
btfss STATUS,Z
BCF INTCON,INTF
RETURN
Podes usar retardos si no te afecta en los tiempos pero, ya con el retardo + limpieza de flag al ultimo ya esta.
el MOVF del MAX_BOTON_0 lo veo absurdo ahi aplicado. Imagino que intentaste aplicar un maximo que puede llegar boton_0, pero no veo que influya sobre el incf. El maximo deberia ser una constante y no un registro, al MOVF le falta el W o F, pero por default va a F, asi que estas preguntando si max_boton_0 es 0 y boton_0 no posee limite de incremento... no tiene sentido.
Recomendacion poner W_temp y los mas usados en direcciones de memoria que sean compartidas entre bancos (desde 0x70 a 0x7F, y pueden ser accedidos desde cualquier banco).
Ajuste_fino
decfsz Ajuste,F ; Se crea esta línea para ajustar aún más el tiempo, se predefine en los valores invariables a principio del código
Ajuste fino... no lo es.. tener que usar un delay para hacer el ajuste, por ahi es mejor que confies en el cristal que estes usando. Ademas... Si usas el flag de interrupcion del CCP, no tiene sentido y me explico el porque.. Supongamos que tu flag del CCP es de 200ms y tu delay de es 4ms.
Se va a preguntar por el flag del CCP, este va a actualizarse cada 200ms, graficamente tenes que:
|----------------------|---------------------|--------------------|
200ms 400ms 600ms 800ms
Esto sin el delay.. veremos que pasa poniendole un delay
|----------------------|---------------------|--------------------|
200+4ms 400+4ms 600+4ms 800+4ms
Si te pones a pensar, entre entrada y entrada, siguen existiendo solo 200ms, el delay no afecto en nada.
Si tu idea es usar un delay mas grande que el flag del CCP, entonces no tiene sentido usar el CCP.
EDIT2: Ahora veo el porque del delay ahi, estas mezclando la funcion de incrementar la hora con la de mostrar. Ningun sentido de hacer esto.
-------------------------------------------------
Principal
movf boton_0,w
sublw uno
btfsc STATUS,Z
call Tabla
call Contar_hora
goto Principal
; ================================================================
; Comienza el programa principal.
; ================================================================
Tabla
movf boton_0,W
addwf PCL,F
call Principal
¿Por que hacerlo ciclico asi? Si va a tabla y tiene que volver a Principal, entonces un RETURN, pero no otro CALL.
------------------------------------------
Mostrar_hora
; .............
call Tabla ;tabla
Si de Tabla llamo a Mostrar_hora, no deberia jamas de Mostrar_hora llamar a Tabla. Esto es lo mismo que antes, y pide a gritos que si no esta muy bien programado termines con un call stack overflow.
Te puedo decir que uses GOTO, pero significa pensar de otra forma el programa.
Por ejemplo linterna, running_mode, y algunos mas que tienen un CALL Principal, se beneficiarian si tuvieran un RETURN y en TABLA fueran GOTO, de esa forma vuelve a Principal por si solo y ejecutaria el CALL Contar_hora, ya que esta volviendo del CALL Tabla. Y como ves, volves a Principal.
------------------------------------------
Por ahora no poseo mas tiempo, para seguir viendolo. Estas son algunas de las cosas que vi.
pero por lo visto, por ahi sugiero que uses una interrupcion del CCP, con un valor comodo de milisegundos que te sirva tanto para el mostrar en los displays como para la demora, es decir que ese valor pueda dividirse y dar enteros para estos casos, luego aplicar contadores.
Y acordate, que cada ves que haces un CALL, se guarda la direccion en un stack que es fijo en cantidad, de alli solo se saca con un RETURN, si un CALL no encuentra un RETURN quiere decir que estas llenandolo y pronto va a llenarse por completo. Una ves lleno se empieza a sobreescribir lo que estaba, y esto implica ya un mal funcionamiento al ejecutar un RETURN por ejemplo.
-
Hola, perdón por tardar tanto en responder pero tengo unas personillas que me absorven un montón :D :D :D :D. Bueno estando de vacaciones sigo con mi reloj. Lo primero que he hecho es poner un condensador de desacoplo de 151nF entre el positivo y el negativo del circuito. Lo he hecho bien? no tenía ni idea de que era eso y parece que la cosa va mejor.
Ahora con el código, deciros que el código funciona la mar de bien, se atrasa un minuto cada dos días pero creo que sabré solucionarlo, aun con mis montones de errores :8} :8} :8} :8} , pero a ver si me entero lo que decis porque empiezo a no comprender.
Int_Rb0
btfss PORTB,0
goto Int_Rb0
call Retardo_2ms
btfss PORTB,0
goto Int_Rb0
incf boton_0,1
movf d'2'
btfss STATUS,Z
BCF INTCON,INTF
RETURN
Bueno he quitado las variables y he puesto constantes y funciona OK. El boton_0 no es inicializado porque haciendo pruebas no lo necesitaba y cuando pulso el boton ya empieza el conteo. Lo de usar el W_temp no tengo ni idea de lo que es, si me pudierais poner un ejemplito.... (si ya se que no debo, pero le he echado mucha voluntad para hacerlo por mi mismo).
Lo del ajuste fino ... perdido por completo lo he ententado lo del CCP pero por más que lo miro no encuentro ejemplos que me ayuden, lo siento.
Sigo con los call, returns y goto. Porque no lo he hecho así?
Tabla
movf boton_0,W
addwf PCL,F
return
call Mostrar_hora
call running_mode
call linternaMuy sencillo, no sabía que podía usar otras instrucciones con el PCL, vi un ejemplo con todo call y así lo hice y como funcionaba ... así se quedó.
Como siempre muchas gracias por las respuestas, aunque me dan un montón de faena siempre apriendo algo nuevo. Si me ayudais con lo del CCP me hariais un favor. Como siempre muuuchas gracias.