Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

RETURN donde retorna?

323 views
Skip to first unread message

LucasBols

unread,
Sep 12, 2008, 10:42:28 PM9/12/08
to
Hola

Estoy dando mis primeros pasos en assembler y los doy dentro del
16F628A.
Vengo de C y C++, asi que tengo conocimientos en programación, pero...

Tengo un código (que copio al final del mensaje) con el que intento
probar los temporizadores y llegar a los 5 minutos, pero me encontre
con un funcionamiento extraño del RETURN.
El tema esta en que después de la dir 0x00 hago un GOTO a Inicio, y
cuando llega al RETURN (tres lineas después del label Tiempo) vuelve a
la linea "GOTO Inicio" posterior a 0x00 y entra en bucle.
Esperaba que RETURN me retorne a la linea posterior al GOTO. ¿Estoy
equivocado? ¿Como se resuelve?

Pero en esto aprendi a desconfiar de todo, :D estoy probando el código
en MPLAB 8.10 y no se si es el entorno o RETURN se comporta diferente
a como esperaba.

¿Como funciona RETURN?

;---------------Encabezado-------------
LIST P=16F628
#include <P16F628.INC>
;--------------------------------------

ORG 0x00
GOTO Inicio

;---------------- OCIO ----------------

OCIO SLEEP

;---- Atención de la interrupción -----

ORG 0x04
GOTO Led
GOTO OCIO

;--------------- Inicio ---------------

Inicio BSF STATUS,5 ; cambio al banco 0 (TRISB)
CLRF TRISB ; seteo todo TRISB como salida

MOVLW 0x07 ; cargo w con 00000111
MOVWF OPTION_REG ; el Divisor = 256
BCF STATUS,5 ; regreso al banco 0

; GIE habilita todas las interrupciones
; T0IE habilita la interrupión del timer 0
MOVLW 0XA0 ; cargo w con 10100000
MOVWF INTCON ; habilitamos GIE y T0IE
CLRF PORTB ; limpiamos PORTB

;------------- Tiempo -----------------

Tiempo MOVLW 0XD8 ; cargo w con 216
MOVWF TMR0 ; lo paso a TMR0
RETURN

;---------------- Led -----------------

Led BTFSS PORTB,0 ; si el led está apagado
GOTO LedEnc ; envio a encender
BCF PORTB,0 ; si no, lo apago
GOTO LedFin

LedEnc BSF PORTB,0 ; enciendo el led
GOTO LedFin

LedFin BCF INTCON,2 ; borro la bandera T0IF
GOTO Tiempo ; cargo el temporizador
RETFIE ; regreso habilitando la int

;--------------------------------------
END
;--------------------------------------

Carmelo J. Morales Muñoz

unread,
Sep 13, 2008, 2:18:26 AM9/13/08
to
no programo ensamblador pero,,,, ¿y si en vez de return usas goto te falla
igual?. si llamas a una rutina con ¿era call? debes usar return pero si
llamas rutina con goto debes salir con goto... vamos, no me hagas mucho
caso, es por si te sirve de pista....

un saludo

"LucasBols" <dna...@gmail.com> escribió en el mensaje de
noticias:bb51c9d8-854e-457d...@d45g2000hsc.googlegroups.com...

Nolo Pongo

unread,
Sep 13, 2008, 4:41:37 AM9/13/08
to
On Fri, 12 Sep 2008 19:42:28 -0700 (PDT), LucasBols <dna...@gmail.com> wrote:

>Vengo de C y C++, asi que tengo conocimientos en programación, pero...
>

un goto es solo un salto, debe de existir una
insuccion call (ahora mismo no recuerdo el juego
de instucciones del pic), cuando haces un call si que se
almacena la direccion de retorno, y entonces return vuelve
a la instuccion siguiente al call. Ojo porque la pila
solo puede almacenar 4 (creo recordar) direcciones, por
lo que solo puede haber 4 call's anidadas

call es el equivalente a llamar a una funcion en C,
return es igual al return del c, y goto es igual al
goto del c


Observer

unread,
Sep 13, 2008, 11:14:42 AM9/13/08
to

>El tema esta en que después de la dir 0x00 hago un GOTO a Inicio, y
>cuando llega al RETURN (tres lineas después del label Tiempo) vuelve a
>la linea "GOTO Inicio" posterior a 0x00 y entra en bucle.
>Esperaba que RETURN me retorne a la linea posterior al GOTO. ¿Estoy
>equivocado? ¿Como se resuelve?

Como te dicen, debes usar un CALL para que te devuelva a la linea siguiente.
El GOTO es un salto incondicional.
CALL y las interrupciones te almacenan la dirección de retorno
automáticamente en el Stack. En estos Pic's no existe PUSH ni POP. En el
Stack puedes almacenar 8 posiciones de retorno, tanto de interrupciones
como de Call y en caso de que metas mas, se sobreescriben. Esto no es, a mi
entender, un obstáculo sino una ventaja, ya que procurarás mantener todo
bien clarito y sin muchos saltos de un lado al otro en el código, que lo
hace indescifrable.
Empiezas con un GOTO inicio que está muy bien, para saltarte la dirección
0x04 de interrupción y luego ejecuta Inicio, pero cuando lo termina sigue
con Tiempo, ya que no hay ninguna instrucción en medio y cuando llega a
Return, como el Stack está a 0 te manda a la dirección 0x00.
En el manejo de la interrupción usas Goto en vez de Call. Al final debes
poner un Retfie, sino sigue con Inicio. También usas un SLEEP desde dentro
de la interrupción que te para el reloj del chip, con lo que el temporizador
tampoco anda.
El Sleep te para el oscilador y hay cosas que dejan de funcionar. Para algo
que sirve es para dormir el chip, con lo que consume menos, y despertarlo
con una interrupción por un cambio en Rb0 o por Rb4-7, por ejemplo, al tocar
el teclado.


;---------------Encabezado-------------
LIST P=16F628
#include <P16F628.INC>
;--------------------------------------

ORG 0x00
GOTO Inicio

;---------------- OCIO ----------------

OCIO SLEEP yo no lo
utilizaría aquí

;---- Atención de la interrupción -----

ORG 0x04
GOTO Led call
GOTO OCIO ?

retfie
;--------------- Inicio ---------------

Inicio BSF STATUS,5 ; cambio al banco 0 (TRISB) banco 1


CLRF TRISB ; seteo todo TRISB como salida

MOVLW 0x07 ; cargo w con 00000111
MOVWF OPTION_REG ; el Divisor = 256
BCF STATUS,5 ; regreso al banco 0

; GIE habilita todas las interrupciones
; T0IE habilita la interrupión del timer 0
MOVLW 0XA0 ; cargo w con 10100000
MOVWF INTCON ; habilitamos GIE y T0IE

CLRF PORTB ; limpiamos PORTB seguría con Tiempo.
Aquí pondría

Main, el programa principal,

que puede ser solo un bucle:

Main NOP

GOTO Main

;------------- Tiempo -----------------

Tiempo MOVLW 0XD8 ; cargo w con 216
MOVWF TMR0 ; lo paso a TMR0
RETURN

;---------------- Led -----------------

Led BTFSS PORTB,0 ; si el led está apagado
GOTO LedEnc ; envio a encender
BCF PORTB,0 ; si no, lo apago
GOTO LedFin

LedEnc BSF PORTB,0 ; enciendo el led
GOTO LedFin

LedFin BCF INTCON,2 ; borro la bandera T0IF
GOTO Tiempo ; cargo el temporizador

RETFIE ; regreso habilitando la int RETURN si usas
CALL y deja el

RETFIE en la Interrupción.

;--------------------------------------
END
;--------------------------------------
Esto es lo que he visto, pero puedo estar equivocado. El código resultante
puede que no funcione o lo haga a una velocidad que no verás el Led
parpadear. Depúralo y nos comentas. Saludos.


LucasBols

unread,
Sep 13, 2008, 12:04:44 PM9/13/08
to
Muchas gracias a todos por las respuestas, con CALL se soluciono el
poblema.
Pero ahora me surgio el tema del SLEEP...

Este PIC tenia un programa que realizaba un bucle de llamadas
telefonicas mediante un ISD1416P y un SIM340CZ, pero como el bucle a
veces duraba mas de 5 minutos, el PIC calentaba y se quemaba. No
existe la posibilidad de un cooler por el habitaculo donde va el PIC y
por el consumo. Estoy intentando desarrollar un nuevo programa que,
despues que lance la primer llamada, se ponga a dormir durante un par
de minutos y lance la segunda llamada (para evitar el calentamiento).
El programa anterior, despues de lanzar la primer llamada, entraba en
un bucle que calculaba el tiempo transcurrido segun los ciclos que
consumia el bucle, y por eso el PIC terminaba quemandose.

En este momento estoy familiarizandome con los timers, despues
extendere el conteo desde los pocos milisegundos del timer a unos
minutos mediante un decremento, pero de una forma o la otra, cuando
procese la interrupcion del timer, supongo que voy a tener que llamar
a un SLEEP para que el procesador descanse hasta la proxima
interrupcion, que sera la que utilizare para la rutina de decremento o
para comunicar que los minutos ya han pasado.

Pero Observer, me decis que el SLEEP para el reloj, como me sugeris
que lo resuelva?

On 13 sep, 12:14, "Observer" <x...@yyzz.es> wrote:
> [ . . . ]

Observer

unread,
Sep 13, 2008, 12:34:16 PM9/13/08
to

Este PIC tenia un programa que realizaba un bucle de llamadas
telefonicas mediante un ISD1416P y un SIM340CZ, pero como el bucle a
veces duraba mas de 5 minutos, el PIC calentaba y se quemaba. No
existe la posibilidad de un cooler por el habitaculo donde va el PIC y
por el consumo. Estoy intentando desarrollar un nuevo programa que,
despues que lance la primer llamada, se ponga a dormir durante un par
de minutos y lance la segunda llamada (para evitar el calentamiento).
El programa anterior, despues de lanzar la primer llamada, entraba en
un bucle que calculaba el tiempo transcurrido segun los ciclos que
consumia el bucle, y por eso el PIC terminaba quemandose.

En este momento estoy familiarizandome con los timers, despues
extendere el conteo desde los pocos milisegundos del timer a unos
minutos mediante un decremento, pero de una forma o la otra, cuando
procese la interrupcion del timer, supongo que voy a tener que llamar
a un SLEEP para que el procesador descanse hasta la proxima
interrupcion, que sera la que utilizare para la rutina de decremento o
para comunicar que los minutos ya han pasado.

Pero Observer, me decis que el SLEEP para el reloj, como me sugeris
que lo resuelva?

-----------------------------------------------------------------------
Es que es muy raro que el Pic se caliente.
¿Cual es la frecuencia del cristal?
¿Has conectado a alguna salida del Pic un Relé directamente u otra carga
importante?
¿Tienes condensadores de desacoplo en la alimentación?
Un Pic en condiciones normales puede consumir 10 mW o menos y esto es un
consumo ridículo que no lo calienta. Dime algo.


LucasBols

unread,
Sep 13, 2008, 7:31:14 PM9/13/08
to
No se como han conectado el pic, yo solamente lo programo, me lo
encargaron por ese tema.

Pero si me decis que no calienta, entonces lo pondre en la placa de
pruebas, lo dejare que ejecute varios ciclos y vere cual es el
problema del calentamiento.

Otra cosita:

Modifique el codigo anterior, y en el MPLAB ejecuta los SLEEP, pero al
agregarle una variable de decremento, si la variable la ubico en 0x0C,
como sugiere algun manual, ocasionalmente el decremento se "come"
varios pasos, por ej: salta en un ciclo de 120 a 70, cambie la dir a
0x20 que es un registro de proposito general como indica la datasheet
del PIC y al ejecutarse, hace un decremento y muere, aparentemente va
al sleep y ahi queda, que puede ser?

el cod es este:

;---------------Encabezado-------------
LIST P=16F628
#include <P16F628.INC>

; ---------Mapa de la memoria ---------

decr equ 0x0E

;--------------------------------------

ORG 0x00
CALL Inicio
CALL Tiempo

;---------------- OCIO ----------------

DORMIR SLEEP

;---- Atención de la interrupción -----

ORG 0x04
CALL Dcrmnt
GOTO DORMIR

;--------------- Inicio ---------------

Inicio BSF STATUS,5 ; cambio al banco 1 (TRISB)


CLRF TRISB ; seteo todo TRISB como salida

MOVLW 0x07 ; 0x07 cargo w con 00000111


MOVWF OPTION_REG ; el Divisor = 256
BCF STATUS,5 ; regreso al banco 0

; GIE habilita todas las interrupciones
; T0IE habilita la interrupión del timer 0
MOVLW 0XA0 ; cargo w con 10100000
MOVWF INTCON ; habilitamos GIE y T0IE
CLRF PORTB ; limpiamos PORTB

movlw 0xC8 ; 0x64 100
movwf decr ; lo cargo para decrementar
RETURN

;----------- Decrementador ------------

Dcrmnt decfsz decr,1 ; decrementa y si no llego a 0
retfie ; retorna habilitando la int
call Led ; si llego, cambia al led
retfie ; retorna habilitando la int

;------------- Tiempo -----------------
; Temporización = (255-TMR0) * Divisor de Frecuencia
Tiempo MOVLW 0X00 ; 0XD8 cargo w con 216


MOVWF TMR0 ; lo paso a TMR0
RETURN

;---------------- Led -----------------

Led movlw 0xC8 ; 0x64 100
movwf decr ; lo cargo para decrementar


BTFSS PORTB,0 ; si el led está apagado
GOTO LedEnc ; envio a encender
BCF PORTB,0 ; si no, lo apago
GOTO LedFin

LedEnc BSF PORTB,0 ; enciendo el led
GOTO LedFin

LedFin BCF INTCON,2 ; borro la bandera T0IF
GOTO Tiempo ; cargo el temporizador

RETURN ; regreso habilitando la int

;--------------------------------------
END
;--------------------------------------

On 13 sep, 13:34, "Observer" <x...@yyzz.es> wrote:
> [ . . . ]

Observer

unread,
Sep 14, 2008, 11:58:37 AM9/14/08
to
No debes ubicar la variable en 0x0C ni en 0x0E, ya que están ocupadas
( en el 16F84 no están ocupadas). Las posiciones libres están a partir
de la 0x20. Mira el datasheet.

Por otro lado, el programa se te para en cuanto pone al chip en SLEEP,
ya que no puede salir de aquí con este diseño. No debes usar para nada
el sleep ya que no lo necesitas y el calentamiento del Pic debe
deberse a la proximidad del módulo GSM, falta de blindaje o falta de
desacoplo en la alimentación.

Animo !

Saludos.


0 new messages