zoukankan      html  css  js  c++  java
  • 调度器,极小资源单片机值得一用(转)

    源:再出个调度器,极小资源单片机值得一用

    自认为有如下特点:

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

    优化无止境!呵呵,330楼看似不能再优化了,但我再尝试做一次优化:

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

    /****小小调度器开始**********************************************/
    #define MAXTASKS 2
    static unsigned char timers[MAXTASKS];
    unsigned char currdt;
    #define _SS static unsigned char _lc; switch(_lc){default: 
    #define _EE ;}; _lc=0; return 255;
    #define WaitX(tickets)  do {_lc=__LINE__+((__LINE__%256)==0); return tickets ;} while(0); case __LINE__+((__LINE__%256)==0): 
    #define RunTask(TaskName,TaskID) do { if (timers[TaskID]==0) timers[TaskID]=TaskName(); }  while(0);
    
    #define CallSub(SubTaskName) do { _lc=__LINE__+((__LINE__%256)==0); return 0; case __LINE__+((__LINE__%256)==0):  currdt=SubTaskName(); if(currdt!=255) return currdt;} while(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;
    
    void InitT0()
    {
            TMOD = 0x21;
            IE |= 0x82;  // 12t
            TL0=0Xff;
            TH0=0XDB;//22M---b7;
            TR0 = 1;
    }
    
    void INTT0(void) interrupt 1 using 1
    {
        UpdateTimers();
    
        TL0=0Xff;    //10ms 重装
        TH0=0XDB;//b7;    
    }
    
    
    void  task1(){
    _SS
      while(1){
       WaitX(50);
       LED1=!LED1;   
      }
    _EE
    }
    
    void  task2(){
    _SS
      while(1){
       WaitX(100);
       LED2=!LED2;   
      }
    _EE
    }
    
    
    void main()
    {
            InitT0();
            while(1){
               RunTask(task1,0);
               RunTask(task2,1);
        }
    }

    在keil下编译,又减少了18字节的ROM(超过10%了)。应该运行效率会更高。

    ------------------以下为说明-----------------------------------

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

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

    本调度器的宗旨是:以最小的代价,实现基于自然语法的多任务并行处理机制。并具备代码的高度可以移植性。
    每个任务占用3个字节RAM。任务数量没有限制。

    其工作原理很简单,大家可在此基础上任意DIY自己的调度方法。

  • 相关阅读:
    iOS 109个Demo范例
    iOS 109个Demo范例
    iOS 完全复制UIView
    iOS 完全复制UIView
    iOS 获取self类型
    Python 进阶_OOP 面向对象编程_类和继承
    Python 进阶_OOP 面向对象编程_类和继承
    Python 进阶_模块 & 包
    Python 进阶_模块 & 包
    Python 进阶_模块 & 包
  • 原文地址:https://www.cnblogs.com/LittleTiger/p/4685581.html
Copyright © 2011-2022 走看看