FSM mealy型状态机实现

news/2024/7/5 6:13:34

FSM mealy型状态机实现

  • FSM 状态机的概念
  • FSM 状态
  • FSM 状态机
  • FSM 输入信号处理&状态切换
  • FSM 状态的行为

  • FSM(finite-state machine) 有限状态机。
  • mealy型状态机:输入不仅与当前状态有关,还与输入有关;

FSM 状态机的概念

有限状态机(finite-state machine,FSM)可以解决有限个状态转换的问题。


  • 状态:表示对象的某种形态,在当前形态下可能会拥有不同的行为和属性。
  • 状态机:每一个时刻只能处于一个状态;拥有对象所有状态的集合;会接受输入,并根据对象当前的状态转换到下一个状态
  • 输出:确切的说,输出指转换到某个状态后,在这个状态内对象所有的行为、表现等都是输出。
  • 动作:指状态机的行为,包括进入状态动作,离开状态动作

以FSM为例,常见的FSM灯的控制大致可以分为几种状态

  • 熄灭状态
  • 常亮状态
  • 闪烁状态

FSM状态切换如图所示:

在这里插入图片描述

FSM 状态

我们将FSM的状态以枚举的形式定义出来。为了方便,我们将默认状态值设置为0,用C表示如下:

typedef enum
{
    FSM_STATE_OFF = 0, // 熄灭状态
    FSM_STATE_ON,      // 常亮状态
    FSM_STATE_BLINK,   // 闪烁状态
    FSM_STATE_BUTTON,  // 状态阈值
} e_FSM_STATE;

对于 FSM 有限状态机中的每一个状态而言,我们可以将状态的行为大致分为 进入状态 运行状态退出状态 三种形式。用C语言来描述如下:

typedef void (*handle_t)(void);
typedef struct 
{
    char name[20];          // 状态名称
    e_FSM_STATE state;      // 状态
    handle_t action_entry;  // 进入状态
    handle_t action_during; // 运行状态
    handle_t action_exit;   // 退出状态
}fsm_state_t;

至此,我们就能将led所有的状态用一张表来描述出来,用C语言来描述如下:

/****************************************************/
// FSM_STATE_OFF = 0, // 熄灭状态下三种行为
void led_off_entry(void);
void led_off_during(void);
void led_off_exit(void);
/****************************************************/
// FSM_STATE_ON,      // 常亮状态下三种行为
void led_on_entry(void);
void led_on_during(void);
void led_on_exit(void);
/****************************************************/
// FSM_STATE_BLINK,   // 闪烁状态下三种行为
void led_blink_entry(void);
void led_blink_during(void);
void led_blink_exit(void);
/****************************************************/
static fsm_state_t g_fsm_state_table[FSM_STATE_BUTTON] = {
    {"led off", FSM_STATE_OFF, led_off_entry, led_off_during, led_off_exit},
    {"led on", FSM_STATE_ON, led_on_entry, led_on_during, led_on_exit},
    {"led blink", FSM_STATE_BLINK, led_blink_entry, led_blink_during, led_blink_exit},
};
/****************************************************/

FSM 状态机

接下来,我们需要知道状态怎样去运行每个状态的行为函数,由于我们已经将所有的状态抽象成一张表,那么我们如何对状态进行运行呢?
对于mealy状态机,状态的切换是和输入的信号以及当前状态紧密相关的。我们需要知道它输入的信号,当前状态,下一个运行状态(是否需要进行跳转)等。用C语言来描述如下:

typedef struct 
{
    int led_on;
    int led_off;
    int led_blink;
}fsm_sig_t; 

typedef struct 
{
    fsm_sig_t sig;              // 状态机输入信号
    e_FSM_STATE cur_state;      // 当前运行状态
    e_FSM_STATE nxt_state;      // 跳转状态 PWR_STATE_BUTTON:下一次运行的还是当前状态
    fsm_state_t *table;         // 状态表指针 g_fsm_state_table
}fsm_info_t;
static fsm_info_t g_fsm_info;

我们对信号的处理(对状态进行状态在下一节进行详细描述)。
我们先研究状态如何进行运行。

  • 状态机运行
    我们不难想象出,一个状态切换到另一个状态的方式应该是cur_state.exit() -> nxt_state.entry() -> nxt_state.during()。保持一个状态运行行为应该处于cur_state.during()中。
    这个时候我们定义状态类型时,FSM_STATE_BUTTON 状态阈值 就能方便对当前状态是否需要进行切换做出判断。状态机的运行实体函数用C语言来描述如下:
void fsm_machine(void)
{
    g_fsm_info.nxt_state = fsm_machine_get_nxt_state(); // 输入信号切换状态 

    if(g_fsm_info.nxt_state < FSM_STATE_BUTTON)    // 状态跳转
    {
        printf("[FSM] exit:%s,%d\r\n",g_fsm_info.table[g_fsm_info.cur_state].name, g_fsm_info.table[g_fsm_info.cur_state].state);
        g_fsm_info.table[g_fsm_info.cur_state].action_exit();

        g_fsm_info.cur_state = g_fsm_info.nxt_state; 
        printf("[FSM] entry:%s,%d\r\n",g_fsm_info.table[g_fsm_info.cur_state].name, g_fsm_info.table[g_fsm_info.cur_state].state);
        g_fsm_info.table[g_fsm_info.cur_state].action_entry();

        g_fsm_info.nxt_state = FSM_STATE_BUTTON;
        printf("[FSM] during:%s,%d\r\n",g_fsm_info.table[g_fsm_info.cur_state].name, g_fsm_info.table[g_fsm_info.cur_state].state);
        g_fsm_info.table[g_fsm_info.cur_state].action_during();
    }
    else // 状态继续运行
    {
        g_fsm_info.table[g_fsm_info.cur_state].action_during();
    }
}
  • 状态机初始化
    • 清零所有的输入信号。
    • 将初始状态设置成默认状态(0)。
    • 给状态表指针赋值。
    • 第一次进入默认状态时,由于nxt_state = FSM_STATE_BUTTON,在fsm_machine中直接进入cur_state.action_during(),不会进入cur_state.action_entry(),需要提前调用。
void fsm_init(void)
{
    memset(&g_fsm_info.sig,0,sizeof(fsm_sig_t)); // 输入信号清零
    g_fsm_info.cur_state = 0;                   // 默认状态     我们认为初始状态为默认状态 方便移植
    g_fsm_info.nxt_state = FSM_STATE_BUTTON;    // 默认状态运行 设置成状态阈值。
    g_fsm_info.table = &g_fsm_state_table[0];   // 状态表指针

    printf("[FSM] entry:%s,%d\r\n",g_fsm_info.table[g_fsm_info.cur_state].name, g_fsm_info.table[g_fsm_info.cur_state].state);
    g_fsm_info.table[g_fsm_info.cur_state].action_entry(); // 默认状态进入行为
}

FSM 输入信号处理&状态切换

最最最重要的来了~在我们的状态机中,如何实现状态的切换。在上述fsm_machine函数中不难看出,fsm_machine_get_nxt_state是状态机切换的根源。我们将所有的输入信号以及当前状态的组成条件放入此函数中,用来切换状态。
首先,我们认为行为action_entryaction_exit在状态中都是瞬间的,在此状态行为下不应该触发状态切换。

e_FSM_STATE fsm_machine_get_nxt_state(void)
{
    e_FSM_STATE state = FSM_STATE_BUTTON;

    fsm_machin_get_sig(&g_fsm_info.sig);    // 获取信号

    if(g_fsm_info.nxt_state == FSM_STATE_BUTTON) // 在during行为下 
    {
        switch(g_fsm_info.cur_state)
        {
            case FSM_STATE_OFF:     // 熄灭状态
            {
                g_fsm_info.sig.led_off = 0;

                if(g_fsm_info.sig.led_on == 1)
                {
                    state = FSM_STATE_ON;
                }
                else if(g_fsm_info.sig.led_blink == 1)
                {
                    state = FSM_STATE_BLINK;
                }

                break;
            }
            case FSM_STATE_ON:      // 常亮状态
            {
                 g_fsm_info.sig.led_on = 0;

                if(g_fsm_info.sig.led_off == 1)
                {
                    state = FSM_STATE_OFF;
                }
                else if(g_fsm_info.sig.led_blink == 1)
                {
                    state = FSM_STATE_BLINK;
                }
                break;
            }
            case FSM_STATE_BLINK:   // 闪烁状态
            {
                g_fsm_info.sig.led_blink = 0;

                if(g_fsm_info.sig.led_on == 1)
                {
                    state = FSM_STATE_ON;
                }
                else if(g_fsm_info.sig.led_off == 1)
                {
                    state = FSM_STATE_OFF;
                }
                break;
            }
            default:
                break;
        }
    } 

    return state;
}

FSM 状态的行为

/****************************************************/
// FSM_STATE_OFF = 0, // 熄灭状态下三种行为
void led_off_entry(void);
void led_off_during(void);
void led_off_exit(void);
/****************************************************/
// FSM_STATE_ON,      // 常亮状态下三种行为
void led_on_entry(void);
void led_on_during(void);
void led_on_exit(void);
/****************************************************/
// FSM_STATE_BLINK,   // 闪烁状态下三种行为
void led_blink_entry(void);
void led_blink_during(void);
void led_blink_exit(void);
/****************************************************/

http://lihuaxi.xjx100.cn/news/88149.html

相关文章

CISP-PTE考前练习-SQL注入

文章目录题目一&#xff1a;联合查询注入题目二&#xff1a;二次注入题目三&#xff1a;文章发布系统题目四&#xff1a;模拟实战练习摘抄题目一&#xff1a;联合查询注入 第一步 常规的 访问页面发现参数id http://192.168.253.207/PTE/1.Sql_Injection/第二步 尝试闭合 id…

安科瑞IoT能源管理系统解决方案在马来西亚某工厂的应用

安科瑞陈沁雨&#xff1a;1-8-7-0-2-1-1-2-8-7-3 1.应用场景 客户需要收集基本能耗数据并上传到管理系统&#xff0c;以便使用PC实现实时和远程数据监控。 2.技术选择 2.1三相监测电路的额定电压为415Vac L-L&#xff0c;而额定电流低于80A AC&#xff0c;因此计量装置的选…

第26章 物联网软件系统测试

目录 一、主要内容 二、物联网概述 1、物联网定义 2、物联网的三个典型特征 3、物联网应用的三项关键技术 4、物联网的安全架构 三、物联网安全架构的设备层 1、定义 2、保护措施 3、原则 四、物联网安全架构的通信层 1、定义 2、保护措施 3、原则 五、物联网安全架构的云平台层…

python 碰到问题

好的 python 文件具有结构性 一个好的python文件具有结构性&#xff0c;即文件中只含有class, if __name__ "__main__". vscode 中的矩形选择问题 mac中使用快捷键shiftoption鼠标选中 mac 中快捷键 mac 打开网页&#xff0c;轻触鼠标两下&#xff08;但是不按下…

后端发送HTTP请求

后端发送HTTP请求 1 原始方式 背景&#xff1a; get&#xff1a;获取微信的accessToken post&#xff1a;设置微信公众号的自定义菜单 1.1 get方式 //get方式发起请求 public String get(String url){try{URL urlObj new URL(url);//开连接URLConnection connection urlObj…

C# 多线程九 任务Task的简单理解与运用三

目录 方法&#xff1a; ConfigureAwait(Boolean) ContinueWith Delay Dispose() Dispose(Boolean) 说明: FromCanceled(CancellationToken) FromCanceled(CancellationToken) FromResult(TResult) FromException(Exception) FromException(Except…

神经网络识别仿真实验,神经网络算法实验报告

1、关于GAN生成式对抗网络中判别器的输出的问题 ... 摘要 生成式对抗网络GAN&#xff08;Generative adversarial networks&#xff09;目前已经成为人工智能学界一个热门的研究方向.GAN的基本思想源自博弈论的二人零和博弈&#xff0c;由一个生成器和一个判别器构成&#xff…

RN基础组件3 —— Image 和ImageBackground

import {Image} from react-native <Image source{}/> 说明&#xff1a; ①RN中加载图片有两种情形&#xff1a; 情形1&#xff1a;加载一张本地(手机App中)图片 —— 必须使用“导入”把图片从PC机打包入手机中 const p1 require(./img/1.jpg) //把图片打包入手机…