[其他MCU] 状态机多任务实现

[复制链接]
3203|11
 楼主| 奥德赛 发表于 2015-12-20 21:12 | 显示全部楼层 |阅读模式
最近工作上的事很多,一直没抽出时间赶进度,为了过好五一,今天下午抽时间移植了一个状态机系统上去,实现多任务的运行,为下一步菜单系统打下基础。

下面简单介绍一下这个状态机系统:

这个状态机是从隔壁论坛里网友的分享里copy过来的,试了几次,很好用,所以打算在小资源的单片机系统里面用下去。

它需要一个时钟,支持多个任务分时并发,支持信号量传递,简单的优先级等等。
 楼主| 奥德赛 发表于 2015-12-20 21:13 | 显示全部楼层
  1. #ifndef TINYOS
  2.         #define TINYOS
  3.         #define MAXTASKS 5                //顶层任务数量最大为255个,顶层任务的任何地方都可以调用子任务.
  4.         extern  volatile unsigned char timers[MAXTASKS];
  5.         #define _SS static unsigned char _lc=0; switch(_lc){default:
  6.         #define _EE ;}; _lc=0; return 255;
  7.         #define WaitX(tickets)  do {_lc=(__LINE__+((__LINE__%256)==0))%256; return tickets ;} while(0); case (__LINE__+((__LINE__%256)==0))%256:

  8.         #define RunTask(TaskName,TaskID) do { if (timers[TaskID]==0) timers[TaskID]=TaskName(); }  while(0);
  9.         #define RunTaskA(TaskName,TaskID) { if (timers[TaskID]==0) {timers[TaskID]=TaskName(); continue;} }   //前面的任务优先保证执行

  10.         #define CallSub(SubTaskName) do {unsigned char currdt; _lc=(__LINE__+((__LINE__%256)==0))%256; return 0; case (__LINE__+((__LINE__%256)==0))%256:  currdt=SubTaskName(); if(currdt!=255) return currdt;} while(0);
  11.         #define InitTasks() {unsigned char i; for(i=MAXTASKS;i>0 ;i--) timers[i-1]=0; }
  12.         #define UpdateTimers() {unsigned char i; for(i=MAXTASKS;i>0 ;i--){if((timers[i-1]!=0)&&(timers[i-1]!=255)) timers[i-1]--;}}

 楼主| 奥德赛 发表于 2015-12-20 21:14 | 显示全部楼层
  1. #define SEM unsigned int
  2.         //初始化信号量
  3.         #define InitSem(sem) sem=0;
  4.         //等待信号量
  5.         #define WaitSem(sem) do{ sem=1; WaitX(0); if (sem>0) return 1;} while(0);
  6.         //等待信号量或定时器溢出, 定时器tickets 最大为0xFFFE
  7.         #define WaitSemX(sem,tickets)  do { sem=tickets+1; WaitX(0); if(sem>1){ sem--;  return 1;} } while(0);
  8.         //发送信号量
  9.         #define SendSem(sem)  do {sem=0;} while(0);
  10. #endif//终止
 楼主| 奥德赛 发表于 2015-12-20 21:15 | 显示全部楼层
首先包含头文件和声明函数和变量
  1. //TinyOS
  2. #include "tinyOS.h"
  3. /*      信号量传递       */
  4. SEM keyPressed;
  5. /*      系统定时器       */
  6. void toggle_OS_timer(void);
  7. //unsigned char  task0();
  8. unsigned char  task1(void);
  9. unsigned char  task2(void);               
  10. unsigned char  task3(void);        
  11. unsigned char  task4(void);      
 楼主| 奥德赛 发表于 2015-12-20 21:16 | 显示全部楼层
编写任务代码,系统需要一个时钟
  1. /*  TinyOS task function */
  2. void toggle_OS_timer(void)
  3. {
  4.     UpdateTimers();
  5.         //RunTask(task0,0); //任务0具有精确按时获得执行的权限
  6. }

  7. /*     按键扫描任务,15ms一次        */
  8. unsigned char  task1(){
  9. _SS
  10.         while(1)
  11.         {
  12.                 key_scan();
  13.                 if(key_status) SendSem(keyPressed);
  14.                 WaitX(15);
  15.                 key_flag_clr();
  16.         }
  17. _EE
  18. }
 楼主| 奥德赛 发表于 2015-12-20 21:17 | 显示全部楼层
  1. /*     菜单响应程序        */
  2. unsigned char  task2(){
  3. _SS
  4.         while(1)
  5.         {
  6.                 WaitSem(keyPressed);        
  7.                 MenuIndex_switch();        
  8.         }
  9. _EE
  10. }
  11. /*     闪烁标题栏程序        */
  12. unsigned char  task3(){
  13. _SS
  14.         while(1)
  15.         {        
  16.     GUI_RectangleFill(0+1, 0+1,0+12,0+12, Magenta);        
  17.     GUI_RectangleFill(0+12, 0+1,0+24-1,0+12, Red);
  18.           GUI_RectangleFill(0+12, 0+12,0+24-1,0+24-1, Yellow);
  19.           GUI_RectangleFill(0+1, 0+12,0+12,0+24-1, Green);
  20.                 WaitX(250);
  21.     GUI_RectangleFill(0+1, 0+1,0+12,0+12, Green);        
  22.     GUI_RectangleFill(0+12, 0+1,0+24-1,0+12,Magenta );
  23.           GUI_RectangleFill(0+12, 0+12,0+24-1,0+24-1,Red );
  24.           GUI_RectangleFill(0+1, 0+12,0+12,0+24-1,Yellow );
  25.                 WaitX(250);
 楼主| 奥德赛 发表于 2015-12-20 21:18 | 显示全部楼层
  1. GUI_RectangleFill(0+1, 0+1,0+12,0+12,Yellow );        
  2.     GUI_RectangleFill(0+12, 0+1,0+24-1,0+12, Green);
  3.           GUI_RectangleFill(0+12, 0+12,0+24-1,0+24-1,Magenta );
  4.           GUI_RectangleFill(0+1, 0+12,0+12,0+24-1, Red);
  5.                 WaitX(250);
  6.     GUI_RectangleFill(0+1, 0+1,0+12,0+12, Red);        
  7.     GUI_RectangleFill(0+12, 0+1,0+24-1,0+12, Yellow);
  8.           GUI_RectangleFill(0+12, 0+12,0+24-1,0+24-1, Green);
  9.           GUI_RectangleFill(0+1, 0+12,0+12,0+24-1,Magenta );
  10.                 WaitX(250);
  11.         }
  12. _EE
  13. }

  14. /*     动画切换程序        */
  15. unsigned char  task4(){
  16.         static uint8 ts=0;
  17. _SS
  18.         while(1)
  19.         {        
  20.                 ts++;
  21.                 Board_LED_SetPortState(1<<(ts&0x03));         
  22.                 WaitX(250); //25fps
  23.         }
  24. _EE
  25. }
 楼主| 奥德赛 发表于 2015-12-20 21:19 | 显示全部楼层
好,一切就绪,初始化并运行任务即可
  1.     /*tinyOS start here */
  2.             InitTasks(); //初始化任务,实际上是给timers清零
  3.             InitSem(keyPressed);//初始化信号量
  4.             MenuIndex_switch();
  5.             while(1)
  6.             {
  7.                     RunTaskA(task1,1);//按键扫描
  8.                     RunTaskA(task2,2);//菜单相应
  9.                     RunTaskA(task4,4);//界面切换动画        
  10.                     RunTaskA(task3,3);//闪烁标题栏                        
  11.             }        
 楼主| 奥德赛 发表于 2015-12-20 21:20 | 显示全部楼层
是不是很简单呢,那我们看实现了哪些功能。

task1进行按键的周期扫描,并把结果传递给task2。

task2平时不运行,直到task1告知有按键按下。这个时候执行界面切换程序来响应按键。

task3闪烁窗口左上角标题栏,告知系统运行。

task4控制桌面流水灯。

评分

参与人数 1威望 +1 收起 理由
cov0xt + 1 谢谢~很有启发!

查看全部评分

yunqingabc 发表于 2016-8-1 16:41 | 显示全部楼层
感谢楼主分享!
cyhuaxiang 发表于 2016-11-12 15:38 | 显示全部楼层

#ifndef TINYOS
        #define TINYOS
        #define MAXTASKS 5                //顶层任务数量最大为255个,顶层任务的任何地方都可以调用子任务.
        extern  volatile unsigned char timers[MAXTASKS];
        #define _SS static unsigned char _lc=0; switch(_lc){default:
        #define _EE ;}; _lc=0; return 255;
        #define WaitX(tickets)  do {_lc=(__LINE__+((__LINE__%256)==0))%256; return tickets ;} while(0); case (__LINE__+((__LINE__%256)==0))%256:

        #define RunTask(TaskName,TaskID) do { if (timers[TaskID]==0) timers[TaskID]=TaskName(); }  while(0);
        #define RunTaskA(TaskName,TaskID) { if (timers[TaskID]==0) {timers[TaskID]=TaskName(); continue;} }   //前面的任务优先保证执行

        #define CallSub(SubTaskName) do {unsigned char currdt; _lc=(__LINE__+((__LINE__%256)==0))%256; return 0; case (__LINE__+((__LINE__%256)==0))%256:  currdt=SubTaskName(); if(currdt!=255) return currdt;} while(0);
        #define InitTasks() {unsigned char i; for(i=MAXTASKS;i>0 ;i--) timers[i-1]=0; }
        #define UpdateTimers() {unsigned char i; for(i=MAXTASKS;i>0 ;i--){if((timers[i-1]!=0)&&(timers[i-1]!=255)) timers[i-1]--;}}
这代码怎么这么整齐怎么加进去的
小小小小鸟 发表于 2016-12-5 20:08 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

46

主题

397

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部