单片机状态机笔记

关于阻塞/非阻塞,同步与异步

阻塞调用:调用某个函数时,需要等待其返回一个正确的结果(这个结果是调用者所希望的),不等到这个结果就不往下执行。
非阻塞调用:调用某个函数时,无论有没有结果或者结果是不是调用者想要的,程序都会继续往下执行。
同步:当调用者调用某个函数时需要等待一个结果,如果没有结果,那么如果是调用者主动去等待这个结果。
异步:当调用者调用某个函数时需要等待一个结果,如果没有结果,那么调用者不去主动等待这个结果,而是被动的去等待结果,当正确结果来临的时候就通知调用者去获取这个结果。

曾在其他博主博文中看过一个例子非常形象:
老张爱喝茶,废话不说,煮开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
1 老张把水壶放到火上,立等水开。(同步阻塞)
老张觉得自己有点傻
2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)
老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。
3 老张把响水壶放到火上,立等水开。(异步阻塞)
老张觉得这样傻等意义不大
4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)
老张觉得自己聪明了。
所谓同步异步,只是对于水壶而言。
普通水壶,同步;响水壶,异步。
虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。
同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。
所谓阻塞非阻塞,仅仅对于老张而言。
立等的老张,阻塞;看电视的老张,非阻塞。
情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。

由此衍生出一个单片机状态机的阻塞调用和非阻塞调用。
单片机状态机伪代码:

enum fsm 
{
	fsm_doing, /* 单片机状态机还未执行完毕 */
	fsm_ok, /* 单片机的整个状态执行完毕 */
};

/* 例如某个流程图需要一整个流程执行完毕才会有一个最终的结果,外部调用者只需要等待这个结果即可,以烤肉为例子 */
enum fsm WaitBarbecue(void)
{
	static enum
	{
		START, 
		BUY_MEAT, /* 买肉 */
		CUT_MEAT, /* 切肉 */
		ROAST_MEAT, /* 烤肉 */
		OVER,
	} WAITBARBRCUE_STA = START;
	switch (WAITBARBRCUE_STA):
	{
		case START:/* 做一些变量初始化的工作 */
			WAITBARBRCUE_STA = BUY_MEAT;
			break;
		case BUY_MEAT:/* 做买肉的任务 */
			WAITBARBRCUE_STA = CUT_MEAT;
			break;
		case CUT_MEAT:/* 做切肉的任务 */
			WAITBARBRCUE_STA = ROAST_MEAT;
			break;
		case ROAST_MEAT:/* 做烤肉的任务 */
			WAITBARBRCUE_STA = OVER;
			break;
		case OVER:/* 做进入下一次烤肉的准备 */
			WAITBARBRCUE_STA = START;
			return fsm_ok;
	}
	return fsm_doing;
}

/* 调用者 */
void main(void)
{
	/* 系统初始化 */
	while(1)
	{
		/* ①阻塞调用 */
		while(WaitBarbecue() == fsm_doing); /* 一直等待烤肉完成 */
		/* ②非阻塞调用 */
		WaitBarbecue(); /* 只调用一次,不管此时处于什么阶段,调用完立马执行下面的代码 */
	}
}

由上面可知可阻塞状态机的使用方法,那么可阻塞状态机的有什么好处呢?
好处就是可以进行可阻塞状态机的无线套娃调用,如:

/* 我要进行减肥,有三个过程:举铁,跑步,拉伸 
	举铁:可分为举杠铃30下,举哑铃30下,可作为一个状态机
	跑步:可分为快跑10分钟,慢跑30分钟,可作为一个状态机
	拉伸:可分为拉手10分钟,拉腿10分钟,可作为一个状态机
*/
enum fsm LoseWeight(void) /* 减肥状态机*/
{
	static enum 
	{
		START,
		LIFT_IRON, /* 举铁 */
		RUN, /* 跑步 */
		STRETCH, /* 拉伸 */
		OVER,
	} LOSEWEIGHT_STA = START;
	switch (LOSEWEIGHT_STA ): 
	{
		case START:/* 初始化 */
			LOSEWEIGHT_STA = LIFT_IRON;
			break;
		case LIFT_IRON:/* 举铁 */
			while(LiftIron() == fsm_doing); /* 等待举铁完成 */
			LOSEWEIGHT_STA = RUN;
			break;
		case RUN: /* 跑步 */
			while(Run() == fsm_doing); /* 等待跑步完成 */
			LOSEWEIGHT_STA = STRETCH;
			break;
		case STRETCH: /* 拉伸 */
			while(Stretch() == fsm_doing); /* 等待跑步完成 */
			LOSEWEIGHT_STA = OVER;
			break;
		case OVER:
			LOSEWEIGHT_STA = START;
			return fsm_ok;
	}
	return fsm_doing;
}

以上纯属个人见解,有误之处还望大家指正。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单片机状态机编程思想是一种常用的软件设计方法,用于处理复杂的系统控制逻辑。它将系统的行为分解为一系列离散的状态,并定义了状态之间的转换条件和动作。以下是单片机状态机编程思想的基本概念和实现方式: 1. 状态(State):表示系统在某一时刻的工作状态,可以是一个具体的功能或操作。例如,一个电梯系统可以有"停止"、"上升"和"下降"等状态。 2. 事件(Event):触发状态转换的外部或内部事件,可以是传感器输入、定时器溢出等。例如,电梯系统中的事件可以是"按下上升按钮"、"到达某一楼层"等。 3. 状态转换(Transition):定义了从一个状态到另一个状态的条件和动作。条件可以是事件的发生、某些输入信号的状态等。动作可以是改变输出、执行某些操作等。例如,当电梯处于"停止"状态时,如果接收到"按下上升按钮"事件,则转换到"上升"状态,并执行相应的动作。 4. 状态机(StateMachine):由一组状态、事件和状态转换组成的模型,描述了系统的行为。通过不断地检测事件和执行状态转换,状态机可以实现系统的控制逻辑。 在单片机中实现状态机编程思想可以采用以下步骤: 1. 定义状态:根据系统需求,确定系统的各个状态,并为每个状态分配一个唯一的标识符。 2. 定义事件:根据系统需求,确定可能触发状态转换的事件,并为每个事件分配一个唯一的标识符。 3. 定义状态转换:为每个状态定义可能的状态转换条件和动作。根据事件和当前状态,确定下一个状态和执行的动作。 4. 实现状态机:在单片机程序中,使用条件语句或查表法等方式实现状态机。通过不断地检测事件和执行状态转换,实现系统的控制逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值