Where does the state machine code belong to ฮผC?

I asked this question on the EE forum. You guys on StackOverflow know more about coding than EE, so maybe you can provide more details on that :)


When I learned about microcontrollers, the teachers taught me to always finish code while(1);

without code inside this loop.

This needed to make sure the software was "stuck" to interrupt. When I asked them if they could put some code in this infinite loop, they told me it was a bad idea. Knowing this, I now try to keep this loop empty.

Now I need to implement a state machine in a microcontroller. At first glance, it looks like this code belongs to this loop. This makes coding easier.

Is this a good idea? What are the pros and cons?

This is what I am planning to do:

void main(void)
{
    // init phase

 while(1)
 {
    switch(current_State)
    {
    case 1:
        if(...)
        {
            current_State = 2;
        }
        else(...)
        {
            current_State = 3;
        }
        else
            current_State = 4;
        break;

    case 2:
        if(...)
        {
            current_State = 3;
        }
        else(...)
        {
            current_State = 1;
        }
        else
            current_State = 5;
        break;
   }
}

      

Instead:

 void main(void)
    {
        // init phase

     while(1);
    }

      

And manage FSM with interruption

+3


source to share


4 answers


It's like bringing back all functions in one place or other habits. There is one type of design where you might want to do this is purely interrupt / event. There are products that are completely different, tried and tested, and not even controlled. And everything in between.

What matters is what your system design does, that's the end of the story. Interruptions add complication and risk, and they have a higher cost than not using them. Automatically generating any design interruption is automatically a bad decision, it just means there was no effort in the project, no risk requirements, etc.

Ideally, you want most of your code to be in the main loop, you want your interrupts to be lean and average to reduce latency for other time critical tasks. Not all MCUs have a complex interrupt priority system that will save you a lot of time or have your entire application in handlers. The inputs to your engineering system might help you choose the mcu, but this is where you add risk again.

You have to ask yourself what are the tasks your mcu needs to do, what if any delay exists for each task when the event happens, until they start to respond, and until they finish, on the event / task if any part of it can be delayed. Whether it can be interrupted while the task is running, there can be a time gap. Any questions you would like to do for hardware design, or cpld or fpga. other than that you have real parallelism.



What you are likely to end up with in real-world solutions is part in the interrupt handlers and some part in the main (infinite) loop. The main loop polling chests left over from interrupts and / or directly registering status registers knows what to do during the loop. If / when you get to where you need to be in real time you can still use the main loop super, your real time response comes from possible paths through the loop and worst case time for any of those paths.

In most cases, you won't have to work hard. Maybe some interrupts, maybe some polls, and a main loop doing some percentage of the work.

As you should know from the EE world, if a teacher / other says that there is one and only one way to do something and everything else is by definition wrong ... Time to find a new teacher and pretend to drink kool let's go through class and continue your life. Also note that the classroom experience is not the real world. There are so many things that can go wrong with MCU development that you are truly in a controlled sandbox, ideally with just a few variables that you can play with so you donโ€™t spend years trying to get by for months. A certain percentage of the rules they define in the class should help you get through the class and / or get the teacher through the class, easier to evaluate paperwork if you tell people,that the function can't be bigger than X or no gotos or whatever. The first thing you need to do when the class ends or add to your slave bucket is to question all of these rules. Explore and try on your own, fall into traps and dig.

+4


source


One common idiom when doing inline programming is to use a "super loop" - ending an infinite loop that begins after initialization is complete, which dispatches the individual components of your program as they run. Under this paradigm, you can run the state machine in a super loop as you suggest and continue to run hardware control functions from the interrupt context as it sounds like you are already doing. One drawback to this is that your processor will always be in high power mode - since you always use this cycle, the processor can never fall asleep. This will also be a problem in any code you write, but even an empty while loop will keep the processor running.The solution to this problem is usually to end the while loop with a series of instructions to put the processor in a low power state (completely architecture dependent) that will wake it up when processing is interrupted. If things are happening in the FSM that are not interrupt driven, the commonly used approach to have the processor wake up at periodic intervals is to initialize a timer for interrupt on a regular basis to force your main loop to continue executing.in order for the processor to wake up at periodic intervals, must initialize the timer to interrupt on a regular basis to force your main loop to continue executing.in order for the processor to wake up at periodic intervals, it must initialize the timer to interrupt on a regular basis to force your main loop to continue executing.



Another note: if you've previously executed all of your code from an interrupt context - the interrupt service routines (ISRs) should really be kept as short as possible, because they literally "interrupt" the main program execution, which can cause unintended side effects if they take too long. a lot of time. The usual way to deal with this is to have handlers in your super-loop that the ISR is just being passed to, so that the bulk of any processing that needs to be done is done in the main context when there is time, not an interrupt potentially a critical section of your main context.

+1


source


What you have to implement is your choice and the ease of debugging your code. There are times when it is correct to use while (1); at the end of the code if your UC will handle all interrupts (ISR). Although in some other application uC will be used with code inside an infinite loop (called a polling method):

while(1) 
{

//code here;

} 

      

And in another application, you can mix the ISR method with the polling method.

When it says "ease of debugging", using only ISR methods (setting while (1); statement at the end) will make it difficult for you to debug your code, because when an interrupt event is triggered, the debugger optionally won't let you step through the event register and then step by step. Also note that writing ISR code is discouraged as ISR events should do minimal coding (e.g. increment counter, raise / clear flag, for example) and be able to exit quickly.

0


source


It belongs to a single thread, which executes it in response to incoming messages from the producer-consumer queue. All interrupts, etc. Fire is injected into the queue and the thread processes them through its FSM in turn.

This is the only way I have found to avoid intractable confusion while maintaining low latency and efficient CPU utilization of interrupt I / O drives.

'while (1);' UGH!

-1


source







All Articles