Modo de usar las interrupciones en el 16f84 en ensamblador

Normalmente cuando se origina una peticion de interrupcion, se procede a ejecutar la rutina pertinente y finalmente se vuelve a la ejecucion del programa principal en el punto donde se habia quedado antes de la interrupcion mediante la utilizacion de la instruccion retfie.

El problema me surge cuando al producirce la interrupcion lo que quiero es que se quede
en una nueva rutina y permanezca en esta indefinidamente hasta que se produzca una nueva interrupcion. Pero si estoy en esta rutina y activo nuevamente las interrupciones devo de utilizar a la fuerza la instruccion retfie, con lo cual me abandona esta rutina y vuelve al punto interior.

He intentado activar las interrupciones poniendo a 1 el bit GIE del registro INTCON, pero no funciona correctamente.

He pensado solucionarlo de la siguiente forma (no se si sera la mas correcta o habra otras formas de hacerlo):
Activare el Watchdog, de modo que cuando se produzca la interrupcion ejecutare un bucle cerrado donde no refrescare el watchdog y transcurrido 18ms se provocara un reset.
Al inicio del programa leere que entrada esta activada (pulsador) y ejecutara la rutina que corresponda a dicha entrada. Creo que todo este proceso sera lo suficiente rapido como para leer el pulsador que acciono la interrupcion.
 
Se me ocurre que utilices una máquina de estados. En la interrupción asignas a una variable un estado según las entradas leídas, y en el bucle principal lees ese valor y ejecutas una rutina u otra en función de lo que indique el estado. Así lo hacía en C, en ensamblador supongo que el concepto será el mismo...

Saludos
 
En vez de terminar la interrupcion uno mantente verificando en bucle infinito el bit de bandera de interrupcion, afortunadamente en el pic este bit siempre se activa a uno cuando se genera la interrupcion, pero el pic solo salta al vector de interrupcion cuando se habilitan todas las banderas de interrupcion

Ejemplo... digamos que la interrupcion externa (INT) me hace saltar el micro al vector de interrupcion, y alli al final me mantengo probando el bit de flag del timer 0 (T0IF) y cuando se active puedo continuar con el vector de interrupciones, recuerda apagar manualmente T0IF e INT antes de terminar el vector de interrupcion o el pic va a volver a saltar a las interrupciones....
 
Se puede hacer como dices, aunque esa variable la tendre que leer en distintos puntos del programa, ya que utilizo varias llamadas Call, y tengo que ir vaciando la Pila.

Resultara algo complejo.

Tambien estuve probando sin refrescar el watchdog, aunque tampoco me convence su foma de trabajar.

Voy a estudiar si hay forma de borrar la pila y cargarle la direccion de retorno que a mi me interese.
 
El problema que despues de ejecutar la rutina de interrupcion, NO quiero volver al punto donde me encontraba antes de la interrupcion.

Intentare engañar a la Pila: en la rutina de interrupcion hare una llamada call a un punto donde repondre las banderas y aplicare el retfie (no utilizare el return). Espero que me finalice las interrupciones y me mande a la intruccion que hay justo detras del call. La direccion de memoria antes de la interrupcion segira en la PILA.

Tambien probare salir de la interrupcion de esta forma:

movlw b'10011000' ; abilita GIE,INTE y RBIE para activar
movwf INTCON ; las interrupciones


ya les contare si funciona.
 
pepechip dijo:
He intentado activar las interrupciones poniendo a 1 el bit GIE del registro INTCON, pero no funciona correctamente. .

pepechip dijo:
Tambien probare salir de la interrupcion de esta forma:

movlw b'10011000' ; abilita GIE,INTE y RBIE para activar
movwf INTCON ; las interrupciones .


He probado esto y me funciona correctamente, aunque al principio no me funcionaba por un fallo que cometi en la programacion en otro punto del programa.

La PILA se ira llenando con las posiciones de memoria de donde abandona el programa para atender las interrupciones, pero esto no me supone ningun inconveniente, ya que al micro no le afecta que la pila se desborde.
 
normalmente para volver a conectar el dispositivo de interrupciones se hace de esta forma

bcf INTCON,RBIF ; limpia el flag RBI de RB4 a RB7
retfie ; vuelve al punto donde estaba el programa antes de la interruccion y al mismo tiempo habilita el bit GIE para volver a activar las interrupciones.

Si quiero que no vuelva al punto donde estaba antes de la interrupcion hago:

bcf INTCON,RBIF ; limpia el flag RBI de RB4 a RB7
bsf GIE; activa las interrupciones y el programa continua con la siguiente instruccion posterior a esta.
 
Hola pepechip....

GRacias por enviarme el link para ver tu problema que tubiste con eso. Sin embargo aún no acabao de entender lo del final.

Me estás diciendo,que cuando vas al bloque de interrupción, justo antes de cabar el bloque de interrupcion, activas el GIE, y sigues en el bloque de intertupción, y depues de esto que?

puedes cambiar a otro sitio a tu gusto?

Verás, es que me he fijado que en el datasheet pone, que cuando se activa una interrupción, el vector apunta a la parte de interrupción. Pero previamente, el chip internamente, graba la dirección del vector donde se activo la interrupción en el programa, y cuando se termina la interrupcioón, el chip lo que hace es coger esa dirección y guardarla en el contador del programa (CP) y vuelve al punto donde se activo la interrupción.

Entonces, esto que pongas el GIE a '1', se salta eso de guardar la direccion de donde estubo por ultima vez?
 
En asembler para salir de las rutina de interrupcion se realiza mediante la instruccion RETFIE, la cual actua de forma similar al return, pero ademas te pone a 1 el bit GIE para volver a activar las interrupciones.

Simplemente tienes que volver a activar las interrupciones mediante bsf GIE. y el programa continuara sin pegar el salto que provoca el return o retfie.
operando de esta manera la pila star no se borra, asi que despues de operar de esta forma olvidate de los datos que tengas en la pila, ya que el ultimo dato sera la posicion donde estaba el programa antes de la interrupcion.
No hay ningn problema en que la pila se desborde, el micro no activa ningun mecanismo de alarma.

En C no se como se haria, pero puedes intentar lo siguiente:
cuando termines la rutina de interrupcion en vez de darle fin de la forma habitual, realizalo como si habilitaras las interrupciones.
 
Ya lo he pensado...

Pero sabes lo que hago en C, supongo que también se deberia hacer en ASM... Que es guardar lo que es registro W, STATUS y el PCL... No se si te suena esto. En fin, esto se hace con el fin de poder volver a tener estos registros antes de volver de la interrupcion, de modo que la operacion que estaba haciendo antes de la interrupcion, no se despeñe por que estaba utilizando estos registros.

En fin, luego me di cuenta en el datasheet que lo que hace cuando hay una interrupcion, es que la dirreccion donde se activo la interrupción se guarda en el Stack 1 de la Pila, de modo que cuando vuelvo de la interrupción, esta dirección que está en el Stack1 se pone en el Contador de programa otravez, de modo que vuelve a sitio donde se activo la interrupción. Esto independiente mente si pones el GIE a 1 otravez.

Entonces, dudaba mucho de que lo que planteaba de, que si se podia cambiar el sitio de retorno, por que creo que no se puede cambiar el valor del Stack1. A noser que desbordemos la pila... pero claro, la dirección que al final hay en el primer Stack despues de debordar la pila será distinta, pero no será la que yo quiero que vuelva. Asi que estamos en la misma...


Bueno, no se si has entendido lo que he pensado y reflexionado depues de haber leido 10 veces el datasheet ... En fin, espero que esto te de ideas, y puedas compartiarlas tambieén...

Un saludo Pepechip
 
JuAnSiTo dijo:
Entonces, dudaba mucho de que lo que planteaba de, que si se podia cambiar el sitio de retorno, por que creo que no se puede cambiar el valor del Stack1. A noser que desbordemos la pila... pero claro, la dirección que al final hay en el primer Stack despues de debordar la pila será distinta, pero no será la que yo quiero que vuelva. Asi que estamos en la misma...

Creo que mo lo has entendido.
Normalmente al confeccionar un programa utilizando las interrupciones seguimos los siguientes pasos:

1º activamos las interrucciones
2º Cuando ocurre la interrupcion ejecutamos la rutina que deseemos
3º ponemos fin a la interrupcion, con lo que el contador de programa vuelve a donde se quedo antes de la interrupcion.

Tu si quieres que no continue donde lo dejo lo haces de esta manera.
1º activamos las interrucciones
2º Cuando ocurre la interrupcion ejecutamos la rutina que deseemos
3º Hago un goto a la rutina nueva que quiera ejecutar, pero en el principio de esta rutina vuelves a poner las instrucciones del 1º punto "activamos las interrupciones"

Lo siento no se explicartelo de otra manera para que lo comprendas.
 
Dentro de una interrupción ver que se produce otra es facil.
Solo tienes que esperar que se produzca otra revisando los flags y cuando se active otra lo envias donde quieras.
No es muy lógico hacer eso en programación si lo tienes bien estructurado pero es una forma de salir del problema.
 
Cuando uno utiliza la interrupción, no es obligatorio usar el RETFIE

Esta instrucción, lo que hace, como dijo pepechip, habilita de nuevo las interrupciones y vulve al punto de dónde se abandonó la tarea. Esto lo hace en dos ciclos de instrucción. Si esta instrucción RETFIE, no estaría, tendríamos que usar el RETURN y luego utilizar el BSF GIE para activar las interrupciones. De esta manera, ocuparíamos 3 ciclos de reloj, pero con el RETFIE, se ahorra un ciclo.

Lo que hiso Pepechips, es totalmente válido, y tiene la suerte que al desbordarce la PILA, por la forma de su programa, no le es problema. Pero es un detalle que hay que tener en cuenta.
 
Ten cuidado si llamas a una secuencia de retatdos en la rutina de interrupciones, esta debe ser distinta a las secuencias de retardo que se llaman durante el programa principal, debido a que el PIC al entrar a la interrupción, solo guarda la línea en donde se genero la interrupcion, no restaura posiciones de memoria etc,
 
Atrás
Arriba