【发布时间】:2015-04-06 01:15:10
【问题描述】:
我从事嵌入式工作,并且我有一些管理硬件的软件模块。这个模块有状态,状态转换很复杂:根据事件,模块可以从状态A 到状态B 或者可能到C。但是,当它退出某个状态时,它应该对硬件执行一些操作,以使其也保持正确的状态。
对于相当简单的模块,我只有几个这样的函数:
enum state_e {
MY_STATE__A,
MY_STATE__B,
};
static enum state_e _cur_state;
void state_on_off(enum state_e state, bool on)
{
switch (state){
case MY_STATE__A:
if (on){
//-- entering the state A
prepare_hardware_1(for_state_a);
prepare_hardware_2(for_state_a);
} else {
//-- exiting the state A
finalize_hardware_2(for_state_a);
finalize_hardware_1(for_state_a);
}
break;
case MY_STATE__B:
if (on){
//-- entering the state B
prepare_hardware_1(for_state_b);
prepare_hardware_2(for_state_b);
} else {
//-- exiting the state B
finalize_hardware_2(for_state_b);
finalize_hardware_1(for_state_b);
}
break;
}
}
void state_set(enum state_e new_state)
{
state_on_off(_cur_state, false);
_cur_state = new_state;
state_on_off(_cur_state, true);
}
显然,我们需要在 _state_on_off() 函数中为所有状态保留所有必要的操作,当我们需要移动到另一个状态时,我们只需调用 _state_set(new_state) 并且状态转换会顺利进行,与方向无关:所有需要执行操作。
但它只适用于简单的情况。如果我们在状态MY_STATE__B 和MY_STATE__C 之间有一些共同点,那么当状态从MY_STATE__B 更改为MY_STATE__C 并返回时,我们应该只执行缩短的析构/构造?但是当我们进入其他状态(例如,MY_STATE__A)时,我们应该执行完全销毁。
想到的是子状态。所以我们有一个状态MY_STATE__BC,还有像MY_BC_SUBSTATE__B和MY_BC_SUBSTATE__C这样的子状态;当然我们也有它自己的函数,比如_state_bc_on_off()。即使这已经是一种痛苦,但想象一下更复杂的事情:它变得可怕。
那么,这样的最佳做法是什么?
【问题讨论】:
-
您所描述的称为状态机。状态机由矩阵定义:行是状态,列是输入,单元格值是要执行的动作元组和要转换到的新状态。把这一切都写在一张纸、Excel 电子表格等上。这不是一个编程问题;这是如何控制您的设备的问题。一旦完成,实现就很简单了,几乎可以归结为一个你已经拥有的 switch 语句。
-
我将采取的方法是绘制一个有向图,显示状态转换以及图中从一个节点移动到另一个节点的条件。这篇文章可以帮助engineering.purdue.edu/ece362/Refs/Pld/pal_state.pdf 以及这篇文章cse.chalmers.se/~coquand/AUTOMATA/book.pdf 以及这篇文章drdobbs.com/cpp/state-machine-design-in-c/184401236
-
这篇带有源代码的项目文章也可以提供帮助。 codeproject.com/Articles/19082/…
-
一般来说,当我实现一个状态机时,每个条件都是一个单独的状态。因此代码当前列出了状态 a、b、c,但实际上有一些中间状态也应列为状态机的一部分。因此,例如,当 a -> ab 或 a ->ac 或 ab->b 或 ac->c 或 c->a 或 c->b 时,声明 a,ab,b,ac,c。是状态转换。每个状态决定做什么以及接下来要进入哪个状态(可能是相同的状态)。写一个状态转移图会阐明所有的条件等等
-
@RichardChambers,感谢您的出色参考。
标签: c state state-machine state-machine-workflow