Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

State Machine in MCU

Status
Not open for further replies.
I would do one thing to Crsh0's code and that would be to make the "states" an enumerated type. That way the state machine could be coded with descriptive state names. Thus, readibility could be maintained while using structured methods.

I fully agree - in a real application, this would be the proper thing to do...
 
Here is what my way looks like: What could be simpler or more readable?

The code would look very similar in C with a switch control. Instead of the Goto, you would set the state which would be processed in the next loop.
Code:
#define FIRST    10
#define SECOND   20
#define THIRD    30
#define DN1      40
#define DN2      50
#define UP2      60
#define UP3      70

int state = FIRST;

--main while loop

switch( state)
{
  case FIRST:
    output_c(0x00);
    if( input(B2)) state = UP2;
    if( input(B3)) state = UP3;
    break;
  case SECOND:
    output_c(0x01);
    if( input(B1)) state = DN1;
    if( input(B3)) state = UP3;
    break;
  case THIRD:
    output_c(0x07);
    if( input(B2)) state = UP2;
    if( input(B3)) state = UP3;
    break;
  case DN1:
    output_c(0x02);
    if( input(L1)) state = FIRST;
    break;
  case DN2:
    output_c(0x03);
    if( input(L2)) state = SECOND;
    break;
  case UP2:
    output_c(0x04);
    if( input(L1)) state = SECOND;
    break;
  case UP3:
    output_c(0x05);
    if( input(L2)) state = THIRD;
    break;
  }

--end of main while loop.

EDIT: Don't look at the syntax too hard. I just took your code and did a quick translate. I may have screwed up the state settings.
 
Last edited:
Hi guys,

Just wondering how you might implement the <up> and <dn> call buttons on each floor? For example, if I'm on the second floor and I press the <dn> call button, an elevator going up from floor 1 to floor 3 will pass me on the 2nd floor without stopping.

Happy Holidays everyone.

Mike McLaren
 
I'm with you MikeMl. The switch/case statement is poor, to the point of being flawed in my mind so that it is only useful for some simple limited tasks.

It has no provision for entering states at any point, or transit from any point in one state to any point in another state.

Goto will do what you need for max efficiency on minimal hardware, which is part of the reason it IS part of the C language. But it's a powerful tool and shouldn't be in the hands of a bad programmer... Which is why they discourage it with students. ;)
 
When there are n>1 entry points to a state, that state should either be broken down into n states or have its own state machine.

The SWITCH-CASE statement is easy for the compiler to optimize. The compiler will create fast code like a computed-jump, hash or jump table.

GOTO is strongly discouraged for all programmers because it leads to spaghetti code. Which is why structured programming was invented.

EDIT: One need to mention scoping too.
 
Last edited:
Hi guys,

Just wondering how you might implement the <up> and <dn> call buttons on each floor? For example, if I'm on the second floor and I press the <dn> call button, an elevator going up from floor 1 to floor 3 will pass me on the 2nd floor without stopping.

Happy Holidays everyone.

Mike McLaren

The original State Transition Diagram I posted wasn't meant to be a full-up solution to a three-floor elevator system, just the simplest example of something that would move a model elevator from floor to floor.

Expanding it to include call buttons would add a few states. The way I would approach it is to expand the State Transition Diagram before touching the code. The State Transition Diagram is the MASTER, and the code becomes the SLAVE. I never add states in the code without first modifying the diagram, unlike most programmers, who would just dive in ;)
 
Last edited:
I'm with you MikeMl. The switch/case statement is poor, to the point of being flawed in my mind so that it is only useful for some simple limited tasks.

It has no provision for entering states at any point, or transit from any point in one state to any point in another state.

Goto will do what you need for max efficiency on minimal hardware, which is part of the reason it IS part of the C language. But it's a powerful tool and shouldn't be in the hands of a bad programmer... Which is why they discourage it with students. ;)

You are basically arguing unstructured programming against structured programming in High Level Languages. If you are defending unstructured programming, then welcome to 1968 and the Go To Statement Considered Harmful article. It's generally accepted that there are some situations where a goto statement can be beneficial, but from a maintenance point of view GoTo is a timebomb even for professional programmers. Arguing it here is a waste of time, just go through the thousands or articles starting from when structured programming started becoming popular. Like 3V0 mentioned, a good optimizing compiler will cut these down to efficient code or at least efficient enough where the code space is worth the maintenance/debugging cost savings. If you are trying to jump into the middle of state processing, mid-state I guess it would be, then you are doing something wrong.

It's funny, because microcontrollers are kinda at this code space/processing transition point that computers where in the early days where you can trade human optimization for structured code. All of these programming arguments are just a rehash of those days, along with the people who want to program as close to the metal as possible. Unstructured programming has it's place when you really need to extract everything out of the hardware and optimization wont cut it, but would never be accepted practice in a professional environment where code needs to be maintained expanded or reused by a programming team.

You mention that C has a Goto statement, but if it was created brand new today, would it? Some new high level languages do not. Java and Python do not have a Goto statement. The most common fallback use for a Goto statement was breaking out of multilevel nested loops and a labeled break does this.
 
I usually implement simple state machines using functions and function pointers. There is one function for each state. This way I can get very good structure even when the state implementation is long.

Code:
/* This is the function pointer */
void (* volatile state)(void);

/* These are the state function declarations */
void first_state(void);
void second_state(void);


int main()
{
    state = first_state;

    /* Infinite loop */
    for(;;) {
        state();
    }
}


/* state definitions */
void
first_state(void)
{
    /* Do state specific things */

    /* Change the state */
    state = second_state;
}

void
second_state(void)
{
    static int state_specific_variable = 0;

    /* Do state specific things */
    state_specific_variable++;

    /* Change the state */
    if(state_specific_variable > 10) {
        state_specific_variable = 0;
        state = first_state;
    }
}
 
Last edited:
  • Like
Reactions: 3v0
Mr T,

As to readability, I am not impressed.

I cant figure out what "state_specific_variable" is vs. what "state" is??? Or why they are needed?

Please code up the elevator example being discussed here, with the same external inputs, outputs, and named states.
 
Last edited:
Code:
void
second_state(void)
{
    static int state_specific_variable = 0;
The static modifer causes this variable to retain it value between calls. You could use a global but making it a local static prevents other code from using it. Easier to maintain.

Code:
/* This is the function pointer */
void (* volatile state)(void);
As you can see from the function prototype state is a function, but perhaps a bit odd. We know it is a function because of the return-type name(parm-list); form. The * indicates it is pointer to a function of that form. volatile tells the compiler that the value of state (the pointer) can be changed to point to another function at anytime, this prevents the compiler from making assumptions about the value of state.

Pointers can make you head spin a bit until you really understand it. But then so does a lot of EE past V=IR and P=IV.
 
Last edited:
I usually implement simple state machines using functions and function pointers. There is one function for each state. This way I can get very good structure even when the state implementation is long.

Simple and very nice. This would be very useful for state machines with large code requirements. I could have used this with my HTTP server code.

As to readability, I am not impressed.

If you are decent with C and have used pointers to functions before, the processing is actually very simple to figure out and is pretty structured. It's certainly not readable or intuitive to understand if you are not familiar with the syntax or the concept.
3V0 does a good job of describing the function of what is happening, but it would be essentially the same as a switch statement, but instead of variable that stores the current state and the loop acts upon it, the state() function points to the current state processing and is updated to point to the new function when the state changes.
 
DirtyLude-
You are basically arguing unstructured programming against structured programming in High Level Languages. If you are defending unstructured programming, then welcome to 1968 ...

I wasn't arguing or defending anything, there is nothing incorrect in anything I said there.

This thread was about microcontrollers, not C practice generalisations.

If your teacher said never use gotos, fine, be faithful to his teachings. If you work on a team where they all "know" you can't use gotos, fine. If you don't ever care about execution performance, fine.

But from someone who makes a living coding on microcontrollers, they may need good performance from minimal hardware. They might need very fast response to real world situations, they might have customers who keep wanting to add features to an existing product with a tiny micro. They might need to be more powerful in their programming options and less closed minded.

You mention that C has a Goto statement, but if it was created brand new today, would it?

Probably not, programmers these days are not taught to give a damn about execution speed and/or reducing their code to the minimum of assembler instructions after compilation and assembling. They seem to think the only thing that matters is how easily someone else can use their code, which might hold true for PCs but really does not in the world of microcontrollers with very limited ROM and speed.

Use tool A when it's the best. Use tool B when it's the best. Know which tool is the best for which job.

K&R knew C had a great weakness in program flow control, and incuded goto for the very good reason of allowing a powerful performance improving option. It's a shame students today are not taught to be as smart as K&R. ;)
 
K&R knew C had a great weakness in program flow control, and incuded goto for the very good reason of allowing a powerful performance improving option. It's a shame students today are not taught to be as smart as K&R. ;)

My physical first-edition copy of K&R reads (paperback, pages 62-63):

"C provides the infinitely-abusable goto statement, and labels to branch to. Formally, the goto is never necessary, and in practice it is almost always easy to write code without it. We have not used goto in this book."

The text then goes on to discuss and show the "deeply nested structure" usage of goto (for arguable "error handling"); it also shows a method to break out of a double nested loop while searching for a negative element in a 2-dimensional array, but then states:

"Code involving a goto can always be written without one, though perhaps at the price of some repeated tests or an extra variable."

It then shows the same negative-element-finding code re-written without the goto. The text ends with:

"Although we are not dogmatic about the matter, it does seem that goto statements should be used sparingly, if at all."

---

I'm not sure the usage within a state-machine context could be considered "sparingly"; maybe for simple state machine definitions. It is likely that today's modern compilers can do a far better optimization of the code whether you use it or not. Many of today's micro-controllers (not all, though) have more capabilities, RAM, ROM, program memory, etc - than some of the mini-computers which were around when K&R were writing the language.

I'm not saying that for micro-controllers a programmer shouldn't have performance in mind, but it should be a careful balance, especially if it is possible (read: likely/always) that the code might be reused or re-visited in the (near/far) future for maintenance. If the balance is met, the code should end up with good performance and good maintainability. Edge cases should be dealt with on an as-needed basis, of course...
 
I wasn't arguing or defending anything, there is nothing incorrect in anything I said there.

Arguing and defending is the very definition of what you were doing and are doing now.

If you read my post you would see I conceded that hand optimized code with gotos can sometimes be better than machine optimized code and if it's needed, go for it.

Just restating Cr0sh's point.
Properly written structured code is almost always the best tool for the job, even in microcontrollers. My assertion is that structured and maintainable code should always be the first thing a programmer should try for (this does not rule out properly thought out and optimized code) and spaghetti code should only be a last resort if the need is there.
 
There has long been a difference in thinking between EE and CS types regarding this matter. The average EE takes a few hours of programming and in general should do a decent, maybe good/great, job of programming smallish projects. This type of coding does not scale well. If this is understood there is no problem.

The quality of a program has more to do with the mind of the person doing the code then the language. An organized mind that understands structure can write a structured program in any language. It takes more time if the language is unstructured.
 
C# is a very modern programming language and it has a Goto statement.
Why goto Still Exists in C# - CodeProject

I especially liked the opening paragraph of that article:

"Developers, Software Engineers, and Programmers are logical, rational, reasonable people right? Sure they are…until you disagree with something they believe in. Then they can become the most enflamed, outraged, foaming-at-the-mouth, intolerant, lunatics you've ever had the pleasure of meeting."

Seems that is exactly what happened in this thread. I for one learned something. Arguing with Software Engineers is just like arguing religion. Fortunately, in my working life, I was always in a position where I managed software engineers, and was in a position to fire them. :D
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top