单片机裸奔之状态机浅谈

出处:电子工程专辑 发布于:2019-05-21 13:55:44

  说到单片机编程,不得不说到状态机,状态机做为软件编程的主要架构已经在各种语言中应用,当然包括C语言,在一个思路清晰而且高效的程序中,必然有状态机的身影浮现。灵活的应用状态机不仅是程序更高效,而且可读性和扩展性也很好。状态无处不在,状态中有状态,只要掌握了这种思维,让它成为您编程中的一种习惯,相信您会受益匪浅。
  状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果联系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下:
  ①现态:是指当前所处的状态。
  ②条件:又称为“事件”。当一个条件被满足,将会触发一个动作,或者执行状态的迁移。
  ③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
  ④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
  如果我们进一步归纳,把“现态”和“次态”统一起来,而把“动作”忽略(降格处理),则只剩下两个关键的要素,即:状态、迁移条件。
  状态机的表示要领有许多种,我们可以用文字、图形或表格的形式来表示一个状态机。
  举个简单的例子:就按键处理来说,击键动作本身也可以看做一个状态机。一个细小的击键动作包含了:释放、抖动、闭合、抖动和重新释放等状态。  当我们打开思路,把状态机作为一种思想导入到程序中去时,就会找到处理疑问的一条有效的捷径。有时候用状态机的思维去思考程序该干什么,比用控制流程的思维去思考,可能会更有效。这样一来状态机便有了更实际的功用。废话不多说,实践才是检验真理的标准。
  也许有人觉得状态机把问题复杂化了,其实做过软件设计的人无形之中已经在用状态机,下面就总结介绍几种状态机。
  种:switch case结构状态机
  switch()。
  case1:。
  if(not反复执行状态1)。
  进入1状态前要做的准备。
  进入1状态的过程。
  if(not反复执行状态1)。
  离开状态1的过程。
  case2:。
  ...。
  但这种方式不能很有效预定义所有的状态,也不能把这些状态之间的切换过程合理的定义出来,“状态”本身没有一个合理的定义,几乎是一种面向过程的方式,只过这种方式足够简单,也容易让人接受,缺点就没有“状态”的定义和指派功能,导致状态的混乱,出现状态处理重复代码,甚至处理不一致的问题,按照OO的观念,状态描述本来就应该是一种实体。
  第二种状态机:ifelse语句结构状态机
  这种状态机相对灵活一点,但对于一些大的项目,系统软件设计会相对复杂。
  以上2种状态机是是大家接触多的,也是经常用到的,这里不多说了。下面重点谈谈第三种状态机。
  第三种状态机:消息触发状态机
  该类型的状态机实现方式也是很多的,形态多样,但万变不离其宗的就是状态机的4要素及现态、条件、动作、次态。
  下面介绍一种消息触发类型的状态机。
  基于消息驱动的状态机机制
  原理:一旦有消息触发,系统服务函数立即寻找所在状态的消息与消息处理函数对,找到后执行消息处理函数
  步骤:
  1.添加消息与消息映射
  …
  BEGIN_MESSAGE_ MAP(Name,Count) :状态机名,消息数
  ADD_NEW_MSG_ITEM (Msg,OnMsg) :消息与消息处理函数
  END_MESSAGE_MAP:结束
  …
  2.在这里注册
  BEGIN_Register_Task:头
  ...
  ADD_Register_Task(Name,Count):状态机名,消息数
  ...
  END_Register_Task:尾
  1.划分电子秤状态,完成以上步骤后,完成OnMsg消息处理函数
  Void OnMsg(void)
  {
  …
  }
  说明:以上用宏完成,具体宏是如下定义:
  #defineBEGIN_MESSAGE_MAP(Name,Count) constMSG_NODE_TYP MSG_node_Array_##Name[(Count)]={
  #define ADD_NEW_MSG_ITEM(Msg,OnMsg) {Msg,OnMsg},
  #define END_MESSAGE_MAP };
  #define BEGIN_Register_Task const MSG_MAP TaskMap[TotalTask]={
  #define ADD_Register_Task(Name,Count) {(MSG_NODE_TYP*)MSG_node_Array_##Name,Count},
  #define END_Register_Task };
  从以上代码可知:
  1. 添加消息与消息映射实际上是定义消息与消息处理函数对的数组,以形成一个表
  2. 注册状态机实际上是把所有消息对数组的入口定义成一个数组,以形成一个表
  消息是如何被执行的?
  分发消息
  void Default_DisposeMessage(unsigned char *pMsg)
  {
  unsigned chari;
  unsigned charcount=TaskMap[g_Status].cItemCount;//定位到状态表
  for(i=0;i<count;i++)
  {
  if(*pMsg==TaskMap[g_Status].pMsgItems.msg)//看能否匹配消息
  {
  TaskMap[g_Status].pMsgItems.pMsgFunc();//找到就执行消息处理函数
  return;
  }
  }
  }
  void DispatchMessage(unsigned char*pMsg)
  {
  if(*pMsg)
  {
  Default_DisposeMessage(pMsg);
  }
  }
  函数:消息处理中心
  void Message_Dispose_Central(void)
  {
  BYTE Msg;
  while(GetMessage(&Msg)) //获取消息
  {
  TranslateMessage(&Msg); //解释消息
  DispatchMessage(&Msg); //分发消息
  }
  }
关键词:单片机

版权与免责声明

凡本网注明“出处:维库电子市场网”的所有作品,版权均属于维库电子市场网,转载请必须注明维库电子市场网,https://www.dzsc.com,违反者本网将追究相关法律责任。

本网转载并注明自其它出处的作品,目的在于传递更多信息,并不代表本网赞同其观点或证实其内容的真实性,不承担此类作品侵权行为的直接责任及连带责任。其他媒体、网站或个人从本网转载时,必须保留本网注明的作品出处,并自负版权等法律责任。

如涉及作品内容、版权等问题,请在作品发表之日起一周内与本网联系,否则视为放弃相关权利。

相关技术资料
广告
上传BOM文件: BOM文件
*公司名:
*联系人:
*手机号码:
QQ:
应用领域:

有效期:
OEM清单文件: OEM清单文件
*公司名:
*联系人:
*手机号码:
QQ:
有效期:

扫码下载APP,
一键连接广大的电子世界。

在线人工客服

买家服务:
卖家服务:

0571-85317607

客服在线时间周一至周五
9:00-17:30

关注官方微信号,
第一时间获取资讯。

建议反馈

联系人:

联系方式:

按住滑块,拖拽到最右边
>>
感谢您向阿库提出的宝贵意见,您的参与是维库提升服务的动力!意见一经采纳,将有感恩红包奉上哦!