小小调度器,极小资源单片机值得一用

admin 2017-5-31 4777

小小调度器


1)  超级可以移植性,与CPU无关,几乎任何支持C语言编程的CPU都可以用!(本文仅仅以51单片机为例而已,但实际上可以任意移植)

2)  小之又小, 原理很简单,一看就懂。

3)  省之又省, 可以说对RAM和ROM省到极致。

4)  取protothread之精华,将定时器与状态机和伪线程语法融合到一个框架,任务函数可以有两种写法。

5)  基于定时器触发,调度效率高,最大化减少无效的代码运行时间。


小小调度器任务函数的写法主要注意的,主要有三点:

1) 任务函数内部变量,建议都用静态局部变量来定义。

2) 任务函数内不能用switch语句。

3) 任务函数内,不能用return语句。 因为return已经被赋予任务延时的特定意义。(这是返回型任务函数版本的一个强制要求)

这三点,并不会明显造成写程序的不方便。

---------------------------

从裸奔到使用OS操作系统或调度系统的代价主要有:

硬件资源代价(对RAM和ROM的消耗),学习代价(学会其原理,并掌握其用法),移植代价(往不同cpu上移植的工作量),效率代价(使用调度系统后带来的额外cpu负担),商业代价(版权费用),稳定性代价(是否引入潜在不稳定因素,或者增大bug跟踪调试工作量)。

从这几方面来讲,应用小小调度器的代价,都是非常小的。

1) 硬件资源代价: 前面的优化版本已经说明问题。keil下,本例程ram消耗 : 22字节,rom消耗126字节.

2) 学习代价: 小小调度器总共只有十多行代码,如果我们做一个简单的解释说明,理解起来其实是很快的。我相信学习时间比其他调度系统要短。

3) 移植代价: 几乎没有什么移植工作量,对于各种cpu,几乎是通吃。

4) 效率代价: 我们一直在努力优化,相信调度效率已经不低了。比如任务切换时间,应该是可以做到uS级别,甚至亚uS级别。

5) 商业代价: 小小本调度器为免费使用,无需支付任何费用。

6) 稳定性代价:小小调度器本质上仅仅是几个宏而已,未涉及任何对内部寄存器或堆栈的操作,避免了引入不稳定风险因素,所有操作都在可预见,可把控的前提下进行。

#include <stc89c51.h>
/****小小调度器开始**********************************************/
#define MAXTASKS 3
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]--;}}
#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);
/*****小小调度器结束*******************************************************/
sbit LED1 = P2^1;
sbit LED2 = P2^2;
sbit LED0 = P2^5;
unsigned char task0(){
_SS
  while(1){
   WaitX(50);
   LED0=!LED0;   
  }
_EE
}
unsigned char  task1(){
_SS
  while(1){
   WaitX(100);
   LED1=!LED1;   
  }
_EE
}
unsigned char  task2(){
_SS
  while(1){
   WaitX(100);
   LED2=!LED2;   
  }
_EE
}
void InitT0()
{
        TMOD = 0x21;
        IE |= 0x82;  // 12t
        TL0=0Xff;
        TH0=0XDB;
        TR0 = 1;
}
void INTT0(void) interrupt 1 using 1
{
    TL0=0Xff;    //10ms 重装
    TH0=0XDB;//b7;    
    UpdateTimers();
    RunTask(task0,0);//任务0具有精确按时获得执行的权限,要求:task0每次执行消耗时间<0.5个 ticket
}
void main()
{
        InitT0();
        InitTasks(); //初始化任务,实际上是给timers清零
        while(1){
//           RunTask(task0,0);
                RunTaskA(task1,1);//任务1具有比任务2高的运行权限                   
           RunTaskA(task2,2);//任务2具有低的运行权限                   
      }
}


上传的附件:
最新回复 [6]
  • admin 2017-5-31
    0 2

    还有一个新塘的移植

  • admin 2017-5-31
    0 3

    我很喜欢这个调度器,  用到几个小产品中了.  可是回帖越来越没味道!  想学想用就把这1000多楼看一遍!  不要妄下结论! 
    关键点:
    1.case后面的是标号,  switch只查找标号,  找到了就直接跳转过去, 
    而不论这个标号在什么地方,  即使是在while中,  for中,  if...else...中.
    2.任务函数内部不能再用switch语句了.  这种情况用  if  else.
    任务不要返回自定义数据,  因为return已经被赋予任务延时的特定意义,  这是返回型任务函数版本的一个强制要求.
  • admin 2017-5-31
    0 4
    再发布一个更新的版本(感谢坛友支持):
    在IAR6.7下编译通过。(选用:Misra C 2004)
    /****小小调度器开始**********************************************/
    #define MAXTASKS 3U
    volatile static unsigned char timers[MAXTASKS];
    #define _SS    static unsigned char _lc=0U; switch(_lc){case 0U:  
    #define _EE     break; default:break;}  _lc=0U;  return 255U;
    #define WaitX(tickets)   _lc=(unsigned char)(__LINE__)%255U+1U;  if(_lc){return (tickets);}  break; case ((unsigned char)(__LINE__)%255U)+1U: 
    #define RunTask(TaskName,TaskID)  do {if (timers[(TaskID)]==0U){ timers[(TaskID)]=(TaskName)(); } } while(0)  
    #define RunTaskA(TaskName,TaskID) { if (timers[(TaskID)]==0U) {timers[(TaskID)]=(TaskName)(); continue;} }    /*前面的任务优先保证执行*/
    #define CallSub(SubTaskName) do {unsigned char currdt; _lc=(unsigned char)(__LINE__)%255U+1U; if(_lc) {return 0U;} break; case (unsigned char)(__LINE__)%255U+1U:  currdt=(SubTaskName)(); if(currdt!=255U) {return currdt;}} while(0);
    #define InitTasks() do {unsigned char i; for(i=MAXTASKS;i>0U ;i--) {timers[i-1U]=0U;} } while(0)
    #define UpdateTimers() do { unsigned char i;  for(i=MAXTASKS;i>0U ;i--){      if(timers[i-1U]!=0U){          if(timers[i-1U]!=255U) { timers[i-1U]--;} } }} while(0)
    #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);
    /*****小小调度器结束*******************************************************/
    static unsigned char task0(void){
      static int i;  
    _SS
      for(i=0;i<11;i++){    
        WaitX(10U);
      }  
    _EE
    }
    static unsigned char task1(void){
        
    _SS
      while(1){    
        WaitX(10U);
      }  
    _EE
    }
    static unsigned char task2(void){
        
    _SS
      while(1){    
        WaitX(10U);   
      }  
    _EE
    }
    void InitT0()
    {
            TMOD = 0x21;
            IE |= 0x82;  // 12t
            TL0=0Xff;
            TH0=0XDB;
            TR0 = 1;
    }
    void INTT0(void) interrupt 1 using 1
    {
        TL0=0Xff;    //10ms 重装
        TH0=0XDB;//b7;    
        UpdateTimers();
        RunTask(task0,0);//任务0具有精确按时获得执行的权限,要求:task0每次执行消耗时间<0.5个 ticket
    }
    int main(void)
    {
      InitT0();
      InitTasks(); 
      while(1){    
        RunTaskA(task1,1);  //任务一具有比任务二优先执行的权限
        RunTaskA(task2,2);  
      } 
    }


  • admin 2017-5-31
    0 5

    2.0版本

    /****小小调度器开始**********************************************/
    #define MAXTASKS 3
    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__%255)+1; return tickets ;} while(0); case (__LINE__%255)+1: 
    #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__%255)+1; return 0; case (__LINE__%255)+1:  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]--;}}
    #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);
    /*****小小调度器结束*******************************************************/
  • 13029881200 2018-7-27
    0 6
    牛x
  • ZHAGN 2018-7-28
    0 7
    这个不错,谢谢分享
返回