TheBest 发表于 2016-4-15 23:10:02

顶一下,这个还

rundream 发表于 2016-4-27 16:29:45

坛友整理的小小调度器说明,写得非常好,可以作为小小调度器的基础教程使用。


hotsauce1861 发表于 2016-4-27 22:12:47

请问楼主哪里可以下载您的调度器的源码?

冬天的野狼V2 发表于 2016-4-27 22:14:03

收起来学习

rundream 发表于 2016-4-27 23:31:01

hotsauce1861 发表于 2016-4-27 22:12
请问楼主哪里可以下载您的调度器的源码?

本帖1153楼就是新版调度器的源码。
1213楼是坛友整理的资料,可当入门教程学习.

au8988 发表于 2016-4-28 09:52:23

精妙源码,必须收藏!

rogerllg 发表于 2016-4-28 12:28:46

收藏,楼主弄得的确不错~

ideality0214 发表于 2016-4-29 15:49:01

看着不错,学习下

acchkr 发表于 2016-4-29 21:28:17

好东西 多谢lz分享!

atg525 发表于 2016-4-30 23:43:11

很不错!                              

modhwh 发表于 2016-7-13 10:23:11

看啦N多次,谢谢楼主的无私供献!

ztg328 发表于 2016-7-21 07:47:00

mark下,话说有推荐的版本吗?

linbin250 发表于 2016-7-21 10:24:50

下次尝试使用一下:)

rundream 发表于 2016-7-21 17:10:41

现在,小小调度器已升级到 2.0版本了,解决了任务重入等问题。

/****小小调度器开始**********************************************/
#define TimeDef         unsigned short
#define LineDef         unsigned char
#define END             ((TimeDef)-1)
#define LINE            ((__LINE__%(LineDef)-1)+1)

#define me(*cp)
#define TaskFun(TaskName)   TimeDef TaskName(C_##TaskName *cp) {switch(me.task.lc){default:
#define Exit            do { me.task.lc=0; return END; }while(0)
#define Restart         do { me.task.lc=0; return 0; }while(0)
#define EndFun            } Exit; }

#define WaitX(ticks)      do { me.task.lc=LINE; return (ticks); case LINE:;} while(0)
#define WaitUntil(A)      do { while(!(A)) WaitX(0);} while(0)

#define UpdateTimer(TaskVar)    do { if((TaskVar.task.timer!=0)&&(TaskVar.task.timer!=END)) TaskVar.task.timer--; }while(0)
#define RunTask(TaskName,TaskVar) do { if(TaskVar.task.timer==0) TaskVar.task.timer=TaskName(&(TaskVar)); }while(0)

#define CallSub(SubTaskName,SubTaskVar)    do { WaitX(0);SubTaskVar.task.timer=SubTaskName(&(SubTaskVar));      \
                  if(SubTaskVar.task.timer!=END) return SubTaskVar.task.timer;} while(0)
   
/****************************************************************/
#define Class(type)         typedef struct C_##type C_##type; struct C_##type
Class(task)
{
TimeDef timer;
LineDef lc;
};
void runtasks();

foxpro2005 发表于 2016-7-21 19:14:18

不错,强烈支持, 看样子这次变化比较大

eliterxzgxu 发表于 2016-7-21 20:14:52

感谢楼主分享

zd0305 发表于 2016-7-22 08:40:20

这个真的要支持,先下载下来测试!

makathy 发表于 2016-7-22 09:41:30

Nice,也研究一下

zd0305 发表于 2016-7-22 09:48:12

WaitX(100); 这个在mplab x + xc8 环境下还是不能编译通过,提示需要常量参数

happy_andy 发表于 2016-7-22 15:36:16

好贴,希望有更多的人参与进来!

gmyu 发表于 2016-8-10 22:00:36

LZ能否新开个帖子,历经4年,2.0的变化有点大,写写注意事项,使用技巧。收获很多啊!

gmyu 发表于 2016-8-11 11:09:25

rundream 发表于 2016-7-21 17:10
现在,小小调度器已升级到 2.0版本了,解决了任务重入等问题。

楼主什么时候出完整版本的?你这个main里面的延时在stm32这种有systick的单片机里面怎么搞最优?

HWY 发表于 2016-8-12 16:22:53

测试暂时没有问题,厉害呀楼主

zwcled 发表于 2016-8-12 17:29:52

不错,学习

four_zhg 发表于 2016-8-12 23:31:12

靠,这是不死贴啊,四年升级成2.0了,楼主有没有更详细的说明

whhb8612 发表于 2016-8-13 17:47:33

感谢分享,下载学习一下!

马拉河尚 发表于 2016-9-1 16:43:00

我想收藏本贴,没找着在哪收藏,好!!!!

nos002 发表于 2016-9-28 19:31:10

本帖最后由 nos002 于 2016-9-29 00:30 编辑

像有人评说法律条文一样:说不服、绕湖涂。
switch语句的状态变量 _lc 根本不需要赋值行号,对_lc 任意赋值一个该变量类型的值(0、255除外)进行跳转 一样可以,如下所示:

extern volatile uint8_t TaskTicks;

#define SCH_BEGIN                                             \
      static uint8_tSCH_State = 0;                        \
      switch( SCH_State ){                                    \
             default:
                                                      
#define SCH_END                                                 \
      ;};                                                       \
      SCH_State = 0;                                          \
      return 255;
#define SCH_SUSPENDreturn 255;

#define SCH_DELAY( tickets )                                     \
      do{                                                      \
             if( SCH_State == 0 )                              \
                SCH_State = 1;                                 \
             return (uint8_t)tickets;                            \
      }while(0);                                             \
      case 1: 而楼主使用当前行号进行状态跳转的宏定义WaitX(ticks)必须写在同一行,为了可读性进行换行的话必须进行相应的修改,_lc 赋值要根据 case所在的行号进行加法运算,如下:

#define SCH_DELAY( tickets )                                     \
      do{                                                      \
             _lc = (uint8_t)( ( __LINE__ + 5 ) & 0xff );         \
             if( _lc == 0 )                                    \
               _lc = 1;                                        \
             return (uint8_t)tickets;                            \
      }while(0);                                             \
      case (uint8_t)( ( __LINE__ & 0xff ) + ( __LINE__ & 0xff ) == 0 ) ):

又或者如944楼 mute 的更直观简练的修改;再看了一下mute的SCH_DELAY宏,当前行号赋值和case所在行换行写还是错误的,要换行写只能如上进行加法运算。注:经实际运行还是mute是对的,上面的那个__LINE__ + 5无法运行
#define SCH_MAX_TICK      0xFFFF
#define SCH_MAX_TASK      16

typedef volatile uint8_t   SCH_LC;
typedef volatile uint16_t SCH_TICK;
typedef volatile uint16_t SCH_SEM;
typedef SCH_TICK SCH_TASK_RESULT;

SCH_TICK SCH_TaskTicks;

/******************************* 调度器 **********************************/
#define SCH_LINE_NUM((__LINE__ + ((__LINE__ % 256) == 0)) % 256)


#define SCH_TASK_BEGIN()                                                \
          static SCH_LC _sch_lc_ = 0;                                    \
          switch (_sch_lc_)                                             \
          {                                                               \
            default:

#define SCH_TASK_END()                                                    \
            ;                                                             \
          };                                                            \
          _sch_lc_ = 0;                                                   \
          return SCH_MAX_TICK

#define SCH_DELAY(ticks)                                                \
          do                                                            \
          {                                                               \
            _sch_lc_ = SCH_LINE_NUM;                                    \
            return ticks;                                             \
          } while (0);                                                    \
          case SCH_LINE_NUM:



modhwh 发表于 2016-9-30 05:45:53

又升级啦!

Yvan 发表于 2016-10-5 19:47:50

rundream 发表于 2016-7-21 17:10
现在,小小调度器已升级到 2.0版本了,解决了任务重入等问题。

小小调度器的作者已经很久没来了。被封了?

Yvan 发表于 2016-10-5 19:56:08

不错哇,这个贴还在继续!!!

xunke 发表于 2016-10-6 12:02:06

没接触过调度器,下来学习一下!
厉害!谢谢分享!

int 发表于 2016-10-21 13:24:42

学习一下。比直接大循环相比优越不少,而且纯C,不依赖处理器,占用资源也小,太巧妙了。

chen849928055 发表于 2016-10-21 13:34:54

smset 发表于 2012-12-18 18:29
优化无止境!呵呵,330楼看似不能再优化了,但我再尝试做一次优化:

敬请评测该版本,看是否还能优化:在k ...

先收藏再说

modhwh 发表于 2016-10-25 22:56:40

又看一次!!

cgh0817_am 发表于 2016-11-12 17:47:13

顶,备查,好东西

lzm2010 发表于 2016-11-12 23:40:53

有没有信号量使用的example啊?{:smile:}

riptell2008 发表于 2016-11-19 21:46:28

很好的帖子,要认真看看!!

jorry 发表于 2016-12-17 21:48:20

学习一下!!!!

cddx 发表于 2016-12-25 21:11:56

找了好久,先收藏起来,以后学习。

ycping 发表于 2017-1-11 15:58:04

2017年是我的。

jiangshaoyatui 发表于 2017-1-11 17:42:10

随然不懂,还是要顶

ycping 发表于 2017-1-11 18:32:22

v2 产生的代码量太大了。不实用。

linquan315 发表于 2017-1-11 21:34:49

可以看看《基于时间触发嵌入式系统设计模式》

jhhoward 发表于 2017-1-11 22:01:00

zan,不错的

1785345205 发表于 2017-1-12 09:46:52

谢谢分享

Lion_K 发表于 2017-1-14 18:27:16

{:smile:}好思想 值得流传 {:victory:}

zhangx_00 发表于 2017-5-31 21:33:52

非常值得学习

jiangyimfs1 发表于 2017-8-16 21:42:24

试用了一下楼主的调度器,用到按键的时候,不知道怎么去用了,楼主能出了实际的例子,包含常用的按键,串口通讯什么的。。。

月光疾風 发表于 2017-9-1 14:23:37

这个调度器可以的 这么精简 拿过来用用

shower.xu 发表于 2017-11-27 15:57:44

rundream 发表于 2016-4-27 23:31
本帖1153楼就是新版调度器的源码。
1213楼是坛友整理的资料,可当入门教程学习. ...

您好,请教你个问题:
我的项目中需要在任务中进入休眠,然后被外部引脚唤醒,唤醒后任务全部重新运行(像复位后的初始状态一样),我该怎么做?

我的想法:
1.如果我在任务中直接休眠,唤醒后继续恢复运行,我要怎样才能把任务重置为像复位后的状态一样开始?
2.如果我采用下面这种方式:

while(1)
{       
        if(flag_cur==FLAG_SLEEP)
        {
                //goto sleep and wait for wakup by Sensor/SetKey.
                Init4Sleep();                       
                flag_cur=sleep();                                //sleep() will return FLAG_XXX
        }
#ifdef        TinyOS
        InitTasks();
        InitSem(SEM_getChar);//init sem
        T2_init();
        T2_SetTime(123);                        //2ms--HeartBeat
#endif

        while(flag_cur)                                //run loop until FLAG_SLEEP
        {
                CLRWDT();
                RunTaskA(task1,1);                // run once.
              RunTaskA(task2,2);                // run by flag_cur, if should sleep, flag_cur=0;
        }
}


会不会有如下问题:
a. sleep()函数能不能使用return;
b. InitTasks();能不能重置任务。

比较迷惑,望赐教。

gaowh 发表于 2018-6-2 09:25:05

楼主,最近用了下这个调度器,发现一个问题:如果我在某个任务的子函数内需要挂起该任务的时候无法处理?

gaowh 发表于 2018-6-2 09:49:19

WaitX(100);
这个等待只能放在task任务函数中,如果task任务下调用了另外一个函数,这个函数里面想调用等待就不行了,除非阻塞住所有的任务用死等方式。

lb0857 发表于 2018-6-2 10:04:43

调度器 精简 {:victory:}{:victory:}

ljgchina 发表于 2018-6-6 10:53:14

先收藏起来,以后学习

zzz1367 发表于 2018-6-6 20:34:09

收藏先,谢谢分享

lzly0302 发表于 2018-7-13 11:00:54

本帖1152楼就是新版调度器的源码。
1211楼是坛友整理的资料,可当入门教程学习.刚刚看了下楼层是这么个情况

文艺小青年 发表于 2018-7-13 11:20:44

真的是很好的资源

Yuki. 发表于 2018-7-20 09:32:44

我移植到STM32去看看行不行

BAOJIWWWJJJWWW 发表于 2018-7-20 21:24:08

没看懂宏用法,还是自己太菜了

unnormal 发表于 2018-8-8 14:31:58

学习了谢谢分享

TKZXJ 发表于 2018-12-19 19:46:25

谢谢分享,学习了

tangly2017 发表于 2018-12-19 20:38:47

有原理图吗??

lianzhong008 发表于 2019-2-17 15:16:45

学无止境,技术推陈出新,佩服佩服

lcw_swust 发表于 2019-4-15 21:17:23

向楼主致敬!
前面的楼层太多,我也没依次细看,比如1223楼的代码似乎也不错。
按照本人的编程习惯,参考了一些其它的程序,稍作了一些修改,将定时器改为了16位;
本以为char改为int就行,没想到在51单片机上WaitX(500)的时候出了BUG:延时不准。
经过多次测试总算明白了,8位机在读写16位变量时,若被中断打断,且中断里对该变量有写操作,则会出问题。
解决办法一是在读写16位变量时关中断(类似OS_ENTER_CRITICAL()),二是增加标志位使在主循环操作变量时中断里不对其操作。
以下为核心代码:
/*--------------------------------------------------
<小小调度器.C>
利用switch语句实现的合作式调度器


参考1:https://www.cnblogs.com/songdechiu/p/5793717.html
<<Protothread 机制>>

参考2:http://www.amobbs.com/thread-5508723-1-1.html   
<<再出个调度器,极小资源单片机值得一用>>
作者:smset
参考3:https://www.amobbs.com/forum.php?mod=viewthread&tid=5702323&highlight=%E8%B0%83%E5%BA%A6%E5%99%A8
<<小小调度器1.1重新整理版,8位16位32位可以选择定义>>
作者:xyb852

LCW修改:timer为int型
LINE的处理参考问星整理版
(__LINE__%255)+1,使行号为:1~255 (避开0,因为0是第一个case标签)
_SS改名为_BEGIN
_EE改名为_END
default改为case 0 (万一后面误写了case 0,可引发error)
currdt类型改为static
16位timers会比原版占用更多的内存

注意事项:
1.任务函数不超过254行,否则可能引起 __LINE__%255+1 重复
2.任务内部的变量,如果要跨过等待或延时,需定义为静态变量.
3.任务中慎用switch,不要在新的switch中WaitX、WaitSem,否则可能引起case 混乱
4.任务函数内不要再用return。
5.运行任务的TaskID不要重复
6.由CallSub调用的任务,不能两个地方同时调用,主循环也不能再RunTask。
7.timer定义为16位时有个问题,读取timer时需关中断,否则可能在256附近读到0,
(8位机读取16位是分两次读取的,中间被中断打断并写入则会引起BUG)
也可另加循环调用WaitX实现长延时,这样就不需关中断了。
若不关中断,读两次连续为0也可以确定其为0;
写入timer时增加tmren标志,只有tmren置1后中断里才会进行减计数,这样就不会乱了。
//--------------------------------------------------*/
/****小小调度器开始**********************************************/
//最大任务数
#define MAXTASKS 3
//最大等待时间,此时任务停止
#define TICKET_MAX 0xFFFF
//任务类型,也是定时器的数据类型
#define TASK                         unsigned int
#define TIMER                        unsigned int
//记录标号,下次进入函数就往下进行
#define LC_SET()                 _lc=(__LINE__%255)+1; case (__LINE__%255)+1:
//初始化定时器
#define InitTasks()         {unsigned char i; for(i=0;i<MAXTASKS;i++) timers=0; }
//任务开始
#define _BEGIN                        static volatile unsigned char _lc=0; switch(_lc){case 0:
//任务结束,不再进入
#define _END                         } _lc=0; return TICKET_MAX;
//延时
#define WaitX(tickets)         do {_lc=(__LINE__%255)+1; return tickets ;} while(0); case (__LINE__%255)+1:
//运行任务
//#define RunTask(TaskName,TaskID)        do{ if (timers==0) timers=TaskName(); }while(0);
/*
//16位timer,读写时需关中断,避免读写过程中被修改
#define RunTask(TaskName,TaskID)        do{EA=0;timert=timers;EA=1;\
                                                                        if (timert==0) {timert=TaskName();\
                                                                        EA=0;timers=timert;EA=1;}}while(0);
*/
//16位timer,两次读取都为0才认为是0,写入时要关使能位(或关中断)。
#define RunTask(TaskName,TaskID)        do\
                                                                        {\
                                                                                if((timers==0)&&(timers==0))\
                                                                                {\
                                                                                        timert=TaskName();\
                                                                                        tmren=0;\
                                                                                        timers=timert;\
                                                                                        tmren=1;\
                                                                                }\
                                                                        }while(0);

//continue使前面的任务优先保证执行
//#define RunTaskA(TaskName,TaskID)        { if (timers==0) {timers=TaskName(); continue;} }
#define RunTaskA(TaskName,TaskID)        {\
                                                                                if((timers==0)&&(timers==0))\
                                                                                {\
                                                                                        timert=TaskName();\
                                                                                        tmren=0;\
                                                                                        timers=timert;\
                                                                                        tmren=1;\
                                                                                        continue;\
                                                                                }\                                                                       
                                                                        }
//调用任务函数(去掉了return 0)
#define CallSub(SubTaskName)                 do{static TIMER currdt;LC_SET();currdt=SubTaskName();if(currdt!=TICKET_MAX) return currdt;} while(0);
//#define CallSub(SubTaskName)                 do{static TIMER currdt; _lc=(__LINE__%255)+1; return 0;case (__LINE__%255)+1:currdt=SubTaskName();if(currdt!=TICKET_MAX) return currdt;} while(0);

//定时中断里调用此函数用于计时
//#define UpdateTimers()                                 {unsigned char i; for(i=0;i<MAXTASKS;i++){if((timers!=0)&&(timers!=TICKET_MAX)) timers--;}}
//tmren非0才计数
#define UpdateTimers()                                 {unsigned char i; for(i=0;i<MAXTASKS;i++){if((tmren!=0)&&(timers!=0)&&(timers!=TICKET_MAX)) timers--;}}

//信号量类型
#define SEM                                                 TIMER
//初始化信号量
#define InitSem(sem)                                 sem=0;
//等待信号量(作了改动,return 0能更快响应,return 1 则可释放CPU一段时间)
#define WaitSem(sem)                                 do{ sem=1; LC_SET(); if (sem>0) return 0;} while(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; LC_SET(); if(sem>1){ sem--;return 1;} } while(0);
//#define WaitSemX(sem,tickets)                 do{ sem=tickets+1; WaitX(0); if(sem>1){ sem--;return 1;} } while(0);
//发送信号量
#define SendSem(sem)                                sem=0;
//等待条件成立(return 0能更快响应,return 1 则可释放CPU一段时间)
#define WaitCond(cond)                                 do {LC_SET();if(!(cond))return 0; }while(0);
//--------------------------------------------------上面的可作为头文件,下面的不可重复定义
//定义定时器数组
volatile TIMER timers={0};//注意初值要为0
volatile char tmren={0};//定时器使能
volatile TIMER timert;//暂存
//定义信号量
SEM Sem1;
char test1=0;
/*****小小调度器结束*******************************************************/
TASK task1(void)
{
        static char i=0;
        char n;
        _BEGIN
        for(n=0;n<3;n++)
                U1Send(0xAA);

        switch(n)
        {
                case 1:U1Send(1);break;
                case 2:U1Send(2);break;
                case 3:U1Send(3);break;
        }
        U1Send(1);
        LED_ON;
        WaitX(500);
        U1Send(2);
        LED_OFF;
        WaitX(1000);
        U1Send(3);
        LED_ON;
        WaitX(500);
        U1Send(4);
        LED_OFF;
        WaitX(500);
        SendSem(Sem1);//发送信号量
        for(i=0;i<10;i++)
        {
                U1Send(5+i);       
                WaitX(1000);
                test1++;
        }
        _END
}

TASK task3(void)
{
        _BEGIN
        WaitX(10);
        U1Send(0x31);
        _END
}

TASK task2(void)
{
        static char i=0x26;
        _BEGIN

        //WaitSem(Sem1);//等待信号量
        WaitSemX(Sem1,1000);//只等1秒
        U1Send(0x21);
        WaitX(500);
        U1Send(0x22);
        WaitX(1000);
        U1Send(0x23);
        WaitCond(test1>8);//等待条件
        U1Send(0x24);

        CallSub(task3);//调用任务
        U1Send(0x25);
        while(1)
        {               
                LED_XOR;
                U1Send(i++);
                WaitX(500);   
        }

        _END
}

/*
//1KHz
void timer0(void) interrupt 1
{
        UpdateTimers();
}
void main(void)
{
        init_devices();//初始化串口、定时器等
        InitTasks();//可省
        while(1)
        {
                RunTask(task1,0);
                RunTask(task2,1);
                //PCON|=1;//睡眠
        }
}*/

su33691 发表于 2019-4-15 23:31:40

//任务结束,不再进入
#define _END                         ;}; _lc=0; return TICKET_MAX;

上述语句在KEIL C51中会有警告。为了消除警告,可改为:
#define _END                         ;};      //用于一直需要执行的任务
#define _END_CLOSE                        ;}; _lc=0; return TICKET_MAX;   //用于仅仅执行有限次的任务

墨逸、 发表于 2019-7-18 17:15:50

eva015401 发表于 2014-2-11 11:04
好东西收下了

原来几年前你就看到这个了

yzh 发表于 2019-7-23 20:26:53

先收藏了,谢谢分享!

xuwuhan 发表于 2019-7-24 09:59:31

几年前的贴又翻出来,好好看看

Oliver 发表于 2019-10-4 16:46:30

多年老帖,思路真好,感谢楼主。

不过信号量这里793楼如果是异步发送信号量有很大的问题,

“读-改-写”没有任何临界保护,即便只是写int也会因为是非原子而出问题

xlee 发表于 2019-12-9 19:39:02

不知有没有人把这种调度器用在实际项目里没有,还是仅仅大家只是玩一下。写几个玩具示例。

diego2003 发表于 2020-1-2 17:38:16

MARKRTOS 调度器。。。。

lhaoyue 发表于 2020-4-2 13:43:40

收藏 mark

Fake-BBA 发表于 2020-4-4 16:43:42

的确简单,小家电应该会很好用

zwxoec 发表于 2020-9-1 11:58:49

用PICC V9.83移植到PIC单片机,源文件上的功能都实现了,但是不能运行SLEEP(),加上这句工作就不正常,不知道什么原因。

zzz1367 发表于 2020-10-3 14:04:40

牛。。。。。。学习下。。。。。。。。。。。。。。

cdpcliujian 发表于 2020-11-2 17:22:27

收藏先,谢谢分享
页: 3 4 5 6 7 8 9 10 11 12 [13]
查看完整版本: 再出个调度器,极小资源单片机值得一用