浅谈状态机的要素、分类

说到单片机编程,不得不说到状态机,状态机做为软件编程的主要架构已经在各种语言中应用,当然包括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 {
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); //分发消息
}
}

原文标题:单片机裸奔之状态机浅谈
文章出处:【微信公众号:嵌入式arm】欢迎添加关注!文章转载请注明出处。

微机电系统(MEMS)主要分类
1月7日CES开展 五大话题最热
中国电信“医疗云专区”方案发布,标志底座能力进一步夯实
泰克公司推出TLA6400系列便携式逻辑分析仪
智能音箱到底智能在哪些地方
浅谈状态机的要素、分类
CAN-bus网络中,出现具有相同ID段的两个节点会发生什么?
低功耗技术与信号检测简介
带通滤波器ACPF-7024和ACPF-7025特性分析
树莓派设计 无线感应报警器DIY创意无限
熔断器如何选型_熔断器选型原则
贴片电阻的工作参数和类别,如何判断贴片电阻的阻值和功率大小?
超声波塑焊机的焊接原理
关于导热硅脂的小知识
使用Python可视化数据,机器人开发编程
MAX9617–MAX9620低功耗、零温漂运算放大器
高频印制板应用与基板材料简介
释放音乐动力 大众帕萨特改装芬朗汽车音响
人工智能已在军事领域引起极大兴趣
想要完成全球先进产能的配套服务,需与海外企业充分合作