Prevenir que un Switch case se interrumpa antes de completar su funcion?

Hola buen día...

El asunto es que tengo un controlador de temperatura que es gobernado por un DS1822... no habia porblemas pero;

El control tiene 3 estados, todos dependen de la temperatura

1-.- enciende compresor (A los 7°C)
2.- Apaga compresor (a los 3°C)
3.- Venitacion controlada.

Cada una es una maquina de estado finito, pero estando aqui con el cliente me platico que el control hace cosas raras... lo estuve observando y cuando la temperatura llego a 6.75°C ... inicio el ciclo de refrigeracion... pero se detuvo por que la sonda marco 7.00 y despues 6.75... con el consiguiente descontrol.

Me gustaria saber si esta es la manera decuada de agregar una guarda boleana para que el programa una vez que inicia la maquina de estado finito... no se detenga hasta completarla...

(solo les dejo el codigo correspondiente, el completo es demasiado grande)

void thermostat()
{
//---------------thermostat sequence 
     
     if(tempC >= highTemp )
     { 
       turnOnCompressor();
       refrigerationBegin = true; 
     }
     
     if(tempC <= lowTemp  )          
     {
       turnOffCompressor(); 
       refrigerattionEnd = true;
     }
     
     
     if( cycleFansvar == true &&  refOff == false )       // to cycle only once the set of the instructions per cycle.)
     {
       if(tempC < highTemp -0.25)  cycleFans();
     }  
      
      Serial.print("temperatura =  "); Serial.println(tempC);  


}

Y aqui esta la supuesta guarda booleana en la maquina de esta finitio.. es correcto?

void turnOnCompressor(){ 

/*
This subrutine is intended to stop the refrigeration cycle 
in the most ordered way, and keeping the refrigerant on 
the high side of the system. 
*/

// boolean refrigerattion = false; // var to handle ref status only once 
// byte compOn = 0; 
// byte pascomOn = 0; //to chek if the variable has updated.
// unsigned long  comOnTime  = 0; 
// unsigend long  comOnDelay = 1500; 
// unsigend long  comOnCT    = 0;     //the current time of the compressor. 

//------for debug only
//Serial.print("comOnCT  =             "); Serial.println(comOnCT); 
//Serial.print("comOnCT - millis()  =  "); Serial.println(millis() - comOnTime ); 

// Serial.println("INICIANDO REFRIGERACION");


if(refrigerationBegin == true ) 
{


if(refrigerattion == true && millis()- comOnTime  >= comOnDelay ){
   compOn ++; 
   comOnTime = millis(); 
 /*
 //--------for debug only
 Serial.println("---------------------"); 
 Serial.print("Var compOn "); Serial.println(compOn);
 Serial.print("comoON  "); Serial.println(compOn);
 Serial.print("pascomON"); Serial.println(pascomOn);
 Serial.println("---------------------"); 
*/
}

if(compOn > pascomOn ){

  switch(compOn){ 
  
  case(1): 
  lcd.setCursor(0,0);  lcd.print(F("      CICLO DE      "));
  lcd.setCursor(0,1);  lcd.print(F("    REFRIGERACION   ")); 
  lcd.setCursor(0,2);  lcd.print(F("                    "));
  break; 
  
  case(2): 
  lcd.setCursor(0,0);  lcd.print(F("    REFRIGERACION   "));
  lcd.setCursor(0,1);  lcd.print(F("     ENCENDIENDO    ")); 
  lcd.setCursor(0,2);  lcd.print(F("       VENT 1       "));
  digitalWrite(dif1, LOW); 
  break; 
  
  case(3):
  lcd.setCursor(0,0);  lcd.print(F("    REFRIGERACION   "));
  lcd.setCursor(0,1);  lcd.print(F("     ENCENDIENDO    ")); 
  lcd.setCursor(0,2);  lcd.print(F("       VENT 2       "));
  digitalWrite(dif2, LOW); 
  break; 

  case(4):
  lcd.setCursor(0,0);  lcd.print(F("    REFRIGERACION   "));
  lcd.setCursor(0,1);  lcd.print(F("     ENCENDIENDO    ")); 
  lcd.setCursor(0,2);  lcd.print(F("      SOLENOIDE     "));
  digitalWrite(solenoid, LOW); 
  break; 

  case(5):
  lcd.setCursor(0,0);  lcd.print(F("    REFRIGERACION   "));
  lcd.setCursor(0,1);  lcd.print(F("     ENCENDIENDO    ")); 
  lcd.setCursor(0,2);  lcd.print(F("      COMPRESOR     "));
  digitalWrite(compressor, LOW);
  break; 
  
  case(6):
  lcd.setCursor(0,1);  lcd.print(F("                    ")); 
  lcd.setCursor(0,2);  lcd.print(F("                    "));
  refrigerattion = false;
  refOff = true     ;       // to cycle only once the set of the instructions per cycle.
  compOn = 0;
  cycleFansvar = false;        //bool to chek the refrigerattion has stop 
  //--------------------------------
  //refrigerattion = true; add this variable at the end of the off routine to cycle the 
  //operation otherwise will just start once
}
}
}

refrigerationBegin = false; 
}

Gracias de antemano.

-Alex.

Lo que veo que estas dentro del error LSB del sensor y no lo previste?
Otra cosa al final de tu switch case veo que no pusiste break;

      case 6: // ERROR
              // porque entre paréntesis case(6) nunca lo había visto

            lcd.setCursor(0,1);  lcd.print(F("                    ")); 
            lcd.setCursor(0,2);  lcd.print(F("                    "));
            refrigerattion = false;
            refOff = true     ;       // to cycle only once the set of the instructions per cycle.
            compOn = 0;
            cycleFansvar = false;        //bool to chek the refrigerattion has stop 
            //--------------------------------
            //refrigerattion = true; add this variable at the end of the off routine to cycle the       
            //operation otherwise will just start once

            //FALTA EL BREAK ???????
            break; // FALTABA ESTE BREAK
        }
  }

No se a que llamas guarda boleeana?

Hola Surbyte... tanto tiempo..

No entiendo las siglas LSB... pero tengo otro control instaldo en una farmaceutica y ese no tiene problemas
el detalle creo yo... surge cuando se interrumpe...

la guarda boleana en la que habia pensado es;

  if(tempC >= highTemp )
     { 
       turnOnCompressor();
       refrigerationBegin = true; //inicia la maquina de estado finito 
     }

case 6: 
refrigerattionbegin = false; // solo se interrumpe esta funcion hasta que haya terminado de arranacar.

Ahora... es curioso lo de los parentisis... lo copie del ide.. es tal como lo tengo aca... te da error?

Estoy usando un arduino mega y la ultima districución del ide.

En otras palabras... como puedo hacer para que una vez que se incie refrigeracion... no se intettumpa el proceso hasta que se complete el ciclo de encendido...
Igual con el apagado...

Gracias.
-Alex.

Otra cosa que supogo que se puede hacer... es

If (temC == highTem)
{
if(millis() - temptime > tempDelay )
{
refrigerattionON
}
}

Como ves?

Un pequeño debounce para que la sonda no nos ande con sus loqueras..
o ... quizas tambien poner un delay de digamos 500ms entre cada lectura
(actualmente el codigo corre solo, es decir tantas veces por loop como pueda)

Pero no se.. en tu experiencia que es mejor?

Que me recomiendas mas?

Gracias.
-Alex

No me da error, solo lo vi y me resulto que estaba mal.
Igualmente viste que el ultimo case no tiene break?
No te diste cuenta de ese detalle. Lee el código donde te pongo ERROR.
Si funciona con () me disculpo. No lo sabía. Tampoco lo voy a probar. Hay cosas con las que estoy acostumbrado a trabajar y si no es necesario no me sirve ni aporta nada usar ().
Es cuestion de gustos.

LSB es dígito menos significativo. Todo AD cuando convierte tiene un error que se expresa en funcion de su dígito LSB. a veces es +-1 a veces es +- 2. En tu caso, tu DS18B20 oscila en las lecturas en 0.25 grados asi que debes considerar eso.
Normalmente se agrega una histeresis, o banda de cambio. Entonces si baja de 7 grados accionas pero para que se restaure la situación debe superar 7 mas un Delta que puede ser 0.5 grados. Asi evitas ese cambio molesto.
Todo depende de la inercia termica de tu sistema. Pero el sensor siempre puede estar dando valores proximos y bascular entre estos.
hasta donde vi tu máquina de estados estaba bien, la haces diferente a mi, pero me gustó tu enfoque.
El debounce no se si funcione... yo lo que haria sería tratar de loggear la situación y luego cuando veas lo loggeado intentar resolverlo.
Pero encararía esto que te dije.

Si... Revisaré el código.... Agregare el break... Cuando dices loggear.. Te refieres a imprimir lo q pasa en la terminal serial?

Gracias.
Gracias.
Alex

No.
Me refería a registrar todo en una SD para luego graficarlo con algo.

Pues si.. Tengo un datalogger pero creó q para esto fuera útil necesitaría... Grabar el voltaje a cada contacto (para saber cual esta encendido) la temperatura..... Y en q línea aproximadamente del programa estamos. (Para verificar dnd se congela)

Revise el código... Si le faltaba un break al original. Subiré alguna otra subrutina a ver si le ves q me falta algo.

Gracias
Alex

Hola de nuevo... bueno pues algo muy raro pasa aqui...
Decidi hacer un programa para un amigo con un arduino y unos reles que le voy a regalar para que se interese en el mundo del arduino y cual fue mi sorpresa cuando estaba escribiendo;

switch (program)
{
  case (1):
  lucesSecuenciales = true;
  lucesMovimiento = false;
  lucesMovimientoSonido = false;
  demo = false;
  break;

  case (2):
  lucesMovimiento = true;
  break;

  case (3):
  lucesMovimientoSonido = true;
  break;

  default:
  demo = true;
  break;

y el complilador me da ERROR!!!!

Lo configure para uno en la mañana por que tuvimos ue improvisar un sensor de temperatura, para una maquina que el suyo se descompuso y tuve que destripar el datalogger... ya no tenia mas placas a la mano...

Lo curioso es que el codigo original puesto aqui, si compila... y se sube a MEGA.. incluso esta funcionando!!!!!

Que cosas de la vida... !!!!

-Alex.

Bueno les cuento que les agregue las guardas boleanas a las maquinas de estado finito.. algo mas pasa... algo que no tenía contemplado... Igual es error de la programacion... (el mentado swich case) Igual es algo mas..
pero ahora... digamos que esta encendiendo o apagado ... se reincia el control. Normalmente tiene el watchdogtimer a 8 segundos pero nunca hasta ahora habia entrado, igual el break que faltaba hacia cosas raras... o no terminaba el programa y quizas no habia pero tampoco habia continudad en la programacion.

Mañana le cambiare los parentesis. Y veremos que sucede. Ahora bien... el asunto de las guardas boleanas puede ser usado para reiniciar la maquina de estado finito. Me imagino algo asi;

if (completeFSMref == true){

If (refrigerattionON == true) 
{
//comienza FST
case 1...
case 2...
case 3...
case 4: refrigerattionON = false;
           completeFSMref = true;
{
else 
{
timporefrigeracion = millis()
refrigeracionSM = 0;
//reinicia las variables de la maquina de estado... de maner que si no se termina e ciclo 
}

Lo de arriba es pseudocodigo, es solo otra redundancia en caso de que algo salga mal.

Bueno, me despido buenas noches.

Gracias por sus comentarios.
-Alex

AlexLPD:
Hola de nuevo... bueno pues algo muy raro pasa aqui...
Decidi hacer un programa para un amigo con un arduino y unos reles que le voy a regalar para que se interese en el mundo del arduino y cual fue mi sorpresa cuando estaba escribiendo;

switch (program)

{
 case (1):
 lucesSecuenciales = true;
 lucesMovimiento = false;
 lucesMovimientoSonido = false;
 demo = false;
 break;

case (2):
 lucesMovimiento = true;
 break;

case (3):
 lucesMovimientoSonido = true;
 break;

default:
 demo = true;
 break;




y el complilador me da ERROR!!!!

Lo configure para uno en la mañana por que tuvimos ue improvisar un sensor de temperatura, para una maquina que el suyo se descompuso y tuve que destripar el datalogger... ya no tenia mas placas a la mano... 

Lo curioso es que el codigo original puesto aqui, si compila... y se sube a MEGA.. incluso esta funcionando!!!!!

Que cosas de la vida... !!!!

-Alex.

o sea que case (1) no es válido o si?
Nunca lo había visto, pero me puedo equivocar. Lo mas justo sería decir que jamas YO lo he usado.

No son necesarios en este caso, pero los paréntesis no afectan. Tan sólo "aislan". Donde se recomiendan típicamente, por ejemplo, es en las expresiones en define, por eso mismo: para aislar la expresión.

El detalle ... es que en el mega todo marchaba "bien"
Pero en cuanto me puse a hacer un porgrama similar en UNO

El compilador me decia que algo estaba mal en switch case... no le vi nada malo, hasta que quite los parentesis del primero y entonces me marco el segunto... le removi todos y dejo de darme error...

Saben si es diferente para uno que para mega?

Lo mejor va a ser como dice surbyte... no usar los parentesis.

Alex.

Sin entrar en detalles en todas las aplicaciones de temperatura deberias hacer una histeresis con codigo
si no sabes lo que es histeresis busca en google

Hola que tal!

Incialmente lo tenía.. lo he buscado creo que te refieres a esto;

IF ((temp>=21) | (temp<=28)){
output_low(RELE);
}
IF ((temp<21) | (temp>28)){
output_high (RELE);

Entiendo que comunmente le denomina hiterisis a un "espacio" para tomar le desicion en este tipo de aparatos, sin emabargo tuve probelamas para implementarlo... por ejemplo... si el cuarto por alguna razón estuviera mas caliente de lo normal no arrancaría.. ya me ha pasado.

Quizas agregar alguna otra condición... la verdad hemos tenido muchas carreras y no me he sentado a ver esto..

Gracias por la sugerencia.

En un comentario en general... la gurada boleana funciona, la maquina de estado finito no se interrumpe mas, asi que solo queda quitarle los parentesis y esperar a ver que sucede.

Gracias.
-Alex.

Post#4

Normalmente se agrega una histeresis, o banda de cambio.

AlexLPD:
Hola que tal!

Incialmente lo tenía.. lo he buscado creo que te refieres a esto;

IF ((temp>=21) | (temp<=28)){
output_low(RELE);
}
IF ((temp<21) | (temp>28)){
output_high (RELE);

Cuidado con estos pequeños detalles, y no me refiero al IF en mayúsculas (supongo que es código hecho "al vuelo"), sino al | , que es operador OR a nivel de bit. Entiendo que lo correcto es ||, osea OR lógico.

Hola noter... de hecho una vez que me dijeron lo de la histerisis fui y busque.. me encontre con ese codigo lo copie y lo pegue... tenía esa duda yo usaba || en arduino, creo que el codigo no es de arduino, si no de alguna otra plataforma.

De cualquier modo...no me funcionaba por que a veces por cualquier error la camara se salia de la temperatura y entonces ya no funcionaba el termostato

If( temC > hightemp || tempC < hightemp + 2.00)

esto sencillamente no me funicionaba... digamos que la temperatura set era de 10C... si por algo se subia a 12... el control ya no operaba...

despues agregue:

if( temC > hightemp) pero habia confilctos, habia que hacerlo tanto para arriba como para abajo...

ahora uso solamente algo asi;

 if(tempC >= highTemp - 0.5 )
     { 
       if( tempC >= highTemp )
       {
       refrigerationBegin = true;  
       turnOnCompressor();
       }
     }
     
     if(tempC <= lowTemp + 0.5 )
     {
       if(tempC <= lowTemp)
       {
       refrigerattionEnd  = true;
       turnOffCompressor();
       }     
     }

En fin... ahora lo que tengo es un problemin... tengo dos estados bien definidos... encender o apagar refrigeracion... pero tengo un tercer estado... cuando el control se inicia y la temperatura esta "en medio" de los extremos... deberia hacer inciar un ciclo de ventilacion... pero hace cosas raras ahora que todo el codigo es "non blocking"

Es que para iniciar la subrutina de ventilacion tengo esto:

if( cycleFansvar == true &&  refOff == false )       // to cycle only once the set of the instructions per cycle.)
     {
       if(tempC < highTemp )  cycleFans();
     }

Ambas variables son false, y true respectivamente, cuando el control recien arranca... intente poner otr if aparte pero... eso solo hace que se conjuguen ambas acciones...

Como puedo hacer mi termostato tome varias desiciones en este caso?

Estaba pensando en varios Ifs... y despues un switch case que lanze! la subrutina correcta

if(temC < hightem)    state = refrigerationON
if(temC > lowtemp)    state= refrigerationOFF
if(temC >lowtmp && temC < hightem)  state= ciclyeFans 

switch ( state) 

case refrigerattionON :
refrigerationON();
break; 

case refrigerationOFF:
refrigerationOFF();
break; 

case cycleFans
cycleFans();
break;

Ahora en este aspecto...
como puedo hacer que el switch case me acepte el texto, para que sea mas explicativo?

como puedo "reiciar" las variables de una subrutina en caso de sea interrumpida por algun otra cosa?

Lo que hago en las que tengo;

case 6:
  lcd.setCursor(0,1);  lcd.print(F("                    ")); 
  lcd.setCursor(0,2);  lcd.print(F("                    "));
  refrigerattion = false;
  refOff = true     ;       // to cycle only once the set of the instructions per cycle.
  compOn = 0;
  cycleFansvar = false;        //bool to chek the refrigerattion has stop 
  break;

Muchas gracias.
-Alex.

Hola, Alex.
¿Podrías explicarme qué acciones debe realizar tu máquina? Es decir, los posibles estados. Pon un ejemplo del "guión de la película" y lo pasamos a un switch/case, que es lo que yo entiendo como máquina de estados. Me parece que tu error es querer tomar todas las decisiones en un solo lugar.

Hola Noter, muchas gracias... Mira la cuestion es esta;

tempC; es la variable de temperatura.

Tengo tres estados bien definidos;
1.- refON - temC es mas alto que el HighPoint (la temperatura esta en el limite superior o es mas alta)
2.- refOFF- temC es mas bajo que el lowPoint (la temperatura esta o es menor que el lim inferior)
3.- cyclefans - temC no "toca" ni el highPoint ni el lowPoitn... esta "en medio" por lo que llamamos la subrutina de ventilacion.

Estos son los 3 estados que deseo controlar en la función termostato, ya tengo hecha cada maquina de estado finito para cada uno de ellos, y por si solas funcionan bien, el detalle que he tenido es;

1.-A veces el "termostato" interrumpe la maquina que se esta ejecutando... y con ello.. impide que se ejecute nuevamente de manera correcta. (creo que he encontrado la solucion a esto)

2.-El termostato tal como se describe arriba puede tener dos o mas condiciones a la vez que sean ciertas, con lo que la subrutina que varia la ventilación me explico;

if(temC <= lowPoint) refrigerationOFF()

if(temC >= lowPoint && temC <= highPoint) cycleFans();

como puedes apreciar, se pueden y de hecho se cumple tanto la funcion superior como la inferior.

Creo que eso se resolveria usando un Switch case, como el comentado en el de arriba
el detalle que quiero que la variable sea explicativa; Var = refrigerattionON, refrigerattionOFF, cycleFans, en lugar de 0,1,2...

Y creo que puedo evitar que la maquina incie donde no se quedo haciendo esto;

Actualmente cada maquina tiene una variable que me dice si se completo, en este caso es; cycleFansVar, por poner algo...

case 6:
  lcd.setCursor(0,1);  lcd.print(F("                    ")); 
  lcd.setCursor(0,2);  lcd.print(F("                    "));
  refrigerattion = false;
  refOff = true     ;       // to cycle only once the set of the instructions per cycle.
  compOn = 0;
  cycleFansvar = false;        //bool to chek the refrigerattion has stop 
  break;

Si agrego un if, en la maquina que diga;
If(cycleFansVar =! false){ //limpia todas las variales}

Puedo reiniciar la maquina de estado finito tantas veces como sea interrumpida. Creo yo.

Gracias, por la ayuda.