INTERRUPCIONES Externas y volver a un estado sin seguir su curso

Hola, quería consultar por las interrupciones.

Yo tengo un programa y le estoy haciendo que la interrupción sea una parada de emergencia, pero se que cuando se ejecuta la interrupción se ejecuta su código que sería para parar todo y abrir compuertas por ejemplo, pero cuando termina de ejecutar eso vuelve al programa principal y sigue ejecutando todo desde donde salió.
Yo quiero evitar eso, es decir que el programa vuelva al inicio del loop para que ingrese el programa al estado de espera.

No se como hacer eso, y por ahora lo único que se me ocurre es realizar un while infinito parando todo y tirandome el mensaje de que es necesario resetear el Arduino para reinicializar todo.
Si me pueden tirar alguna idea para no bloquear el Arduino se los agradecería.

Se me ocurre una forma de hacer lo que quieres, tal vez te sirva.

Voy a suponer que usas un pulsador de los típicos diseñados para tal fin (digo, perilla roja y con retención, ¿me explico?).

En principio usaría un pin para poder manejar el reset (luego vemos como conectarlo). Se podría usar el watchdog timer pero no funciona en todas las placas, depende del bootloader que venga cargado.

En el setup(), luego de inicializar todo pero antes de inicializar las interrupciones verificaría el estado del pulsador.

Si está pulsado imprimiría algo como "Emergencia, libere pulsador" o lo que sea conveniente. Y luego entraría a un while() hasta que se libere el pulsador.
Eso detendría la ejecución en tanto el pulsador de emergencia esté retenido.

Luego seguiría la inicialización de la interrupción y lo que quedase pendiente.

Cuando se dispara la interrupción (se pulsó el botón), haces la secuencia que ya tienes, muestras en el display lo que creas conveniente si hace falta, le das un tiempo de retardo para que se lea ese mensaje (recuerda que no se puede usar delay() ) y finalmente pones en bajo el pin que maneja el reset.

Se resetea el arduino pero al encontrar que el pulsador sigue pulsado, ahí queda en espera de que se libere, como expliqué antes.

Respecto a la conexión entre el pin y el reset, tengo algo en mente con una resistencia y un capacitor pero prefiero buscar información para confirmarlo antes.

Fíjate si te sirve y avanzamos.

Saludos

PD: Antes que "me salten a la yugular" aclaro que sé perfectamente que teóricamente una interrupción debe ser lo más corta posible pero este es un caso excepcional en que hay que hacer un "parate" abrupto del programa y realizar determinadas maniobras de cierre entonces ya no importa lo que la interrupción dure.

Hola : ¿ Y por que no utilizais un reset mediante software?.
Definimos antes del setup:
#define RESET asm("jmp (0x0000)")
y utilizamos el comando RESET; donde nos convenga dentro o fuera de la interrupción.
Saludos.

Porque por un lado primero quiero saber si le sirve la propuesta antes de profundizar y por otro el reset por soft no hace exactamente lo mismo que un reset hard (por lo que estuve leyendo) aunque siempre se podría emular poniendo todos los pines y registros como "de fábrica". También hay algunos detalles que salvar para hacer un hard reset.
Como dije, para mejorar la idea hay tiempo, el tema es ver que sirva.

Propongo otra cosa: Si usas una máquina de estado lo que propones es muy fácil de hacer.
Tu maquina elabora todo lo que tiene que hacer y mientras tanto se chequea el estado del pulsador parada de emergencia. Si se presiona vas simplemente al estado 0 o inicio de la maquina de estados y listo.
Muy simple. No hay por que complicarse con resets, jmp, etc. Ni siquiera se requiere una interrupción aunque si quieres por mala programación (algo común) poner la variable de la maquina de estados en la posición inicial es muy simple y no consume mucho tiempo.

Lo pensé pero ¿de esa manera no terminaría primero el proceso que se está ejecutando?
Digamos que el estado X baja una cuchilla y se quiere evitar que la cuchilla siga bajando y apagar todos los periféricos (un apagado virtual, digamos, ¿cómo se haría?
¿Habría que dividir el movimiento de la cuchilla en varios estados?

Lo pregunto porque me ha tocado trabajar con máquinas grandes (atracciones mecánicas) y la emergencia cortaba todo inmediatamente, salvo algunas que debían realizar alguna maniobra para alcanzar el estado de "reposo" o "standby".

Si consideras que mi duda es off-topic simplemente la dejamos para otra oportunidad.

Estoy de acuerdo con Surbyte, no hace falta ni reset ni interrupciones: solo una máquina de estados bien hecha.

Depende de como implementes la máquina de estados. Si has hecho una buena maquina de estados, al generarse la transición puedes llamar a un método que pare todo.

Toda buena máquina de estados debería tener al menos: accion en el estado, acción al entrar a un estado, acción al salir de este; y en las transiciones poder realizar también una acción.

Yo me hice una libreria con una máquina de estados, que he ido refinando y es la que uso para mis proyectos, hago automatas y no necesito ninguna interrupcion para parar todos. Hablé de ella en Máquina de estados/Instanciación de objetos/Compilación C++

Añado una nota importante:

NO USAR DELAY!!!!!

Lo digo porque se me ha venido a la cabeza que @seba0396 este usando un programa que realiza una secuencia y esta la delimita por tiempos, usando delay. Tampoco ha puesto código y nada para que no tengamos que especular.

Gracias a todos por las respuestas e ideas.
Les explico un poco el funcionamiento de la máquina. Es una Inyectora de Poliuretano donde se apreta un pulsador y habilita dos válvulas para que ingresen dos líquidos básicamente. Tengo varios estados que son ESPERA, INYECTADO, LAVADO y SECADO. No estoy usando delay, pero el inyectado, lavado y secado tiene un tiempo de ejecución que los estaba realizando con un while (t<t_ref) y cuando termina lo mando al estado de ESPERA. La cosa que si hago la interrupción cuando vuelva va a seguir dentro del while accionándome la válvula hasta que termine ese tiempo.
Espero que se entienda.
Lo de maquina de estado está muy bueno para hacerlo, pero no se me ocurre como podría ir fraccionando el tiempo para que lo pueda sacar del estado INYECCION y mandarlo a ESPERA.

Hola, Aunque sigo opinando que lo del reset es lo menos complicado,( y si es igual que uno por Harware, comprobarlo si no lo creis), Para lo que quieres no seria necesario ni siquiera usar interrupciones por ejemplo:

while (t<t_ref){
//Lo que tengas que hacer
   if (emergencia){
       //apagas , enciendes etc para dejarlo como en principio.
        break;
    }
// lo que tengas que seguir haciendo
}//fin del while

O esta otra, que como alguien decia "me pueden saltar ala yugular"
Lo primero del loop antes que nada colocas INICIO: , y dentro del programa donde quieras y cuantas veces quieras:

 if (emergencia){
       //apagas , enciendes etc para dejarlo como en principio.
        goto INICIO;
    }

Saludos.
PD: con el reset te evitas //apagas , enciendes etc para dejarlo como en principio. Y te quedaria If(emergencia){RESET;}

1 Like

Gracias #gonpezzi, nunca me di cuenta de ingresar un if dentro del while, pero gracias a eso me di cuenta de también de ponerle un Flag al while y con eso lo solucione.
El caso es que al hacer la interrupción, ahí paro todo lo que hace la Inyectora y coloco el Flag en "1" y así se sale del while que tiene la condición:

while ( ( t < t_ref ) && ( Flag == 0 )) {

// Programación de Inyección.
}

Gracias a todos por sus aportes, aprendí otras cosas que me van a ser útiles en el futuro, como resetear por software o por el pin de reset que nunca los tenía en cuenta.

Te prometo que lo voy a probar en un micro real (no Proteus) en cuanto diseñe un código que chequee el estado de todos los registros para ver si inician igual que en un hard reset o algunos conservan su estado anterior.
El tema es que para ser lo más fidedigno posible tendría que ser en assembler y es algo a lo que evito volver.

Según la hoja de datos "Durante el reset, todos registros I/O se ponen en su estado inicial y el programa inicia en el Vector de Reset".
Eso me hace sospechar que el soft reset no hace exactamente lo mismo que un hard reset.

No digo que no tengas razón, de hecho yo podría coincidir en que es como dices, pero por experiencia con otros micros se que normalmente no es lo mismo, que por ej. hay registros que no se reinician.

Ya lo probaré y te cuento

Saludos

Hola @gatul.
Si leemos el datasheet del cip atmega328p, la Tabla 11-6 es una tabla de "Vectores de reinicio e interrupción en ATmega328P" y muestra exactamente a dónde irá el chip cuando reciba una "interrupción". Por ejemplo, si nos fijamos en vector número 1. La "fuente" de la interrupción es "RESET" que se define como "Pasador externo, Reinicio de encendido, Restablecimiento de brown-out y restablecimiento del sistema watchdog",lo que significa que, si alguna de esas cosas le sucede a nuestro microcontrolador,el chip comenzará a ejecutar nuestro programa en la ubicación de la memoria del programa 0x0000. Luego la instruccion asm("jmp (0x0000)") es exactamente lo mismo que si hubiera ocurrido una de
esas situaciones.
Saludos.

Editado el numero de tabla.

Totalmente de acuerdo con lo que ocurre a nivel de microcódigo al momento de cargar el PC (program counter) y hacer el salto, en lo que no concordamos es en que hay una inicialización previa del hardware.

No estoy encontrando información sobre la secuencia de inicio en frío del micro, pero en el mientras tanto te comento que todos los artículos que encuentro sobre el soft reset (jmp0000) dicen que no reinicia los registros.

Creo que, sin mayores datos, es lo mismo que si estuviéramos discutiendo sobre religión. :grin:

Saludos