单片机编程中的一种习惯,你会受益匪浅吗?!

说到MCU编程,就不得不说状态机了。状态机作为软件编程的主要架构,已经在各种语言中得到应用,当然也包括C语言。在一个清晰高效的程序中,必须有一个状态机。出现。灵活的应用程序状态机不仅更高效,而且可读性和可扩展性强。国无处不在,国中有国。只要你掌握了这种思维,并在你的编程中养成一种习惯,相信你会受益匪浅。

本文引用地址:

状态机可以分为四个元素,即当前状态、条件、动作和下一个状态。这样的归纳主要是基于对状态机内部因果关系的考虑。“现在的状态”和“条件”是原因,“行动”和“第二状态”是结果。详情如下:

① 现状:指目前的状态。

②条件:又称“事件”。当满足条件时,触发动作或执行状态转换。

③ 动作:条件满足后要执行的动作。动作执行后,可以迁移到新的状态状态机c语言编程,也可以保持原来的状态。不需要操作,当满足条件时,您可以直接转换到新状态,无需执行任何操作。

④次要状态:条件满足后要迁移到的新状态。“次要状态”是相对于“当前状态”而言的。一旦“二级状态”被激活,它就会转变为一个新的“当前状态”。

如果我们进一步概括,统一“当前状态”和“次要状态”,忽略“动作”(降级处理),就只剩下两个最关键的元素,即:状态和转移条件。

状态机表示

状态机的表示方式有很多种,我们可以用文字、图形或表格的形式来表示状态机。

举个简单的例子:在按键处理方面,按键动作本身也可以看作是一个状态机。一个小的击键包含状态:释放、摇动、关闭、摇动和重新释放。

当我们敞开心扉,将状态机作为一种思想引入到程序中时,就会找到应对疑惑的有效捷径。有时,从状态机的角度考虑程序应该做什么可能比从控制流的角度考虑更有效。这样,状态机就具有了更实用的功能。事不宜迟,实践是检验真理的唯一标准。

几种状态机介绍

有些人可能认为状态机使问题复杂化。事实上,做过软件设计的人已经在无形中使用状态机了。以下是几种状态机的总结。

1、switch case结构状态机

转变( )

情况1:

if(不重复执行状态1)

进入状态1前的准备

进入状态1的过程

if(不重复执行状态1)

离开状态1的过程

案例2:

但是,这种方法不能有效地预定义所有状态,也不能合理定义这些状态之间的切换过程。“状态”本身并没有合理的定义,几乎是一种面向过程的方式。这种方法很简单,也是最容易接受的。缺点是没有“状态”定义和赋值函数,导致状态混乱状态机c语言编程,状态处理代码重复,甚至不一致。根据OO的概念,状态描述本质上应该是一个实体。

2、ifelse 语句结构状态机

这种状态机比较灵活,但是对于一些大型项目,系统软件设计会比较复杂。

3、消息触发状态机

这种状态机的实现方式也很多,形式多种多样,但状态机的四要素与当前状态、条件、动作、次要状态是密不可分的。

原理:一旦触发消息,系统服务函数立即寻找状态中的消息和消息处理函数对,找到后执行消息处理函数。

步:

(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:尾巴

(3)划分电子秤的状态。完成以上步骤后,完成OnMsg消息处理功能。

无效 OnMsg(无效)

{

图片[1]-单片机编程中的一种习惯,你会受益匪浅吗?!-老王博客

}

注意:以上是用宏完成的。具体宏定义如下:

#defineBEGIN_MESSAGE_MAP(Name,Count)constMSG_NODE_TYP MSG_node_Array_##Name[(Count)]={

#defineADD_NEW_MSG_ITEM(Msg,OnMsg){Msg,OnMsg},

#define END_MESSAGE_MAP };

#define BEGIN_Register_Task const MSG_MAP TaskMap[TotalTask​​]={

#defineADD_Register_Task(Name,Count) {(MSG_NODE_TYP*)MSG_node_Array_##Name,Count},

#define END_Register_Task };

从上面的代码可以看出,添加一个消息和一个消息映射其实就是一个定义消息和消息处理函数对的数组,组成一个表;注册状态机其实就是将所有消息对数组的入口定义为一个数组组成一个表。

消息是如何执行的

1.分发消息

void Default_DisposeMessage(unsigned char *pMsg)

{

未签名的chari;

unsigned charcount=TaskMap[g_Status].cItemCount;

//定位到状态表

对于(我=0;我

{

if(*pMsg==TaskMap[g_Status].pMsgItems.msg)

// 看是否匹配消息

{

任务映射[g_Status].pMsgItems.pMsgFunc();

// 找到时执行消息处理函数

返回;

}

}

}

无效调度消息(无符号字符* pMsg)

{

如果(*pMsg)

{

Default_DisposeMessage(pMsg);

}

}

2.核心功能:消息处理中心

无效 Message_Dispose_Central(无效)

{

字节消息;

while(GetMessage(&Msg)) //获取消息

{

TranslateMessage(&Msg); //解释消息

DispatchMessage(&Msg); //发送消息

}

}

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论