How to prevent my FSM from being interrupted?

EXTRACT:
Im using severar FSM in a refrigerattion control, is not common, but how I can prevent something to happen unitil the current FSM ends its job??

I have this on the loop;

void loop() {

 
  //---------------thermostat sequence 
     if(tempC >= highTemp )                   turnOnCompressor();
     
     if(tempC <= lowTemp  )                   turnOffCompressor();
     
     if( cycleFansvar == true &&  refOff == false )       // to cycle only once the set of the instructions           per cycle.)
{
if(tempC < highTemp )  cycleFans();
     }  
     }

All of the FSM are governed by the temperature… I know is unlikley to happend but… whath if the temperature drops and interrupt one of the FSM?

How can I add some sort of latch… to prevent this from happen?

I mean… yes we will be using the temperature, but only once the FST has ended…

This is one of what Im using;

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(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("                    "));
 // lcd.setCursor(0,3);  lcd.print(F("    TEMP 10.00 C    "));
  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       "));
 // lcd.setCursor(0,3);  lcd.print(F("    TEMP 10.00 C    "));
  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       "));
 // lcd.setCursor(0,3);  lcd.print(F("    TEMP 10.00 C    "));
  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     "));
//  lcd.setCursor(0,3);  lcd.print(F("    TEMP 10.00 C    "));
  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     "));
 // lcd.setCursor(0,3);  lcd.print(F("    TEMP 10.00 C    "));
  digitalWrite(compressor, LOW);
  break; 
  
  case(6):
//  lcd.clear(); 
  //lcd.setCursor(0,0);  lcd.print(F("    REFRIGERACION   "));
  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
}
}
}

Has you can see the FSM clear its own variables in the last stage… how can I prevent something outside to prevent the FST from not complete its cycle?

Thanks.
-Alex.

What is an FSM?

If you have a potential interrupt pending then just disable them in the function you don't want interrupting.

However I feel you might be using the wrong words here.

Flying Spaghetti Monster

Or finite state machine.

It's a bad idea to mix physical actions (compressor on/off) with display code. Split your code up into separate functions that only work with one external device at a time.

It may be worth re-reading Robin's "Planning and implementing an Arduino program" at the top of the Programming section.

MorganS: It's a bad idea to mix physical actions (compressor on/off) with display code. Split your code up into separate functions that only work with one external device at a time.

It may be with re-reading Robin's "Planning and implementing an Arduino program" at the top of the Programming section.

Thanks!

Actually, thats come to mind... if for example I put buttuns to changue the settings... either or cant be pressed while the program is doing something or either... they act but interrupt the FSM... Any how... thanks for the hint... will look in to the post.

-Alex.

The other way would be to have Boolean flags that need to be clear as well as the time criteria being met before each state function can be called. Have a different flag for each state function. Then on entry to each function you set the flags of the functions you no longer want to be called, and clear them when this function is through.

Based on what you’ve shown - you don’t have an FSM. Your function “turnOnCompressor()” has some timing logic controlling the actions of a switch-case; that does not make an FSM.

An FSM jumps from one state to another, based on the knowing what current state the system is in, and while in that state, using logic to check what the next state is needed to transition to.

For instance - maybe you have the three states of “CheckTemp”, “FanOn”, and “FanOff” - plus you have knowledge of “elapsedtime” (seconds), and “temperature” - a state machine might look like:

TurnFanOff()

State = CheckTemp

Loop:
  elapsedtime = GetElapsedTime()
  temperature = GetTemperature()

  Switch (State):
    Case CheckTemp Then:
      If temperature > 70 Then:
        State = FanOn
      
      If temperature < 60 Then:
        ZeroElapsedTime()
        State = FanOff

      Break

    Case FanOn Then:
      TurnFanOn()    
      State = CheckTemp

      Break

    Case FanOff Then:
      If elapsedtime > 20 Then:
        TurnFanOff()
        State = CheckTemp

        Break

    Default Then:

        State = CheckTemp

As you can see - the system is only in one state at any single point in time, and it only transitions states as dictated by the logic of the current state. In some cases, this happens slowly - like when checking the temperature. In other cases, it’s immediate - such as when the fan gets turned on. In yet another, it only happens when a certain amount of time passes - such as when the fan is turned off (this causes the system to wait 20 seconds before turning the fan off and going back to checking temperatures).

As you can also see, each state is independent of the others - and so there isn’t any way for one state or issue to cause a problem inadvertently due to transitions or otherwise.

Grumpy_Mike: The other way would be to have Boolean flags that need to be clear as well as the time criteria being met before each state function can be called. Have a different flag for each state function. Then on entry to each function you set the flags of the functions you no longer want to be called, and clear them when this function is through.

I was thinking some like this something but, At one point, I migth need to display set temperature and by dont have a way to use the lcd without crashing some process...

Still, be better for the actual code... to have boolean guards. Thanks a lot. -Alex

@cr0sh I see I migth dont have a FST after all, in the concrete case you mentioned...

In any case... is work in progress.. in a short example... how can I separate th lcd display printing from the relay control?

I undestand I can meke two switch statement and each control or the lcd or the relay... but how control them? boolean flags?

Thanks.

-Alex.

AlexLPD: In any case... is work in progress.. in a short example... how can I separate th lcd display printing from the relay control?

loop() {
  readInputs();
  setRelays();
  displayLCD();
}

Job done. Now just write those functions.

Note that each function has a name related to what it does. If you find that you have some code inside setRelays() that is setting something other than a relay, then add a new function or change the name of the function to describe its new action.

Yes! I got the functions. The part I dont know is how to... Implement a syncronization from the relay control and the LCD?

For instance, let say the refrigerattion is on.. And there is no button press, un thath case we want to show the display accordingly to the refrigerattion status.

But if a button is pressed the the refrigeración cycle will continúe even if the LCD is showing something else.

Is the part I dont know.

I can guess something like.. If button pressed... Temperature set screen() if not input in 10sec, or cancel is push.. Currentscreen()

But how curren screen will know whath to draw???

Thanks. -Alex

The key is that each of those functions is "non blocking". That means that readInputs() doesn't wait for an input. It just checks if any buttons are currently pressed. So it doesn't matter what the input is but it always goes through to the next function a thousand times per second, so the relays can be switched any time they need to be switched.

I haven't seen you confirm what FSM means but you haven't denied the forum's guess of "finite state machine". The button inputs will each have their own state machine to keep track of not-pressed, was-pressed, is-pressed and so on. With debouncing, it's actually not a simple two state system.

So when readInputs() detects a button push action it should update a global variable. Different actions will change different things, obviously. The display function will have its own state machine to keep track of what it is doing. If a global variable currently displayed on the screen changes from what was previously displayed, the it can update the screen.

I understand the non bloking code…

For the lcd printing … something like ;

void loop()
{

if (temp >  highTemp ) turnONrefrigerattion(); 
if (temp <  lowTemp  ) turnOFFrefrigerattion(); 

}

turn ONrefrigerattion()
{
if ( refrigerattion == true ) 
{
if (millis() - reftime > refDelay)
{
ref++
}
case(ref)
case 1: r
}
turnOFFrefrigerattion()
{
case( refrSM )

case (1)
digitalWrite (compressor, LOW) 
lcdprint = 4; 
}

and with the lcd print variable make some stuff change?

-Alex.

I was going to complain that it's not properly formatted but this is just pseudocode, so it doesn't need to have all the braces line up perfectly. If you are going to use braces, at least check that they match. There's no matching brace to close turnOnRegrigerattion().

This is an example of what not to do. The main loop reads one variable and then calls one of two functions. Those two functions then act on different sets of (global?) variables which don't appear to have any relation to anything. Then one of them updates the LCD.

Go back to Planning and Implementing an Arduino Program and try again. Put all the LCD updates into one function. Don't let any other function touch the LCD. Don't let the LCD function touch the other outputs.

Ok.... I read the whole article but... still I remain in my code...

is interesting... I was thinking each step of the FSTM must refresh an lcd variable, and this variable uptdate the FSTM ... if there is no menu button preessed...

The week has been a maddnes... maybe in these days... I can upload something like the appointed...

Thanks. -Alex.