C语言——简单状态机

文章介绍了状态机的概念,包括状态、转移、动作和事件等核心元素,并通过逐步示例展示了如何在单片机编程中使用状态机,从简单的基于标志位的任务切换到优化后的switch语句,再到封装的状态机实现,强调了状态机在项目中的高内聚低耦合优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

状态机:一般指有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机(英语:finite-state automaton,缩写:FSA),是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型

状态机中有几个术语:state(状态) 、transition(转移) 、action(动作) 、transition condition(转移条件) 。

  • state(状态) :将一个系统离散化,可以得到很多种状态,当然这些状态是有限的。例如:门禁闸机可以划分为开启状态、关闭状态;电扇可以划分为关、一档、二档、三档等状态。
  • transition(转移) :一个状态接收一个输入执行了某些动作到达了另外一个状态的过程就是一个transition(转移)。定义transition(转移)就是在定义状态机的转移流程。
  • transition condition(转移条件) :也叫做Event(事件),在某一状态下,只有达到了transition condition(转移条件),才会按照状态机的转移流程转移到下一状态,并执行相应的动作。
  • action(动作):在状态机的运转过程中会有很多种动作。如:进入动作(entry action)[在进入状态时进行]、退出动作(exit action)[在退出状态时进行]、转移动作[在进行特定转移时进行]。

如下图,就定义了一个只有opened 和closed两种状态的状态机。当系统处于opened状态,在收到输入“关闭事件”,达到了状态机转移条件,系统就转移到了closed状态,并执行相应的动作,此例有一个进入动作(entry action),进入closed状态,会执行close door动作。

状态机转换示意图

二、简单状态机

相信读者们刚入门学习单片机的时候,应该比较常使用标志位来触发任务运行,例如,通过按键来控制LED灯的亮灭,这就是简单的状态机。

1.简单示例:

// 主函数
int main()
{
    int flag = 0;
    while (1)
    {
        if( flag == 0 )
        {
            task_A();
        }
        else if( flag == 1 )
        {
            task_B();
        }
        else if( flag == 2 )
        {
            task_C();
        }
        ......
    }
}

2.代码优化:

往往判断语句太多不利于阅读,那就需要对上面的代码进行优化:

// 主函数
int main()
{
    int flag = 0;
    while (1)
    {
        switch (flag)
        {
        case 0x00:
            task_A();
            break;
        case 0x01:
            task_B();
            break;
        case 0x02:
            task_C();
            break;
        ......
        default:
            break;
        }
    }
}

 3.封装状态机:

在项目中使用状态机往往需要封装一下,避免全局变量标志到处飞就不好修改和维护项目,最好的方法就是高内聚低耦合

void test(void)
{
    static state;
    if( state == 0 )
    {
        if( !task_A() )
        {
            state = 1;
        }
    }
    else if( state == 1 )
    {
        if( !task_B() )
        {
            state = 2;
        }
    }
    else if( state == 2 )
    {
        if( !task_C() )
        {
            state = 0;
        }
    }
}

int main()
{
    while (1)
    {
        test();
    }
}

三、完整示例

简单写个小demo,加深一下对状态机的理解,这些状态都是面向有限的状态而言。

#include "stdio.h"
#include "stdint.h"

typedef struct
{
    uint8_t flag;
}task_struct;

// 触发任务
void task_open(task_struct *task)
{
    if (!task->flag)
    {
        task->flag = !task->flag;
    }
}

// 关闭任务
void task_close(task_struct *task)
{
    if (task->flag)
    {
        task->flag = !task->flag;
    }
}

// 任务初始化
void task_init(void)
{
    /* 初始化 */
    // printf("test init\n");
}

// 任务处理
void task_handle(void)
{
    printf("test handle\n");
}

// 轮训任务
void task_A(task_struct *task, uint8_t type)
{
    if (!task->flag)
    {
        task_init();
    }
    else
    {
        if (!type)
        {
            /* 单次执行 */
            task_handle();
            /* 关闭任务 */
            task_close(task);
        }
        else
        {
            /* 循环执行 */
            task_handle();
        }
    }
}

int main()
{
    task_struct taskA;
    task_open(&taskA);
    while (1)
    {
        task_A(&taskA, 0);
    }

}

 #END

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值