搜索
bottom↓
回复: 18

傻孩子状态机例子 移植IAR C++

[复制链接]

出0入0汤圆

发表于 2012-4-21 06:12:05 | 显示全部楼层 |阅读模式
本帖最后由 uc_c++ 于 2012-4-21 08:33 编辑

http://www.ourdev.cn/thread-5468708-1-1.html
傻孩子的例子取的很好。

我们看主程序,有三个状态机Ping_Pang_Demo,Stream_Output,Hello_World。
状态机Ping_Pang_Demo 有3个状态:Ping_Pang_Demo_Start,Ping_Pang_Demo_Wait_Busy_Flag,Ping_Pang_Demo_Output.
状态机Stream_Output有2个状态,Stream_Out_Start,Stream_Out_Byte_Output
状态机Hello_World有3个状态,HW_Start,HW_Init_Delay,HW_Delay。

状态机Ping_Pang_Demo的功能是等待收到串口一字节数据,然后向串口发送收到的数据。
状态Ping_Pang_Demo_Start等待串口接受到数据,跳转到Ping_Pang_Demo_Wait_Busy_Flag。
状态Ping_Pang_Demo_Wait_Busy_Flag等待s_bBusyFlag为false,跳转到Ping_Pang_Demo_Output
状态Ping_Pang_Demo_Output向串口发送接受到得数据,置s_bBusyFlag为false,跳转到Ping_Pang_Demo_Start。

因为有多个状态机都使用串口,为了保证某一时刻串口只能被一个状态机使用,使用s_bBusyFlag标志,串口互斥访问。

状态机Hello_World周期向串口发送"hello world"字符串。
状态HW_Start等待s_bBusyFlag为false,开始向串口发送字符串,跳转到HW_Init_Delay
状态HW_Init_Delay置s_bBusyFlag为false,初始化状态机等待时间,跳转到HW_Delay
状态HW_Delay等待时间到,跳转到HW_Start

状态HW_Start向串口发送字符串,又调用了子状态机Stream_Output
子状态机Stream_Output的状态有两个,
Stream_Out_Start检测参数,是否还有数据要发。没有数据,则子状态机返回(返回到父状态机Hello_World)。有数据要发,则跳转到Stream_Out_Byte_Output
Stream_Out_Byte_Output串口发送1字节,跳转到Stream_Out_Start。

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2012-4-21 06:13:53 | 显示全部楼层
本帖最后由 uc_c++ 于 2012-4-21 07:52 编辑

有了状态机跳转关系,有可以移植到IAR C++。
LGT板子还没到,没有在硬件上验证过。

说明:
由于我的状态机没有子状态机,改用状态机等待另一个状态机为IDLE,
因此Hello_World_CLASS加入状态HW_WaitSendEnd,等待发送完毕。

另外,我的状态机可以直接延时,不需要再定义延时状态,因此,
将状态HW_Init_Delay,HW_Delay删除。
  1. #include "proj_incs.h"

  2. class Ping_Pang_Demo_CLASS:public VSTATE_SCHED_CLASS
  3. {
  4. public:
  5.   //状态机初始化,初始状态为Ping_Pang_Demo_Start
  6.   void Init(void)
  7.   {
  8.     *this<<VSTATE_OBJECT(Ping_Pang_Demo_Start);
  9.   }
  10. private:
  11.   //状态声明
  12.   VSTATE_DeclarationIn(Ping_Pang_Demo_CLASS,Ping_Pang_Demo_Start);            
  13.   VSTATE_DeclarationIn(Ping_Pang_Demo_CLASS,Ping_Pang_Demo_Wait_Busy_Flag);   
  14.   VSTATE_DeclarationIn(Ping_Pang_Demo_CLASS,Ping_Pang_Demo_Output);            
  15. };


  16. class Hello_World_CLASS:public VSTATE_SCHED_CLASS
  17. {
  18. public:
  19.   //状态机初始化,初始状态为HW_Start
  20.   void Init(void)
  21.   {
  22.     *this<<VSTATE_OBJECT(HW_Start);       //初始状态
  23.   }
  24. private:
  25.   //状态声明
  26.   VSTATE_DeclarationIn(Hello_World_CLASS,HW_Start);         
  27.   VSTATE_DeclarationIn(Hello_World_CLASS,HW_WaitSendEnd);
  28. };


  29. class Stream_Output_CLASS:public VSTATE_SCHED_CLASS
  30. {
  31. public:
  32.   //状态机初始化,初始状态为IDLE
  33.   void Init(void)
  34.   {     
  35.   }
  36. private:
  37.   //状态声明
  38.   VSTATE_DeclarationIn(Stream_Output_CLASS,Stream_Out_Start);         
  39.   VSTATE_DeclarationIn(Stream_Output_CLASS,Stream_Out_Byte_Output);   
  40.   
  41.   friend class Hello_World_CLASS;   
  42. };

  43. Ping_Pang_Demo_CLASS Ping_Pang_Demo;       //状态机定义
  44. Hello_World_CLASS  Hello_World;            //状态机定义
  45. Stream_Output_CLASS  Stream_Output;        //状态机定义

  46. static uint8 s_chByte;
  47. static bool  s_bBusyFlag = false;
  48. static uint8 *pchSrc;
  49. static uint8 chLength;

  50. //==============================================================================
  51. //==============================================================================
  52. VSTATE_ImplementationIn(Ping_Pang_Demo_CLASS,Ping_Pang_Demo_Start)  
  53. {
  54.   if (usart_serial_in_byte(&s_chByte))  //如果串口收到数据
  55.   {
  56.     *this<<VSTATE_OBJECT(Ping_Pang_Demo_Wait_Busy_Flag);  //跳转到Ping_Pang_Demo_Wait_Busy_Flag
  57.     return;
  58.   }
  59.   //没有跳转,状态机保持原来的状态,继续在Ping_Pang_Demo_Start运行
  60. }

  61. VSTATE_ImplementationIn(Ping_Pang_Demo_CLASS,Ping_Pang_Demo_Wait_Busy_Flag)  
  62. {
  63.   if (!s_bBusyFlag)       //如果串口不繁忙
  64.   {
  65.     s_bBusyFlag = true;   //置串口繁忙
  66.     *this<<VSTATE_OBJECT(Ping_Pang_Demo_Output);  //跳转到Ping_Pang_Demo_Output
  67.     return;
  68.   }
  69. }

  70. VSTATE_ImplementationIn(Ping_Pang_Demo_CLASS,Ping_Pang_Demo_Output)  
  71. {
  72.   if (usart_serial_out_byte(s_chByte))
  73.   {
  74.     s_bBusyFlag = false;   //释放串口
  75.     *this<<VSTATE_OBJECT(Ping_Pang_Demo_Start);  //跳转到Ping_Pang_Demo_Start
  76.   }
  77. }

  78. //==============================================================================
  79. //==============================================================================
  80. VSTATE_ImplementationIn(Stream_Output_CLASS,Stream_Out_Start)  
  81. {
  82.   if(!((pchSrc!=NULL)&&(chLength!=0)))   //如果没有数据发送
  83.   {
  84.     *this<<VSTATE_OBJECT_IDLE();         //跳转到Idle,表示数据发送完毕
  85.     return ;
  86.   }
  87.   
  88.   *this<<VSTATE_OBJECT(Stream_Out_Byte_Output);   //跳转到 Stream_Out_Byte_Output
  89.   return;
  90. }

  91. VSTATE_ImplementationIn(Stream_Output_CLASS,Stream_Out_Byte_Output)  
  92. {
  93.   uint8 chByte = *pchSrc;
  94.   if (usart_serial_out_byte(chByte))
  95.   {
  96.     pchSrc++;
  97.     chLength--;
  98.     *this<<VSTATE_OBJECT(Stream_Out_Start);   //跳转到 Stream_Out_Start
  99.     return;
  100.   }
  101. }  

  102. //==============================================================================
  103. //==============================================================================
  104. VSTATE_ImplementationIn(Hello_World_CLASS,HW_Start)  
  105. {
  106.   if (!s_bBusyFlag)
  107.   {
  108.     s_bBusyFlag = true;     //置串口繁忙
  109.    
  110.     pchSrc = (uint8 *)"Hello world!\r\n";
  111.     chLength = sizeof( "Hello world!\r\n");
  112.    
  113.     Stream_Output<<VSTATE_OBJECT_IN(Stream_Output_CLASS,Stream_Out_Start);//Stream_Output跳转到Stream_Out_Start
  114.    
  115.     *this<<VSTATE_OBJECT(HW_WaitSendEnd);//跳转到HW_WaitSendEnd
  116.     return;
  117.   }  
  118. }

  119. VSTATE_ImplementationIn(Hello_World_CLASS,HW_WaitSendEnd)  
  120. {
  121.   if(Stream_Output.IsInIdle())  //如果状态机Stream_Output状态为IDLE,说明串口数据已经发送完毕
  122.   {
  123.     s_bBusyFlag = false;      //释放串口
  124.     *this<<(HS_TICKS_PER_SEC*2)<<VSTATE_OBJECT(HW_Start);  //延时两秒,跳转到HW_Start
  125.     return;
  126.   }
  127. }

  128. int main()
  129. {  
  130.   usart_init(9600);
  131.   
  132.   Ping_Pang_Demo.Init();
  133.   Hello_World.Init();
  134.   Stream_Output.Init();
  135.   
  136.   while(1)
  137.   {
  138.     Ping_Pang_Demo.Do();
  139.     Hello_World.Do();
  140.     Stream_Output.Do();
  141.   }
  142. }
复制代码

出0入0汤圆

发表于 2012-4-21 06:18:06 | 显示全部楼层
等LZ开课

出0入0汤圆

发表于 2012-4-21 07:33:48 | 显示全部楼层
上官的C++,玩的牛啊。

出0入0汤圆

发表于 2012-4-21 07:41:22 来自手机 | 显示全部楼层
做等听课

出0入0汤圆

发表于 2012-4-21 09:04:04 | 显示全部楼层
学习了,

出0入296汤圆

发表于 2012-4-21 09:56:08 | 显示全部楼层
哈哈~你的基于C++的状态机也很简洁实用。赞一个先!你的描述太好了,请允许我粘贴你的描述到我的原贴中……

出0入0汤圆

发表于 2012-4-21 10:22:04 | 显示全部楼层
学习,学习

出0入0汤圆

发表于 2012-4-21 17:28:57 | 显示全部楼层
请教楼主,我直接打开你的工程文件,为什么那些头文件都是没有认到?AVR studio 需要什么出来吗?谢谢!

出0入0汤圆

发表于 2012-4-21 17:34:18 | 显示全部楼层
楼主不放弃C++,值得佩服啊。。。。呵呵。

出0入0汤圆

发表于 2012-5-4 16:50:42 | 显示全部楼层
一直用C,还没到C++的转变嘞,可以学习学习~~

出0入0汤圆

发表于 2012-5-4 19:11:24 | 显示全部楼层
傻孩子,写得东西太有学习意义的,看过不少

出425入0汤圆

发表于 2012-5-7 17:25:56 | 显示全部楼层
uc_c++ 发表于 2012-4-21 06:13
有了状态机跳转关系,有可以移植到IAR C++。
LGT板子还没到,没有在硬件上验证过。

我一直写不出下面的代码。

class io{
        its_dir;  // 输入输出方向,如:DDB1
        its_pin;        // 用于读入的引脚,如:PINB1
        its_port;   // 用于输出的引脚,如:PORTB1
  public:
        io(dir,pin,port){}  //  构造函数,把方向,引脚,端口参数传递进去.
};

class led{
        io p1;
  public:
        led(dir,pin,port){ }         //构造函数,把方向,引脚,端口参数传递给P1.       
};

这时,我们可以这样用

led LED_1(DDB1,PINB1,PORTB1);
led LED_2(DDB2,PINB2,PORTB2);

是不是在IAR里面不可能实现?

出0入0汤圆

发表于 2012-5-7 18:20:18 | 显示全部楼层
本帖最后由 单片机玩C++ 于 2012-5-7 18:22 编辑
guolun 发表于 2012-5-7 17:25
我一直写不出下面的代码。

class io{


public:
        io(dir,pin,port){}  //  构造函数,把方向,引脚,端口参数传递进去.
----------------------------------------------------------------------------------------------------------
传递IO口参数,你只能用指针,或者引用。

更好办法是用模板,这样编译效率更高。
http://www.ourdev.cn/thread-5469748-1-3.html

出425入0汤圆

发表于 2012-5-7 20:58:18 | 显示全部楼层
本帖最后由 guolun 于 2012-5-7 21:02 编辑
单片机玩C++ 发表于 2012-5-7 18:20
public:
        io(dir,pin,port){}  //  构造函数,把方向,引脚,端口参数传递进去.
---------------- ...


IAR好像不支持io空间的指针。不知道有什么好方法传递进去?
我上面的io是基础类,led类包含了io类的。
我这样写法,方便把各种外设封装成类。比如LED类,不单有端口的操作,还有LED闪烁的次数,时间,等参数,要封装进一个类里面,++兄的模板类好像如何能做到?

出0入0汤圆

发表于 2012-5-26 12:14:43 | 显示全部楼层
protothread 的核心是:

1)每个任务的本质都是一个基于状态机的函数,多任务并行实际上是不断执行各个基于状态机的函数
...这一点,我想大家都很清楚。

2)对于任务函数:自动实现状态机,无需编程者主动去设计状态机的各个状态,巧妙的应用了c 编译器的特点,行号 __LINE__ 就用作状态,每个代码行都自带了一个隐含状态,用行号作为状态,就无需人为再设计状态了!这是protothread的精华,也是令人震撼的思想。

因此任务函数本质上是状态机,但是又被精妙的自动实现了,无需编程人员以状态机的方式思考,极大的提高了程序代码的自然度。

其实protothread的真正意义,就是这两条, 其他所代码,都是辅助其实现而已。

出0入0汤圆

发表于 2012-5-29 11:28:08 | 显示全部楼层
想基于mcu的面向对象。

出0入0汤圆

发表于 2012-5-31 00:30:36 | 显示全部楼层
顶一下!
头像被屏蔽

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-4-26 06:21

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

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