OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6176|回复: 31

。。。。。。。。。。。。。。

[复制链接]

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
发表于 2015-6-12 12:16:13 | 显示全部楼层 |阅读模式
只求最好!
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-12 14:29:28 | 显示全部楼层
没人识货吗,已经把宏用出模板的效果了~_~
只求最好!
回复 支持 反对

使用道具 举报

16

主题

147

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7140
金钱
7140
注册时间
2015-1-23
在线时间
106 小时
发表于 2015-6-12 14:37:36 | 显示全部楼层
STATE_LIST(DEFINE_STATE)

是不是应该换成    DEFINE_STATE(STATE_LIST)
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
21
金钱
21
注册时间
2015-6-12
在线时间
0 小时
发表于 2015-6-12 14:39:42 | 显示全部楼层
回复【2楼】Tangerious:
---------------------------------
厉害,不过一般人还真看不懂,个人觉得里面的前一篇已经够用了
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-12 14:47:17 | 显示全部楼层
回复【3楼】东方赤那:
---------------------------------
代码是我调试过的,不会有问题,2楼说的不对,我给你解释下如果换成DEFINE_STATE(STATE_LIST)那替换出来就是State_STATE_LIST而无法进行第二层替换,因为没有State_STATE_LIST这个Token,你仔细阅读再回复下吧,或者自己动手调试下就知道了。
只求最好!
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-12 14:50:10 | 显示全部楼层
回复【4楼】技术不宅:
---------------------------------
谢谢,这里懂的人还真不多,握手。。。
只求最好!
回复 支持 反对

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2015-6-12 15:26:50 | 显示全部楼层
精益求精,不错。

不过我看完你第一篇博客的时候,佩服之余也思考了一个问题,我用这种方式写的状态机,不是所有人都能懂,这样在实际项目里多少有点麻烦,不利于维护。而且目前MCU的使用大多是性能过剩,正常应用处理分支数量的switch-case并不会成为系统负担。

之所以会考虑这个问题,也是自己研究了许多有意思的东西,很想应用于实际项目,然后遇到上面的问题,最后还是用传统方法。

anyway,楼主的方法很棒!
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
发表于 2015-6-12 15:55:51 | 显示全部楼层
手动帮顶,有时间学习一下
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

70

主题

6763

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
13129
金钱
13129
注册时间
2012-11-26
在线时间
3814 小时
发表于 2015-6-12 15:59:28 | 显示全部楼层
还是习惯用  switch case
学无止境
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-12 16:00:38 | 显示全部楼层
回复【7楼】ianhom:
---------------------------------
又见面了,多谢关注。你说的很对,如果有团队合作或项目接替,的确应当以简单至上,根据实际需求来!但如果在一些低功耗低性能单片机场合,这个方法优势还是比较明显的。个人比较追求极致吧,不管怎么说,你的回帖就是我前进追求的动力!
只求最好!
回复 支持 反对

使用道具 举报

3

主题

401

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1769
金钱
1769
注册时间
2015-6-11
在线时间
313 小时
发表于 2015-6-12 16:02:23 | 显示全部楼层
这个只能说饶了很多弯,理解起来蛮困难的,说下我理解的替换吧(初始化为例)
 Steps[NS](invar); NS = State_init
首先替换
Steps[State_init](&var),后面变量不用考虑
下面就是Steps[State_init],枚举,State_init默认为0,那么就替换成了
STATE_PROCEDURE(init)//这是一个指针
另外这是Steps是指向函数指针的数组
typedef State(*Procedure)(void *);   
其实也就替换成了State STATE_PROCEDURE(init)(&var)
因为#define STATE_PROCEDURE(State) Step##_##State,(中间是强制联合,##语句的用法)
那么STATE_PROCEDURE(init)也就是Step_init
所以最后等同于NS = Step_init(&var)
回复 支持 反对

使用道具 举报

3

主题

401

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1769
金钱
1769
注册时间
2015-6-11
在线时间
313 小时
发表于 2015-6-12 16:06:35 | 显示全部楼层
后面的其实也都是用这个替换的,static State NS = State_init; //定义下一状态这句话我觉得有问题
应该定义为static States NS = State_init; //定义下一状态这句话我觉得有问题
因为枚举虽然转换为unsigned char 是没问题的,但你既然限定了,这样写不严谨
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-12 16:16:15 | 显示全部楼层
回复【12楼】zc123:
---------------------------------
谢谢你的耐心阅读,某些注释没太斟酌,可能写的造成不好理解,这句应该注释为//次态储存变量,你说的枚举转换为unsigned char也是我太追求极致了吧,不想浪费半分储存空间,强迫症吧,的确写成int更为严谨^_^
只求最好!
回复 支持 反对

使用道具 举报

3

主题

401

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1769
金钱
1769
注册时间
2015-6-11
在线时间
313 小时
发表于 2015-6-12 16:19:29 | 显示全部楼层
回复【13楼】Tangerious:
---------------------------------
恩,追求极致赞一个,对于我来说,看懂还行,让我写绝对没那个耐心,这弯子绕的,你心也太细了
回复 支持 反对

使用道具 举报

29

主题

311

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1530
金钱
1530
注册时间
2012-9-4
在线时间
262 小时
发表于 2015-6-12 16:36:37 | 显示全部楼层
刚开始用  switch case,感觉不错。。。。你这个看看,以后可以尝试一下。。。。
STM32---STM32---STM32---STM32---STM32---STM32---STM32---STM32---STM32
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-12 16:41:19 | 显示全部楼层
回复【15楼】aben:
---------------------------------
握手。。。
只求最好!
回复 支持 反对

使用道具 举报

5

主题

154

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
205
金钱
205
注册时间
2013-6-8
在线时间
2 小时
发表于 2015-6-12 16:59:43 | 显示全部楼层
没有看到事件派发,这个叫动作表
即使爬到最高的山上,一次也只能脚踏实地地迈一步。
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-12 17:15:53 | 显示全部楼层
回复【17楼】倒拔萝卜:
---------------------------------
谢谢你的回复,这里我只是举了个片面的例子,如果需要事件驱动状态跳转,只需要将结构体类型参数改成全局变量就行了啊,事件产生更改全局结构体变量封装的参数,以指针传入在状态函数判断就行了,而且对于IO事件就跟容易了,他们本身就是全局的,另外你说的“动作表”我没百度出来,如果你说这不是状态机,那我感觉以前在用Verilog写的都是你说的 “动作表了”。
只求最好!
回复 支持 反对

使用道具 举报

5

主题

154

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
205
金钱
205
注册时间
2013-6-8
在线时间
2 小时
发表于 2015-6-12 19:24:20 | 显示全部楼层
没有事件驱动的我都管它叫动作表,因为我看到下面这句,
以为你只是把函数指针顺序的执行一遍就完事了
for (i = 0; i <= 8; i++)
{BestStateMachine(&
var); }

我分析了一下,好像是一个这样的状态图:



=========
我很纳闷的是这种写法你打算怎么把事件驱动加进去呢?
而且只能玩有限状态机,层次状态机怎么弄?
即使爬到最高的山上,一次也只能脚踏实地地迈一步。
回复 支持 反对

使用道具 举报

3

主题

62

帖子

0

精华

初级会员

Rank: 2

积分
94
金钱
94
注册时间
2015-5-29
在线时间
0 小时
发表于 2015-6-12 20:58:35 | 显示全部楼层
先学好函数指针吧。
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-12 21:09:25 | 显示全部楼层
回复【20楼】XCDesigner:
---------------------------------
等你学好!^_^
只求最好!
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-12 21:14:05 | 显示全部楼层
回复【19楼】倒拔萝卜:
---------------------------------
先给你的专业分析点个赞!这个标题的确不对,应该改为FSM,我给的例子,只是为便于理解,是个原型,实际应用比如单片机上,只需把BestStateMachine(&var)这个放到定时器中断或者某个线程里面周期调用就可以了,至于事件驱动,比如用户按键事件在状态函数里面判断I/O状态就可以了啊,那个void*参数都可省了,如果你觉得这还不对,那好,我在这里用数组模拟个
int event_queue[]={1,2,2,0,0,4,4,4,0,0};//不同数字代表不同事件
typedef struct _SM_VAR  //对状态机参数封装
{
int cnt;
int current_event;//加个变量做事件缓存
}SM_VAR;
int main(void)
{
SM_VAR var;
int i;
for (i = 0; i <= 8; i++){ //实际以下四行代码应当放到定时器中断,或某一线程,再不就while(1),状态机总得有个时钟吧
lock_acquire(eq_lock);//上锁,这个根据实际实现
var.current_event=event_queue;//读取事件
lock_release(eq_lock);//解锁
BestStateMachine(&var);//传入事件
}
return 0;
}
事件怎么用,在不同状态的Guard定义和Action就根据实际情况了,而且你也可以在Action中分发事件,这里就不赘述了。还有这个并不能实现HSM,这种复杂的东西我想必须有良好的数据结构做支撑,以后有时间我会研究。
只求最好!
回复 支持 反对

使用道具 举报

16

主题

147

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7140
金钱
7140
注册时间
2015-1-23
在线时间
106 小时
发表于 2015-6-13 09:04:44 | 显示全部楼层
回复【5楼】Tangerious:
---------------------------------
你说的对,我这次看懂了
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-13 10:41:40 | 显示全部楼层
之所以这样写是因为接触状态机是从FGPA开始的,也玩了较长时间的FGPA习惯了状态机(此处限FSM,后面也是)编程,很多人没搞过硬件的状态机,不能体会状态机的要点在于高效性和可靠性,这个状态机的编写我是依照写硬件状态机的思维模式来写的,于是你会看到NS这个变量名。另外附上一片《用状态机原理进行软件设计》百度得到,你可以对比一下里面的FSM,会发现里面的状态机太软件思维了,其实状态机适合一些机械性的操作,是偏向硬件的。
只求最好!
回复 支持 反对

使用道具 举报

5

主题

154

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
205
金钱
205
注册时间
2013-6-8
在线时间
2 小时
发表于 2015-6-13 16:21:57 | 显示全部楼层
不会FPGA哦,感觉好难

楼主有没有研究过qp状态机,很有名的,
也是以函数指针高效实现的fsm和hsm,很精彩
顺便传个文档

Practical UML Statecharts in CC++(2nd,中文版).pdf

4.67 MB, 下载次数: 63

即使爬到最高的山上,一次也只能脚踏实地地迈一步。
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-13 19:28:15 | 显示全部楼层
是Quantum latform吧,QFSM在《用状态机原理进行软件设计》也讲到了不过较为浅显,你的书非常不错收下了,以后有时间研究下,快毕业了,只怕以后没有在学校这么多闲暇时间了。
只求最好!
回复 支持 反对

使用道具 举报

21

主题

123

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
355
金钱
355
注册时间
2012-3-11
在线时间
49 小时
发表于 2015-6-13 20:34:44 | 显示全部楼层
回复【26楼】Tangerious:
---------------------------------
请问楼主:State Step##_##state(void * arg); 中“##_##”的井号怎么理解,你博客中说“(##起连接Token的作用”,不怎么理解,第二个例子在CodeBlocks编译不了,还请赐教,第一个例子编译没问题。
这辈子只会两件事:这也不会,那也不会!
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-14 12:31:30 | 显示全部楼层
 回复【27楼】 hkys_lxh :
---------------------------------
##的用法你搜下就知道了我这里给个参考吧http://wenku.baidu.com/link?url=K_4sZYVk6X3MTlACiyJ_srHsha12Qgxk7U9nFkUgH0ldw-WRB5FOxCLMFoNHGopUHaSm0TAtf0b7FQJAm7rBGTUEAnIE5xHjwUSNBFZMTlq,至于token就是编译原理中词法分析器对字符串序列转化的产物,比如int xxx里的的int和xxx都是token,至于你说的Code::Blocks编译(应该是用的GCC吧),我没试过,可否贴上错误?另外GCC的话有个&&的语法糖,叫做Labels as Values,http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Labels-as-Values.html?这个什么switch或者函数指针都可去掉,实现状态机更容易。

只求最好!
回复 支持 反对

使用道具 举报

22

主题

181

帖子

0

精华

高级会员

Rank: 4

积分
878
金钱
878
注册时间
2014-7-7
在线时间
311 小时
发表于 2015-6-14 13:43:03 | 显示全部楼层
回复【28楼】Tangerious:
---------------------------------
有限状态机,虽然写的不错,不过换汤不换药,差不了多少的,而且还不如if else来的灵活
 #define FSM_ACTION_FLAG             s_tbState.Bits 
    #define FSM_STOP_ALL_ACTIONS()      do {s_tbState.Value = 0;}while(0) 
    #define FSM_START                   (0 == s_tbState.Value) 
    #define FSM_STATE_A                 FSM_ACTION_FLAG.BIT0 
    #define FSM_STATE_B                 FSM_ACTION_FLAG.BIT1 
    … 
    #define FSM_STATE_H                 FSM_ACTION_FLAG.BIT7 
  
    bool fsm_example_B( <</span>形参列表> ) { 
        static byte_t s_tbState = {0};                               //!< 定义状态变量 
  
        if (FSM_START) {                                             //!< 起始状态 
            //! 这里放置状态机初始化的代码 
            … 
           FSM_STATE_A = true;                                       //!< 进入状态B,start装台自动结束 
        } 
  
        if (FSM_STATE_A) {                                           //!< 一个典型的简单状态 
            //! 这里放置状态A的代码或者 
            … 
            //! 这里放置某些条件以开启别的状态 
            if (<</span>某些条件>) { 
                //! 这里做一些“进入”下一个状态之前的准备工作 
                FSM_STATE_B = true;                                  //!< 开启下一个状态 
                FSM_STATE_A = false;                                 //!< 结束当前状态 
            } 
        } 
  
        if (FSM_STATE_B) {                                           //!< 一个典型的监视状态 
            … 
            //! 这里检测某些条件 
            if (<</span>某些条件>) { 
                //! 这里做一些“开启”某个状态的准备工作 
                FSM_STATE_C = true;                                  //!< 开启某一个状态而不结束当前状态 
                FSM_STATE_D = true;                                  //!< 你当然可以一次触发多个状态 
                … 
            } else if (<</span>某些条件>) { 
                //! 满足某些条件以后关闭当前状态 
                FSM_STATE_B = false; 
            } 
        } 
        … 
        if (FSM_STATE_F) {                                            //!< 一个典型的子状态机调用 
            if (!fsm_example_a(<</span>实参列表>)) {                  //!< 等待子状态机返回false 
                //!子状态机运行完成,进入下一状态 
                … 
                FSM_STATE_F = false;                                  //!< 结束当前状态 
                FSM_STATE_x = true;                                   //!< 进入下一状态x代表某个字母 
            } 
        } 
  
        if (FSM_STATE_H) {                                            //!< 一个典型的中止状态 
            //!< 某些状态机的操作,比如释放某些资源 
            … 
            FSM_STOP_ALL_ACTIONS();                                   //!< 复位状态机 
            return false;                                             //!< 返回false表示状态机结束 
        } 
  
        return true;                                                  //!< 返回true表示状态机保持运行 
    } 

以上代码转载傻孩子的帖子:FSM状态机实践入门。
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-14 16:20:30 | 显示全部楼层
回复【27楼】 hkys_lxh :
---------------------------------
在Eclipse下GCC我编译试过了没问题!而且用GCC明显有更好的方式实现,我以前到单片机都用GCC(开始用的iar和keil,后来发现平台切换太麻烦),现在我已不玩单片机了,这也是GCC带来的好处,他的通用性,https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/C-Extensions.html#C-Extensions里面的第二和第三个扩展,实现状态机简直跟好玩似的。
只求最好!
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-14 16:49:15 | 显示全部楼层
回复【29楼】 our单片机 :
---------------------------------
if-else不叫灵活,叫简单,很多初中生也能写出看起来不错的代码,实现像样的功能!以你的思维,坑定是无法接受QP状态机了,肯定会说if-else灵活!如果我用的Protothreads写状态机,你肯定也还是会说if-else灵活!灵不灵活,是个人思维习惯,就像让一个老外用筷子肯定觉得还是勺子和餐叉灵活,但是让一个中国人用勺子,他会觉得没什么不灵活的!
只求最好!
回复 支持 反对

使用道具 举报

3

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2015-4-21
在线时间
0 小时
 楼主| 发表于 2015-6-14 17:18:43 | 显示全部楼层
这里不好玩!Bye-Bye各位!
只求最好!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-21 07:02

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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