Fallo de desbordamiento de pila en 16F84

Buenos días :D

Estoy practicando con esto de los PICS, en cuestión el 16F84 esto es un simple reloj, y me ocurre que solo con añadir cualquier instrucción más me da un error en Proteus de desbordamiento de pila, además de que el circuito funciona erráticamente.

Este el trozo de código en el que ocurre el error:

Check_BSet comprueba si se ha el pulsado el botón de Set (el que ajustaría la hora)
en ese caso se llama a la función TestA (Muestra una A en la primera posición de la
línea 2 del display LCD.

Línea 122:
Código:
Aumentar_Unidades_Segundos
	call	Retardo_500micros
	
	call	Check_BSet

	incf	Unidades_Seg ,F
	Posicionar_Digito	Posicion_Unidades_Segundos
	movf	Unidades_Seg,W
	call	LCD_Caracter
	movf	Unidades_Seg,W
	sublw	0x39
	btfss	STATUS,Z
	goto	Aumentar_Unidades_Segundos
	goto	Resetea_Segundos	
	
Check_BSet
	nop
;	btfss	BSet
;	call	TestA
	return


A continuación el código del reloj completo, cuenta desde 00:00:00 hasta 23:59:59,
los botones por el fallo comentado aún no funcionan.
El *.DSN, y archivos INC están en el ZIP adjunto.


Código:
; Libro Microcontrolador PIC16f84. Desarrollo de proyectos
; Editorial RAMA
; Prueba de libreria LCD_4BIT.INC


	LIST		P=16F84A	; Le decimos el tipo de procesador a utilizar
	INCLUDE		<P16F84A.INC>	; Include del pic16f84A

	; Configuramos proteccion de codigo a off, perro guardian a off, power reset a on, y cristal on.
	__CONFIG	_CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC

;-----------------------------
; Registros donde guardar datos.
; Comienzan a guardarse en la posición 0x0C, la primera de la RAM disponible para el usuario
;-----------------------------
	CBLOCK 0x0C
		Unidades_Seg, Decenas_Seg
		Unidades_Min, Decenas_Min
	 	Unidades_Hora, Decenas_Hora
		Digito, cmh
	ENDC

; Definimos las posiciones de las segundos, minutos y horas en el Display empezando por la izquierda 
; Así se visualiza la hora en el display en la segunda línea (línea inferior) "    00:00:00    "
Posicion_Unidades_Segundos	equ	d'11'
Posicion_Decenas_Segundos	equ	d'10'
Posicion_Unidades_Minutos	equ	d'8'
Posicion_Decenas_Minutos	equ	d'7'
Posicion_Unidades_Hora		equ	d'5'
Posicion_Decenas_Hora		equ	d'4'

#Define	BSet	PORTB,0
#Define BHour	PORTB,1
#Define BMin	PORTB,2
#Define	BAlarm	PORTB,3

;-----------------------------
; Zona de codigos
;-----------------------------

;-------------------------------------
;       Posiciona un dígito
;-------------------------------------	
Posicionar_Digito	MACRO	Posicion
	movlw	Posicion		; La posición del dígito		
	call	LCD_PosicionLinea2	; Nos desplazamos a esa posicion en la linea2
	ENDM

	org	0
Inicio
;-----------------------------------------
;      Visualizamos el mensaje de cabecera
;-----------------------------------------
	call	LCD_Inicializa
	bsf	STATUS,RP0		; Acceso al banco 1 (Para configurar los puertos)
	clrf	PORTA			; Configuramos el PORTA como salida

	movlw	b'00001111'		; El nibble bajo se configuran como entradas para los pulsadores
	movwf	PORTB			; el alto como salidas para el LCD
	
	bcf	STATUS,RP0		; Volvemos al banco 0
	
	
	call LCD_Linea1
	movlw Mensaje_Radio		; Visualiza "Radio" en la linea1
	call LCD_Mensaje


	call LCD_Linea2	
	movlw Mensaje_Despertador	; Visualiza "Despertador" en la linea2
	call LCD_Mensaje

	call Retardo_500micros
	call LCD_Borra

	call LCD_Linea1	
	movlw Mensaje_V01		; Visualiza la version
	call LCD_Mensaje


	call LCD_Linea2
	movlw Mensaje_Autor		; Visualiza el autor
	call LCD_Mensaje

;------------------------------------------------
;       Despues de 1 segundo borramos la pantalla
;------------------------------------------------	
	call Retardo_500micros
	call LCD_Borra

;------------------------------------------------
;       Frase final del mensaje de inicio
;------------------------------------------------	
;	call LCD_Linea1
;	movlw Mensaje_Foros
;	call LCD_MensajeMovimiento
;	call	Retardo_200ms


;-------------------------------------
;       Mostramos la hora
;-------------------------------------	
	call LCD_Borra
        call LCD_Linea2
	call Mostrar_Hora



;--------------------------
; Inicializar_Hora
;--------------------------
Inicializar_Hora
	movlw	0x30
	movwf	Unidades_Seg
	movwf	Decenas_Seg
	movwf	Unidades_Min
	movwf	Decenas_Min
	movwf	Unidades_Hora
	movwf	Decenas_Hora
	return	

Aumentar_Unidades_Segundos
	call	Retardo_500micros
	
	call	Check_BSet

	incf	Unidades_Seg ,F
	Posicionar_Digito	Posicion_Unidades_Segundos
	movf	Unidades_Seg,W
	call	LCD_Caracter
	movf	Unidades_Seg,W
	sublw	0x39
	btfss	STATUS,Z
	goto	Aumentar_Unidades_Segundos
	goto	Resetea_Segundos	
	
Check_BSet
	nop
;	btfss	BSet
;	call	TestA
	return	
	
	
Aumentar_Decenas_Segundos
	incf	Decenas_Seg, F
	Posicionar_Digito	Posicion_Decenas_Segundos
	movf	Decenas_Seg,W
	call	LCD_Caracter	; Visualiza el dígito
	movf	Decenas_Seg,W
	sublw	0x36
	btfss	STATUS,Z
	goto	Aumentar_Unidades_Segundos
	goto	Resetea_Decenas_Segundos
	
Aumentar_Unidades_Minutos
	incf	Unidades_Min, F
	Posicionar_Digito	Posicion_Unidades_Minutos
	movf	Unidades_Min,W
	call	LCD_Caracter	; Visualiza el dígito
	movf	Unidades_Min,W
	sublw	0x3A
	btfss	STATUS,Z
	goto	Aumentar_Unidades_Segundos
	goto	Resetea_Unidades_Minutos
	
Aumentar_Decenas_Minutos
	incf	Decenas_Min, F
	Posicionar_Digito	Posicion_Decenas_Minutos
	movf	Decenas_Min,W
	call	LCD_Caracter	; Visualiza el dígito
	movf	Decenas_Min,W
	sublw	0x36
	btfss	STATUS,Z
	goto	Aumentar_Unidades_Segundos
	goto	Resetea_Decenas_Minutos

;----------------------	
Aumentar_Unidades_Hora
;----------------------
; Cada vez que se aumentar una unidad en la hora se comprueba si se ha llegado al máximo.
	call	Comprueba_Maximo_Hora
	incf	Unidades_Hora, F
	Posicionar_Digito	Posicion_Unidades_Hora
	movf	Unidades_Hora, W
	call	LCD_Caracter	; Visualiza el dígito
	movf	Unidades_Hora, W
	sublw	0x3A
	btfss	STATUS,Z
	goto	Aumentar_Unidades_Segundos
	goto	Resetea_Unidades_Hora
	
Aumentar_Decenas_Hora
	incf	Decenas_Hora, F
	Posicionar_Digito	Posicion_Decenas_Hora
	movf	Decenas_Hora, W
	call	LCD_Caracter	; Visualiza el dígito
	movf	Decenas_Hora, W
	sublw	0x33
	btfss	STATUS,Z
	goto	Aumentar_Unidades_Segundos
	goto	Resetea_Decenas_Hora
	return

;-------------------------
Comprueba_Maximo_Hora
;--------------------------
; Compara los registros Decenas_Hora y Unidades_Hora con 2 y 4 (24 Horas)
; Por cada registro que coincida suma uno a cmh (comprueba máximo hora)
; Si cmh es igual a 0x2 se resetean primero las Decenas_horas y luego las Unidades_Hora
; Si alguno no coincide simplemente sale de la llamada.
;	call	TestA ;----------- Funciona
	movf	Decenas_Hora,W	;Movemos el valor de Decenas_Hora al registro W
	sublw	0x32		;Le restamos 32 ((comparamos W con 0x32)
	btfsc	STATUS,Z	;Si el resultado es cero  se salta la siguiente instrucción
	incf	cmh,F		;aumentar cmh (esta instrucción se salta si se activó el flag Z

	movf	Unidades_Hora,W ; Lo mismo que el código anterior, pero con Unidades Hora
	sublw	0x33
	btfsc	STATUS,Z
	incf	cmh,F
	
	movf	cmh,W		; Hacemos la comparión pero ahora con 2
	sublw	0x2		; W menos 2
	btfss	STATUS,Z	; Si la comparación fue cero se salta la siguiente instrucción llamando a Resetea_Maximo_Hora
	goto	Fuera
	call	Resetea_Maximo_Hora
Fuera	
	clrf	cmh		; Ponemos a cero el registro cmh
	return

;-----------------------------------------------------------------------------------------------------------------------------------
; Reseteo de dígitos
; Primero se posiciona el dígito, se mueve el valor 0x30 (0 ascii) a W, se posiciona y se muestra el carácter
;-----------------------------------------------------------------------------------------------------------------------------------

;--------------------------
Resetea_Segundos
;--------------------------
	call	Retardo_500micros
	Posicionar_Digito Posicion_Unidades_Segundos
	movlw	0x30
	movwf	Unidades_Seg
	call	LCD_Caracter
	goto	Aumentar_Decenas_Segundos

;--------------------------
Resetea_Decenas_Segundos
;--------------------------
	Posicionar_Digito Posicion_Decenas_Segundos
	movlw	0x30
	movwf	Decenas_Seg
	call	LCD_Caracter
	goto	Aumentar_Unidades_Minutos
	
;--------------------------
Resetea_Unidades_Minutos
;--------------------------
	Posicionar_Digito Posicion_Unidades_Minutos
	movlw	0x30
	movwf	Unidades_Min
	call	LCD_Caracter
	goto	Aumentar_Decenas_Minutos

;--------------------------
Resetea_Decenas_Minutos
;--------------------------
	Posicionar_Digito Posicion_Decenas_Minutos
	movlw	0x30
	movwf	Decenas_Min
	call	LCD_Caracter
	goto	Aumentar_Unidades_Hora

;--------------------------
Resetea_Unidades_Hora
;--------------------------
	Posicionar_Digito Posicion_Unidades_Hora
	movlw	0x30
	movwf	Unidades_Hora
	call	LCD_Caracter
	goto	Aumentar_Decenas_Hora

;--------------------------
Resetea_Decenas_Hora
;--------------------------
	Posicionar_Digito Posicion_Decenas_Hora
	movlw	0x30
	movwf	Decenas_Hora
	call	LCD_Caracter
	goto	Aumentar_Unidades_Segundos
	
;--------------------------	
Resetea_Maximo_Hora
;--------------------------
;	call	TestA
	Posicionar_Digito Posicion_Decenas_Hora
	movlw	0x30
	movwf	Decenas_Hora	
	call	LCD_Caracter
	Posicionar_Digito Posicion_Unidades_Hora
	movlw	0x30
	movwf	Unidades_Hora	
	call	LCD_Caracter
	return	
	

;----------------------------------------
;       Visualizacion de la hora 00:00:00
;----------------------------------------
Mostrar_Hora
	movlw	Hora
	call	LCD_Mensaje
	call	Inicializar_Hora

	call	Aumentar_Unidades_Segundos	


;----------------------------------------
;       Mensajes
;-----------------------------------------
Mensajes
	addwf PCL,F
Mensaje_Radio
	DT "Radio",0x00
Mensaje_Despertador
	DT "Despertador",0x00
Mensaje_V01
	DT "V-0.0.1",0x00
Mensaje_Autor
	DT "Thevenin",0x00	
Mensaje_Foros
	DT "para forosdelweb"	
	DT "                ",0x00	

Hora
	DT	"    00:00:00    ",0x00
Alarma 
	DT	"AL",0x00
Prog
	DT "PROG",0x00	


	INCLUDE "LCD_4BIT.INC"
	INCLUDE "LCD_MENS.INC"
	INCLUDE "RETARDOS.INC"
	INCLUDE "TESTCASE.INC"
	END
 

Adjuntos

  • archivos_reloj_152.zip
    64.5 KB · Visitas: 24
Si tienes un desbordamiento es culpa de algun call sin su return.

Ya en el codigo veo un call dentro de otro call, es lo que se llama anidamiento , aunque no recuerdo muy bien el pic soporta muy pocos anidamientos, Eight-level deep hardware stack o sea solo puedes hacer ocho call uno dentro del otro

call
call
call
call
call
call
call
call
call ERROR


de forma correcta seria

call
call
call
call
call
call
call
call
return
return
return
return
return
return
return
return

Si no me he descontador, debe haber siempre su call y su return
 
Tienes un fallo en la estructura del programa. Si sigues el proceso dede inicio deberias tener un bucle en el cual vayas visualizando. Es decir: si aumentas cada segundo, deberia el bucle ir visualizando cada segundo. Al igual saltas al bucle con un call eso no debería ser así, gastas un nivel en la pila.
Si vas viendo el proceso, desde Inicio, te metes en las subrutinas siguiendo el ciclo uno detras de otro. Te emetes en inicializar_hora (que lleva un return) despues de un Call.

Eso es a groso modo. simula paso a apaso y ves el crecimiento de la pila.
 
Entiendo lo que decís de las llamadas call y return, al parecer el puntero de pila se queda
apuntando entre el cuarto y quinto nivel ya con todos los dígitos funcionando,
o sea, solo parece haber hasta 5 niveles en la pila ocupados, de un total de 8;

pero llegando a aislar código, quedando la función Aumentar_Unidades_Segundos
de esta manera.:


Código:
Aumentar_Unidades_Segundos

	call	Retardo_500micros

        nop ;                       <---------------------- Este NOP

	incf	Unidades_Seg ,F
	Posicionar_Digito	Posicion_Unidades_Segundos
	movf	Unidades_Seg,W
	call	LCD_Caracter
	movf	Unidades_Seg,W
	sublw	0x39
	btfss	STATUS,Z
	goto	Aumentar_Unidades_Segundos
	goto	Resetea_Segundos

Basta sólo con añadir un NOP para que deje de funcionar.
Si lo comento o lo borro vuelve a funcionar.

Eso es lo que no me explico.
 
Ya te lo he comentado

¿deespues de las tres inst4rucciones de "mostramos la hora" a donde va? inicia una "inicializar hora"

No tengo tiempo para seguir todo el flujo pero cuando vuelvas del ultimo call de producirá un problema.

Simula paso a paso y te daras cuenta
tienes algún call en vez de goto
 
Parece que es el return de Resetear_Hora, lo he quitado y funciona, con y sin NOP.

Lo que no me explico es que tiene que ver un simple NOP para que desborde o no la pila.
 
Atrás
Arriba