Thread: Sequential state machine skeleton

  1. #1
    Registered User
    Join Date
    Sep 2012
    Posts
    68

    Sequential state machine skeleton

    Hello Experts,
    I came up with this state machine for one of my embedded projects, looking at a few reference programs online. And was wondering if someone could verify it for me, I am not able to simulated the timers are parallel operations on windows.

    Basically I have 3 cpu timers which overflow at 50,100 and 150 microseconds respectively. And each timer is associated with a 'branch' and each branch is further has 3 states. And these states should run at regular intervals.
    Here is the code:
    Code:
    #include <stdio.h>
    #include <stdint.h>
    #include <time.h>
    #include <unistd.h>
    
    
    // USER Variables
    unsigned int taskA1_counter = 0;
    unsigned int taskA2_counter = 0;
    unsigned int taskA3_counter = 0;
    unsigned int taskB1_counter = 0;
    unsigned int taskB2_counter = 0;
    unsigned int taskB3_counter = 0;
    unsigned int taskC1_counter = 0;
    unsigned int taskC2_counter = 0;
    unsigned int taskC3_counter = 0;
    
    
    // Alpha states
    void A0(void);  //state A0
    void B0(void);  //state B0
    void C0(void);  //state C0
    
    
    // A branch states
    void A1(void);  //state A1
    void A2(void);  //state A2
    void A3(void);  //state A3
    
    
    // B branch states
    void B1(void);  //state B1
    void B2(void);  //state B2
    void B3(void);  //state B3
    
    
    // C branch states
    void C1(void);  //state C1
    void C2(void);  //state C2
    void C3(void);  //state C3
    
    
    // Variable declarations
    void (*Alpha_State_Ptr)(void);  // Base States pointer
    void (*A_Task_Ptr)(void);       // State pointer A branch
    void (*B_Task_Ptr)(void);       // State pointer B branch
    void (*C_Task_Ptr)(void);       // State pointer C branch
    
    
    int main()
    {
        // Tasks State-machine init
        Alpha_State_Ptr = &A0;
        A_Task_Ptr = &A1;
        B_Task_Ptr = &B1;
        C_Task_Ptr = &C1;
    
    
        for (;;)
        {
            // State machine entry & exit point
            (*Alpha_State_Ptr)();   // jump to an Alpha state (A0,B0,...)
        }
        
        return 0;
    }
    
    
    void A0(void)
    {
        // loop rate synchronizer for A-tasks
        if (CPUTimer_getTimerOverflowStatus(CPUTIMER0_BASE))        //overflowes every 50 usec
        {
            TestA = 0;
            CPUTimer_clearOverflowFlag(CPUTIMER0_BASE);  // clear flag
    
    
            (*A_Task_Ptr)();        // jump to an A Task (A1,A2,A3,...)
        }
    
    
        Alpha_State_Ptr = &B0;      // Comment out to allow only A tasks
    }
    
    
    void B0(void)
    {
        // loop rate synchronizer for B-tasks
        if (CPUTimer_getTimerOverflowStatus(CPUTIMER1_BASE))        //overflowes every 100 usec
        {
            CPUTimer_clearOverflowFlag(CPUTIMER1_BASE);  // clear flag
        TestB = 0;
            (*B_Task_Ptr)();        // jump to a B Task (B1,B2,B3,...)
        }
    
    
        Alpha_State_Ptr = &C0;      // Allow C state tasks
    }
    
    
    void C0(void)
    {
        // loop rate synchronizer for C-tasks
        if (CPUTimer_getTimerOverflowStatus(CPUTIMER2_BASE))        //overflowes every 150 usec
        {
            TestC = 0;
            CPUTimer_clearOverflowFlag(CPUTIMER2_BASE);  // clear flag
    
    
            (*C_Task_Ptr)();        // jump to a C Task (C1,C2,C3,...)
        }
    
    
        Alpha_State_Ptr = &A0;  // Back to State A0
    }
    
    
    void A1(void)
    //--------------------------------------------------------
    {
        //A1 task
        taskA1_counter++;
        printf("A1 \n");
        //-------------------
        //the next time CpuTimer0 'counter' reaches Period value go to A2
        A_Task_Ptr = &A2;
        //-------------------
    }
    void A2(void)
    //--------------------------------------------------------
    {
        //A2 task
        taskA2_counter++;
        printf("A2 \n");
        //-------------------
        //the next time CpuTimer0 'counter' reaches Period value go to A3
        A_Task_Ptr = &A3;
        //-------------------
    }
    void A3(void)
    //--------------------------------------------------------
    {
        //A3 task
        taskA3_counter++;
        printf("A3 \n");
        //-------------------
        //the next time CpuTimer0 'counter' reaches Period value go to A1
        A_Task_Ptr = &A1;
        //-------------------
    }
    
    
    void B1(void)
    //--------------------------------------------------------
    {
        //B1 task
        taskB1_counter++;
        printf("B1 \n");
        //-------------------
        //the next time CpuTimer1 'counter' reaches Period value go to B2
        B_Task_Ptr = &B2;
        //-------------------
    }
    void B2(void)
    //--------------------------------------------------------
    {
        //A2 task
        taskB2_counter++;
        printf("B2 \n");
        //-------------------
        //the next time CpuTimer1 'counter' reaches Period value go to B3
        B_Task_Ptr = &B3;
        //-------------------
    }
    void B3(void)
    //--------------------------------------------------------
    {
        //B3 task
        taskB3_counter++;
        printf("B3 \n");
        //-------------------
        //the next time CpuTimer1 'counter' reaches Period value go to B1
        B_Task_Ptr = &B1;
        //-------------------
    }
    void C1(void)
    //----------------------------------------
    {
        //C1 task
        taskC1_counter++;
        printf("C1 \n");
        //-----------------
        //the next time CpuTimer2 'counter' reaches Period value go to C2
        C_Task_Ptr = &C2;
        //-----------------
    }
    void C2(void)
    //----------------------------------------
    {
        //C2 task
        taskC2_counter++;
        printf("C2 \n");
        //-----------------
        //the next time CpuTimer2 'counter' reaches Period value go to C3
        C_Task_Ptr = &C3;
        //-----------------
    }
    void C3(void)
    //----------------------------------------
    {
        //C3 task
        taskC3_counter++;
        printf("C3 \n");
        //-----------------
        //the next time CpuTimer2 'counter' reaches Period value go to C3
        C_Task_Ptr = &C3;
        //-----------------
    }
    This is the end result that I need:
    https://cboard.cprogramming.com/imag...BJRU5ErkJggg==

  2. #2
    Registered User
    Join Date
    Sep 2012
    Posts
    68
    Sequential state machine skeleton-stateresult-png

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    You only need one timer, running at some multiple of the smallest interval resolution.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    // USER Variables
    unsigned int taskA1_counter = 0;
    unsigned int taskA2_counter = 0;
    unsigned int taskA3_counter = 0;
    unsigned int taskB1_counter = 0;
    unsigned int taskB2_counter = 0;
    unsigned int taskB3_counter = 0;
    unsigned int taskC1_counter = 0;
    unsigned int taskC2_counter = 0;
    unsigned int taskC3_counter = 0;
    
    void A1(void)
    {
        taskA1_counter++;
        printf("A1 \n");
    }
    void A2(void)
    {
        taskA2_counter++;
        printf("A2 \n");
    }
    void A3(void)
    {
        taskA3_counter++;
        printf("A3 \n");
    }
     
    void B1(void)
    {
        taskB1_counter++;
        printf("B1 \n");
    }
    void B2(void)
    {
        taskB2_counter++;
        printf("B2 \n");
    }
    void B3(void)
    {
        taskB3_counter++;
        printf("B3 \n");
    }
    void C1(void)
    {
        taskC1_counter++;
        printf("C1 \n");
    }
    void C2(void)
    {
        taskC2_counter++;
        printf("C2 \n");
    }
    void C3(void)
    {
        taskC3_counter++;
        printf("C3 \n");
    }
    
    typedef void (*fn)(void);
    
    struct {
        int timeout;
        int reset;
        fn  func;
    } workers[] = {
        {  50,   150,    A1 },
        { 100,   150,    A2 },
        { 150,   150,    A3 },
        { 100,   300,    B1 },
        { 200,   300,    B2 },
        { 300,   300,    B3 },
        { 150,   450,    C1 },
        { 300,   450,    C2 },
        { 450,   450,    C3 },
    };
    
    int main ( ) {
        int tick = 10;
        for ( int t = 0 ; t < 1000 ; t += tick ) {
            for ( int i = 0 ; i < 9 ; i++ ) {
                workers[i].timeout -= tick;
                if ( workers[i].timeout <= 0 ) {
                    printf("time=%d ", t+tick);
                    workers[i].timeout = workers[i].reset;
                    workers[i].func();
                }
            }
        }
    }
    
    
    $ gcc foo.c
    $ ./a.out 
    time=50 A1 
    time=100 A2 
    time=100 B1 
    time=150 A3 
    time=150 C1 
    time=200 A1 
    time=200 B2 
    time=250 A2 
    time=300 A3 
    time=300 B3 
    time=300 C2 
    time=350 A1 
    time=400 A2 
    time=400 B1 
    time=450 A3 
    time=450 C3 
    time=500 A1 
    time=500 B2 
    time=550 A2 
    time=600 A3 
    time=600 B3 
    time=600 C1 
    time=650 A1 
    time=700 A2 
    time=700 B1 
    time=750 A3 
    time=750 C2 
    time=800 A1 
    time=800 B2 
    time=850 A2 
    time=900 A3 
    time=900 B3 
    time=900 C3 
    time=950 A1 
    time=1000 A2 
    time=1000 B1
    None of the worker functions know what is supposed to happen next, or what may happen at the same time.
    All that information is contained in a single table.

    If you really have 3 clocks, you could easily have 3 tables instead, each with 3 entries.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Sep 2012
    Posts
    68
    Thanks Salem, this is very elegant
    Will try it and let you know!

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Another possibility, simulating the timers.
    Code:
    #include <stdio.h>
     
    typedef struct Worker {
        void (*fn)(void);
        const char *name;
        int counter;
    } Worker;
     
    typedef struct Controller {
        int overflow;
        int n; // next worker to call
        Worker workers[3];
    } Controller;
     
    typedef struct Timer {
        int count;
        int max;
        int overflow_flag;
    } Timer;
     
    Timer timers[3] = {
        { 0,  50, 0 },
        { 0, 100, 0 },
        { 0, 150, 0 }
    };
     
    enum { CPUTIMER0_BASE, CPUTIMER1_BASE, CPUTIMER2_BASE };
     
    int overall_timer = 0;
     
    void update_timers() {
        overall_timer += 10;
        for (int i = 0; i < 3; ++i)
            if ((timers[i].count += 10) >= timers[i].max)
                timers[i].overflow_flag = 1;
    }
     
    int CPUTimer_getTimerOverflowStatus(int cputimer) {
        return timers[cputimer].overflow_flag;
    }
     
    void CPUTimer_clearOverflowFlag(int cputimer) {
        timers[cputimer].overflow_flag = 0;
        timers[cputimer].count = 0;
    }
     
    void A1(void) { }
    void A2(void) { }
    void A3(void) { }
    void B1(void) { }
    void B2(void) { }
    void B3(void) { }
    void C1(void) { }
    void C2(void) { }
    void C3(void) { }
     
    Controller controllers[3] = {
        {
            CPUTIMER0_BASE,
            0,
            {
                { A1, "A1", 0 },
                { A2, "A2", 0 },
                { A3, "A3", 0 }
            },
        },
        {
            CPUTIMER1_BASE,
            0,
            {
                { B1, "B1", 0 },
                { B2, "B2", 0 },
                { B3, "B3", 0 }
            },
        },
        {
            CPUTIMER2_BASE,
            0,
            {
                { C1, "C1", 0 },
                { C2, "C2", 0 },
                { C3, "C3", 0 }
            },
        }
    };
     
    int main() {
        for (int t = 0; t < 100; ++t) {
            update_timers();
            for (int i = 0; i < 3; ++i) {
                Controller *c = &controllers[i];
                if (CPUTimer_getTimerOverflowStatus(c->overflow))
                {
                    CPUTimer_clearOverflowFlag(c->overflow);
     
                    Worker *w = &c->workers[c->n];
                    w->fn();
                    ++w->counter;
     
                    printf("%4d %s %3d\n", overall_timer, w->name, w->counter);
     
                    c->n = (c->n + 1) % 3;
                }
            }
        }
     
        printf("\nCounts:\n"); 
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; ++j) {
                Worker *w = &controllers[i].workers[j];
                printf("%s %4d\n", w->name, w->counter);
            }
        }
     
        return 0;
    }
    
      50 A1   1
     100 A2   1
     100 B1   1
     150 A3   1
     150 C1   1
     200 A1   2
     200 B2   1
     250 A2   2
     300 A3   2
     300 B3   1
     300 C2   1
     350 A1   3
     400 A2   3
     400 B1   2
     450 A3   3
     450 C3   1
     500 A1   4
     500 B2   2
     550 A2   4
     600 A3   4
     600 B3   2
     600 C1   2
     650 A1   5
     700 A2   5
     700 B1   3
     750 A3   5
     750 C2   2
     800 A1   6
     800 B2   3
     850 A2   6
     900 A3   6
     900 B3   3
     900 C3   2
     950 A1   7
    1000 A2   7
    1000 B1   4
    
    Counts:
    A1    7
    A2    7
    A3    6
    B1    4
    B2    3
    B3    3
    C1    2
    C2    2
    C3    2
    A little inaccuracy saves tons of explanation. - H.H. Munro

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. State machine Slot machine
    By NewguytoC in forum C Programming
    Replies: 4
    Last Post: 04-25-2021, 01:46 PM
  2. Attempting to create a skeleton C code on a slot machine
    By NewguytoC in forum C Programming
    Replies: 3
    Last Post: 03-25-2021, 11:46 AM
  3. Structs with a state machine
    By CodeSlapper in forum C Programming
    Replies: 5
    Last Post: 03-05-2016, 12:04 PM
  4. Sequential State Machine
    By Blacky Ducky in forum C++ Programming
    Replies: 6
    Last Post: 07-16-2011, 09:44 PM
  5. State machine
    By sergio in forum General Discussions
    Replies: 3
    Last Post: 07-03-2009, 09:03 AM

Tags for this Thread