搜索
bottom↓
回复: 166

分享:用10行代码实现的C语言状态机,支持超时机制

  [复制链接]

出0入0汤圆

发表于 2015-1-14 22:23:45 | 显示全部楼层 |阅读模式
本帖最后由 mdb3 于 2015-1-15 21:32 编辑
刚逛坛子,发现有前辈总结了状态机的原理和分析方法,觉得不错,分享:http://www.amobbs.com/thread-3316176-1-1.html
个人觉得,现实中的软件,特别是嵌入式软件,至少80%都可以轻松的套用状态机思想分析和实现。

代码如下,是ansi c编写的demo,大家可以在vc货mdk中编译看看。
这个简单的状态机使用c语言函数指针实现,从我的一个STM32工程中摘出来的;
可以支持状态转换、状态超时。
反正我用这种方法,实现了自动售货机售卖、收钱、找钱、上位机通信等完整功能,已经商用一段时间,还算稳定。已经把这种思想推行到其他项目中。

实现原理简介:
每一个状态就是一个void func(void) 类型的函数,每个函数只需要知道两件事:
1)自己要做什么(业务)
2)自己的下一个状态是什么(状态切换)
就像接力棒跑一样,每个人拿到棒子后全力跑完自己那一段(业务),把棒子递给下一个人(状态迁移)。
用我这种方法实现,比switch实现的方案,好在没有集中的状态转换,而是把状态转换分散到每一个状态中,最大的优点有两个:
1)无论多复杂的业务流程,状态切换的代码都只需要负责几个分支,不用通盘考虑。
2)对流程变化更友好:哪些流程变化,修改对应状态的函数即可;没有涉及到的内容完全无需考虑,无需担心引入bug。

相比较其他框架,这个方案的唯一优点就是简单,就几行代码而已嘛,随时根据自己的需求,添加特殊代码,实现特殊功能,对g_state_timeout_milliseconds的使用就是一个典型实例。
归根结底,最重要的还是对业务需求的分析,合理的状态划分,具体实现方案,只是个工具而已


核心代码是“状态机 BEGIN ”到“状态机 END”中的那10句话。

  1. #include <time.h>
  2. #include <stdio.h>

  3. void delay_ms(int ms)
  4. {
  5.     //系统延时函数
  6. }

  7. unsigned int systemMs(void)
  8. {
  9.     clock_t c = clock()+100;
  10.     return c;
  11. }

  12. /************ 状态机 BEGIN *****************/
  13. typedef void (*state_func_t)(void);
  14. static unsigned int g_state_timeout_milliseconds=0;
  15. static state_func_t g_state_func = NULL;

  16. void main_setNextState(state_func_t func)
  17. {
  18.     /*
  19.      * g_state_timeout_milliseconds
  20.      * 可以用于判断是否进入一个新状态;
  21.      * 还可以用于判断进入某个状态多长时间了。
  22.      */
  23.     g_state_timeout_milliseconds = 0;

  24.     g_state_func = func;
  25. }
  26. state_func_t main_getNextState(void)
  27. {
  28.     return g_state_func;
  29. }
  30. /************ 状态机 END *****************/

  31. /************ 状态函数 BEGIN *************/
  32. void main_state1(void);
  33. void main_state2(void);

  34. void main_state1(void)
  35. {
  36.     if(0 == g_state_timeout_milliseconds) {
  37.         g_state_timeout_milliseconds = systemMs();
  38.         printf("enter state1\n");
  39.     }
  40.     /* 5000毫秒超时 */
  41.     if(systemMs() - g_state_timeout_milliseconds > 5*1000) {
  42.         printf("exit state1\n");
  43.         main_setNextState(main_state2);
  44.         return;
  45.     }

  46.     /*
  47.      * TODO 这里实现业务逻辑
  48.      * 比如到达某种条件,进入其他状态
  49.      * 比如收到某条消息,进入其他状态
  50.      */
  51. }
  52. void main_state2(void)
  53. {
  54.     if(0 == g_state_timeout_milliseconds) {
  55.         g_state_timeout_milliseconds = systemMs();
  56.         printf("enter state2\n");
  57.     }
  58.     /* 2000毫秒超时 */
  59.     if(systemMs() - g_state_timeout_milliseconds > 2*1000) {
  60.         printf("exit state2\n");
  61.         main_setNextState(main_state1);
  62.         return;
  63.     }

  64.     /*
  65.      * TODO 这里实现业务逻辑
  66.      * 比如到达某种条件,进入其他状态
  67.      * 比如收到某条消息,进入其他状态
  68.      */
  69. }
  70. /************ 状态函数 END *************/

  71. int main(int argc, char *argv[])
  72. {
  73.     printf("Hello, state machine!\n");
  74.     /*
  75.      * 设置初始状态
  76.      */
  77.     main_setNextState(main_state1);

  78.     /*
  79.      * 状态驱动
  80.      * 每一个状态,处理完自己的事情后,负责指定下一个状态(使用main_setNextState函数)
  81.      */
  82.     while(1) {
  83.         (*main_getNextState())();
  84.         delay_ms(1);
  85.     }
  86.     return 0;
  87. }
复制代码


==================1月15日添加==================
看了下面的评论,看来很多同学不理解状态机,比如拿状态机和switch比较,甚至拿状态机和RTOS比较、协作库比较。
状态机最精妙的应用,同时也是最一般的应用,就是对一个复杂的业务流程解耦合,实现“高内聚、低耦合”的至高境界。
状态机是23个设计模式中的一个,实现方案、框架也非常多,我这里的这个仅仅是根据自己的需要实现的的一个最简模型,完全手写。
systemMs()函数的作用,就是返回系统从启动到现在,经过了多少个毫秒

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2015-1-14 22:40:19 | 显示全部楼层
完全看不懂,但是知道比较牛逼。学习膜拜。谢谢分享代码。

出0入0汤圆

发表于 2015-1-14 22:44:45 来自手机 | 显示全部楼层
顶一下楼主,谢谢分享,与傻孩子的一个帖子里的状态机很相似。

出0入0汤圆

发表于 2015-1-14 22:45:21 | 显示全部楼层
觉得你的main_state1()和main_state2()函数里面的应该有while(1);不然你的超时切换只在进入时判断一次?
不知道理解对了么。

出0入0汤圆

发表于 2015-1-14 22:57:53 | 显示全部楼层
看不懂,支持一下。

出0入0汤圆

发表于 2015-1-14 22:58:17 | 显示全部楼层
shower.xu 发表于 2015-1-14 22:45
觉得你的main_state1()和main_state2()函数里面的应该有while(1);不然你的超时切换只在进入时判断一次?
不 ...

有WHILE(1);状态都没法切换。

出0入0汤圆

发表于 2015-1-14 23:13:14 | 显示全部楼层
shower.xu 发表于 2015-1-14 22:45
觉得你的main_state1()和main_state2()函数里面的应该有while(1);不然你的超时切换只在进入时判断一次?
不 ...

如果不跳转的话,超时会在大循环里面一直判断

出0入0汤圆

发表于 2015-1-14 23:15:53 | 显示全部楼层
这样还是不如上操作系统,或者事件驱动,具体LZ可以在arduino英文论坛里面找到,国内好像有个比较牛逼的叫做pthread也不错。

出0入0汤圆

发表于 2015-1-15 00:02:38 | 显示全部楼层
7nian 发表于 2015-1-14 23:13
如果不跳转的话,超时会在大循环里面一直判断

明白了,返回主函数循环了,谢谢

出0入0汤圆

发表于 2015-1-15 00:03:48 | 显示全部楼层
Zigbee2012 发表于 2015-1-14 22:58
有WHILE(1);状态都没法切换。

明白了,返回主函数循环了

出0入0汤圆

发表于 2015-1-15 00:40:20 来自手机 | 显示全部楼层
谢谢楼主 看能不能来个详细点的例子 比如按键加跑马灯啥的 更好理解一些 谢谢

出0入0汤圆

发表于 2015-1-15 06:24:07 | 显示全部楼层
支持楼主出来讲解一下

出0入0汤圆

发表于 2015-1-15 07:19:12 | 显示全部楼层
skefer 发表于 2015-1-14 23:15
这样还是不如上操作系统,或者事件驱动,具体LZ可以在arduino英文论坛里面找到,国内好像有个比较牛逼的叫 ...

事件驱动怎么写,谢谢

出0入0汤圆

发表于 2015-1-15 07:35:26 | 显示全部楼层
谢谢。下来好好深刻理解一下编程思想,在实践中慢慢领会。

出0入0汤圆

发表于 2015-1-15 08:21:51 | 显示全部楼层
完全看不懂,但是知道比较牛逼。学习膜拜。谢谢分享代码。

出0入0汤圆

发表于 2015-1-15 08:38:27 | 显示全部楼层
看不懂,看来我太水了

出0入0汤圆

发表于 2015-1-15 08:45:59 | 显示全部楼层
用这个方法实现不如switch+case结构清晰,LZ你这个程序结构更适合实现简单任务调度:main中主循环调度各个task,每个task都定时运行,在每个task中单独实现完整的状态机

出0入0汤圆

发表于 2015-1-15 08:49:16 | 显示全部楼层
状态用if来区分没有switch效率高啊

出0入76汤圆

发表于 2015-1-15 08:50:34 | 显示全部楼层
本帖最后由 foxpro2005 于 2015-1-15 09:00 编辑

见过类似的代码, 跟傻孩子大师的比较相似, 也就是用函数指针来代替代了switch, if-else结构, 这样在状态机结构形式上得以简化。
其实还有一种,Protothreads那种结构也是非常不错的, 论坛中有几个坛友(smset、summarize)都改进得非常好,结构与思路都变化得清晰。

出0入0汤圆

发表于 2015-1-15 08:52:33 | 显示全部楼层
tiger5 发表于 2015-1-15 08:21
完全看不懂,但是知道比较牛逼。学习膜拜。谢谢分享代码。

函数指针 每个状态一个函数 状态完成时 指针指向下一个函数。。。。。。。。
感觉不如PTthread。。。。。。。。

出0入0汤圆

发表于 2015-1-15 08:54:26 | 显示全部楼层
我还能跟别人说我学过C语言么???完全看不懂啊~~~

出0入0汤圆

发表于 2015-1-15 08:55:53 | 显示全部楼层
100行了,代码不清晰

出0入0汤圆

发表于 2015-1-15 08:57:30 | 显示全部楼层
值的学习
但是对状态划分能力要求很高啊

出0入0汤圆

发表于 2015-1-15 08:58:15 | 显示全部楼层
感觉跟普通状态机也没什么区别...

出0入0汤圆

发表于 2015-1-15 09:00:07 | 显示全部楼层
只是一个超时状态转换,简单的多任务也做不了

出0入0汤圆

发表于 2015-1-15 09:05:54 | 显示全部楼层
巧妙。。。

出0入4汤圆

发表于 2015-1-15 09:10:14 | 显示全部楼层
先收藏,慢慢看

出0入0汤圆

发表于 2015-1-15 09:11:57 | 显示全部楼层
收藏了慢慢吸收谢谢了!

出0入0汤圆

发表于 2015-1-15 09:12:31 | 显示全部楼层
能不能解释一下
unsigned int systemMs(void)
{
    clock_t c = clock()+100;
    return c;
}
clock()  做什么用的呢?

出0入0汤圆

发表于 2015-1-15 09:13:43 | 显示全部楼层
foxpro2005 发表于 2015-1-15 08:50
见过类似的代码, 跟傻孩子大师的比较相似, 也就是用函数指针来代替代了switch, if-else结构, 这样在状态 ...

哪边有改进的链接。。。

出0入264汤圆

发表于 2015-1-15 09:17:14 | 显示全部楼层
妙。亮点在g_state_timeout_milliseconds 的应用。一般人体会不到。

出0入0汤圆

发表于 2015-1-15 09:25:23 | 显示全部楼层
膜拜,但是看不出比switch...case结构好在哪里。

出0入0汤圆

发表于 2015-1-15 09:31:50 | 显示全部楼层
记得某个四轴飞行器   采用类似的结构    其实就是计数超时

出0入0汤圆

发表于 2015-1-15 09:32:21 | 显示全部楼层
本帖最后由 skefer 于 2015-1-15 09:33 编辑
彼岸花开@ 发表于 2015-1-15 07:19
事件驱动怎么写,谢谢


具体参看这个帖子:http://www.amobbs.com/thread-5478957-1-1.html
还有这个:http://forum.arduino.cc/index.php/topic,37650.0.html

出0入0汤圆

发表于 2015-1-15 09:40:27 | 显示全部楼层
时间片轮转方式,还比较好理解。

出0入0汤圆

发表于 2015-1-15 09:41:47 | 显示全部楼层
非常不错,超时的引入 感觉是骚点

出0入0汤圆

发表于 2015-1-15 09:45:53 | 显示全部楼层
这算不上状态机,只算得是时间片轮转系统。

出0入0汤圆

发表于 2015-1-15 09:53:49 | 显示全部楼层
我是从51 avr过来的,看到(*main_getNextState())();这种用法又涨知识了,请教state_func_t这个是怎么定义的啊!

出0入0汤圆

 楼主| 发表于 2015-1-15 10:23:39 | 显示全部楼层
mcu_lover 发表于 2015-1-15 09:17
妙。亮点在g_state_timeout_milliseconds 的应用。一般人体会不到。

是啊,基于这个变量实现了“状态初次进入”和“状态超时”两大功能。
由于代码异常简单,其实还可以扩充n多特有的功能,抛砖迎玉~

出0入0汤圆

发表于 2015-1-15 10:26:40 | 显示全部楼层
判断一次状态要10条语句,不算什么,带超时处理还不错

出0入0汤圆

 楼主| 发表于 2015-1-15 10:28:25 | 显示全部楼层
本帖最后由 mdb3 于 2015-1-15 21:04 编辑
jdh99 发表于 2015-1-15 08:45
用这个方法实现不如switch+case结构清晰,LZ你这个程序结构更适合实现简单任务调度:main中主循环调度各个t ...


这只是个演示demo,只有两个状态,肯定不如switch case结构清晰。
当有100个状态时,情况就会反过来了。
话说回来,所有的工程方法,都是解决大型复杂软件项目的,对于写个玩具,或数学算法,肯定不适用。

出0入0汤圆

发表于 2015-1-15 10:33:54 | 显示全部楼层
先顶一个,再去研究下,

出0入0汤圆

发表于 2015-1-15 10:38:08 | 显示全部楼层
先顶一下,收藏在再研究

出0入296汤圆

发表于 2015-1-15 10:53:00 | 显示全部楼层
本帖最后由 Gorgon_Meducer 于 2015-1-15 10:56 编辑

赞一下。属于函数指针法的状态机。
稍微复杂一点的,原理相同的状态机调度器,可以参考这两个帖子:
http://www.amobbs.com/thread-5507175-1-1.html
http://www.amobbs.com/thread-5509424-1-1.html

更复杂的可以去看QP的源代码和书籍。

出0入0汤圆

发表于 2015-1-15 10:58:18 | 显示全部楼层
题外话,突然想到很多人用lua的尾递归来写状态机。

出0入0汤圆

发表于 2015-1-15 11:06:52 | 显示全部楼层
mdb3 发表于 2015-1-15 10:23
是啊,基于这个变量实现了“状态初次进入”和“状态超时”两大功能。
由于代码异常简单,其实还可以扩充n ...

不错。又看了一遍,有点体会,有时间试试。

出0入0汤圆

发表于 2015-1-15 11:08:09 | 显示全部楼层
fish47 发表于 2015-1-15 10:58
题外话,突然想到很多人用lua的尾递归来写状态机。

麻烦发些资料看看

出0入0汤圆

发表于 2015-1-15 11:46:18 | 显示全部楼层
不错,都是基于函数指针的。简单够用就好

出0入0汤圆

 楼主| 发表于 2015-1-15 12:06:27 | 显示全部楼层
片羽之神 发表于 2015-1-15 09:53
我是从51 avr过来的,看到(*main_getNextState())();这种用法又涨知识了,请教state_func_t这个是怎么定义 ...

state_func_t 就是一个函数指针啊。
你仔细看下,代码里有他的typedef

出0入0汤圆

发表于 2015-1-15 12:26:41 | 显示全部楼层
foxpro2005 发表于 2015-1-15 08:50
见过类似的代码, 跟傻孩子大师的比较相似, 也就是用函数指针来代替代了switch, if-else结构, 这样在状态 ...

不错,赞+10086

出0入0汤圆

发表于 2015-1-15 12:27:02 | 显示全部楼层
表示完全看不懂,还停留在主函数写死循环延时的阶段

出0入0汤圆

发表于 2015-1-15 12:33:48 | 显示全部楼层
mdb3 发表于 2015-1-15 10:23
是啊,基于这个变量实现了“状态初次进入”和“状态超时”两大功能。
由于代码异常简单,其实还可以扩充n ...

没感觉到这个变量妙在哪里,状态机如何处理中断?如何让任务“并行”?

出0入0汤圆

发表于 2015-1-15 12:34:20 | 显示全部楼层
下载学习

出0入0汤圆

 楼主| 发表于 2015-1-15 13:03:17 | 显示全部楼层
ALUMEI 发表于 2015-1-15 12:33
没感觉到这个变量妙在哪里,状态机如何处理中断?如何让任务“并行”? ...

状态机的作用是把一个工作流分解多个步骤,每个步骤单独实现,一个大代码就这样分解为多个小代码了。
我实际的工程就是ucos开多个线程,某些线程使用了状态机,某些线程没使用。线程之间使用消息队列传输数据。

出0入17汤圆

发表于 2015-1-15 13:26:13 | 显示全部楼层
void main_state1(void)
{
    if(0 == g_state_timeout_milliseconds) {
        g_state_timeout_milliseconds = systemMs();
        printf("enter state1\n");
    }
    /* 5000毫秒超时 */
    if(systemMs() - g_state_timeout_milliseconds > 5*1000) {
        printf("exit state1\n");
        main_setNextState(main_state2);
        return;
    }

    /*
     * TODO 这里实现业务逻辑
     * 比如到达某种条件,进入其他状态
     * 比如收到某条消息,进入其他状态
     */
}
===================================
计时部分很不严格, 如果main_state1进入是, g_state_timeout_milliseconds=systemMs()=最大值-4999, 还不到5000时,  g_state_timeout_milliseconds将会变成0,又执行一遍 printf("enter state1\n"),同时此任务执行时间翻了一倍。

出10入120汤圆

发表于 2015-1-15 13:45:09 | 显示全部楼层
写的不错,实时任务可以安排在中断中运行,这种架构适合初学者编写稍大一点的程序,比整个程序都是if...else.....case....switch来的清晰。

出10入120汤圆

发表于 2015-1-15 13:47:52 | 显示全部楼层
本帖最后由 makesoft 于 2015-1-15 14:14 编辑
wicy001 发表于 2015-1-15 13:26
void main_state1(void)
{
    if(0 == g_state_timeout_milliseconds) {


楼主表达的其实就是一种编程思路 ,仔细看了下程序,这个地方楼主写的没有问题。

出0入0汤圆

发表于 2015-1-15 14:01:58 | 显示全部楼层
看不大懂,貌似很好用的样子

出0入0汤圆

发表于 2015-1-15 14:07:35 | 显示全部楼层
clock()是计算程序运行时间,具体没怎么用过,奇怪的是又没有相关定时器,它是如何记录程序运行时间的呢,其次clock + 100意欲为何,楼主有空解答下,多谢。

出0入0汤圆

发表于 2015-1-15 14:23:54 | 显示全部楼层
rossih 发表于 2015-1-15 11:08
麻烦发些资料看看

哦,写得不太准确,应该是"尾调用"实现状态机,在最后return到另一个函数。
C语言不能直接用的,C语言的"尾调用"会爆栈,lua对"尾调用"不会。

出0入0汤圆

发表于 2015-1-15 14:25:46 | 显示全部楼层
又涨姿势了。。。

出0入17汤圆

发表于 2015-1-15 14:34:43 | 显示全部楼层
makesoft 发表于 2015-1-15 13:47
楼主表达的其实就是一种编程思路 ,仔细看了下程序,这个地方楼主写的没有问题。 ...

楼主的思路是可用的,关键还是整个项目,怎么结合这个思路,对任务进行合理的划分。

关于时间那一段,也是我看错了。  第一次进入状态时,执行一遍 printf("enter state1\n"),如果此时 g_state_timeout_milliseconds=systemMs()=0 ,下次执行时,还会执行 printf("enter state1\n")。
只会存在几率打印两遍信息,任务时间不会翻倍。

出0入0汤圆

发表于 2015-1-15 15:28:46 | 显示全部楼层
重点还是在指针函数吧

出0入0汤圆

 楼主| 发表于 2015-1-15 17:10:14 | 显示全部楼层
卢台长 发表于 2015-1-15 14:07
clock()是计算程序运行时间,具体没怎么用过,奇怪的是又没有相关定时器,它是如何记录程序运行时间的呢, ...

clock()+100是为了防止程序刚启动时,clock()返回0的情况。

这个程序是为了方便大家在PC上测试,才使用的clock()函数;真正的stm32上,是采用如下的方法:

//启动一个定时器,每毫秒中断一次,在中断函数中把 g_milliseconds 加1
static u32 g_milliseconds=0;
u32 systemMs(void)
{
    return g_milliseconds;
}

出0入0汤圆

 楼主| 发表于 2015-1-15 17:16:33 | 显示全部楼层
wicy001 发表于 2015-1-15 13:26
void main_state1(void)
{
    if(0 == g_state_timeout_milliseconds) {

你说的问题完全不存在。
也不会出现打印两次"enter_state1"的情况。

出0入0汤圆

 楼主| 发表于 2015-1-15 17:17:58 | 显示全部楼层
wicy001 发表于 2015-1-15 14:34
楼主的思路是可用的,关键还是整个项目,怎么结合这个思路,对任务进行合理的划分。

关于时间那一段,也 ...

由于考虑到你说的这种情况,所以我的 systemMs()中,给clock()的值加了100,呵呵

出0入0汤圆

发表于 2015-1-15 17:34:01 | 显示全部楼层
请教一些基础的问题啊!不要笑话我啊!typedef void (*state_func_t)(void);这个是什么用法啊!static state_func_t g_state_func = NULL;怎么就定义了一个函数空指针啊!

出0入0汤圆

发表于 2015-1-15 17:49:31 | 显示全部楼层
本帖最后由 卢台长 于 2015-1-15 19:29 编辑
片羽之神 发表于 2015-1-15 17:34
请教一些基础的问题啊!不要笑话我啊!typedef void (*state_func_t)(void);这个是什么用法啊!static stat ...


typedef void (*state_func_t)(void); 重定义函数指针,类型名为 state_func_t,  无返回值,无参数。

static state_func_t g_state_func = NULL 定义一个state_func_t类型函数指针取名为g_state_func ,初值为NULL。

更多细节 搜索 typedef 定义函数指针。

出0入0汤圆

发表于 2015-1-15 17:58:06 | 显示全部楼层
mdb3 发表于 2015-1-15 17:10
clock()+100是为了防止程序刚启动时,clock()返回0的情况。

这个程序是为了方便大家在PC上测试,才使用 ...

多谢楼主,你这么说我就想明白了,但是在程序如果真正的用clock()函数(在keil中能打开time.h),会出现怎么样的效果。

出0入85汤圆

发表于 2015-1-15 20:14:00 | 显示全部楼层
懂得人看很简单,不懂的还是不懂

出0入0汤圆

发表于 2015-1-15 20:42:56 | 显示全部楼层
本帖最后由 lcw_swust 于 2015-1-15 20:47 编辑

看起来不错,先收藏了。

出0入0汤圆

发表于 2015-1-15 21:26:36 | 显示全部楼层
感觉很深奥的样子

出0入0汤圆

发表于 2015-1-15 21:40:01 | 显示全部楼层
重点还是在指针函数吧

出0入0汤圆

发表于 2015-1-15 21:55:35 | 显示全部楼层
挺不错的。。。不过例子里只有一个状态机在跑,实际上可以多个状态机同时跑的,但是要注意那几个static变量的定义。一般大家用状态机也主要是来处理多任务。

出0入0汤圆

发表于 2015-1-15 21:59:05 | 显示全部楼层
这个有点像轮询的机制。

出0入0汤圆

发表于 2015-1-15 22:08:59 来自手机 | 显示全部楼层
有时间看一下是否合适我

出10入0汤圆

发表于 2015-1-15 23:17:05 来自手机 | 显示全部楼层
mark一下!!有空看看!

出0入0汤圆

发表于 2015-1-16 08:47:12 | 显示全部楼层
先收藏起来,感谢分享

出140入158汤圆

发表于 2015-1-16 09:06:41 | 显示全部楼层
恕我水平太低,觉得完全没用,无论是写几十行还是几十万行的程序。

出0入0汤圆

 楼主| 发表于 2015-1-16 10:26:21 | 显示全部楼层
amigenius 发表于 2015-1-16 09:06
恕我水平太低,觉得完全没用,无论是写几十行还是几十万行的程序。


我说有用,理由是这个方法能实现状态机模式。
你说没用,理由是什么?
自己不思进取就算了,还老发表些武断的言论来误导新人!

出0入0汤圆

发表于 2015-1-16 10:59:56 | 显示全部楼层
很有用,谢谢分享!

出140入158汤圆

发表于 2015-1-16 11:10:41 | 显示全部楼层
mdb3 发表于 2015-1-16 10:26
我说有用,理由是这个方法能实现状态机模式。
你说没用,理由是什么?
自己不思进取就算了,还老发表些武 ...

这东西见人见智,状态机只是一种编程思路,实现方式多样,无需拘泥于什么形式实现。我从4位机到32位机,PC机,POWERPC各式单片机CPU用过不下十多种,程序写过从几十行到几十万行,从未觉得自己有什么不思进取的地方,您却帮我下结论了,也是在是太武断了吧

出140入158汤圆

发表于 2015-1-16 11:17:27 | 显示全部楼层
mdb3 发表于 2015-1-16 10:26
我说有用,理由是这个方法能实现状态机模式。
你说没用,理由是什么?
自己不思进取就算了,还老发表些武 ...

见人见智,本来简单无比的东西,非要弄得这么复杂,关键还不实用,除了拿来装逼使用什么“机制”这种听起来牛逼的词语之外,实在找不到让我使用的理由

出0入0汤圆

发表于 2015-1-16 15:15:45 | 显示全部楼层
表示完全看不懂,突然有点伤心的感觉了。

出0入0汤圆

发表于 2015-1-16 18:13:29 | 显示全部楼层
本帖最后由 cheungman 于 2015-1-16 18:17 编辑
niechao15 发表于 2015-1-16 15:15
表示完全看不懂,突然有点伤心的感觉了。


原来用switch和if的状态机代码,后来改成函数指针方式,代码清晰很多。
  1. static int fsm_state1(void)
  2. {
  3.         state = fsm_state2;
  4.         return 0;
  5. }

  6. static int fsm_state2(void)
  7. {
  8.         state = fsm_state1;
  9.         return 0;
  10. }

  11. typedef struct
  12. {
  13.         int (*pFun)(void);
  14. }STATE_ITEM;

  15. static STATE_ITEM fsm_map[2] =
  16. {
  17.         {fsm_state1},
  18.         {fsm_state2}
  19. };

  20. void fsm_porcessor(void)
  21. {
  22.         fsm_map[state].pFun();
  23. }
复制代码

出0入0汤圆

发表于 2015-1-16 19:18:58 | 显示全部楼层
表示一直想学,但是一直都不懂

出0入0汤圆

发表于 2015-1-16 19:38:20 | 显示全部楼层
业余做的东东都很简单,一直没用过状态机。

出0入0汤圆

发表于 2015-1-16 19:41:48 | 显示全部楼层
膜拜高大上的东东啊

出0入0汤圆

发表于 2015-1-19 10:08:15 | 显示全部楼层
cheungman 发表于 2015-1-16 18:13
原来用switch和if的状态机代码,后来改成函数指针方式,代码清晰很多。
...

你这里面的state是定义为什么类型的呢?

出0入0汤圆

发表于 2015-1-19 10:08:45 | 显示全部楼层
cheungman 发表于 2015-1-16 18:13
原来用switch和if的状态机代码,后来改成函数指针方式,代码清晰很多。
...

也是STAE_ITEM?

出0入0汤圆

发表于 2015-1-19 14:23:40 | 显示全部楼层
初看发现是函数指针,有空仔细看看

出0入0汤圆

发表于 2015-1-19 21:20:55 来自手机 | 显示全部楼层
谢谢楼主分享,让我可解到了另一种思路

出0入0汤圆

发表于 2015-1-21 09:31:55 | 显示全部楼层
谢谢分享

出100入101汤圆

发表于 2015-1-21 09:47:00 | 显示全部楼层
空了慢慢看!

出0入0汤圆

发表于 2015-1-21 17:26:42 | 显示全部楼层
不错,学习了!

出0入0汤圆

发表于 2015-1-21 19:24:30 | 显示全部楼层
好吧,我居然看完了评论,发现自己水平亟待提高啊

出0入0汤圆

发表于 2015-1-21 23:26:07 | 显示全部楼层
思路非常好啊

出0入0汤圆

发表于 2015-1-22 04:41:07 | 显示全部楼层
量子的状态机比较完整,支持继承等概念

出0入0汤圆

发表于 2015-1-31 11:04:46 | 显示全部楼层
mcu_lover 发表于 2015-1-15 09:17
妙。亮点在g_state_timeout_milliseconds 的应用。一般人体会不到。

这个没有什么妙点吧,就一个超时,感觉给switch一个样。。呵呵。

出0入264汤圆

发表于 2015-1-31 12:27:40 | 显示全部楼层
STM32LOU 发表于 2015-1-31 11:04
这个没有什么妙点吧,就一个超时,感觉给switch一个样。。呵呵。

那你还得接着看。慢慢揣摩。如果没有实际使用,体会不到妙处的。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-11 11:03

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表