适用于小资源的小小调度器程序(原创)

2020-01-16 18:27发布

发布这个小小调度器主要起个抛砖引玉的作用。

自认为有如下特点:

1)  超级可以移植性,与CPU无关,几乎任何支持C语言编程的CPU都可以用!
2)  小之又小, 原理很简单,一看就懂。
3)  省之又省, 可以说对RAM和ROM省到极致。
4)  取protothread之精华,将定时器与状态机和伪线程语法融合到一个框架,任务函数可以有两种写法。
5)  基于定时器触发,调度效率高,最大化减少无效的代码运行时间。
***********************************************************/  
#include <stc89c51.h>
#include <stdio.h>

/*****************小小调度器部分开始********************************************/
#define  _SS   static char lc=0; switch(lc){   case 0: lc=0;
#define  _EE   }; lc=0;
#define  WaitX(a,b)  settimer(&lc,__LINE__,a,b); return ; case __LINE__:
struct TASK {
  char td;
  void (*fp)();
};
#define MAXTASKS 5
struct TASK tasks[MAXTASKS];

//设置定时器
void settimer(char *lc,char  line,char  tmrid,int d){
  *lc=line;
  tasks[tmrid].td=d;
}
//逻辑定时器处理,在定时器中断里调用
void dectimers() {
unsigned char i;   
for (i=0;i<MAXTASKS;i++){
   if (tasks[i].td>0)  tasks[i].td--;  
}
}
//任务调度函数,在main里面运行
void runtasks() {
   unsigned char i;   
   for(i=0;i<MAXTASKS;i++)       
   {   
     if (tasks[i].fp!=0){   
           if (tasks[i].td==0){
             tasks[i].td=-1;  
             tasks[i].fp();
                }  
         }         
        }
}
/****************小小调度器部分结束*******************************************************/


sbit KEY = P3^2;
unsigned char code numtab[16]={0x24,0x6F,0xE0,0x62,0x2B,0x32,0x30,0x67,0x20,0x22,0x21,0x38,0xB4,0x68,0xB0,0xB1};


sfr IAP_CONTR = 0xC7;
sfr WDT_CONTR = 0xC1;

//清除看门狗
void clr_wdt()
{
  WDT_CONTR =0x3C;
}

//初始化定时器
void InitT0()
{
        TMOD = 0x21;
        IE |= 0x82;  // 12t
        TL0=0Xff;
        TH0=0Xb7;
        TR0 = 1;
}
//定时器中断
void INTT0(void) interrupt 1 using 1
{
        TL0=0Xff;    //10ms 重装
        TH0=0Xb7;
        dectimers();
}

sbit LED1= P2^4;  

//任务一,状态机写法
void ontimer0(){
  LED1=!LED1;  // LED1引脚接在发光管负极,LED1=0 为亮,LED1=1为灭。

  //重装定时器
  if (LED1) tasks[0].td=45;  //450mS 灭
  else tasks[0].td=5;  //50ms  亮
}

//任务二,状态机写法
char keycount=0;
void task1(){
if(KEY==0) {
   keycount++;
   if (keycount>20) IAP_CONTR = 0x60;  //持续按下键1秒,将重启并进入固件升级
}
else{
    keycount=0;
}
//重装定时器
tasks[1].td=5;
}


//任务三,伪线程写法
void  task2()
{
static char i;
_SS

while(1){

for(i=0;i<=9;i++){   //从0--9快速显示,间隔200mS
   WaitX(2,20);         //    等待200mS,实际是设置定时器2为200mS
   P1=numtab[i];
}
for(i=0;i<=9;i++){ //从0--9慢速显示,间隔500mS
   WaitX(2,50);       //    等待500mS,实际是设置定时器2为500mS
   P1=numtab[i];
}
}

_EE
}



void main()
{
        unsigned char         KeyNum;
        P3M0 = 0x00;
        P3M1 =0x00;
        //WDT_CONTR= 0x00;   //关闭看门狗
        P1 = 0xff;         //关显示

          clr_wdt();

        InitT0();

        KEY =1;                                //按键IO口
        KeyNum=0;                        //按下次数

    //装载任务:
        tasks[0].fp=ontimer0;
        tasks[1].fp=task1;
        tasks[2].fp=task2;

    //循环调度
        while(1){
         runtasks();
         clr_wdt();
        }
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
48条回答
lixiao7892998
1楼-- · 2020-01-20 22:58
强悍,学习了!
fnems
2楼-- · 2020-01-21 00:42
本帖最后由 fnems 于 2012-12-6 21:01 编辑

牛!

Wait配合伪线程这个结构LZ怎么想出来的……

能不能再加入事件等待呢?这样就更完美了,因为线程block有时候是等待时间,有时候是等待事件

另外感觉可以在任务中加入this指针全局变量,切换任务的时候顺便切换this,this指向的结构体可以包含任务号的信息,这样wait函数中不用指定任务号了。


还有,以前我用STM8状态机的时候,主循环喜欢加上WFI,类似这样的结构:
  1. #define WFI   _asm("wfi")

  2. main(void) {
  3.   init();
  4.   while(1) {
  5.     switch(state) {
  6.     case STATE_INIT:
  7.     case STATE_A:
  8.     case STATE_B:
  9.     } /* end switch */
  10.     WFI;
  11.   } /* end while */
  12. }
复制代码
smset
3楼-- · 2020-01-21 01:23
本帖最后由 smset 于 2012-12-7 09:55 编辑

新版本已无需指定定时器的。

  1. /**********************************************************/
  2. #include "STC89C51.h"

  3. /****小小调度器开始**********************************************/
  4. #define MAXTASKS 3
  5. unsigned char currid;
  6. unsigned char timers[MAXTASKS];
  7. #define _SS   static unsigned char lc=0; switch(lc){   case 0:
  8. #define _EE   ;}; lc=0;
  9. #define WaitX(b) {lc=__LINE__; timers[currid]=b;} return ; case __LINE__:
  10. #define RunTask(a,b) {currid=b; if (timers[b]==0){timers[b]=255; a();}}
  11. #define CallSub(x)   WaitX(0); x(); if (timers[currid]!=255) return;
  12. /*****小小调度器结束*******************************************************/

  13. sbit LED1 = P2^1;
  14. sbit LED2 = P2^2;

  15. void InitT0()
  16. {
  17.         TMOD = 0x21;
  18.         IE |= 0x82;  // 12t
  19.         TL0=0Xff;
  20.         TH0=0XDB;//22M---b7;
  21.         TR0 = 1;
  22. }

  23. void INTT0(void) interrupt 1 using 1
  24. {
  25.     unsigned char i;
  26.         TL0=0Xff;    //10ms 重装
  27.         TH0=0XDB;//b7;

  28.     for (i=0;i<MAXTASKS;i++){
  29.      if ((timers[i]!=0)&&(timers[i]!=255)) {
  30.            timers[i]--;
  31.          }
  32.     }       
  33. }


  34. void  task1(){
  35. _SS
  36.   while(1){
  37.    WaitX(100);
  38.    LED1=!LED1;   
  39.   }
  40. _EE
  41. }

  42. void  task2(){
  43. _SS
  44.   while(1){
  45.    WaitX(100);
  46.    LED2=!LED2;   
  47.   }
  48. _EE
  49. }


  50. void main()
  51. {
  52.         InitT0();
  53.         while(1){
  54.            RunTask(task1,1);
  55.            RunTask(task2,2);
  56.     }
  57. }

复制代码
zj_871112
4楼-- · 2020-01-21 03:21
好贴,慢慢学习~~
zhizhiyu
5楼-- · 2020-01-21 05:13
 精彩回答 2  元偷偷看……
modelsim
6楼-- · 2020-01-21 07:09
本帖最后由 modelsim 于 2012-12-7 14:00 编辑

settimer(&lc,__LINE__,500);return;case __LINE__:

void settimer(char *lc,char line,unsigned char d)
{
  *lc=line;  
  timers[currid]=d;
}

这段代码没看懂,请楼主讲解下,那个_LINE_宏有什么用,为什么要加入这个,如何能去掉

一周热门 更多>