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]