历史上的今天
返回首页

历史上的今天

今天是:2026年01月30日(星期五)

正在发生

2023年01月30日 | 最简洁的单片机状态机模型(X-状态机)

2023-01-30 来源:zhihu

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


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


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


为了与通常所讲的状态机模型区分,个人给这个状态机模型起个名字: 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;

        //...

    }

}


推荐阅读

史海拾趣

General Semiconductor ( Vishay )公司的发展小趣事

Vishay一直致力于技术创新和产品升级。在2001年,公司收购了全球二极管和整流器领先制造商General Semiconductor,这一收购极大地增强了Vishay在二极管和整流器领域的实力。同时,Vishay还通过收购RFWaves公司,涉足无线领域,为公司带来了新的增长动力。此外,Vishay还在全球范围内布局制造基地和销售办事处,确保能够为客户提供优质的产品和服务。

FWBELL公司的发展小趣事
根据电压比较器的输出信号控制充电电流的大小和充电模式。
Astro Tool Corp公司的发展小趣事

在市场竞争日益激烈的背景下,Astro Tool Corp公司始终坚持以创新驱动发展。公司不断投入研发资金,引进先进技术和设备,推出了一系列具有创新性和竞争力的新产品。这些产品不仅满足了客户日益多样化的需求,也为公司带来了可观的利润。同时,公司还注重人才培养和团队建设,打造了一支高效、专业的研发团队,为公司的持续发展提供了有力保障。

GarrettCom公司的发展小趣事

研发:GarrettCom(现为Belden的一部分)始终将技术创新作为企业发展的核心驱动力。公司不断投入研发资源,致力于开发更加先进、可靠的工业网络通信产品。通过持续的技术创新,GarrettCom不仅推动了工业通信技术的进步,还为客户提供了更加高效、便捷的通信解决方案。

应用:这些创新产品被广泛应用于工业自动化、交通监控、能源管理等多个领域,为客户创造了巨大的价值。同时,GarrettCom还积极参与国际标准的制定和推广工作,为行业的标准化发展做出了积极贡献。

Broadcom(博通)公司的发展小趣事

2015年,博通迎来了历史性的时刻。安华高科技以170亿美元现金与200亿美元的股票,合计370亿美元并购了博通,使其成为安华高科技的子公司。这一并购不仅使博通获得了更多的资源和支持,也为其后续的快速发展奠定了坚实的基础。此后,博通通过一系列的并购活动,不断扩张其业务范围和市场份额。

Deltrol Controls公司的发展小趣事

随着电子设备的日益复杂,对内部连接件的要求也越来越高。Deltrol Controls意识到,传统的连接方式已经无法满足行业的需求。为此,公司投入大量资金研发新型软管组件,该组件不仅具有优异的耐温、耐压性能,而且安装简便、维护方便。这一突破性的产品迅速赢得了客户的青睐,Deltrol Controls在电子行业的影响力也进一步扩大。

问答坊 | AI 解惑

状态机资料

状态机资料的资料,设计例子加资料…

查看全部问答>

PMO与PDT

项目管理办公室(Project Management Office)是为让企业内共享项目管理的技能、经验等而建立的全公司的一个职能性组织。在企业中,它可能有各种各样的称谓,比如:产品线管理办(Product-line Management Office)、项目管理办、运作支撑部等等。 ...…

查看全部问答>

EVC下的Process.h问题

现在我要把一个VC下的控制台程序移植到EVC环境下,我装了EVC 4.0 , SP4 和Standard SDK,但还是发现没有Process.h和errno.h等一些C库函数,怎么解决这个问题呢?我从网上看到 说有人整理了这些文件,licence是LGPL的. LGPL是什么意思呢?我想最好能 ...…

查看全部问答>

请教一下CE下开发多语言程序的问题(MUI)

最近需要解决CE下开发多语言程序的问题 在论坛上找到一个相关的帖子,使用资源DLL实现的。 http://community.eeworld.net/Expert/TopicView3.asp?id=5679121 这个简单。 -- 我看CE的帮助文档里有MUI(Multilingual User Interface)的内容,应该 ...…

查看全部问答>

STM32:如何关联:“stm32f10x_vector.c”文件?

在 STM32 Firmware library 目录:...STM32F10xFWLibFWLibprojectRIDE  有一个stm32f10x_vector.c  文件, 这个 ..._vector.c  就是跟中断向量有关的吧。对于 Ride7  ...…

查看全部问答>

我的CAN模块程序 出现这样的错误 求高手解答啊!

我在调试LM3S9L97板子的Can模块时 系统一直提示identifier \"GPIO_PB4_CAN0RX\" is undefined 但是 我在上面已经声明了 #define PART_LM3S9L97#include \"driverlib/pin_map.h\"了啊   下面是我的can模块的初始化代码 SysCtlPeripheralEn ...…

查看全部问答>

单片机用汇编语言的问题

我做的项目本来用ATmega128去驱动SSD1289的屏幕时,使用的是UTFT的代码,结果显示速度不能令人满意。后来发现有人说使用汇编会快一些,后来证实了这个是正确的。 所以我想问,有没有会写关于I2C和SPI的汇编代码?这样能不能使得SD卡读写速度、I2C ...…

查看全部问答>

脉宽参数测量

       前阵子做了个脉宽参数测量仪,好像是12年的电赛题目。        做这个题我主要是基于STC12C5A60S2的硬件资源上折腾的。        首先峰值测量用的是单片机上十位AD,通过在某 ...…

查看全部问答>

最小系统板最后一步,JTAG接口的问题,求助啊

28027最小系统板,如图黄色高亮的地方,jtag接口的电源引脚要不要接到芯片上?? …

查看全部问答>

用protel铺铜问题

我用protel铺铜时如图所示,铜线都是呈十字架的形式和引脚链接,这种连接方式在功率器件上怕不能满足电流的需要,请大家指点如何设置使铺铜像过孔一样是包在一起的…

查看全部问答>