Problem writing state machine

This is my first attempt to organize this application as a state machine. It is still under construction and full of development notes so I will NOT post the whole code. If you have an issue with that , just move on. I really do not need or want a step by step code help, I just need some ideas how to improve things. My state / flow is controlled by switch command. The switch is inside the Loop and gets processed indefinitely.

The idle case 0 / state is changed to case 1 to output data to the LCD. External interrupts sets the SystemState to 1.

I do not want to keep updating the LCD if there in no data change, so I change the state to do nothing, just fall thru. It works, but I am open to other options. Perhaps staying in same state with sub-state / flag / paramater?

There will be another interrupt input the application, for now it is just an test input.

Here is the essence of the code:

   switch(SystemState)
    {
      case 0: // monitor selector button and output frequency 
      {
         lcd.clear(); 
         lcd.print("Running....");
         delay(Delay); 
         break; 
      }
         case 1: // frequency updated  
        {
             lcd.clear(); 
        .....................
            SystemState = 0xf; // do not update display 
            break; 
        }
        
        case 2: // rotary selector 
        {
            lcd.clear(); 
            lcd.print("Rotary selector..." );  // change rotary to selector  
.............
          break;
        }
        
      case 0xf: // do not update display 
      {
....                    do nothing for now 
          break;
      }
    }
   
 #if DEBUG
     debugFunction ("loop() START");

I write user interface libraries and make such hardware. If I want to update LCD every say 50 ms or when new contents arrive, I make the LCD update code a separate machine, I.e. An LCD updater class. It will have up to 80 bytes of buffer and some methods such as print and run. You print to it if you need to display things and include the run in a loop so the LCD update state machine will run. Inside run, the code decides whether to render LCD, depending on recent rendering and a timer. Also you can implement new line, tab, back space, and move LCD cursor if you want. This way your code that needs LCD output is separate from the code that does the LCD output.

If you want a simple solution, a flag will do. Set it when you need update LCD, and the LCD update code updates the LCD and resets the flag.

I'm a little uncomfortable with the state variable being changed in an interrupt - I'd prefer that it only be changed in the state machine code, i.e. your switch. So, although it's much the same, I'd have the interrupt set a flag and have your idle state check it to see whether to update the LCD and then clear it.

Without a better idea of what your full set of states is of course, it's hard to say what the best approach is.

liudr: I write user interface libraries and make such hardware. If I want to update LCD every say 50 ms or when new contents arrive, I make the LCD update code a separate machine, I.e. An LCD updater class. It will have up to 80 bytes of buffer and some methods such as print and run. You print to it if you need to display things and include the run in a loop so the LCD update state machine will run. Inside run, the code decides whether to render LCD, depending on recent rendering and a timer. Also you can implement new line, tab, back space, and move LCD cursor if you want. This way your code that needs LCD output is separate from the code that does the LCD output.

If you want a simple solution, a flag will do. Set it when you need update LCD, and the LCD update code updates the LCD and resets the flag.

Thanks, the more I think about this the more I like the current "fall thru" state. I'll try the flag method when I clean up the current mess. Somehow I feel the real solution is to start using Arduino Main as an event function controller - much like windoze messaging schema. But I need to finish this project first. Vaclav

wildbill: I'm a little uncomfortable with the state variable being changed in an interrupt - I'd prefer that it only be changed in the state machine code, i.e. your switch. So, although it's much the same, I'd have the interrupt set a flag and have your idle state check it to see whether to update the LCD and then clear it.

Without a better idea of what your full set of states is of course, it's hard to say what the best approach is.

I think this needs more explanations. The switch (SM) is in Loop, so far the SM is only controlling LCD. The LCD is updated on interrupt, after the interrupt does some calculations. So SM changes from idle state to one shot update state ( by interrupt) and than change to running state . Now I process another interrupt whenever. So the interrupt is the external event putting the SM to one shot state etc. Maybe it is not a true SM, by definition. Or the interrupt is a state even if not within the switch. Vaclav

Enough hand-waving. Post code.

I think this needs more explanations.

I used "uncomfortable" and "prefer" to try to suggest that this is subjective. It feels wrong to have the state variable messed with in a routine that may be a long way away from the state machine code, possibly in a different source file. In a small arduino sketch, it probably doesn't matter, but it presents the possibility to make it harder to debug if that interrupt servicing function is put somewhere else and forgotten - there'll be a "What the hell is changing that thing?" moment until you recall what you did.

In your current case, the sketch is simple and short and so it's not an issue. Once the sketch is 1000 lines long and/or spread over several files, it might cause a problem. Much of the software engineering discipline is just hard learned techniques to prevent you making life difficult for yourself. You needn't use those methods, but you'll set fewer traps for yourself if you do. Letting the interrupt set the state variable has a potential to be one of those traps.

, but it presents the possibility to make it harder to debug if that interrupt servicing function is put somewhere else and forgotten

There's also the possibility of directly setting the state variable in the ISR, just before the main context was going to set it to a different value, in which case (no pun intended), the state switch will never see the value set by the ISR.

So to prevent the scenario AWOL described, there needs to be atomic commands to make the state change and the state machine run as a single step, like compare and swap. People usually get away with disabling interrupts during "atomic like" processes. In the case of LCD update, the update takes possibly dozens of milliseconds so you should only disable interrupt for the cases where the LCD needs no updating. If you do polling (if you are happy with the speed of polling) instead of interrupt, then this problem will not exist.

wildbill: It feels wrong to have the state variable messed with in a routine that may be a long way away from the state machine code, possibly in a different source file

Yes, that feels like a very bad idea.

I would say that if the state machine needs to poll for events, which would be a common Arduino architecture, it would make sense to do that polling within a function that encapsulates the state machine logic. If some other mechanism needs to generate events and send them to the state machine, it would make sense to write an event-handling function which contains the FSM logic for handling that type of event. I would aim to make the FSM consistent one way or the other though - if most of the events are detected by polling, I would try to incorporate the spontaneous events into the polling architecture e.g. by implementing an event buffer that can be polled. Above all, I would try to avoid having parts of the FSM logic running in different execution contexts and that probably implies that [u]none[/u] of the FSM logic should execute in an interrupt context.