有限状态机在单片机编程中的应用_第1页
有限状态机在单片机编程中的应用_第2页
有限状态机在单片机编程中的应用_第3页
有限状态机在单片机编程中的应用_第4页
有限状态机在单片机编程中的应用_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

学习笔记有限状态机在单片机编程中的应用在单片机编程中,如果在不使用操作系统的情况下同时执行多个任务,可能会遇到下面这些情况:一个任务的执行时间过长,导致其他任务无法及时执行在一些任务中大量使用delay()等函数进行软件延时,这些延时函数占用过多时间,影响其他任务的执行一些复杂任务的程序逻辑不清晰,不便于以后对程序进行维护,或添加新功能本文介绍的有限状态机,可以做到将一个耗时较长的复杂任务分解为多个简单任务,同时使代码逻辑更加清晰,从而解决上述问题。目录:什么是有限状态机有限状态机的作用2.1分解耗时过长的任务2.2避免软件延时对CPU资源造成浪费2.3使程序逻辑更加清晰有限状态机的实现3.1通过switch-casel吾句实现3.2通过Arduino库实现3.3其他方式示例一:按键去抖动程序的优化4.1传统的按键去抖动程序4.2优化后的按键去抖动程序示例二:通过有限状态机实现的闹钟程序后记什么是有限状态机根据维基百科上的定义,有限状态机(finite-statemachine,FSM简称状态机)是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。1为了理解这句话,假设自己还有三天就要考试,这时候就要进入紧张的备考状态,将空闲时间用复习上。但是,为了保证足够的精力,小睡一会儿也是十分有必要的。那么,什么时候复习,什么时候睡觉呢?可以这样描述:在复习的时候:如果感到瞌睡,则睡觉如果没有感觉到瞌睡,则继续复习在小睡的时候:如果感觉不再瞌睡,则开始复习如果感觉依旧瞌睡,则继续睡觉也可通过一幅简单的示意图(也叫「状态转移图」)表示出来:感觉清醒这个例子其实就是一个简单的有限状态机,其中,复习和小睡是两个状态,感觉瞌睡和感觉清醒这两个条件可以使状态发生转换。2另外,ProgrammingBasics3网站上也提供了状态机相关的教程,用形象化的图片解释了什么是有限状态机,可通过此链接访问在嵌入式程序设计中,如果一个系统需要处理一系列连续发生的任务,或在不同的模式下对输入进行不同的处理,常常使用有限状态机实现。例如测量、监测、控制等控制逻辑型应用。4

有限状态机的作用2.1分解耗时过长的任务大家应该都知道,CPU没有并行执行任务的能力。计算机「同时」运行多个程序,其实是多个程序依次交替执行,给人以程序同时运行的错觉。各个程序在什么时候开始执行,执行多长时间后切换到下一个程序,由操作系统决定。单片机执行多任务也是类似的过程,但由于其资源有限,为了节省对CPU和存储空间的占用,在很多情况下没有使用操作系统。这时,单片机中运行的各个任务必须在一定时间内主动执行完毕,才能保证下一个任务能够及时执行对于一些需要长时间执行的任务,例如按键去除抖动、读取和播放MP3文件等,采用有限状态机的方式,将任务划分为多个小的步骤(状态),每次只执行其中的一步。这样,其他任务就有机会「插入」到这个任务之中,确保了各个任务都能按时执行。任务B任务B任务A任务女我要执行一件审斐的事,能否始我让出点时间?任努A:不行,我还没执行完。任务A未使用状态机,其他任会不能及时执行任务史我要执行一件审耍的事'能杏给我让出点时间?任封A:好的.我很快就会把我的第一部分执行完,剩下的时间伽来执行,然后我在执行我的其余部分任务Afill分为三个状态,其他任务可以及时执行

2.2避免软件延时对CPU资源造成浪费对于一些简单的程序,可通过delay(),delay_ms(之类的函数进行软件延时。这些延时函数,一般是通过将某个变量循环递加或递加,到达一定值后跳出循环,从而通过消耗CPU时间实现了延时这种方式虽然简单,但在延时函数执行的过程中,其他程序无法运行,消耗了大量CPU资源。而通过状态机,有助于减少软件延时的使用,提高CPU利用率任务此第一部分延时函数占用

大量时间任务A;第任务此第一部分延时函数占用

大量时间任务A;第二部分满足适当的条件时.发生状态转换未使用状态机

软件延时占用了较多时间使用状态机需要延时的时间可以让其他任务执行请参考下文中的示例一:按键去抖动程序的优化,这一例子展示了如何通过软件延时分解耗时较长的任务,同时减少软件延时的使用。2.3使程序逻辑更加清晰通过状态机,将一个复杂任务划分为多个状态,可以使程序清晰易懂,便于维护。以后想要添加、删除程序中的功能,都会变得非常容易。

113ELLLELIJIllimiLCUULE113ELLLELIJIllimiLCUULE……functionf)…… case…else...switchu—gbtD一2……define顷"return fun2() 5仓…“ ■*扣w.if .else....,…,^..functian()…… LlddSswitch define.return fun2() ^case - els已....….if,gfurKtion()心if,gfurKtion()心程序诺辑不清晰 程序逻辑清晰下文中的示例二:通过状态机实现的闹钟展示了如何通过状态机优化程序逻辑。有限状态机的实现如果使用C语言,switch-case吾句,即可简单地实现有限状态机。3.1通过switch-case语句实现如果使用C语言,switch-case吾句,即可简单地实现有限状态机。/*通过状态机实现的某个任务,*需要放入while(1)等地方循环执行*/switch(currentStatus)/*根据现在的状态执行相应的程序*/^3cOSe^?A?US_A^^状^^*^^^^^^^^^^^^BdoThingsForStatusA();/*执行状态A中需要执行的任务*/*若满足状态转换的条件,则转换到另一个状态*/if(condition_1X^urreniSiatus^^TATUEaB^^^^^^^^^Mbreak;doThingsForStatusB();/*执行状态B中需要执行的任务*/*若满足状态转换的条件,则转换到另一个状态*/if(condition_2){currentStatus=STATUE_C;^^^^^^^^^^if(conditipn_3){^urrenSiatus^^TATUE_A^^^^^^^^^Ibreak;doThingsForStatusB();/*执行状态B中需要执行的任务*/*若满足状态转换的条件,则转换到另一个状态*/if(condition_4)^urrenSatus^^TATUE_Ai^^^^^^^^^lbreak;default:通过这段程序,即可实现一个具有三个状态的状态机。状态转移图如下图所示:3.2通过Arduino库实现对于Arduino用户,还可以使用FSMLibrary实现。这一库将有限状态机进行了封装,可以以更简洁的方式实现状态机。下载地址及使用说明:http://playground.arduino.cc/Code/FiniteStateMachine3.3其他方式对于一些更复杂的任务,使用switch-case语句,代码可能会太简洁。这时候,使用其他方式实现状态机,可能会更好。具体请查阅相关资料。示例一:按键去抖动程序的优化4.1传统的按键去抖动程序初学单片机时,我们接触的按键去抖动程序一般是这样的5

技键技下?延时函数占用时回较长执行按下按擢后需要执行的程序结束从流程图中可知,delayms()延时函数和最后的等待按键释放的程序,会占用过多时间。4.2技键技下?延时函数占用时回较长执行按下按擢后需要执行的程序结束从流程图中可知,delayms()延时函数和最后的等待按键释放的程序,会占用过多时间。4.2优化后的按键去抖动程序对应的流程图如下:if(key1==0)//再次检测按键1,如果依旧按下{doSomething();//此时说明按键1已按下,执行按键1需要执行的任务while(!key1);//等待按键释放}此封CPU—直在等待按祯粹放,如果不翔州CPU就无法执行其他任务延时10ms如果按谴依旧按下如果使用有限状态机的思路,可以按照下图方式实现:该状态机有三个状态,分别是按键未按下,等待,按键按下。当按键按下时,则会进入等待状态,若在等待状态中按键一直保持按下,说明按键已经稳定地按下,进入按键按下的状态,等待按键释放。程序代码如下:/其他情况返回not_pressedkeyState=KEY_STATE_RELEASE;其他情况返回not_pressedkeyState=KEY_STATE_RELEASE;returnN#defineKEY_STATE_RELEASE //键未按#defineKEY_STATE_WAITING //等待(消抖<^^[^^^^^^^^^|「defineKEY_STATE_PRESSED //按键按下(等待释放/*等待状态持续时间*需要根据单片机速度和按键消抖程序被调用的速度来进行调整*//*按键检测函数的返回值,按下为1,未按下为0*/#definePRESSED1「defineNOT_PREsSEdO^^^^^^^^^^^^^^^^^^^^^^^B/*按键扫描程序所处的状态|*初始状态为:按键按下Tey_staTE_RELEASET^^^^^^^^^J*/Uint8_tkeyState=KEY_STATE_RELeASE^^^^^^^^^^^^^^^M/*按键检测函数,通过有限状态机实现*函数在从等待状态转换到按键按下状态时返回PRESSED,代表按键已被触发*/{staticuint8_tduration;//用于在等待状态中计数switch(keyState)H^CaSe^|x_^^TE_RELEA^^^^^^^^^^^^^^^^^^^^^^^^HifreadKey()==1) /7^果按键按下^^eySSBS|_S?A?S_WA!S^^换至下一个状return^O?_mSi5^^^回:按键未按break;if(readKey()==1) //如果按键按下duriation++;{ //说明没有抖动了,可以确定按键已按下duriation=0;keyState=k£Y_SJATE_PRESSED;//转换至下一个状态returnPRESSED;^^IS^^果此时按键松{ //可能存在抖动或干扰duriation=0;//清零的目的是便于下次重新计数break;caseif(readKey()==0) //如果按键松开{松开的状returnNOT_PRESSED,break;default:该程序也可经过扩展,实现判断按键双击、长按等功能。只需增加相应的状态和转移条件即可。示例二:通过有限状态机实现的闹钟程序最近正在制作一个闹钟。这个闹钟支持播放MP3格式的闹钟声6,支持贪睡模式,同时还有一些功能打算以后再添加上。为了使程序逻辑更加清晰,也为了更方便地添加新功能,我打算采用有限状态机实现。相关程序如下:^nZiude<USART1.h"^^^^^^^^^^^^^^^^^^^^^^^Minclude"diag/Trace.h"*相关常量定义 displayMessege()用于在显示屏上显示相关的提示信息 displayMessege()用于在显示屏上显示相关的提示信息*/用嘉。MESSEGE_SET_ALARM_TIME (0)//提示:设置闹钟时间{ //如果打开了闹钟alarmState=PLAY_ALARM_MUSIC;//进入下一个状态:播放闹钟音乐成fineALARM_MUSlC_END0 //闹钟音乐播放完毕用efineFORMAT_OK 0 〃格式正确用efineFORMAT_ERROR (-1) //格式错误*输入信息定义*作为函数的返回值供函数getInput()使用getInput()将获取并返回键盘或触摸屏等设备中输入的控制命令或闹钟时间值*/用efineINPUT_CANCEL (-2) //输入了「取消」命令用efineINPUT_SNOOZE (-3) //输入了「小睡」命令用efineINPUT_ALARM_ON(-4) //输入了「打开闹钟」"命用efineNO_INPUT (-10)//没有输X^J^^^^^^^^^^B*输出信息定义*作为为函数的参数供函数displayMessege()使用

defineMESSEGE_CLEAR (1)//提示:已取消,defineMESSEGE_GET_UP (5)//提示:节起床了/*闹钟的状态*/enumalarmStates{闹钟关闭1//默认状态:闹钟关闭/*相关函数的定义*/int16_tgetInput(void);|1nt8_tcheckSnoozeFormat(int16_t);**闹钟主程序,需要放入while(1)中循环调用/oidalarmApp(void),//输入值暂存在这个变量中switch(alarmState)//获取闹钟状态,下面程序将根据闹钟的状态执行相应的任务/*状态:闹钟关闭*在此状态中,将会不断检查是否打开闹钟,如果打开了闹钟,则会进入下一个状态:设置闹钟时间*/caseif(getInput()==INPUT_ALARM_ON)//检查是否打开了闹钟请设置闹钟时间| break;/*状态:设置闹钟时间*在此状态中,将会检查输入值,*如果输入“取消”命令,则取消闹钟设置,返回到闹钟关闭的状态输入闹钟时间格式错误,则状态不变,等待下一次重新输入输入了正确的闹钟时间,则设置闹钟,显示闹钟设置成功,并进入下一状态:等待闹钟响casesetalarm"time:^^^^B^^^^^^^^^^^^^^^^^^^^^Minput=getInput(); //获取输入值ifi^put==INPUT_CANCEL) //如果输入了取消^^i!PlayMe!Sege(MESSEGE_CLEAR)^^示“已取消I alarmstate=ALARM_OFF; //进入状态:关闭闹钟~ejs^fCheckAlarmFormst(!nput)^=^ORMAT_OK^^^^如果输入格式正I ^^iplayMEg!(MESIE5E_ALARM_IS_ON^^示“成功设置闹钟^闹钟已^动”setAlarm(input);//根据输入值设置闹钟| break;/*状态:等待闹钟响起*在此状态中,将会检查是否到达闹钟时间,如果到达,则进入下一状态:播放闹钟音乐*同时,在此状态中也会检查输入,如果输入了“取消”的命令,则进入闹钟关闭的状态=/] casewating_for_alarm:^^^^^^^^^^^^^^^^^^^^^^^^^^displayMessege(MESSEGE_WAITING);//显示等待闹钟响起的信息,例如离闹钟响起|还有多长时间if(alarmTimeDiff()<=0)//检查离闹钟响起还有多少时间,如果时间小于等于零(到达闹钟时间)if^SPSSmS_CAS^/F如果输入了取消命■alarmState=ALARM_OFF; //进入闹钟关闭的状态break/*状态:播放闹钟音乐*在此状态中,将播放闹钟音乐,若播放完毕,进入闹钟关闭的状态*同时,在此状态中也会检查输入,如果输入了“小睡”的命令,则进入状态:设置小睡时间如果输入了“取消”的命令,则进入状态:闹钟关闭*/cas;PLAY_ALARM_MUS^C^^^^^^^^B^^^^^^^^^^^^^^^^jdisplayMessege(MESSEGE_GE?_UpT^^示消息:该起床了if(playAlarmMusic()无ALARM_MUSIC_END)//播放闹钟音乐{//若音乐播放完毕alarmState=ALARM_OFF;//进入状态:闹钟关闭input=getInput();ifi?put==INPUT_SNOOZE)//若输入了“小睡”的命令^^ipsyMEg!(MESGE_SS_

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论