搜索
bottom↓
回复: 15

多任务调度器头文件

[复制链接]

出0入0汤圆

发表于 2014-4-15 20:29:48 | 显示全部楼层 |阅读模式
attach://184272.zip
学习了smset的帖子后,按自己的理解写的。花了不少时间,但效果不怎么样,维二的好处是只有一个头文件,可以在工程里所有的C文件里引用,容易实现模拟化编程。具体看头文件里的注释

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-15 21:31:50 | 显示全部楼层
下载来看看。谢谢

出0入0汤圆

 楼主| 发表于 2014-4-16 01:58:38 | 显示全部楼层
  1. #ifndef __OS_H__
  2. #define __OS_H__
  3. /*顶层任务数量,可按需增加,最大为255个*/
  4. #define MAXTASKS 3
  5. /*信号数量,可按需增加,最大为255个*/
  6. #define MAXSEM 1

  7. typedef struct
  8. {
  9.         unsigned char time;
  10. } task;//任务状态结构

  11. typedef struct
  12. {
  13.         unsigned char sem;
  14. }semaphore;//信号结构

  15. /*声明任务状态数组*/
  16. extern volatile task tasks[MAXTASKS];

  17. #if MAXSEM
  18. extern semaphore SEM[MAXSEM];
  19. #define sem0 0/*定义信号0的名字,取有意义的名字*/
  20. #define sem1 1

  21. /*OS初始化设置,在主文件内所有任务前引用*/
  22. #define _OSInit volatile task tasks[MAXTASKS];semaphore SEM[MAXSEM];
  23. #else
  24. /*OS初始化设置,在主文件内所有任务前引用*/
  25. #define _OSInit volatile task tasks[MAXTASKS];
  26. #endif

  27. /*任务开始宏,在任务函数的变量声明后引用*/
  28. #define _SS static unsigned char _lc=0;switch(_lc){default:

  29. /*任务结束宏,在任务尾引用*/
  30. #define _EE ;}; _lc=0;return 255;

  31. /*任务中断宏,在任务开始宏和结束宏之间的任意位置引用*/
  32. #define WaitX(tickets) do{_lc=(__LINE__+((__LINE__%256)==0))%256;return tickets ;} while(0);case (__LINE__+((__LINE__%256)==0))%256:

  33. /*初始化顶层任务,实际上是给timers清零;初始化信号量。在main()内任务调度前引用*/
  34. #define InitTasks() {        unsigned char i; for(i=MAXTASKS;i>0 ;i--) tasks[i-1].time=0;for(i=MAXSEM;i>0 ;i--) SEM[i-1].sem=0;}

  35. /*执行一次顶层任务,在时钟中断内引用,具有最高优先级*/
  36. #define RunTask(TaskName,TaskID) do {if (tasks[TaskID].time==0) tasks[TaskID].time=TaskName(); } while(0);

  37. /*执行一次顶层任务,在main()内引用,在前的优先执行*/
  38. #define RunTaskA(TaskName,TaskID) { if (tasks[TaskID].time==0) {        tasks[TaskID].time=TaskName();         continue;} }  

  39. /*调用子任务,在任务函数内引用,可以多层嵌套*/
  40. #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);

  41. /*计时,在定时器中断内引用*/
  42. #define UpdateTimers() {unsigned char i; for(i=MAXTASKS;i>0 ;i--)        {if((tasks[i-1].time!=0)&&(tasks[i-1].time!=255)) tasks[i-1].time --;}}

  43. /*初始化信号量*/
  44. //#define InitSem(sem) sem=0;

  45. /*等待信号量,接收到信号后先把信号量置1,处理完成后必须引用一次EndWaitSem(semx),以便其它在等待相同信号的任务接收信号。*/
  46. #define WaitSem(semx) do{ SEM[semx].sem=1; WaitX(0);         if (SEM[semx].sem>0) return 1; else SEM[semx].sem=1;} while(0);
  47. #define EndWaitSem(semx) SendSem(semx)/*传递信号以便其它在等待相同信号的任务接收信号。*/

  48. /*等待信号量或定时器溢出,接收到信号后先把信号量置1,处理完成后必须引用一次EndWaitSem(semx),以便其它在等待相同信号的任务接收信号。*/
  49. /*tickets为定时器(超时时间),最大为0xFFFE,溢出后任务不再等待,继续往下执行*/
  50. #define WaitSemX(semx,tickets)  {unsigned int xxxxxxxooooooo;xxxxxxxooooooo=tickets;do { SEM[semx].sem=1; WaitX(0); if(SEM[semx].sem>0 && xxxxxxxooooooo>0){ xxxxxxxooooooo--;  return 1;}else if (SEM[semx].sem==0) SEM[semx].sem=1; } while(0);
  51. #define EndWaitSemX(semx) if(xxxxxxxooooooo>0)SendSem(semx)}/*如果是信号触发,则传递信号以便其它在等待相同信号的任务接收信号。*/

  52. /*发送信号量*/
  53. #define SendSem(semx)  do {SEM[semx].sem=0;} while(0);

  54. #endif
复制代码

出0入0汤圆

 楼主| 发表于 2014-4-16 01:59:11 | 显示全部楼层

  1. #include <reg51.h>
  2. #include"os.h"
  3. /****小小调度器开始**********************************************/

  4. _OSInit

  5. /*****小小调度器结束*******************************************************/


  6. sbit LED1 = P2^1;
  7. sbit LED2 = P2^2;

  8. sbit LED0 = P2^5;

  9. unsigned char task0(){
  10. _SS
  11.   while(1){
  12.    //WaitX(50);
  13.    WaitSem(0);
  14.    LED0=!LED0;  
  15.    EndWaitSem(0);
  16.   }
  17. _EE
  18. }

  19. unsigned char  task1(){
  20. _SS
  21.   while(1){
  22.    WaitX(100);
  23.    LED1=!LED1;
  24.    
  25.   }
  26. _EE
  27. }

  28. unsigned char  task2(){
  29. _SS
  30.   while(1){
  31.    WaitX(200);
  32.    LED2=!LED2;
  33.    SendSem(0);
  34.   }
  35. _EE
  36. }

  37. void InitT0()
  38. {
  39.         TMOD = 0x21;
  40.         IE |= 0x82;  // 12t
  41.         TL0=0Xff;
  42.         TH0=0XDB;
  43.         TR0 = 1;
  44. }

  45. void INTT0(void) interrupt 1 using 1
  46. {
  47.     TL0=0Xff;    //10ms 重装
  48.     TH0=0XDB;//b7;   

  49.     UpdateTimers();

  50.     RunTask(task0,0);//任务0具有精确按时获得执行的权限,要求:task0每次执行消耗时间<0.5个 ticket
  51. }




  52. void main()
  53. {
  54.         InitT0();
  55.         InitTasks(); //初始化任务,实际上是给timers清零
  56.         while(1){
  57.                         RunTaskA(task1,1);//任务1具有比任务2高的运行权限                  
  58.                         RunTaskA(task2,2);//任务2具有低的运行权限                  
  59.       }
  60. }
复制代码

出0入0汤圆

 楼主| 发表于 2014-4-16 02:02:01 | 显示全部楼层
这个是我按smset的http://www.amobbs.com/thread-5508723-1-1.html代码改的,这个调度器好用,值得拥有。

出0入0汤圆

 楼主| 发表于 2014-4-16 02:04:56 | 显示全部楼层
这个是预编译后的代码
  1. volatile task tasks[3];semaphore SEM[1];




  2. sbit LED1 = P2^1;
  3. sbit LED2 = P2^2;

  4. sbit LED0 = P2^5;

  5. unsigned char task0(){
  6.   static unsigned char _lc=0;switch(_lc){default:
  7. while(1){

  8.   do{ SEM[0].sem=1; do{_lc=(20+((20%256)==0))%256;return 0 ;} while(0);case (20+((20%256)==0))%256:; if (SEM[0].sem>0) return 1; else SEM[0].sem=1;} while(0);;
  9. LED0=!LED0;  
  10.    do {SEM[0].sem=0;} while(0);;
  11. }
  12.   ;}; _lc=0;return 255;
  13. }

  14. unsigned char  task1(){
  15.   static unsigned char _lc=0;switch(_lc){default:
  16. while(1){
  17.   do{_lc=(30+((30%256)==0))%256;return 100 ;} while(0);case (30+((30%256)==0))%256:;
  18. LED1=!LED1;

  19. }
  20.   ;}; _lc=0;return 255;
  21. }

  22. unsigned char  task2(){
  23.   static unsigned char _lc=0;switch(_lc){default:
  24. while(1){
  25.   do{_lc=(40+((40%256)==0))%256;return 200 ;} while(0);case (40+((40%256)==0))%256:;
  26. LED2=!LED2;
  27.   do {SEM[0].sem=0;} while(0);;
  28. }
  29.   ;}; _lc=0;return 255;
  30. }

  31. void InitT0()
  32. {
  33. TMOD = 0x21;
  34. IE |= 0x82;   
  35. TL0=0Xff;
  36. TH0=0XDB;
  37. TR0 = 1;
  38. }

  39. void INTT0(void) interrupt 1 using 1
  40. {
  41. TL0=0Xff;     
  42. TH0=0XDB;

  43.   {unsigned char i; for(i=3;i>0 ;i--)        {if((tasks[i-1].time!=0)&&(tasks[i-1].time!=255)) tasks[i-1].time --;}};

  44.   do {if (tasks[0].time==0) tasks[0].time=task0(); } while(0);;
  45. }




  46. void main()
  47. {
  48. InitT0();
  49.   {        unsigned char i; for(i=3;i>0 ;i--) tasks[i-1].time=0;for(i=1;i>0 ;i--) SEM[i-1].sem=0;};  
  50. while(1){

  51.   { if (tasks[1].time==0) {        tasks[1].time=task1(); continue;} };
  52.   { if (tasks[2].time==0) {        tasks[2].time=task2(); continue;} };
  53. }
  54. }
复制代码

出0入0汤圆

发表于 2014-4-16 10:49:01 来自手机 | 显示全部楼层
mark                     

出0入0汤圆

发表于 2014-4-17 11:57:54 | 显示全部楼层
将小小调度器纳入一个头文件,这个想法本身是很好的。

论坛里面没有放入到一个头文件里面,是更方便大家看帖。我自己使用时,实际上也是把小小调度器宏定义部分纳入到一个专门的头文件里面去的。

楼主还是花了些心思去写出这个新版本,并且加上详细的注释,使得可读性更好,这很不错。

小小调度器的原始代码,也只是传递一个核心的思路,每个人都可以理解这个核心原理之后,然后根据自己的需要进行修改。

出0入0汤圆

 楼主| 发表于 2014-4-17 14:55:10 | 显示全部楼层
lianglee 发表于 2014-4-16 10:26
我发现高手都是想将简单的问题复杂化.

昨天我刚好看到smset大神的贴子,和同事一起研究了一下.

以我小菜的眼光认为,smset 并没有把问题复杂化,显而易见的好处是把重复逻辑复杂的跳转代码隐藏了,使程序的可读性更好一些。

出0入0汤圆

 楼主| 发表于 2014-4-19 01:11:30 | 显示全部楼层
本帖最后由 rh.s 于 2014-4-19 01:17 编辑

没事干,再改了一下,用了函数指针实现任务的装载挂起,但资源消耗多了好多。

  1. #ifndef __OS_H__
  2. #define __OS_H__
  3. /*顶层任务数量,可按需增加,最大为255个*/
  4. #define MAXTASKS 3
  5. /*信号数量,可按需增加,最大为255个*/
  6. #define MAXSEM 1

  7. typedef struct
  8. {
  9.         unsigned char time;
  10.         unsigned char (*fun)(void);
  11. } task;//任务状态结构

  12. typedef struct
  13. {
  14.         unsigned char sem;
  15. }semaphore;//信号结构

  16. /*声明任务状态数组*/
  17. extern volatile task tasks[MAXTASKS];

  18. #if MAXSEM
  19. extern semaphore SEM[MAXSEM];
  20. #define sem0 0/*定义信号0的名字,取有意义的名字*/
  21. #define sem1 1

  22. /*OS初始化设置,在主文件内所有任务前引用*/
  23. #define _OSInit volatile task tasks[MAXTASKS];semaphore SEM[MAXSEM];
  24. #else
  25. /*OS初始化设置,在主文件内所有任务前引用*/
  26. #define _OSInit volatile task tasks[MAXTASKS];
  27. #endif

  28. /*任务开始宏,在任务函数的变量声明后引用*/
  29. #define _SS static unsigned char _lc=0;switch(_lc){default:

  30. /*任务结束宏,在任务尾引用*/
  31. #define _EE ;}; _lc=0;return 255;

  32. /*任务中断宏,在任务开始宏和结束宏之间的任意位置引用*/
  33. #define WaitX(tickets) do{_lc=(__LINE__+((__LINE__%256)==0))%256;return tickets ;} while(0);case (__LINE__+((__LINE__%256)==0))%256:

  34. /*初始化顶层任务,实际上是给timers清零;初始化信号量。在main()内任务调度前引用*/
  35. #define InitTasks() {unsigned char i; for(i=MAXTASKS;i>0 ;i--) tasks[i-1].time=255;for(i=MAXSEM;i>0 ;i--) SEM[i-1].sem=0;}

  36. #define Loadtask(TaskName,TaskID,Time) tasks[TaskID].fun =TaskName;tasks[TaskID].time=Time;  
  37. #define Runtasks() {while(1){unsigned char i;for(i=1;i<MAXTASKS;i++){if(tasks[i].time==0) tasks[i].time=(tasks[i].fun)();}}}
  38. #define RuntasksA() if(tasks[0].time==0){tasks[0].time=(tasks[0].fun)();}
  39. #define Stoptask(TaskID) Tasks[TaskID].time=255;


  40. /*调用子任务,在任务函数内引用,可以多层嵌套*/
  41. #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);
  42. /*
  43. CallSub(x)是基于循环的,并非一次姓调用。 不管子任务中间有多少断点,也会忠实执行。
  44. 之所以 在X();前面加了一个WaitX(0); 就是为了保存调用的位置。 下次可以继续运行x();
  45. 这样就实现了循环。 而if (timer[currid]!=255) return 则正是为了保证在子任务没执行完的时候,调用者继续等待。
  46. */
  47. /*计时,在定时器中断内引用*/
  48. #define UpdateTimers() {unsigned char i; for(i=MAXTASKS;i>0 ;i--)        {if((tasks[i-1].time!=0)&&(tasks[i-1].time!=255)) tasks[i-1].time --;}}

  49. /*初始化信号量*/
  50. //#define InitSem(sem) sem=0;

  51. /*等待信号量,接收到信号后先把信号量置1,处理完成后必须引用一次EndWaitSem(semx),以便其它在等待相同信号的任务接收信号。*/
  52. #define WaitSem(semx) do{SEM[semx].sem=1; WaitX(0); if (SEM[semx].sem>0) return 1; else SEM[semx].sem=1;} while(0);
  53. #define EndWaitSem(semx) SendSem(semx)/*传递信号以便其它在等待相同信号的任务接收信号。*/

  54. /*等待信号量或定时器溢出,接收到信号后先把信号量置1,处理完成后必须引用一次EndWaitSem(semx),以便其它在等待相同信号的任务接收信号。*/
  55. /*tickets为定时器(超时时间),最大为0xFFFE,溢出后任务不再等待,继续往下执行*/
  56. #define WaitSemX(semx,tickets)  {unsigned int xxxxxxxooooooo;xxxxxxxooooooo=tickets;do { SEM[semx].sem=1; WaitX(0); if(SEM[semx].sem>0 && xxxxxxxooooooo>0){ xxxxxxxooooooo--;  return 1;}else if (SEM[semx].sem==0) SEM[semx].sem=1; } while(0);
  57. #define EndWaitSemX(semx) if(xxxxxxxooooooo>0)SendSem(semx)}/*如果是信号触发,则传递信号以便其它在等待相同信号的任务接收信号。*/

  58. /*发送信号量*/
  59. #define SendSem(semx)  do {SEM[semx].sem=0;} while(0);

  60. #endif
复制代码

  1. #include <reg51.h>
  2. #include"os.h"
  3. /****小小调度器开始**********************************************/

  4. _OSInit

  5. /*****小小调度器结束*******************************************************/


  6. sbit LED1 = P2^1;
  7. sbit LED2 = P2^2;

  8. sbit LED0 = P2^5;

  9. unsigned char task0(){
  10. _SS
  11.   while(1){
  12.    //WaitX(50);
  13.    WaitSemX(0,500);
  14.    LED0=!LED0;  
  15.    EndWaitSemX(0);
  16.   }
  17. _EE
  18. }

  19. unsigned char  task1(){
  20. _SS
  21.   while(1){
  22.    WaitX(100);
  23.    LED1=!LED1;
  24.    
  25.   }
  26. _EE
  27. }

  28. unsigned char  task2(){
  29. _SS
  30.   while(1){
  31.   WaitX(200);
  32.   LED2=!LED2;
  33.   //SendSem(0);
  34.   }
  35. _EE
  36. }

  37. void InitT0()
  38. {
  39.   TMOD = 0x21;
  40.   IE |= 0x82;  // 12t
  41.   TL0=0Xff;
  42.   TH0=0XDB;
  43.   TR0 = 1;
  44. }

  45. void INTT0(void) interrupt 1 using 1
  46. {
  47.   TL0=0Xff;    //10ms 重装
  48.   TH0=0XDB;//b7;
  49.   UpdateTimers();
  50.         RuntasksA();//任务0具有精确按时获得执行的权限,要求:task0每次执行消耗时间<0.5个 ticket
  51. }




  52. void main()
  53. {
  54.   InitT0();
  55.   InitTasks(); //初始化任务,实际上是给timers清零
  56.   Loadtask(task1,1,0);
  57.         Loadtask(task2,2,0);
  58.         Loadtask(task0,0,0);
  59.         Runtasks();
  60. }
复制代码

出0入0汤圆

发表于 2014-4-19 09:17:41 | 显示全部楼层
本帖最后由 bondxie3 于 2014-4-19 09:23 编辑

这个调度器确实好用,希望大家一起改进!
貌似51中使用函数指针需要OVERLAY,不太方便。

出0入4汤圆

发表于 2014-5-23 22:24:17 | 显示全部楼层
多任务调度器头文件先标记,稍后研究

出0入0汤圆

发表于 2014-5-23 23:26:26 来自手机 | 显示全部楼层
关注一下,用到再看

出0入0汤圆

发表于 2014-5-24 15:49:02 | 显示全部楼层
请问lz预编译 怎么实现呢? keil C51

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-5-5 20:52

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

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