状态机在单片机C程序中的应用
- 格式:doc
- 大小:273.50 KB
- 文档页数:16
单片机中常见的软件bug分析与修复方法在单片机开发过程中,软件bug是难以避免的。
这些bug可能会导致系统崩溃、功能异常或不可预测的行为。
因此,准确分析bug并修复它们至关重要。
本文将针对单片机中常见的软件bug,介绍一些分析和修复方法。
1. 编译错误和警告的处理在单片机软件开发过程中,编译错误和警告是最常见的bug。
编译器通常会提供有关错误和警告的详细信息,例如变量未声明、语法错误或类型不匹配等。
开发者应仔细阅读编译器的输出,查找并修复错误和警告。
2. 内存相关问题的解决内存相关问题可能会导致单片机系统异常甚至崩溃。
常见的内存问题包括栈溢出和堆溢出。
栈溢出通常发生在递归调用或局部变量过多的情况下,可以通过增加栈的大小来解决。
堆溢出通常是由于动态分配的内存没有正确释放导致的,应当对内存的分配和释放进行仔细管理。
3. 时序相关问题的分析与调试时序相关问题可能会导致设备无法按照预期的时间表执行任务,从而导致功能异常。
在分析和调试时序问题时,可以使用逻辑分析仪、示波器和调试器等工具来观察信号的时序关系。
还可以通过增添延时、优化中断服务程序或调整时钟频率等方法来修复时序问题。
4. 中断问题的排查和修复中断是单片机系统中常见的机制,用于处理实时事件或外部信号。
中断问题可能导致系统死锁或响应时间延长等问题。
在排查和修复中断问题时,可以检查中断向量表和中断服务程序的正确性。
还可以逐个排查外部中断源是否正常工作,以确保正确触发中断并及时处理。
5. 状态机的设计与调试在单片机程序中,状态机常用于描述复杂的系统行为。
状态机相关的bug可能导致状态转换错误或系统无法恢复。
为了分析和修复状态机问题,可以通过绘制状态转换图或使用状态转换表来更好地理解系统行为。
同时,使用断点调试和仿真工具来观察状态机的状态转换和变量值变化,以找到问题并进行修复。
6. 输入输出问题的分析和修复输入输出问题是单片机系统中常见的bug类型,可能导致设备无法正确响应输入或输出信号。
五种编程方式实现流水灯的单片机C程序流水灯是一种常见的灯光效果,常用于装饰和展示。
实现流水灯的程序可以使用多种不同的编程方式,包括传统的顺序编程、状态机编程、中断编程、调度器编程和面向对象编程。
下面分别介绍这五种方式实现流水灯的程序。
1.顺序编程方式:顺序编程是最常见的编程方式,也是最直接的方式。
下面是使用顺序编程方式实现流水灯的C程序:```c#include <reg52.h>void delay(unsigned int t)while(t--)for(int i=0; i<50; i++);}void mainunsigned char led = 0x80; // 初始灯光状态while(1)P0 = led; // 输出灯光状态delay(500); // 延时一段时间led >>= 1; // 右移一位,实现流水灯效果if(led == 0) // 到达最右边后重新开始led = 0x80;}}```2.状态机编程方式:状态机编程是一种基于状态的编程方式,通过定义不同的状态和状态转换来实现流水灯效果。
下面是使用状态机编程方式实现流水灯的C程序:```c#include <reg52.h>typedef enumState1,State2,State3,State4,State5} State;void delay(unsigned int t)while(t--)for(int i=0; i<50; i++);}void mainState state = State1; // 初始状态为State1 while(1)switch(state)case State1:P0=0x80;delay(500);state = State2;break;case State2:P0=0x40;delay(500);state = State3;break;case State3:P0=0x20;delay(500);state = State4;break;case State4:P0=0x10;delay(500);state = State5;break;case State5:P0=0x08;delay(500);state = State1;break;}}```3.中断编程方式:中断编程方式是一种基于中断事件的编程方式,通过在特定的中断事件触发时改变灯光状态来实现流水灯效果。
状态机的应用场景1. 自动化控制系统自动化控制系统是现代工业中非常常见的应用场景。
在这些系统中,状态机可以被用来描述系统的运行状态,以及控制系统在状态之间的转移。
例如,在工厂生产线中,一个状态机可以用来描述产品在生产过程中的不同阶段,以及产品在这些阶段之间的转移规则。
通过使用状态机,工程师可以更加清晰地了解系统的行为,方便系统的调试和维护。
2. 编程语言解析器在编程语言解析中,状态机也有着重要的应用。
通过将编程语言的语法规则表示为状态机的形式,可以实现对程序代码的分析和解析。
例如,词法分析器和语法分析器通常使用有限状态机来构建,以便将程序代码分解成语法单元并进行语法分析。
状态机的这种应用可以帮助编程语言解析器更加高效和准确地分析程序代码,提高编程语言开发的效率。
3. 通信协议通信协议是网络通信中非常重要的一部分。
状态机可以被用来描述通信协议在不同状态下的行为,并定义状态之间的转移规则。
通过使用状态机,网络通信系统可以更加清晰地了解通信协议的工作原理,从而更容易地实现通信协议的正确性和稳定性。
状态机在通信协议中的应用有助于提高通信系统的可靠性和性能。
4. 游戏开发在游戏开发中,状态机常常被用来描述游戏中的不同状态和角色之间的转移规则。
例如,在角色扮演游戏中,状态机可以用来描述角色在不同状态下的行为,并定义状态之间的转移规则。
通过使用状态机,游戏开发者可以更好地管理游戏中的复杂逻辑关系,提高游戏的可玩性和趣味性。
状态机在游戏开发中的应用有助于开发者更加灵活地设计游戏,并快速响应玩家的操作。
5. 智能系统在人工智能领域,状态机也有着广泛的应用。
通过将智能系统的行为表示为状态机模型,可以帮助智能系统更好地理解环境和做出合适的决策。
例如,在自动驾驶汽车中,状态机可以用来描述汽车在不同交通情况下的行为,并定义汽车在这些情况下的转移规则。
通过使用状态机,自动驾驶汽车可以更加准确地理解道路情况,避免交通事故,提高行驶的安全性和效率。
单片机的状态机编译单片机是一种微处理器,能够在特定的指令下执行一系列的任务。
在单片机的程序设计中,状态机编译起着非常重要的作用。
状态机是指由一组状态和状态之间的转移所组成的一种模型,它能够描述系统在不同条件下的行为和变化。
状态机编译在单片机的程序设计中具有至关重要的作用。
它能够让程序更加清晰、流畅地执行各种任务,提高代码的可读性和可维护性。
一个良好设计的状态机能够使得程序的逻辑更加清晰明了,易于调试和修改。
在状态机编译中,首先需要定义系统的各个状态,并将其表示为程序中的不同函数或子程序。
这些函数表示了系统在不同的状态下应该执行的操作。
在每个状态函数中,需要编写相应的代码来实现该状态下的任务。
这些任务可以是控制某些硬件设备的操作,或者是根据某些条件进行判断和处理。
在状态机编译中,状态之间的转移也是非常重要的。
转移可以根据条件判断来执行不同的操作,或者根据计时器来定时切换状态。
在每个状态函数中,需要编写相应的代码来决定下一个状态应该是什么,从而实现状态之间的切换。
这些代码可以是简单的if语句或者switch 语句,也可以是更复杂的条件判断表达式。
为了使得状态机编译更加生动和实用,我们可以举一个简单的例子来说明。
假设我们设计了一个智能家居系统,其中有三个状态:待机状态、正常工作状态和故障状态。
在待机状态下,系统会等待用户的操作来切换到其他状态;在正常工作状态下,系统会根据用户的设置来自动控制家居设备的工作;在故障状态下,系统会自动报警并等待用户的处理。
首先,在程序中定义这三个状态,分别表示为idle、working和fault。
然后,编写对应的状态函数,例如idle_state()、working_state()和fault_state()。
在每个状态函数中,编写相应的代码来实现该状态下的任务。
接下来,我们需要定义状态之间的转移条件。
例如,在idle_state()函数中,如果检测到用户的操作,则切换到working状态;在working_state()函数中,如果检测到故障,则切换到fault状态;在fault_state()函数中,如果用户处理完毕,则切换到idle状态。
状态机在ic设计中的作用和意义状态机在IC设计中扮演着非常重要的角色,它是数字电路设计和自动控制系统中的一个基础概念。
状态机的作用主要体现在以下方面:1.描述系统行为:状态机是一种模型化工具,可以描述系统的行为模式和状态转换规则。
通过定义输入和输出信号,以及状态转移条件和动作,可以清晰地描述系统的逻辑关系和动作序列,帮助设计师更好地理解和分析系统行为。
2.分析和验证设计:状态机可以用于形式化验证和验证设计的正确性。
通过状态机的形式化建模,可以应用形式化验证技术对设计进行验证,分析设计中是否存在死锁、冲突等问题。
这样可以在设计阶段发现和解决潜在的问题,提高设计的可靠性和稳定性。
3.驱动复杂控制逻辑:在许多系统中,特别是在通信、网络和计算机体系结构中,存在着复杂的控制逻辑。
状态机可以用于驱动这些复杂的逻辑,指导数据的处理和动作的执行。
通过将复杂逻辑拆分为不同状态和状态转移条件,可以降低系统设计的复杂度和难度。
4.多线程控制:在多线程系统中,状态机可以用于控制不同线程之间的协调和同步。
通过定义不同的状态和状态转移条件,可以控制不同线程的执行顺序,避免冲突和竞争条件,提高系统的效率和性能。
5.识别和解析序列:在通信和协议分析中,状态机可以用于识别和解析输入序列。
通过定义状态和状态转移条件,可以建立输入信号和操作的对应关系,识别和解析复杂的通信协议和数据格式,以实现有效的数据处理和解析。
6.功耗优化:状态机可以用于实现功耗优化策略。
通过定义不同的状态和状态转移条件,可以根据输入信号的变化情况选择合适的动作和操作,以减少功耗的消耗和资源的使用,提高系统的能效和性能。
7.逻辑综合与优化:在数字电路的设计中,逻辑综合是将高层次的设计描述转换为低层次的门级电路描述的过程。
状态机可以作为逻辑综合的重要输入,通过状态机的描述,可以进行逻辑综合和优化,优化电路的布局和布线,提高电路的性能和可靠性。
总之,状态机在IC设计中具有重要的作用和意义。
状态机在ic设计中的作用和意义摘要:1.引言2.状态机的基本概念和原理3.状态机在IC 设计中的应用4.状态机在IC 设计中的重要性5.总结正文:【引言】在现代电子技术中,集成电路(IC)的设计和应用已经越来越广泛。
状态机作为控制电子设备状态的核心部分,对于IC 设计有着重要的作用和意义。
本文将从状态机的基本概念和原理入手,分析其在IC 设计中的应用和重要性。
【状态机的基本概念和原理】状态机,又称有限状态自动机(FSM),是一种用来表示和控制设备状态的数学模型。
它由一组状态、一组事件和一组动作构成。
状态机根据输入事件,从一个状态转移到另一个状态,同时执行相应的动作。
这种状态转移和动作执行的过程,可以用来描述和控制设备的运行状态。
【状态机在IC 设计中的应用】在IC 设计中,状态机的应用非常广泛。
它被用来控制各种设备的状态,如处理器、存储器、传感器等。
例如,在处理器设计中,状态机被用来控制指令的执行顺序和操作,确保处理器能够正确地处理各种指令。
在存储器设计中,状态机被用来控制存储器的读写操作,确保数据能够正确地被读取和写入。
在传感器设计中,状态机被用来控制传感器的工作状态,确保传感器能够准确地检测到各种物理量。
【状态机在IC 设计中的重要性】状态机在IC 设计中的重要性不言而喻。
首先,状态机能够精确地控制设备的状态,确保设备能够正确地运行。
其次,状态机能够简化设备的控制逻辑,提高设备的运行效率。
最后,状态机能够提高设备的可靠性,延长设备的使用寿命。
【总结】总的来说,状态机在IC 设计中起着重要的作用,不仅能够精确地控制设备的状态,提高设备的运行效率,还能够提高设备的可靠性,延长设备的使用寿命。
单片机状态机写法单片机(Microcontroller)中的状态机(State Machine)是一种常见的编程方法,用于管理复杂系统的状态和行为。
通过定义一组状态以及在这些状态之间转换的规则,状态机可以清晰地表示系统的动态行为。
以下是一个简单的状态机在单片机中的写法示例,假设我们正在为一个LED灯编写控制程序,LED灯有三种状态:关闭(OFF)、闪烁(BLINK)和常亮(ON)。
c#include <stdio.h>#include <stdint.h>// 定义LED灯的状态typedef enum {STATE_OFF,STATE_BLINK,STATE_ON} LedState;// 定义LED灯结构体typedef struct {LedState state; // 当前状态uint8_t blink_count; // 闪烁计数器} LedController;// 初始化LED灯void led_init(LedController *led) {led->state = STATE_OFF;led->blink_count = 0;}// 更新LED灯状态void led_update(LedController *led) { switch (led->state) {case STATE_OFF:// 在此处添加关闭LED的代码 break;case STATE_BLINK:// 根据闪烁计数器切换LED状态if (led->blink_count % 2 == 0) { // 在此处添加打开LED的代码} else {// 在此处添加关闭LED的代码}led->blink_count++;if (led->blink_count >= 10) {led->blink_count = 0;}break;case STATE_ON:// 在此处添加打开LED的代码break;default:// 未知状态处理break;}}// 设置LED灯状态void led_set_state(LedController *led, LedState state) { led->state = state;}int main() {LedController led;led_init(&led);// 设置LED为闪烁状态led_set_state(&led, STATE_BLINK);// 模拟LED灯更新for (int i = 0; i < 20; i++) {led_update(&led);printf("Update LED\n");}return 0;注意:上述代码是一个简化的示例,用于说明状态机在单片机中的基本实现。
状态机思路在单片机程序设计中的应用状态机的概念状态机是软件编程中的一个重要概念。
比这个概念更重要的是对它的灵活应用。
在一个思路清晰而且高效的程序中,必然有状态机的身影浮现。
比如说一个按键命令解析程序,就可以被看做状态机:本来在A状态下,触发一个按键后切换到了B状态;再触发另一个键后切换到C状态,或者返回到A状态。
这就是最简单的按键状态机例子。
实际的按键解析程序会比这更复杂些,但这不影响我们对状态机的认识。
进一步看,击键动作本身也可以看做一个状态机。
一个细小的击键动作包含了:释放、抖动、闭合、抖动和重新释放等状态。
同样,一个串行通信的时序(不管它是遵循何种协议,标准串口也好、I2C也好;也不管它是有线的、还是红外的、无线的)也都可以看做由一系列有限的状态构成。
显示扫描程序也是状态机;通信命令解析程序也是状态机;甚至连继电器的吸合/释放控制、发光管(LED)的亮/灭控制又何尝不是个状态机。
当我们打开思路,把状态机作为一种思想导入到程序中去时,就会找到解决问题的一条有效的捷径。
有时候用状态机的思维去思考程序该干什么,比用控制流程的思维去思考,可能会更有效。
这样一来状态机便有了更实际的功用。
程序其实就是状态机。
也许你还不理解上面这句话。
请想想看,计算机的大厦不就是建立在“0”和“1”两个基本状态的地基之上么?状态机的要素状态机可归纳为4个要素,即现态、条件、动作、次态。
这样的归纳,主要是出于对状态机的内在因果关系的考虑。
“现态”和“条件”是因,“动作”和“次态”是果。
详解如下:①现态:是指当前所处的状态。
②条件:又称为“事件”。
当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
③动作:条件满足后执行的动作。
动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。
动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
④次态:条件满足后要迁往的新状态。
“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
状态机思路在单片机程序设计中的应用1,状态机的概念:状态机是软件编程中的一个重要概念。
比这个概念更重要的是对它的灵活应用。
在一个思路清晰而且高效的程序中,必然有状态机的身影浮现。
比如说一个按键命令解析程序,就可被看做状态机:本来在A状态下,触发一个按键后切换到了B状态;再触发另一个键后切换到C状态,或者返回到A状态。
最简按键状态机例。
实际按键解析程序比这更复杂,但不影响我们对状态机的认识。
进一步,击键动作本身也可看做一个状态机。
一个细小的击键动作包含了:释放、抖动、闭合、抖动和重新释放等状态。
同样,一个串行通信的时序(不管它是遵循何种协议,标准串口也好、I2C也好;也不管它是有线的、还是红外的、无线的)也都可看做由一系列有限的状态构成。
显示扫描程序也是状态机;通信命令解析程序也是状态机;甚至连继电器的吸合/释放控制、发光管(LED)的亮/灭控制又何尝不是个状态机。
当我们打开思路,把状态机作为一种思想导入到程序中去时,就会找到解决问题的一条有效的捷径。
有时候用状态机的思维去思考程序该干什么,比用控制流程的思维去思考,可能会更有效。
这样一来状态机便有了更实际的功用。
2,程序其实就是状态机:也许你还不理解上面这句话。
请想想看,计算机的大厦不就是建立在“0”和“1”两个基本状态的地基之上么?3,状态机的要素:状态机可归纳为4个要素,即现态、条件、动作、次态。
这样的归纳,主要是出于对状态机的内在因果关系的考虑。
“现态”和“条件”是因,“动作”和“次态”是果。
详解如下:①现态:是指当前所处的状态。
②条件:又称为“事件”。
当一条件被满足,将触发一动作,或执行一状态的迁移。
③动作:条件满足后执行的动作。
动作执行完毕后,可迁移到新状态,也可仍旧保持原状。
动作非必需的,当条件满足后,也可不执行任何动作,直接迁移到新状态。
④次态:条件满足后要迁往的新状态。
“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
若我们进一步归纳,把“现态”和“次态”统一起来,而把“动作”忽略(降格处理),则只剩下两个最关键的要素,即:状态、迁移条件。
状态机的表示方法有多种,可用文字、图形或表格的形式来表示一个状态机。
纯粹用文字描述是很低效的,所以就不介绍了。
接下来先介绍图形的方式。
4,状态迁移图(STD):状态迁移图的画法有许多种,不过一般都大同小异。
我们结合一个例子来说明一下它的画法,如图1所示。
图1 状态迁移图①状态框:用方框表示状态,包括所谓的“现态”和“次态”。
②条件及迁移箭头:用箭头表示状态迁移的方向,并在该箭头上标注触发条件。
③节点圆圈:当多个箭头指向一个状态时,可用节点符号(小圆圈)连接汇总。
④动作框:用椭圆框表示。
⑤附加条件判断框:用六角菱形框表示。
状态迁移图和我们常见的流程图相比有着本质的区别,具体体现为:在流程图中,箭头代表了程序PC指针的跳转;而在状态迁移图中,箭头代表的是状态的改变。
我们会发现,这种状态迁移图比普通程序流程图更简练、直观、易懂。
这正是我们需要达到的目的。
状态迁移表除了状态迁移图,我们还可用表格的形式来表示状态之间的关系。
这种表一般称为状态迁移表。
表1就是前面介绍的那张状态迁移图的另一种描述形式。
表1 状态迁移表状态(现态)状态描述条件动作次态状态1 条件1 状态2条件2 动作1 状态3状态2 条件3 附加条件满足状态4 附加条件不满足状态3条件5 状态1条件6 动作2 状态2状态3 条件4 状态4条件5 状态1 状态4 条件5 状态1①采用表格方式来描述状态机,优点是可容纳更多的文字信息。
例如,我们不但可在状态迁移表中描述状态的迁移关系,还可把每个状态的特征描述也包含在内。
②若表格内容较多,过于臃肿不利于阅读,我们也可将状态迁移表进行拆分。
经过拆分后的表格根据其具体内容,表格名称也有所变化。
③比如,我们可把状态特征和迁移关系分开列表。
被单独拆分出来的描述状态特征的表格,也可称为“状态真值表”。
这其中比较常见的就是把每个状态的显示内容单独列表。
这种描述每个状态显示内容的表称之为“显示真值表”。
同样,我们把单独表述基于按键的状态迁移表称为“按键功能真值表”。
另外,若每一个状态包含的信息量过多,我们也可把每个状态单独列表。
④由此可见,状态迁移表作为状态迁移图的有益补充,它的表现形式是灵活的。
⑤状态迁移表优点是信息涵盖面大,缺点是视觉上不够直观,因此它并不能取代状态迁移图。
比较理想的是将图形和表格结合应用。
用图形展现宏观,用表格说明细节。
二者互为参照,相得益彰。
用状态机思路实现一个时钟程序接下来,我将就状态机的应用,结合流程图、状态迁移图和状态迁移,举一个实际例子。
下面这张图是一个时钟程序的状态迁移图,如图2所示。
图2 时钟程序状态迁移图把这张图稍做归纳,就可得到它的另一种表现形式——状态迁移表,如表2所示。
表2 时钟程序状态迁移表工作状态(现态)A键B键显示内容编号说明次态功能次态功能0 显示时间 1 - 3 - 时:分:秒(12:00:00)1 显示闹钟2 - 5 - 时:分(12:00)2 显示秒表0 - - 启动/停止时:分:秒(12:00:00)3 设置小时- 时+14 - (12:▋▋:▋▋)4 设置分钟- 分+1;秒=0 0 - (▋▋:00:00)5 设置闹钟“时”- 时+16 - (TM:00:▋▋)6 设置闹钟“分”- 分+17 - (TM:▋▋:00)状态机应用的注意事项基于状态机的程序调度机制,其应用的难点并不在于对状态机概念的理解,而在于对系统工作状态的合理划分。
初学者往往会把某个“程序动作”当作是一种“状态”来处理。
我称之为“伪态”。
那么如何区分“动作”和“状态”。
本匠人的心得是看二者的本质:“动作”是不稳定的,即使没有条件的触发,“动作”一旦执行完毕就结束了;而“状态”是相对稳定的,若没有外部条件的触发,一个状态会一直持续下去。
初学者的另一种比较致命的错误,就是在状态划分时漏掉一些状态。
我称之为“漏态”。
“伪态”和“漏态”这两种错误的存在,将会导致程序结构的涣散。
因此要特别小心避免。
更复杂的状态机前面介绍的是一种简单的状态结构。
它只有一级,并且只有一维,如图3所示。
图3 线性状态机结构若有必要,我们可建立更复杂的状态机模型。
1 多级状态结构状态机可是多级的。
在分层的多级状态机系统中,一“父状态”下可划分多个“子状态”,这些子状态共同拥有上级父状态的某些共性,同时又各自拥有自己的一些个性。
在某些状态下,还可进一步划分子状态。
如我们可把前面的时钟例子修改如下:把所有和时钟功能有关的状态,合并成1个一级状态。
在这个状态下,又可划分出3个二级子状态,分别为显示时间、设置小时、设置分钟;下,再划分出4个二级子状态,分别为显示闹钟、设置“时”、设置“分”、设置鸣叫时间。
我们需要用另一个状态变量(寄存器)来表示这些子状态。
子状态下面当然还可有更低一级的孙状态(子子孙孙无穷尽也),从而将整个状态体系变成了树状多级状态结构,如图4所示。
图4 树状多级状态结构2 多维状态结构状态结构也可是多维的。
从不同的角度对系统进行状态的划分,这些状态的某些特性是交叉的。
比如,在按照按键和显示划分状态的同时,又按照系统的工作进程做出另一种状态划分。
这两种状态划分同时存在,相互交叉,从而构成了二维的状态结构空间。
举一个这方面的例子,如:空调遥控器,如图5所示。
图5 多维状态机结构同样,我们也可构建三维、四维甚至更多维的状态结构。
每一维的状态都需要用一个状态变量(寄存器)来表示。
无论多级状态结构和多维状态结构看上去多么迷人,匠人的忠告是:我们依然要尽可能地简化状态结构,能用单级、单维的结构,就不要给自己找事,去玩那噩梦般的复杂结构。
简单的才是最有效的。
结束语对状态机的理解需要一个由浅入深的过程。
这个过程应该是与实践应用和具体案例思考相结合的。
当一种良好的思路成为设计的习惯,它就能给设计者带来回报。
愿这篇手记里介绍的基于状态机的编程思路能给新手们带来一些启迪,帮助大家找到“程序设计”的感觉。
【转载1】有限状态机的实现< type="text/javascript">有限状态机(Finite State Machine或者Finite State Automata)是软件领域中一种重要的工具,很多东西的模型实际上就是有限状态机。
最近看了一些游戏编程AI的材料,感觉游戏中的AI,第一要说的就是有限状态机来实现精灵的AI,然后才是A*寻路,其他学术界讨论比较多的神经网络、模糊控制等问题还不是很热。
FSM的实现方式:1)switch/case或者if/else这无意是最直观的方式,使用一堆条件判断,会编程的人都可做到,对简单小巧的状态机来说最合适,但是毫无疑问,这样的方式比较原始,对庞大的状态机难以维护。
2)状态表维护一个二维状态表,横坐标表示当前状态,纵坐标表示输入,表中一个元素存储下一个状态和对应的操作。
这一招易于维护,但是运行时间和存储空间的代价较大。
3)使用State Pattern使用State Pattern使得代码的维护比switch/case方式稍好,性能上也不会有很多的影响,但是也不是100%完美。
不过Robert C. Martin做了两个自动产生FSM代码的工具,for java和for C++各一个,在/resources/index上有免费下载,这个工具的输入是纯文本的状态机描述,自动产生符合State Pattern的代码,这样developer的工作只需要维护状态机的文本描述,每必要冒引入bug的风险去维护code。
4)使用宏定义描述状态机一般来说,C++编程中应该避免使用#define,但是这主要是因为若用宏来定义函数的话,很容易产生这样那样的问题,但是巧妙的使用,还是能够产生奇妙的效果。
MFC就是使用宏定义来实现大的架构的。
在代码中可3)中状态机描述文本一样写,通过编译器的预编译处理产生1)一样的效果,我见过产生C代码的宏,若要产生C++代码,己软MFC可,那么理论上也是可行的。
这儿以四位密码校验作为状态机的例子,连续输入2479就可通过密码测试。
一个非常简单的例子,在实际的状态机实例中,状态转移表要更復雜一些,不過方式非常類似。
在狀態查詢的地方可做優化,同時對于輸入量也可做有效性優化。
具體代碼如下:view plaincopy to clipboardprint?c.htypedef enum{STATE1 = 1,STATE2,STATE3,STATE4,STATE5,//password pass//...ADD here}STATE;typedef enum{INPUT1 = '2',INPUT2 = '4',INPUT3 = '7',INPUT4 = '9',}INPUT;typedef struct{STATE cur_state;INPUT input;STATE next_state;}STATE_TRANS;c.htypedef enum{STATE1 = 1,STATE2,STATE5,//password pass//...ADD here}STATE;typedef enum{INPUT1 = '2',INPUT2 = '4',INPUT3 = '7',INPUT4 = '9',}INPUT;typedef struct{STATE cur_state;INPUT input;STATE next_state;}STATE_TRANS;c.c#include <stdio.h>#include "c.h"STATE_TRANS state_trans_arry[] ={{STATE1,INPUT1,STATE2},{STATE2,INPUT2,STATE3},{STATE3,INPUT3,STATE4},{STATE4,INPUT4,STATE5},};#define STATE_TRANS_CNT (sizeof(state_trans_arry)/sizeof(state_trans_arry[0]))int main(){STATE state_machine = STATE1;while(ch != 'e'){ch = getchar();if((ch >= '0') && (ch <= '9'))//for digit password input only{for(i = 0;i < STATE_TRANS_CNT;i++){if((ch == state_trans_arry[i].input) && (state_machine == state_trans_arry[i].cur_state)){state_machine = state_trans_arry[i].next_state;continue;}else if(i == (STATE_TRANS_CNT - 1))//no transfer match,reset state{state_machine = STATE1;}}if(state_machine == STATE5)printf("Password correct,state transfer machine pass!\n");}}return 0;}c.c#include <stdio.h>#include "c.h"STATE_TRANS state_trans_arry[] ={{STATE1,INPUT1,STATE2},{STATE2,INPUT2,STATE3},{STATE3,INPUT3,STATE4},#define STATE_TRANS_CNT (sizeof(state_trans_arry)/sizeof(state_trans_arry[0]))int main(){int i;char ch;STATE state_machine = STATE1;while(ch != 'e'){ch = getchar();if((ch >= '0') && (ch <= '9'))//for digit password input only{for(i = 0;i < STATE_TRANS_CNT;i++){if((ch == state_trans_arry[i].input) && (state_machine == state_trans_arry[i].cur_state)){state_machine = state_trans_arry[i].next_state;continue;}else if(i == (STATE_TRANS_CNT - 1))//no transfer match,reset state{state_machine = STATE1;}}if(state_machine == STATE5)printf("Password correct,state transfer machine pass!\n");}}return 0;}状态图--一个图的数据结构!1.while + switch;2.状态机:是指定系统的所有可能的状态及状态间跳转的条件,然后设一个初始状态输入给这台机器,机器就会自动运转,或最后处于终止状态,或在某一个状态不断循环。