最简洁的单片机状态机模型(X-状态机)

发布时间:2023-01-30  

单片机如果控制的设备趋向复杂,使用状态机模式写程序会更清晰,但是网上讲的状态机图晦涩难懂,实际状态机就是一张表,并且这张表对应单片机的输入输出引脚就能完成大部分状态罗列。


看问题看本质,单片机内部运行的程序用户不关心,但是单片机显示、发声、按键操作、控制设备是最关注的。


把输入组合作为条件,输出仅做动作,就是最简洁的单片机状态机。


为了与通常所讲的状态机模型区分,个人给这个状态机模型起个名字: X-状态机 (X-FSM)


输入可以是传感器、按键、开关信号等

输出可以是开关信号、数码管显示、LCD显示、蜂鸣器、语音喇叭发声、指示灯等。


一图胜万言,一表见真章:

表一(行输出,列输入)

表二

有限状态机FSM(Finite State Machine)及实现方式介绍

表一 是向导个人简化的单片机状态表

表二 是目前通用的状态机表示方法

首先为什么简化成关注单片机输出输出的状态机模型:


单片机资源容量受限 所以将传感器、按键等输入作组合

直接借鉴单片机的状态寄存器作为条件组合

X-状态机与流行的通用状态机模型区别:


通用型实际上是将输出组合的变化作为初态和次态

X-状态机实际上主要输入作为条件,输出作为状态

通用型状态机关注于初态、次态、条件判断

X-状态机不关心初态、次态,依照单个输出反推输入条件组合

更好的理解X-状态机本质:


简化后的X-状态机将多维(多个条件组合)的结构变成单层结构,简化设计

事物的本质之一为 (输入-->本体-->输出),也就是接收到一定刺激、做出一定反馈

输入基本上可以分为两种,一种是连续量(模拟量)一种是开关量(数字量)

连续量: 例如温度变化、时间变化,开关量:各种开关

处理连续量除非是显示,实际上也可以转换为有限判断,例如温度到达多少度作为一个条件

连续量分几档(看表一 温度状态)+开关---组合成一组(本例16位的条件组合)

开关量一般是多个开关一起判断,例如开机状态下,是否按下某个键

实现:


客户需求变更,程序员只关注增加一个开关量或者一组8位、16位开关量、连续量判断

以一个输出的变化作为状态反推需要的条件组合 举例,加热1输出只有开关两种状态,开的条件和关的条件依照输入确定,可以先关掉,依照一定条件触发开,条件组合少的优先作为触发条件。默认状态是条件组合多的。

其他就是C语言和单片机的通用规则

划重点:

输入组合作为条件

输出仅做动作,输出的动作是输入的变化引起的

输出的变更(客户需求变更)必然引发输入条件变化

最关键的是表一,用传统方式写,状态机表清楚一样事半功倍。

放码过来:


#include "fsm_x.h"



//inputState bit  16bit

#define TEMP_BIT_0 0

#define TEMP_BIT_1_7 1

#define TEMP_BIT_8_13 2

#define TEMP_BIT_14_SETLOW 3

#define TEMP_BIT_SETLOW_SETHIGH 4

#define TEMP_BIT_SETHIGH_HIGH 5

#define TEMP_BIT_HIGH_HHTEMP 6

#define TEMP_BIT_HHTEMP 7  //同

#define WATER_LEVEL_BIT 8

#define POWER_BIT 9

#define TIMER_BIT 10

#define ADD_DEC_BIT 11

//#define DEC_BIT 12

#define WARMUP_BIT 12

#define SLEEP_BIT 13

#define ANION_BIT 14    //彩屏产品用

#define BABY_LOCK_BIT 15 //彩屏产品用


//state bit 扩展位



#define LoadWaterLevelState isWaterLevelLow?Set16(inputState,WATER_LEVEL_BIT):Clr16(inputState,WATER_LEVEL_BIT)

#define LoadPowerState  powerOpen?Set16(inputState,POWER_BIT):Clr16(inputState,POWER_BIT)

#define LoadTimerState  timerOpen?Set16(inputState,TIMER_BIT):Clr16(inputState,TIMER_BIT)

#define LoadAddDecState    isAddOrDec?Set16(inputState,ADD_DEC_BIT):Clr16(inputState,ADD_DEC_BIT)

#define LoadWarmUpState     warmupOpen?Set16(inputState,WARMUP_BIT):Clr16(inputState,WARMUP_BIT)

#define LoadSleepState    sleepOpen?Set16(inputState,SLEEP_BIT):Clr16(inputState,SLEEP_BIT)

#define LoadAnionState    anionOpen?Set16(inputState,SLEEP_BIT):Clr16(inputState,SLEEP_BIT)

#define LoadBabyLockstate babyLockOpen?Set16(inputState,SLEEP_BIT):Clr16(inputState,SLEEP_BIT)


//其他开关量状态装箱

void LoadSwitchState(Bit state,unsigned char stateBit)

{

    state?Set16(inputState,stateBit):Clr16(inputState,stateBit);

}


//此处专用于温度传感器状态装箱

void LoadSensorState(unsigned char sensorValue)

{

    sensorValue<=0? Set16(inputState,TEMP_BIT_0):Clr16(inputState,TEMP_BIT_0);

    (sensorValue>=1)&&(sensorValue<=7)? Set16(inputState,TEMP_BIT_1_7):Clr16(inputState,TEMP_BIT_1_7);

    (sensorValue>=8)&&(sensorValue<=13)? Set16(inputState,TEMP_BIT_8_13):Clr16(inputState,TEMP_BIT_8_13);

    (sensorValue>=14)&&(sensorValue    (sensorValue>=TEMP_NORMAL_DL)&&(sensorValue<=gTempSet)? Set16(inputState,TEMP_BIT_SETLOW_SETHIGH):Clr16(inputState,TEMP_BIT_SETLOW_SETHIGH);

    (sensorValue>gTempSet)&&(sensorValue<=TEMP_HIGH_WARNING)? Set16(inputState,TEMP_BIT_SETHIGH_HIGH):Clr16(inputState,TEMP_BIT_SETHIGH_HIGH);

    (sensorValue>TEMP_HIGH_WARNING)&&(sensorValue<=TEMP_SENSOR_WARNING)? Set16(inputState,TEMP_BIT_HIGH_HHTEMP):Clr16(inputState,TEMP_BIT_HIGH_HHTEMP);

    sensorValue>TEMP_HIGH_WARNING? Set16(inputState,TEMP_BIT_HHTEMP):Clr16(inputState,TEMP_BIT_HHTEMP);

}


void RunFsm(void)

{

    //iputState32=inputState8[3]<<24|inputState8[2]<<16|inputState8[1]<<8|inputState8[0]; //4个字节状态寄存器组合成32位

    //iputState32=inputState16[1]<<16|inputState16[0];//2个字状态寄存器组合成32位状态机 32位状态寄存器

    //switch(inputState32){...}

    //也可以状态表画好(关键) 回归传统方式 直接if(inputState8[0]&&inputState8[1])else if()... 

    switch(inputState)

    {

    case 0b0000000000000001://温度<=0 状态

        CloseHeat1; //关加热器1

        CloseHeat2; //关加热器2

        OpenPump;   //水泵不关 仍然水循环

        show(errorCode,1); //数码管显示错误值

        SendVoice(0x0f); //语音播报温度故障

        errorCode=0xE0; //温度小于等于0度

        FlashLed(); //所有Led闪烁

        break;


    case 0b0000000000000010:

        //温度在1~7状态

        break;

        //...

    }

}


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    谈谈单片机编程思想——状态机;玩单片机还可以,各个外设也都会驱动,但是如果让你完整的写一套代码时,却无逻辑与框架可言。这说明编程还处于比较低的水平,你需要学会一种好的编程框架或者一种编程思想!比如模块化编程......
    单片机的状态机编程思路;不知道大家有没有这样一种感觉,就是感觉自己玩单片机还可以,各个功能模块也都会驱动,但如果让你完整地写一套代码,却无逻辑与框架可言,上来就是开始写!东抄抄西抄抄,说明编程......
    最简洁的单片机状态机模型(X-状态机);单片机如果控制的设备趋向复杂,使用状态机模式写程序会更清晰,但是网上讲的状态机图晦涩难懂,实际状态机就是一张表,并且这张表对应单片机的输入输出引脚就能完成大部分状态......
    单片机编程思想——状态机;本文来说一下状态机编程。 什么是状态机状态机(state machine)有5个要素: ·状态(state) ·迁移(transition) ·事件(event......
    STM32按键消抖——入门状态机思维;在嵌入式软件开发中,状态机编程是一个十分重要的编程思想,它也是嵌入式开发中一个常用的编程框架。掌握了状态机编程思想,可以......
    。 如果你是大学生,未来想从事这个行业,我建议还是以单片机开发学习为主,否则可能对找工作不利。 很多人之所以觉得单片机编程难,很大原因是学习的路径不清晰。 这就导致你在学习的时候可能完全懵逼状态......
    单片机是什么?单片机编程怎么入门?;我不是电子专业毕业,后面是通过自学的单片机进入了这个行业。 当初我和很多人一样,不知道单片机是什么。 网上搜集了一些资料,说的太学术化,看的云里雾里。 今天......
    keil单片机编程软件的使用方法说明;单片机编程软件的使用尤为必要,每一款单片机编程软件都有各自特色。大家在选用单片机编程软件时,可依据自身情况而定。本文对单片机编程软件的介绍基于Keil,主要......
    盘点那些常见的单片机编程框架!;随着科技的不断发展,单片机已经广泛应用于各种各样的领域。而随着单片机编程的需求越来越大,编程框架也变得越来越重要。本文将为大家盘点常见的单片机编程框架。 1......
    很多人说单片机很简单,有些本专业学生为什么学起来这么吃力?;在网上看到这么一个话题,自己特别有感触,不自觉的想写一下自己的看法。 单片机编程,我们的教材是《单片机原理及应用》。 当时我们的很多同学都觉得单片......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>