Interrupciones en una ejecución.

Hola, Saludes a todos.

En esta ocasión vengo presentando un pequeño inconveniente que he estado teniendo con un experimento que llevo en proceso, y es una pequeña cocina, el código que he estado trabajando lo tengo casi finalizado sino es porque no he logrado aplicar un botón de paro del proceso mientras el mismo este en curso.

El experimento consiste en una serie de push botton, un termistor, una LCD y una cocina. Se presenta un menú para seleccionar el tiempo de encendido de la cocina y la LCD para mostrar ese tiempo, este podra ser seleccionado desde 4 push botton, 3 para seleccionar el tiempo y 1 para parar el proceso (STOP), ademas de el termistor que lo quiero usar para comparar si la temperatura es mayor a 80 grados, se mande al menú principal.

Esas interrupciones si se pueden decir asi, son las que no he logrado hacer, el uso del termistor para reset el proceso y el del push botton para de igual manera reset el programa. He hecho algo ahi pero no me funciona, por lo tanto se que está mal.

adjunto el codigo que tengo hasta el momento.

#include <math.h>
// incluimos la libreria LiquidCrystal
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
// Vss=Neg, Vdd=Pos, Vo=Pot, Rs=7, Rw=Gnd, E=8, D4=9, D5=10, D6=11, D7=12

int T;
// --------------- Variable de salida
const int rele=1;                // Salida del Relé(Cocina)
int buzzer=2;
// ---------------- Variables de lectura --------------
int inPin=3;     //STOP
int inPin1=4;    //PUSH 1
int inPin2=5;    //PUSH 2
int inPin3=6;     //PUSH 3
// ---------------- Variables de asignación --------------
int val0=0;
int val1=0;
int val2=0;
int val3=0;
//-----------------------------------------------------------------------------



//---------------------- Inicio del programa ------------------
void setup()
{
    Serial.begin(9600);
    lcd.begin(16, 2);                    // establecemos el numero de columnas y filas del display 
    lcd.setCursor(3, 0);
    lcd.print("Bienvenido");           // enviamos el mensaje a mostrar en el display
    delay(2000);
    pinMode(buzzer,OUTPUT);
    pinMode(inPin,INPUT);
    pinMode(inPin1,INPUT);
    pinMode(inPin2,INPUT);
    pinMode(inPin3,INPUT);
    pinMode(rele,OUTPUT);
}    
//-----------------------------------------------------------------------------


//-------------------- Función Principal ----------------------
void loop() 
{
        T=Thermistor(analogRead(0));
        delay(1000);
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Seleccione El");
        lcd.setCursor(2,1);
        lcd.print(" tiempo");
        delay(2000);
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("1. 1min. 2. 2min");
        lcd.setCursor(3,1);
        lcd.print("3. 3 min");
        delay(4000);
        TipoTiempo();
}
//-----------------------------------------------------------------------------




//-------------------- Función Secundaria ----------------------
void TipoTiempo()
{
 lcd.clear();
        //--------- Tiempo 1 ----------
  val1= digitalRead(inPin1);
    if(val1 == HIGH)
      {
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("1 MIN");
        lcd.setCursor(1,1);
        lcd.print("Seleccionado");
        delay(2000);
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Espere");
        delay(1000);
        tiempo1();
      } 


        //--------- TIEMPO 2 ----------
  val2= digitalRead(inPin2);
    if(val2 == HIGH)
      {
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("2 MIN");
        lcd.setCursor(1,1);
        lcd.print("Seleccionado");
        delay(2000);
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Espere");
        delay(1000);
        tiempo2();
      }


        //--------- TIEMPO 3 ----------
  val3= digitalRead(inPin3);
    if(val3 == HIGH)
      {
        lcd.clear();
        lcd.setCursor(5,0);
        lcd.print("3 MIN");
        lcd.setCursor(1,1);
        lcd.print("Seleccionado");
        delay(2000);
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Espere");
        delay(1000);
        tiempo3();
      }     
}
//-----------------------------------------------------------------------------


//  --------------- Funciones para los tipos de tiempo ------------------------
void tiempo1()
{
      val0= digitalRead(inPin);       // Se lee si el boton de Stop ha sido presionado
      if(val0 == HIGH)                // Si es igual a 1 se procede a abortar el procedimiento
        {
            digitalWrite(rele,LOW);       //Desactivamos la bobina del relé y apagamos la cocina
            TiposPapel();
            delay(1500);
        }
    
      if (T<=30.0)
          {
              lcd.clear();
              digitalWrite(rele,HIGH);      //Activamos la bobina del relé y encendemos la cocina
              lcd.setCursor(0, 1);          // enviamos la posicion del cursor al display (nota: la linea 1 es la segunda fila, empieza a contar en 0
              contar(1);
              digitalWrite(rele,LOW);       //Desactivamos la bobina del relé y apagamos la cocina
              lcd.clear();
              lcd.setCursor(0,0);
              lcd.print("La Impresion");
              lcd.setCursor(0,1);
              lcd.print("esta Lista");
              delay(2000);
              digitalWrite(buzzer,HIGH);
              delay(100);
              digitalWrite(buzzer,LOW);
              delay(1000);
           }
      else
          {
            if (T>30.0)
              {
                digitalWrite(rele,LOW);       //Desactivamos la bobina del relé y apagamos la cocina
               delay(1500);
                digitalWrite(buzzer,LOW);
                delay(1500);
                lcd.clear();
                lcd.setCursor(1,0);
                lcd.print("Alerta Temprtura");
               lcd.setCursor(1,1);
                lcd.print("Sobrepasada");
                delay(2000);
                lcd.clear();
                lcd.setCursor(0,0);
                lcd.print("Espere");
                delay(1000);
                TiposPapel();               
              }
          }
 }
//------------------------------------------------------------------------------------------

De antemano muchas gracias por la ayuda.

Saludes. :slight_smile:

Apenas veo el código me encuentro con tu problema (pero este es un comentario rápido sin ver con detenimiento tu código que haré ahora). Si usas delay de 1, 2, 4 seg y esperar que algo sea reconocido en esas condiciones te termina ocurriendo lo que experimentas aún que además tengas algún otro problema. Tienes que cambiar tu programa y usar millis().

Oh! Ya veo.

Ya me había dicho eso antes sino mal recuerdo, que cuando uso el delay en ese tiempo de uso no lee alguna otra entrada.

Ahora bien, cambiaré esos delay a milis, y veré el comportamiento del mismo. Ya os digo que fue lo que ha sucedido.

Lo que si no sé como hacer, es esa interrupción de que si la lectura del termistor es mayor a "X" mientras el codigo esta corriendo me mande al menu principal, y si es menos, pues el programa continua normal, tenia pensado un switch pero no sabría como estructurarlo. :(

El cambio no es tan fácil. Debe repensar todo el código para que trabaje y haga lo que quieres.
No uses nunca delay cuando esperas que reaccione a cambios con pulsadores.
Mira tu código y ve los momento de NO HAGO NADA en el que tu esperas que reaccione a un pulsador y sin embargo esta terminando de NO HACER NADA. Lo enfatizo porque es el error mas recurrente del foro.

Si, tiene toda la razón, he estado probando y efectivamente no responde a los llamados del pushbotton el proceso mientras esta en delay, tengo que mantener presionado el push y hasta que termina el delay ya me lo acepta, el uso de ese delay y de millis siempre se me ha sido dificil de entender. Por la forma en estructurar el millis.

:(

Esto es algo parcial, la última secuencia con la T>30.0 y luego <30.0 tiene muchos delays para el buzzer y demás y realmente me parece muy tedioso pero ve imaginando como hacerlo

#include <math.h>

// incluimos la libreria LiquidCrystal
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
// Vss=Neg, Vdd=Pos, Vo=Pot, Rs=7, Rw=Gnd, E=8, D4=9, D5=10, D6=11, D7=12

int T;
// --------------- Variable de salida
const int rele  = 1;                // Salida del Relé(Cocina)
int buzzer      = 2;
// ---------------- Variables de lectura --------------
const byte inPin0 = 3;     //STOP
const byte inPin1 = 4;    //PUSH 1
const byte inPin2 = 5;    //PUSH 2
const byte inPin3 = 6;     //PUSH 3
// ---------------- Variables de asignación --------------
bool val0, val1, val2, val3;
bool val
//-----------------------------------------------------------------------------



//---------------------- Inicio del programa ------------------
void setup() {

    Serial.begin(9600);
    lcd.begin(16, 2);                    // establecemos el numero de columnas y filas del display 
    lcd.setCursor(3, 0);
    lcd.print("Bienvenido");           // enviamos el mensaje a mostrar en el display
    delay(2000);
    pinMode(buzzer,OUTPUT);
    pinMode(inPin,INPUT);
    pinMode(inPin1,INPUT);
    pinMode(inPin2,INPUT);
    pinMode(inPin3,INPUT);
    pinMode(rele,OUTPUT);
}    
//-----------------------------------------------------------------------------


//-------------------- Función Principal ----------------------
void loop()  {

  T = Thermistor(analogRead(0));
  
  delay(1000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Seleccione El");
  lcd.setCursor(2,1);
  lcd.print(" tiempo");
  delay(2000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("1. 1min. 2. 2min");
  lcd.setCursor(3,1);
  lcd.print("3. 3 min");
  delay(4000);
  TipoTiempo();
}


//-------------------- Función Secundaria ----------------------
void TipoTiempo() {
  //--------- Tiempo 1 ----------
  val1 = digitalRead(inPin1); // 1 min
  if (val1 && !val1Ant) {
      estado = 0;
  }
  val1Ant = val1;

  val2 = digitalRead(inPin2); // 2 min
  if (val2 && !val2Ant) {
      estado = 1;
  }
  val2Ant = val2;

  val3 = digitalRead(inPin3); // 3 min
  if (val3 && !val3Ant) {
      estado = 2;
  }
  val3Ant = val3;
  
  val0 = digitalRead(inPin0);  // stop
  if (val0 && !val0Ant) {
      estado = 9;
  }
  val0Ant = val0;
  
  switch (estado) {
      case 0: lcd.clear();
              lcd.setCursor(0,0);
              lcd.print("1 MIN");
              lcd.setCursor(1,1);
              lcd.print("Seleccionado");
              start = millis()+2000UL;
              break;
      case 1: lcd.clear();
              lcd.setCursor(0,0);
              lcd.print("2 MIN");
              lcd.setCursor(1,1);
              lcd.print("Seleccionado");
              start = millis()+2000UL;
              break;
      case 2: lcd.clear();
              lcd.setCursor(0,0);
              lcd.print("3 MIN");
              lcd.setCursor(1,1);
              lcd.print("Seleccionado");
              start = millis()+2000UL;
              estado = 3;
              break;
      case 3: if (millis() > start) {
                  lcd.clear();
                  lcd.setCursor(0,0);
                  lcd.print("Espere");            
                  start = millis()+1000UL;
                  estado = 4; 
              }
              break;
      case 4: if (stop) {
                  digitalWrite(rele,LOW);       //Desactivamos la bobina del relé y apagamos la cocina
                  TiposPapel();
                  start = millis() + 1500UL;
              } 
              estado = 5;
              break;
      case 5: if (T <= 30.0) {
                  lcd.clear();
                  digitalWrite(rele,HIGH);      //Activamos la bobina del relé y encendemos la cocina
                  lcd.setCursor(0, 1);          // enviamos la posicion del cursor al display (nota: la linea 1 es la segunda fila, empieza a contar en 0
                  contar(1);
                  digitalWrite(rele,LOW);       //Desactivamos la bobina del relé y apagamos la cocina
                  lcd.clear();
                  lcd.setCursor(0,0);
                  lcd.print("La Impresion");
                  lcd.setCursor(0,1);
                  lcd.print("esta Lista");
                  buzzer();
              }
              else {
                  lcd.clear();
                  lcd.setCursor(1,0);
                  lcd.print("Alerta Temprtura");
                  lcd.setCursor(1,1);
                  lcd.print("Sobrepasada");
              }
              break;
  }
}

Ohh!!!! Esa mejora de ese código si ha quedado bastante fuera de mis conocimientos jejeje, es decir, hay cosillas que no logro entender como por ejemplo

start = millis()+2000UL;

esas partes asi, que denota el "UL" ?

Estuve leyendo acerca de la función de millis() y me convencí que son una buena forma de usar a la hora de implementar los push, pero me cuesta poder aplicarla, es decir estructurar la sentencia.

Ahora bien, eso que ha implementado es algo a lo que llaman "maquinas de estados"?? Porque se ve sinceramente bastante complicada esa programación.

Os agradezco una vez mas por su ayuda y cooperación. Estaré aplicando el código lo mas antes posible.

Saludes!!!

Neythan: start = millis()+2000UL;

esas partes asi, que denota el "UL"

Son "reglas de compilación":

"U" o "u": le dice al compilador que esa constante se debe tratar como unsigned (sin la posibilidad de ser negativo). "L" o "l": le dice al compilador que esa constante se debe tratar como long (tipo de dato número-entero más grande).

No lo terminé porque faltan llamados a tu buzzer, pero es aprender a programar de otro modo, del modo que requiere arduino cuando hay retardos y pulsadores que atender. Entonces, como haces para que las dos cosas ocurran? De la manera clásica no se puede. Debes pensar en un formato diferente que ahora luce raro. Ve a Documentación y lee el excelente comentario que nuestro compañero cgriell escribió sobre máquinas de estado. Qué es y cómo funciona una máquina de estados luego mira mi comentario final donde ayudo a alguien con un problema similar al tuyo

Comportamiendo no esperado de Delay(). Similar porque usaba delay y su solución de nuevo es la máquina de estados.

delay(1000) no puede reemplazarse directamente por millis()+1000; ni nada por el estilo. millis() es un cronómetro con milisegundos y tu debes tomar un valor parcial t1 que yo llamo start pero lo puedes llamar como gustes y tomas un valor. Como millis() se incrementa con cada milisegundo, a los 1000 mseg despues se produce la situación que buscamos... ejemplo... supon esta situación... arranaca arduino y por razones que no importan presionas un pulsador y cargas start estamos en miillis() = 12000 mseg desde que arrancó el arduino. Se energizó. en el sketch start = millis()+1000UL = 12000+1000=13000 o sea.. a los 13 segundos yo hare algo. y estamos a 12 seg del momento que presionaste el pulsador y se cargó start. Lo recalco porque es importante.

Entonces el código sigue y sigue.. ejecutándose y atento a todo lo que deba hacer, actualizar sensores, lcd, pulsadores, etc. transcurrido ese tiempo y luego de los 13000 llega 13001 y mira que pasa cuando hago if (millis>start) resuelta que start se cargó con 13000 y ahora millis vale 13001 entonces 13001 > 13000 y ejecuto tu código prendo rele, activo buzzer etc.

Bien, esto explica una tarea, pero luego haces muchas mas cosas, y ese complica y por eso uso estados. La situación anterior me cambia el estado. Ahora estoy en un estado en el que debo hacer todo lo que tengo dentro de tu cóndición anterior y tal vez requiera de sub estados.. y así.

Si analizas tu programa y lo miras como estados de cosas que ocurren solo una vez, podrías cambiar el criterio de como funciona para lograr lo mismo pero con máquina de estados, no lo mismo porque ahora reaccionará a cosas como cambios de tus pulsadores y antes no lo hacía.

:) Hola, me disculpo por responder hasta ahorita, pero ahora que leo la respuesta agradezco con gran sinceridad su tiempo para poder explicarme de forma tan detallada el funcionamiento de esta función (millis), la verdad si en la universidad explicaran tan detallado estas cosas, quizás fuésemos mas eficientes a la hora de programar.

Entendí muy bien como trabaja esta función, y ya me tenia que en algún momento las maquinas de estados tenían que entrar en juego. A veces me complica el entender ese proceso que pasan estas maquinas de estados, porque un estado puede entrar en un sub-estado y asi sucesivamente, y el programar ese tipo de cosas se me vienen muy enredadas, quizás por la falta de experiencia en la programación, sin embargo me causa demasiado interés el poder entenderlas y aplicarlas.

Creo que en mi caso, el código se reduciría si uso maquinas de estados, tendré que analizarlo mejor a ver como continuo trabajando con lo que son los buzzer y otras cosillas que quiero agregar.

Sin embargo, agradezco una vez más el tiempo tomado para la explicación, eso me anima mas a entrar mas a este mundo de la programación.

Quedo pendiente de la finalización de mi código, cuando logre concluirlo estaré presentándolo. Ya con su ayuda llevo bastante trecho recorrido.

Saludes. N.A.V!

En algún momento cuando termines tu carrera vas a comprender que la Universidad no puede explicarlo todo. Si te ABRE la cabeza y te prepara que tu tengas las herramientas para entender y aprender todo lo que irá apareciendo. Cuando termines la Universidad terminará tu capacitación? Noooooooo. Debes seguir estudiando y aprendiendo y lo harás toda la vida. Yo estudié ingeniería electrónica y no dejo de aprender cosas. Ayer justamente veía a otro electrónico que tuvo el mismo dilema que yo, hay que saber/aprender Electrónica, bases de datos, HTML, PHP, JAVA, node.js, programación objetos, C++, no termina nunca... y se vuelve muy abrumador. Debes aprender ESP8266, debes aprender raspberry, arduino, freescale, teensy, 200 plataformas, bueno gracias a dios llego para mi ST + DEVIOT + Platformio que junta todo y me resuelve ese problema. Te lo recomiendo. Solo para programar del mismo modo con 200 placas diferentes. Pero el resto requiere de su tiempo y sabes... yo dejé la Universidad hace muchos años. Espero que este comentario te aliente y aliente al lector a no bajar los brazos y seguir estudiando siempre. Las cosas se han vuelto muy dificiles por la globalización, asi que solo triunfarás si tienes valor agregado intelectual. Para terminar remato con una intimidad: en mi casa cuando llegan ciertas fechas (cumpleaños, Navidad, etc) mi Sra me pregunta que te gustaría recibir como regalo, y siempre le respondo: "Conocimiento".