Autor Tema: Interrupciones - On Interrupt - No entiendo - soy de madera  (Leído 3470 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado wolfman77

  • PIC12
  • **
  • Mensajes: 82
    • Dos en la ruta
Interrupciones - On Interrupt - No entiendo - soy de madera
« en: 27 de Abril de 2016, 11:09:40 »
Hola a todos, volvi a decir presente despues de mucho tiempo (aunque ando sin loguearme seguido por el foro)
Tengo un problema, la cosa es que lei todo, busque, probe, y NO ENTIENDO, soy de madera, no hay forma que lo entienda, y para eso necesito de su ayuda.
Mi problema son las interrupciones, no logro entender como en medio de la ejecucion de un programa se lee el estado en un pin del micro y ejecuta otra tarea segun este programado. Vi muchos ejemplos y todos con RB.0 y quiero aprender a que ademas de ese pin me lea otros ya sea en puerto A o B.

Vamos por partes
- Programo bajo Pic Simulator IDE
- El micro con el que hago las pruebas 16F84a

Que quiero hacer bien basico para ver si aprendo?, esto, bien simple
- Parpadea un led en PORTB.0, pulso en PORTA.0 y que ese led se apague y encienda el led en PORTB.1 parpadeando
Pulso en PORTA.1 y se apagan todos los leds y comienza a parpadear en PORTB.2

Yo creo que aprendiendo eso mi karma, mi piedra que es al menos por ahora las interrupciones me lo saco de encima.
Esto tengo de codigo:

Código: [Seleccionar]
AllDigital
TRISA = 1  'Puerto A como entrada
TRISB = 0  'Puerto B como salida
INTCON = 1
INTCON.GIE = 1

led1:
PORTB.0 = 1
WaitMs 200
PORTB.0 = 0
WaitMs 200
Goto led1

led2:
PORTB.1 = 1
WaitMs 200
PORTB.1 = 0
WaitMs 200
Goto led2

led3:
PORTB.2 = 1
WaitMs 200
PORTB.2 = 0
WaitMs 200
Goto led3
End                                               

On Interrupt

If RA.0 = False Then Goto led1
If RA.1 = False Then Goto led2
If RA.2 = False Then Goto led3
INTCON.1 = 0
INTCON.INTF = 0

Resume                                             


Y ese codigo no anda, alguien puede iluminarme? no quiero que lo hagan por mi, necesito que alguien me explique por que ya me esta quemando muchos los pelos  :?
Yo hasta ahora lo que hacia era intercalar en el codigo lineas que leyeran el estado de las entradas, pero con On Interrupt me ahorraria eso
y optimizaria el programa..
Algo asi hago ahora, y funciona bien
Código: [Seleccionar]
AllDigital
TRISA = 1  'Puerto A como entrada
TRISB = 0  'Puerto B como salida
INTCON = %10000000
PORTB = 0

led1:
PORTB = 0
PORTB.0 = 1
WaitMs 200
If PORTA.1 = 1 Then Goto led2
If PORTA.2 = 1 Then Goto led3
PORTB.0 = 0
WaitMs 200
If PORTA.1 = 1 Then Goto led2
If PORTA.2 = 1 Then Goto led3
Goto led1

led2:
PORTB = 0
PORTB.1 = 1
WaitMs 200
If PORTA.0 = 1 Then Goto led1
If PORTA.2 = 1 Then Goto led3
PORTB.1 = 0
WaitMs 200
If PORTA.0 = 1 Then Goto led1
If PORTA.2 = 1 Then Goto led3
Goto led2

led3:
PORTB = 0
PORTB.2 = 1
WaitMs 200
If PORTA.0 = 1 Then Goto led1
If PORTA.1 = 1 Then Goto led2
PORTB.2 = 0
WaitMs 200
If PORTA.0 = 1 Then Goto led1
If PORTA.1 = 1 Then Goto led2
Goto led3

End                                               


gracias por leer  :)



« Última modificación: 27 de Abril de 2016, 11:35:23 por wolfman77 »
Volviendo al mundo de los PIC....

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Interrupciones - On Interrupt - No entiendo - soy de madera
« Respuesta #1 en: 27 de Abril de 2016, 15:02:14 »
Citar
Mi problema son las interrupciones, no logro entender como en medio de la ejecucion de un programa se lee el estado en un pin del micro y ejecuta otra tarea segun este programado. Vi muchos ejemplos y todos con RB.0 y quiero aprender a que ademas de ese pin me lea otros ya sea en puerto A o B.

Yo te puedo responder algunas cosas, pero nada de BASIC. Pero espero que con lo que diga te resuelva las dudas y puedas ver los ejemplos de otra forma.

Primero en principal:

No todos los pines tienen interrupcion, la interrupcion es algo realizado en hardware por el micro, lo mas comun de ver es que tengan interrupcion por flanco en RB0, es decir cuando hay un flanco ascendente ( de 0 a 1 ) o descendente ( de 1 a 0 ) en el estado del pin, Otra fuente de interrupcion en los pines suele estar en RB4 a RB7 ( esos 4 pines) estas interrupcion son POR NIVEL. Cuando cambie una no importa si pasa de 0 a 1 , o de 1 a 0 entra a la interrupcion, es 1 interrupcion para los 4 pines. Asi que es tu deber saber que pin cambio.

Hay varios modulos mas que tienen interrupciones, como los timers en el que cuando llegan a 0xFF ( o 0xFFFF en caso de 16bits ) y pasan a 0x00 se activa el flag de interrupcion.

Sabiendo que interrupciones tiene tu micro, ahora tenes que entender como es que funcionan. Cuando se produce una interrupcion se activa el flag de interrupcion de la misma (esta no depende de si esta habilitada la interrupcion o no), unicamente si esta habilitada la interrupcion esta pasa al nucleo del microcontrolador.

El microcontrolador al recibir esa señal, internamente guarda la posicion de memoria ( direccion de la  instruccion que iba a ejecutar ) en un STACK, y procede a ir al vector de interrupcion, en ese vector vas a tener tu programa de la interrupcion, al salir de la interrupcion, recupera esa direccion que habia guardado y sigue desde alli. Entonces pareciera que las cosas se ejecutan al mismo tiempo, cuando en realidad se entra a la interrupcion cuando ocurre algun evento y luego se vuelve al programa principal.

Voy a intentar usar un ejemplo encontrado por internet:


Código: QBasic/QuickBASIC
  1. DIM x AS byte
  2. x = 225
  3. trisa = 0
  4. trisa = a
  5. intcon.inte = 1
  6. enable
  7. LOOP:
  8. GOTO LOOP
  9.  
  10. ON interrupt
  11. porta = x
  12. x = x - 1
  13. intcon.intf = 0
  14. RESUME

Observamos que activa la interrupcion externa ( RB0 ) el cual el bit es el INTE del registro INTCON, podria haber tambien modificado en que flanco lo deseaba, supongamos un boton cuando lo suelta, otra cosa es que nunca se pregunta por RB0, por que esto se hace por hardware como decia. Observaras tambien que su programa principal no es mas que un loop infinito sin ninguna instruccion dentro. Es decir que el programa se queda ahi hasta que el hardware del pin RB0 detecta ese flanco y le avisa al micro, entonces ahi es donde guarda donde estaba y entra a la interrupcion, realiza lo que debe realizar y al final de la interrupcion limpia el flag de interrupcion.

¿Que ocurre si no limpias el flag?
Cuando se ejecute el resume deberia volver el programa principal, pero como el flag sigue activo sigue pidiendole al micro entrar a la interrupcion, en resumen nuca saldria de la interrupcion, por eso es necesario poner el flag en 0.

Supongamos que tenes mas de una interrupcion, por ejemplo la de RB0 y la de RB4a7, ¿ como haces ?, en la rutina de interrupcion haces lo siguiente:

Código: [Seleccionar]
On interrupt

Flag de interrupcion de RB0 en 1 ?
Si -> Hago lo que debo hacer cuando ocurre la interrupcion de RB0, y limpio el flag
No->No hago nada
Flag de interrupcion de RB4a7 en 1?
Si -> hago lo que debo hacer cuando ocurre la misma y limpio el flag
No -> No hago nada

Salgo de interrupcion

Yo quiero leer los pines RB1,2 y 3 y que entren a la interrupcion cuando se pongan en 1!.
NO SE PUEDE, esos pines NO poseen interrupcion, Se puede realizar algo "parecido" y extensible a todos los pines, en el que usas un timer para generar una interrupcion cada tanto. Y cuando entra a la interrupcion del timer verificas que todos los pines sean iguales a la anterior ves que entro, si hay alguno distinto, sabes que uno cambio y actuas en consecuencia.

Esto no es lo mismo que los casos anteriores, los casos anteriores que se usa el mismo hardware que provee el micro, apenas se produce el evento que dispara la interrupcion entra a la misma, lo cual podes pensarlo como que una interrupcion es un evento que debe atenderse rapidamente y apenas ocurre.

¿ Que ocurriria si el programa esta dentro de una interrupcion y ocurre otra ?

Cuando el micro entra a la interrupcion, deshabilita las interrupciones ( especificamente pone a 0 el GIE por si solo ) asi que no va a atender la otra interrupcion hasta que salgas de la misma, cuando salgas de la interrupcion con el resume, este solo pone un 1 en el GIE, activandolas de nuevo y que si hay una esperando va a entrar nuevamente a la interrupcion.

Esto quiere decir que si usas un delay ( WaitMs por ejemplo ) dentro de la interrupcion, estas inhabilitando a cualquier otra interrupcion. Y por lo tanto cualquier instruccion ( LCD, delays, etc) que dure mucho tiempo o quede esperando DENTRO de la interrupcion esta prohibido, tu interrupcion debe ser rapida, entrar hacer las cosas y salir, si queres enviar un mensaje por LCD supongamos cuando se detecta la interrupcion de RB0, lo que haces en la interrupcion es poner una variable ( de 1 bit casi siempre ) a 1, y luego en tu loop principal lees esa variable y envias el mensaje al LCD.

-----------

Espero que te haya contestado varias preguntas acerca de las interrupciones, lamentablemente no puedo ser de ayuda en la parte de BASIC.

Desconectado wolfman77

  • PIC12
  • **
  • Mensajes: 82
    • Dos en la ruta
Re:Interrupciones - On Interrupt - No entiendo - soy de madera
« Respuesta #2 en: 27 de Abril de 2016, 15:35:17 »
Muchisimas gracias! me aclaraste un monton de cosas, mi error principal entonces es querer ejecutar interrupcion en donde no se puede o sea, en el caso del 16F84a deberia ser unicamente en RB0 y en RB4 a RB7.
Ya con eso evito quemarme un monton los pelos.
Deberia entonces empezar a ver el tema de utilizar algun timer como bien decis, voy a empezar a verlo de ese lado

Millon de gracias!!! ((:-))
Volviendo al mundo de los PIC....

Desconectado dogflu66

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 3549
Re:Interrupciones - On Interrupt - No entiendo - soy de madera
« Respuesta #3 en: 27 de Abril de 2016, 20:12:48 »
On Interrupt
   If RA.0 = False Then Goto led1
   If RA.1 = False Then Goto led2
   If RA.2 = False Then Goto led3
   INTCON.1 = 0
   INTCON.INTF = 0
Resume

No puedes salir de On Interrupt/Resume usando Goto, si lo haces tú programa se volverá inestable porque saturas la memoria rápida llamada Pila o Stack, que para estos micros tiene 8 niveles de 13 bits de longitud o palabra para cada nivel.

Te recomiendo que releas sobre Pila o Stack de los micros y los tipos de saltos, en este lenguaje hay 3 disponibles para el usuario: Gosub/Return, Call función y Goto. Más otros de tipo interno como el salto producido por las interrupciones que provocará que se ejecute el código que se encuentre entre On Interrupt y Resume.

Cada vez que se genera un salto del tipo Gosub/Return, Call Función o los internos como el tipo que salta a On Interrupción/Resume el micro guarda una dirección de memoria en el Stack, y una vez terminado el código cuando se ejecutan las correspondientes terninaciones Return, Resume o End Funcction se lee la dirección almacenada en el stack dejando libre el nivel de stack usado. El stack es un tipo de memoria especial que para quedar libre hay que hacer una lectura, si esa lectura no se realiza por las terminaciones de este tipo de saltos el nivel no queda libre y en el siguiente salto se ocupara otro nivel hasta 8, el problema es que este tipo de memoria no se puede sobre escribir y en el siguiente salto no se guardará la dirección de retorno ni las sucesivas, por lo que el micro no sabrá donde retornar y comenzará a hacer cosas raras.
Para entender la utilidad del Stack; si el micro se encuentra con la siguiente sentencia: a = a + 1023, el micro guardará la siguiente posición de memoria en la que está en el stack , saltará al código que sabe sumar y realizara el cálculo y luego leerá del stack donde estaba para retornar y terminar con a = a + 1023. Esto permite ahorrar memoria, imagina que cada vez que realizamos una suma tenemos que copiar el algoritmo que sabe sumar, esto no tienen sentido, lo más lógico es que el algoritmo sumar solo esté una sola vez en memoria y se salta a el cuando haga falta.
Otro ejemplo más ilustrativo serie el del algoritmo que opera con números reales, este algoritmo puede ocupar en memoria el solo 1k (imagina que se produce una interrupción en medio de esta rutina, cuando se está procesando una división con decimales, el nucleo del micro hace el apunte (puntero) en el stack para saber por donde iba antes de la interrupción, para luego posteriormente volver exactamente a la siguiente dirección de donde estaba dentro del algoritmo que se encarga de operar con numeros reales), como se puede deducir no es factible repetirlo varias veces en la memoria de un micro que no tiene más de 2k, lo lógico es llamarlo cada vez que haga falta y luego retornar por donde se iba ejecutando el código. Cada llamada o salto de este tipo (que pueden ser muchos por segundo) requiere una escritura en el stack y una posterior lectura de este y solo se pueden realizar (anidar) 8 en esta familia de micros.
Lo mismo con la escritura en el LCD:
Lcdout "TodoPic" 'Salto (guarda dirección en el Stack) al algoritmo de control escritura en el LCD y retorno (Lee dirección en el Stack y deja libre el nivel)
Lcdout "Otro TodoPic" 'Salto (guarda dirección en el Stack) al algoritmo de control escritura en el LCD y retorno (Lee dirección en el Stack y deja libre el nivel)
Etc.

No sé si habré logrado explicar la peligrosidad del Goto, en fin, ahí queda.

Yo no he utilizado nunca el Pic16F84A pero revisando su datasheet he podido comprobar que no tiene ningún modulo interno que use entradas analógicas, por lo que el comando Alldigital no es necesario aplicarlo en el código, imagino que si indicas al compilador que deshabilite las entradas analógicas a un microcontrolador que no las tiene ignorará el comando, y no lo compilará porque el comando en cuestión no se puede traducir para este pic.
« Última modificación: 28 de Abril de 2016, 13:28:24 por dogflu66 »
Saludos desde Granada, España.

Desconectado wolfman77

  • PIC12
  • **
  • Mensajes: 82
    • Dos en la ruta
Re:Interrupciones - On Interrupt - No entiendo - soy de madera
« Respuesta #4 en: 29 de Abril de 2016, 20:26:49 »
Gracias dogflu66
Veo que esto de los pic si bien no es tan complicado, hay reglas que se tienen que tener en cuenta. Vere lo del goto, ya que en todos mis programas lo uso a mansalva, si bien hasta ahora no he tenido problemas, no quiero que por saturar la memoria del pic empiece con algun problema..

muchas gracias!
Volviendo al mundo de los PIC....

Desconectado dogflu66

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 3549
Re:Interrupciones - On Interrupt - No entiendo - soy de madera
« Respuesta #5 en: 09 de Mayo de 2016, 07:23:03 »
Solo hago recomendaciones, si usas goto, por lo menos no lo uses dentro de la rutina de interrupciones. Debatir si el goto se debe de usar o no se debe de usar es un terreno en el que no entro, porque hace ya casi 40 años unos señores que sabían mucho del tema recomendaron el no utilizarlo en los lenguajes de alto nivel con razones bien documentadas.

Solo añadiré y no hablare más sobre este tema:
Mientras que en los libros de lenguaje C es normal encontrar una pequeña indicación sobre el goto y su razón por la que no se usa, de echo es difícil encontrar ejemplos para ese lenguaje, sin embargo, en muchos libros del lenguaje Basic es normal el uso del goto a diestro y siniestro, esto es porque los libros están escritor por amater o por programadores de lenguaje maquina que un día decidieron que también eran expertos en lenguaje de alto nivel como el Basic.
Saludos desde Granada, España.