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
;--------------------------------------
un saludo
"LucasBols" <dna...@gmail.com> escribió en el mensaje de
noticias:bb51c9d8-854e-457d...@d45g2000hsc.googlegroups.com...
>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
>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.
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:
> [ . . . ]
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.
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:
> [ . . . ]
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.