打印
[其他MCU]

状态机多任务实现

[复制链接]
2756|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
奥德赛|  楼主 | 2015-12-20 21:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近工作上的事很多,一直没抽出时间赶进度,为了过好五一,今天下午抽时间移植了一个状态机系统上去,实现多任务的运行,为下一步菜单系统打下基础。

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

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

它需要一个时钟,支持多个任务分时并发,支持信号量传递,简单的优先级等等。

相关帖子

沙发
奥德赛|  楼主 | 2015-12-20 21:13 | 只看该作者
#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]--;}}

使用特权

评论回复
板凳
奥德赛|  楼主 | 2015-12-20 21:14 | 只看该作者
#define SEM unsigned int
        //初始化信号量
        #define InitSem(sem) sem=0;
        //等待信号量
        #define WaitSem(sem) do{ sem=1; WaitX(0); if (sem>0) return 1;} while(0);
        //等待信号量或定时器溢出, 定时器tickets 最大为0xFFFE
        #define WaitSemX(sem,tickets)  do { sem=tickets+1; WaitX(0); if(sem>1){ sem--;  return 1;} } while(0);
        //发送信号量
        #define SendSem(sem)  do {sem=0;} while(0);
#endif//终止

使用特权

评论回复
地板
奥德赛|  楼主 | 2015-12-20 21:15 | 只看该作者
首先包含头文件和声明函数和变量
//TinyOS
#include "tinyOS.h"
/*      信号量传递       */
SEM keyPressed;
/*      系统定时器       */
void toggle_OS_timer(void);
//unsigned char  task0();
unsigned char  task1(void);
unsigned char  task2(void);               
unsigned char  task3(void);        
unsigned char  task4(void);      

使用特权

评论回复
5
奥德赛|  楼主 | 2015-12-20 21:16 | 只看该作者
编写任务代码,系统需要一个时钟
/*  TinyOS task function */
void toggle_OS_timer(void)
{
    UpdateTimers();
        //RunTask(task0,0); //任务0具有精确按时获得执行的权限
}

/*     按键扫描任务,15ms一次        */
unsigned char  task1(){
_SS
        while(1)
        {
                key_scan();
                if(key_status) SendSem(keyPressed);
                WaitX(15);
                key_flag_clr();
        }
_EE
}

使用特权

评论回复
6
奥德赛|  楼主 | 2015-12-20 21:17 | 只看该作者
/*     菜单响应程序        */
unsigned char  task2(){
_SS
        while(1)
        {
                WaitSem(keyPressed);        
                MenuIndex_switch();        
        }
_EE
}
/*     闪烁标题栏程序        */
unsigned char  task3(){
_SS
        while(1)
        {        
    GUI_RectangleFill(0+1, 0+1,0+12,0+12, Magenta);        
    GUI_RectangleFill(0+12, 0+1,0+24-1,0+12, Red);
          GUI_RectangleFill(0+12, 0+12,0+24-1,0+24-1, Yellow);
          GUI_RectangleFill(0+1, 0+12,0+12,0+24-1, Green);
                WaitX(250);
    GUI_RectangleFill(0+1, 0+1,0+12,0+12, Green);        
    GUI_RectangleFill(0+12, 0+1,0+24-1,0+12,Magenta );
          GUI_RectangleFill(0+12, 0+12,0+24-1,0+24-1,Red );
          GUI_RectangleFill(0+1, 0+12,0+12,0+24-1,Yellow );
                WaitX(250);

使用特权

评论回复
7
奥德赛|  楼主 | 2015-12-20 21:18 | 只看该作者
GUI_RectangleFill(0+1, 0+1,0+12,0+12,Yellow );        
    GUI_RectangleFill(0+12, 0+1,0+24-1,0+12, Green);
          GUI_RectangleFill(0+12, 0+12,0+24-1,0+24-1,Magenta );
          GUI_RectangleFill(0+1, 0+12,0+12,0+24-1, Red);
                WaitX(250);
    GUI_RectangleFill(0+1, 0+1,0+12,0+12, Red);        
    GUI_RectangleFill(0+12, 0+1,0+24-1,0+12, Yellow);
          GUI_RectangleFill(0+12, 0+12,0+24-1,0+24-1, Green);
          GUI_RectangleFill(0+1, 0+12,0+12,0+24-1,Magenta );
                WaitX(250);
        }
_EE
}

/*     动画切换程序        */
unsigned char  task4(){
        static uint8 ts=0;
_SS
        while(1)
        {        
                ts++;
                Board_LED_SetPortState(1<<(ts&0x03));         
                WaitX(250); //25fps
        }
_EE
}

使用特权

评论回复
8
奥德赛|  楼主 | 2015-12-20 21:19 | 只看该作者
好,一切就绪,初始化并运行任务即可
    /*tinyOS start here */
            InitTasks(); //初始化任务,实际上是给timers清零
            InitSem(keyPressed);//初始化信号量
            MenuIndex_switch();
            while(1)
            {
                    RunTaskA(task1,1);//按键扫描
                    RunTaskA(task2,2);//菜单相应
                    RunTaskA(task4,4);//界面切换动画        
                    RunTaskA(task3,3);//闪烁标题栏                        
            }        

使用特权

评论回复
9
奥德赛|  楼主 | 2015-12-20 21:20 | 只看该作者
是不是很简单呢,那我们看实现了哪些功能。

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

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

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

task4控制桌面流水灯。

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
cov0xt + 1 谢谢~很有启发!
10
yunqingabc| | 2016-8-1 16:41 | 只看该作者
感谢楼主分享!

使用特权

评论回复
11
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]--;}}
这代码怎么这么整齐怎么加进去的

使用特权

评论回复
12
小小小小鸟| | 2016-12-5 20:08 | 只看该作者
MARK

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

46

主题

397

帖子

3

粉丝