State machine programming ideas for single-chip microcomputer

Publisher:玉树琼花Latest update time:2023-04-06 Source: zhihu Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

I don’t know if you have such a feeling, that is, you feel that you can play with a microcontroller and each functional module can be driven. But if you are asked to write a complete set of code, but there is no logic and framework at all, just start writing! Copying from east to west shows that programming is still at a relatively low level. So, how can you improve your programming skills?


Learning a good programming framework or a programming idea may be useful for life! For example, modular programming, framework programming, state machine programming, etc. are all good frameworks.

What we are talking about today is state machine programming. Since it is quite long, please take your time to enjoy it. So, what kind of thing is a state machine?

A state machine has five elements, namely state, transition, event, action, and guard.


What is a state machine?

A state machine is something like this: a state machine has five elements, namely state, transition, event, action, and guard.


State: The stable working condition of a system at a certain moment. The system may have multiple states throughout the entire work cycle. For example, a motor has three states: forward rotation, reverse rotation, and stalled rotation.


A state machine needs to select a state from the state set as the initial state.


Migration: The process of a system moving from one state to another is called migration. Migration does not happen automatically and requires external influence on the system. A stalled motor will not start on its own, so it must be powered on.


Event: Something meaningful to the system occurs at a certain moment. The reason why the state machine undergoes state transition is because of the occurrence of events. For motors, adding positive voltage, adding negative voltage, and cutting off power are events.


Action: During the migration process of the state machine, the state machine performs some other behaviors. These behaviors are actions. Actions are the state machine's response to events. Applying positive voltage to the stalled motor will cause the motor to move from the stalled state to the forward rotating state, and at the same time it will start the motor. This starting process can be regarded as an action, that is, a response to the power-on event.


Conditions: The state machine is not responsive to events. With events, the state machine must meet certain conditions before state transition can occur. Let's take the motor in the stalled state as an example. Although it is closed and powered on, if there is a problem with the power supply line, the motor still cannot start.


Just talking about the concept is too empty. The previous small example: one microcontroller, one button, two LED lights (recorded as L1 and L2), and one person is enough!


Rule description:

1. L1L2 state transition sequence OFF/OFF--->ON/OFF--->ON/ON--->OFF/ON--->OFF/OFF

2. Control the state of L1L2 by pressing buttons. Each state transition requires pressing the button 5 times continuously.

3. L1L2 initial state OFF/OFF

figure 1

The following program is code written according to functional requirements.

Program list List1:

void main(void)

{

 sys_init();

 led_off(LED1);

 led_off(LED2);

 g_stFSM.u8LedStat = LS_OFFOFF;

 g_stFSM.u8KeyCnt = 0;

 while(1)

 {

  if(test_key()==TRUE)

  {

   fsm_active();

  }

  else

  {

   ; /*idle code*/

  }

 }

}

void fsm_active(void)

{

 if(g_stFSM.u8KeyCnt > 3) /*Whether the keystrokes have been completed 5 times*/

 {

  switch(g_stFSM.u8LedStat)

  {

   case LS_OFFOFF:

    led_on(LED1); /*Output action*/

    g_stFSM.u8KeyCnt = 0;

    g_stFSM.u8LedStat = LS_ONOFF; /*Status migration*/

    break;

   case LS_ONOFF:

    led_on(LED2); /*Output action*/

    g_stFSM.u8KeyCnt = 0;

    g_stFSM.u8LedStat = LS_ONON; /*Status migration*/

    break;

   case LS_ONON:

    led_off(LED1); /*Output action*/

    g_stFSM.u8KeyCnt = 0;

    g_stFSM.u8LedStat = LS_OFFON; /*Status migration*/

    break;

   case LS_OFFON:

    led_off(LED2); /*Output action*/

    g_stFSM.u8KeyCnt = 0;

    g_stFSM.u8LedStat = LS_OFFOFF; /*Status migration*/

    break;

   default: /*illegal status*/

    led_off(LED1);

    led_off(LED2);

    g_stFSM.u8KeyCnt = 0;

    g_stFSM.u8LedStat = LS_OFFOFF; /*Restore initial state*/

    break;

  }

 }

 else

 {

  g_stFSM.u8KeyCnt++; /*The status does not migrate, only the number of keystrokes is recorded*/

 }

}


In fact, in state machine programming, the correct order should be to have the state transition diagram first, then the program. The program should be written based on the designed state diagram. However, considering that some children may think that code is more friendly than conversion diagram, I will put the program first.


This state transition diagram is drawn using the syntax elements of UML (Unified Modeling Language). The syntax is not very standard, but it is enough to explain the problem.

Figure 2 Button control flow lamp state transition diagram

The rounded rectangle represents each state of the state machine, and the name of the state is marked inside.

The straight lines or arcs with arrows represent state transitions, starting from the initial state and ending in the secondary state.

The text content in the picture is a description of the migration, and the format is: event [condition]/action list (the last two items are optional).


The meaning of "event [condition]/action list" is: if an "event" occurs in a certain state, and the state machine satisfies the "[condition]", then the state transition must be executed and an event must be generated. A series of "actions" in response to an event. In this example, I use "KEY" to represent keystroke events.


There is a solid black dot in the figure, which represents an unknown state that the state machine is in before it works. Before running, the state machine must be forcibly migrated from this state to the initial state. This migration can have an action list (as shown in the figure) 1), but no event triggering is required.


There is also a circle containing a solid black dot in the figure, which represents the end of the state machine's life cycle. The state machine in this example is endless, so there is no state pointing to the circle.


I won’t say much about this state transition diagram. I believe you can easily understand it based on the above code. Now let's talk about the program list List1.


Let’s take a look at the fsm_active() function first. g_stFSM.u8KeyCnt = 0; this statement appears 5 times in switch-case. The first 4 times appear as actions for each state migration. From the perspective of code simplification and efficiency improvement, we can completely merge these 5 times into 1 and put it before the switch-case statement. The effect of the two is exactly the same. The reason why the code is so verbose is to clearly indicate All the action details in each state transition are completely consistent with the intention expressed by the state transition diagram in Figure 2.


Take another look at the g_stFSM state machine structure variable. It has two members: u8LedStat and u8KeyCnt. Using this structure to make a state machine seems a bit cumbersome. Can we just use an integer variable like u8LedStat to make the state machine?


sure! We split each of the 4 states in Figure 2 into 5 small states, so that this state machine can also be implemented with 20 states, and only one unsigned char type variable is enough, and each keystroke will trigger Status migration can change the status of the LED light every 5 times. From the outside, the effects of the two methods are exactly the same.


Suppose I change the functional requirements from 5 consecutive keystrokes to change the state of L1L2 to 100 consecutive keystrokes to change the state of L1L2. In this case, the second method requires 4X100=400 states! Moreover, there must be 400 cases in the switch-case statement in the function fsm_active(). Is there any way to write such a program? !


For the same functional change, if you use the g_stFSM structure to implement the state machine, the function fsm_active() only needs to change if(g_stFSM.u8KeyCnt>3) to if(g_stFSM.u8KeyCnt > 98)!

Among the two members of the g_stFSM structure, u8LedStat can be regarded as a qualitative change factor, equivalent to the main variable; u8KeyCnt can be regarded as a quantitative change factor, equivalent to the auxiliary variable. The gradual accumulation of quantitative factors will trigger changes in qualitative factors.


A state machine like g_stFSM is called an Extended State Machine. I don’t know how to use the formal Chinese terminology in the industry, so I had to move the English phrase over.


2. Advantages of state machine programming

Having said so much, everyone probably understands what a state machine is, and how to write a state machine-based program. So what are the benefits of using a state machine method to write a microcontroller program?


(1) Improve CPU usage efficiency

In other words, whenever I see a program full of delay_ms(), I get sick. Software delays of tens of milliseconds and dozens of milliseconds are a huge waste of CPU resources. Precious CPU time is wasted on NOP. on instructions. That kind of program that stays still just waiting for a pin level jump or a serial port data also makes me very entangled. If the event never happens, do you want to wait until the end of the world?


By turning the program into a state machine, this situation will be significantly improved. The program only needs to use global variables to record the working status, and then it can turn around and do other work. Of course, after finishing those tasks, you should check to see if there is any change in your work status. As long as the target event (timing has not arrived, the level has not jumped, and the serial port data has not been completed) has not occurred, the working status will not change, and the program will keep repeating "query-do something else-query-do something else". Loop, so that the CPU will not be idle.


In the program list List3, the content under else in the if{}else{} statement (not added in the code, just a comment indicating /*idle code*/) is the "other work" mentioned above.

[1] [2]
Reference address:State machine programming ideas for single-chip microcomputer

Previous article:Selection of microcontroller, a few steps that have to be mentioned
Next article:Doesn’t the microcontroller deserve to be called embedded? What is the relationship between embedded and microcontroller?

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号