terminar abruptamente una interrupcion

hola gente del foro!

estoy comenzando a programar los pics en C con el CCS y no puedo hacer algo que en assembler resultaba muy simple y es finalizar el proceso de interrupcion en cualquier momento

por ejemplo para la interrupcion con RB0: pulsando el pulsador conectado al pin cambio el estado y voy a la rutina de interrupcion

pero luego si quiero pulsarlo de nuevo para cortar la interrupcion no se como hacerlo y tengo que esperar a que termine todo el proceso de interrupcion !!!

he probado varias formas testeando el pin por ejemplo haciendo:
if (input_state(PIN_B0)==0)
break;

pero no me resulta nada de nada y ya se me acabaron las ideas :rolleyes:, alguien puede ayudarme con esto ?

gracias
 
Receurda que C es un lenguaje estructurado, y por lo tanto no esta bien visto (desde C) que acabes las cosas abruptamente, lo que en lenguaje de programación quiere decir que el programa esta mal estructurado

Podrias publicar la rutina de interrupciones? tal vez podamos re-estructurla para que no sea necesario interrumpirla abruptamente..
 
No entiendo que pretendes hacer.
Hasta donde se la idea de una interrupción es algo muy urgente y corto que se ejecuta y termina. Cuando vuelve a entrar la interrupción lo normal es que ya esté acabada hace tiempo.
Si uno salta a una interrupción y se queda a vivir allí es muy peligroso porque se puede desbordar la pila etc, es la causa mas frecuente de bugs y problemas en el soft.
Por lo tanto nunca se ponen bucles infinitos en las interrupciones y se trata de evitar poner bucles largos.

Todo esto es lo mismo en C o en ensamblador
 
les adjunto el codigo y una imagen del circuito en proteus

le agregue mas comentarios con mas dudas que tenia, perdon pero soy muy nuevo con C

como dijieron ustedes tambien probe de entrar a la interrupcion y dentro de la interrupcion cambiar el valor de un flag (inventado por mi) y despues en el main con un Switch segun el valor de este flag seleccionaba una de 2 funciones: con una funcion se iniciaba el conteo y con la otra funcion lo detenia, pero se me complico bastante y no me funcionaba, entonces meti el contador de 00 a 99 dentro de la interrupcion, ahora si me anda pero no lo puedo detener :(

saludos y gracias por las respuestas!
 

Adjuntos

  • int_rb0.rar
    15.5 KB · Visitas: 14
Por si acaso son rebotes prueba a fitrarlos con algún condensador y pon una resistencia a positivo o pon el mejor pulsador que tengas para quitar problemas.

De C estoy flojo pero yo lo hubiese hecho así: (pseudocódigo)

Interrupción:
if flag == 1 flag = 0
if flag == 0 flag = 1
Y ya está, salgo corriendo de la interrupción

Main:
If flag == 1 cuento
If flag == 0 no cuento
 
hola nuevamente, cambie el programa segun recomendo scooter pero sigue sin cortar el contador cuando uno desee, hay que esperar a que termine el contador :( ja :p

subo el programa en txt (maximizarlo para verlo bien) esta bastante comentado para que no pierdan tiempo en entender el programa

se puede simular con el mismo circuito que adjunte en el post#1 en proteus

a ver si me ayudan a encontrar la solucion , gracias
 

Adjuntos

  • int_RB0.txt
    4.4 KB · Visitas: 17
Hola ilcapo, te comento que la forma en que esta estructurado tu programa no es muy apropiada, recuerda que cada vez que se oprime el pulsador(interrupcion externa) este hace que la cpu reinicie la interrupcion externa y como ya estavas dentro de la interrupcion externa ocacionas que se carge un nuevo valor en el stack(pila) y asi hasta que se desborde si se sigue primiendo el pulsador.

adjunto un parche al primer programa que subiste para que funcione algo mejor(esto sin hacer cambios significativos en tu programa anterior).

Recurda que;
"la cave es" distribuir mejor las tareas que ejecuta el uC, por ejemplo.
- que que le procedimiento principal( void main() ) configure todas las interrupciones, puertos,etc.
- que una interrupcion temporizada multiplexe a los displays
- que otra interrupcion se ocupe de hacer de contador
- que la interrupcion externa active y desactive al temporizador que hace de contador.
asi se tendra un trabajo ordenado del uC.
un saludo.
Atte:Saint_
 

Adjuntos

  • contador.rar
    33.2 KB · Visitas: 8
Última edición:
Hola ilcapo, "otra vez".
Te comento que el programa que acabas de subir esta algo mejor estructurado.
soloque se "te fue" el preguntar el estado del flag en cada conteo que realizas.
"tienes que cranearla un poco mas" o usar un mejor depurador para detectar las fallas del programa.

adjunto un "parchesito" a tu programa.
Atte:Saint_
 

Adjuntos

  • contador_1.rar
    33.1 KB · Visitas: 5
Para descartar rebotes yo probaría con algo que seguro que no los de. Por ejemplo un astable leeeento con un 555 o el famoso antirebotes on un biestable RS
 
bien muchas gracias por la colaboracion (y)

para el segundo parchesito que me enviaste reemplazaste int1 flag por unsigned char flag

por algun motivo en especial ? :unsure:

la mejora colocando: if(flag==0)
{
return;
}
es exelente para que no repita y repita y repita el ciclo :apreton:



scooter : y un antirrebote por software en C como se hace ? porque no es bien visto usar goto
en assembler yo lo hacia con goto adjunto una imagen
 

Adjuntos

  • programa-botones.png
    programa-botones.png
    7.4 KB · Visitas: 10
Última edición:
Eso he estado pensando estos días, como acoplar un antirebote a una interrupción, si es en C o en lo que sea es lo mismo.

La idea que se me ha ocurrido mas o menos es:

Interrupción:
if rebote == 0 then todo lo demás
cuenta=cuenta xor 1 'Si es 0 pone 1 y si es 1 pone 0
fin



Main:
inicializar cuenta=0 y rebote =0
while siempre{
if cuenta== 1 then {
rebote = "un número por determinar"
while bucle de la cuenta {
if rebote!= 0 rebote-=1
aquí lo que sea para ir contando
}
}
}

No se si se entiende la idea, es que aunque entren varias interrupciones seguidas solo haga cosas si ha pasado cierto tiempo.

Edito:
Bueno, otra posibilidad es inhabilitar la interrupción hasta que rebote sea cero. Quizás esta sea mas "científica"
 
Última edición:
Un antirebote por soft sería inhabilitar la interrupción por un cierto tiempo una vez que se ejecutó y verificar que en ese lapso la entrada se encuentra en la misma condición para descartar posibles rebotes. Ejemplo:

1- Salta interrupción (no se sabe si por rebote o por una pulsación del usuario).

2- Se inhabilita la interrupción externa y se lanza un timer, de 5 mSeg.

3- Salta la interrupción del timmer por los 5mSeg pasados y se verifica que el puerto de entrada mantenga el mismo valor que en el punto 1, de lo contrario se trata de un rebote y se descarta la pulsación (se habilita la interrupción externa y volvemos al punto 1).

4- Si llegará a mantener el valor, o tomamos como válido esa pulsación o reforzamos el anti-rebote con 5mSeg más (es decir repetimos el procedimiento desde 2 hasta 4).

5- Ya válida esa pulsación, dejamos inhabilitado la interrupción externa durante un cierto tiempo (será cuestión de ir probando, por ej. 140mS ó 150mS), para lo cual volvemos a usar el timer, pero con una nueva cuenta de tiempo.

6- Pasado el tiempo del timer, volvemos habilitar la interrupción externa.

Estadísticamente entre pulsación y pulsación de una persona es de unos 300mS (o algo así), es decir que el dedo del usuario estará mucho tiempo más de 10mS apretando el pulsador.
 
Última edición:
bueno gracias a ver si entendi bien en resumen es una interrupcion dentro de una interrupcion ? ( osea dentro de la interrupcion por RBO coloco la int por TMR0 ?

suponiendo que esta bien lo que entendi ,,, como regreso a la interrupcion por RB0 luego de verificar que no fue un rebote ? u si fue un rebote como hago para volver al mail ?

voy a probar agregarle al mismo programa que estamos viendo el antirrebote por software segun sus comentarios y lo envio, pero paciencia que hace menos de una semana que estoy con el CCS y el C se me complica :) , me malcrié con el assembler ja
 
En general, no es muy aceptado que digamos "matar" interrupciones periodicas que suelen ser base de tiempo de muchos procesos, y no solo de los antirrebotes. Hay muchas maneras (contadores, registros de desplazamiento) de realizar el antirrebotes, si estan interesados pongo rutinas para el MSP.
 
aca la envio pero se vuelve loca la simulacion y no responde



hola chclau que es MSP ?

fijate si podes hacer un antirrebote segun tu sugerencia en el programa que estamos viendo, saludos
 

Adjuntos

  • contador_1.rar
    42.2 KB · Visitas: 5
Última edición:
bueno gracias a ver si entendi bien en resumen es una interrupcion dentro de una interrupcion ? ( osea dentro de la interrupcion por RBO coloco la int por TMR0 ?
...

NO.

Cada interrupción será corta y lo único que hará es levantar un flag, tal como te aconsejaron arriba. Dentro de la rutina main, deberás ir resolviendo en base a los flags que se producen en las interrupciones.

Mi consejo, es que al principio pruebes usando programación basada en máquinas de estados (que es recontra estructurado), y después cuando ya tengas un buen manejo de C, te largues solo.

Acá tenés algo:

http://tecbolivia.com/index.php?option=com_content&view=article&id=13

Después si me hago algo de tiempo subo al foro un mini-tutorial de como hacer una máquina de estado, lo bueno es que sirven tanto para C como para assembler.
 
bueno gracias a ver si entendi bien en resumen es una interrupcion dentro de una interrupcion ? ( osea dentro de la interrupcion por RBO coloco la int por TMR0 ?

suponiendo que esta bien lo que entendi ,,, como regreso a la interrupcion por RB0 luego de verificar que no fue un rebote ? u si fue un rebote como hago para volver al mail ?

voy a probar agregarle al mismo programa que estamos viendo el antirrebote por software segun sus comentarios y lo envio, pero paciencia que hace menos de una semana que estoy con el CCS y el C se me complica :) , me malcrié con el assembler ja

No, eso nunca.
La rutina de interrupción desactiva la interrupción, activa el timer o lago que hará de timer, activa el flag y vuelve.
La rutina de interrupción ideal tiene una sola instrucción.

En el cuerpo principal se activa de nuevo la interrupción al acabar el timer o sencillamente al llegar a cierta cuenta.
 
pero como se hace ? si interrumpo por RB0 y quiero hacer un antirrebote ya estoy adentro de la interrupcion?

,,, como dicen ustedes: estoy en el main entonces interrumpo por RB0, luego regreso al main , interrumpo por TIMER0, verificar en la int por Timer0 que no sea un rebote, salir de la int por Timer0 regreso hacia el main, y vover a la Int por RB0 para continuar ??

no es muy complicado eso ? o casi imposible ? yo diria que la verificacion si fue o no un rebote hay que hacerla dentro de la int por RB0 y salir en el caso de ser un rebote, disculpen que sea tan necio ja XD!
pero a lo mejor es que estoy entendiendo mal como es que dicen ustedes
saludos!
 
Veamos, lo que yo te diga tampoco es la biblia. Es mi filosofía y la de bastantes mas (creo) pero no es la única forma de hacer las cosas.

A ver si me explico.

En la interrupción solo se invierte el bit que indica si el contador cuenta o no y se deshabilita la interrupción, dependiendo del micro eso es automático; en algunos las interrupciones necesitan reamarse.

En el bucle principal cuando se detecta que hay que ir contando hacemos dos cosas, la evidente que es contar y otra a la vez que es dar un pequeño retardo hasta que se vuelve a habilitar la interrupción.

Como se hace el pequeño retardo ya al gusto del consumidor, con un timer, contando instrucciones etc..

A lo que le tengo manía persecutoria es a los bucles vacíos para temporizaciones largas, y dentro de la interrupción ya ni en broma. Eso programando en lo que mas manía te de. El motivo está claro; si pago X $ por tener unos MIPS y luego los tiro por la ventana no se sostiene. Siempre hay cosas que hacer; actualizar un display, enviar datos, mirar pulsadores etc.
 
Atrás
Arriba