搜索
bottom↓
回复: 8

ucos2移植尝试:“剔除”空闲任务,由主函数代替

[复制链接]

出0入0汤圆

发表于 2009-6-15 22:02:44 | 显示全部楼层 |阅读模式
ucos2移植尝试:“剔除”空闲任务,并不是真的剔除,
空闲任务控制块仍然存在,同样参与调度,只是任务空闲时,并不是进入空闲任务,而是直接切换到主函数。
没有了空闲任务,也就不用给空闲任务分配堆栈了。只支持OS_TASK_CREATE_EXT_EN为0的情况。

ucos不熟,只是移植尝试,不保证正确。
没有在硬件平台测试。

移植平台:atmega16+iaravr,atmega16+avrgcc,cc1110+iar8051

#include "config.h"

#define TASK1_STK_SIZE 150
#define TASK2_STK_SIZE 150

OS_STK Task1Stk[TASK1_STK_SIZE];
OS_STK Task2Stk[TASK2_STK_SIZE];

void Task1(void *pdata)
{
volatile float f1=(int)pdata;
while(1)
    {         
       PORTD^=0x80;
       f1+=0.1;        //浮点数测试
       OSTimeDly(2);
    }
}

void Task2(void *pdata)
{
volatile float f2=(int)pdata;
while(1)
    {     
         PORTD^=0x40;
         f2+=0.1;        //浮点数测试
         OSTimeDly(3);
    }
}

int main(void)
{

     DDRD=_BV(7)|_BV(6);
     PORTD=_BV(7)|_BV(6);
         
     TCNT2 = 0;
     TCCR2=_BV(WGM21) | T2_CLK_DIV_128;
     OCR2=OCR2_INIT;
     TIFR|=_BV(OCF2);
     TIMSK=_BV(OCIE2);

    OSInit();

    OSTaskCreate(Task1,(void *)1,&Task1Stk[TASK1_STK_SIZE-1],1);
    OSTaskCreate(Task2,(void *)2,&Task2Stk[TASK2_STK_SIZE-1],2);
   
    OSStart();

    volatile  float f3=0;
    sei();         //主函数(相当于空闲任务)开中断
         
   while(1)
   {
        CRITICAL()     //临界段段
        {
          OSIdleCtr++;
        }
        
        OSTaskIdleHook();   
     
        f3+=0.1;      
   }
   
   
}

ISR(TIMER2_COMP_vect)
{
    OSIntEnter();                                       
    OSTimeTick();                                                              
    OSIntExit();                     
}


点击此处下载 ourdev_453558.rar(文件大小:300K) (原文件名:ucos.7z.rar)

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2009-6-15 22:47:43 | 显示全部楼层
ucos2移植尝试:“剔除”空闲任务,并不是真的剔除,
空闲任务控制块仍然存在,同样参与调度,只是任务空闲时,并不是进入空闲任务,而是直接切换到主函数。
没有了空闲任务,也就不用给空闲任务分配堆栈了。只支持OS_TASK_CREATE_EXT_EN为0的情况。

你怎么返回到主任务,考虑过这个问题没有
每个任务要有自己的任务控制块以及优先级
调用 OSStart();之后就永远不反回了,你这么干只会跑飞了,跑飞的原因是就绪表里面没有任务,而其他任务处于阻塞中。
程序没有去处了
延时任务阻塞后会调用OS_Sched
此时如果没有任务就绪 OSRdyGrp=0
  y             = OSUnMapTbl[OSRdyGrp];          /* Get pointer to HPT ready to run              */
        OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
计算出最高优先级为0

如果你0优先级有任务的话,那还好说,比如是延时任务,接着延时的位置继续运行,但实际上延时的次数根本就没到
你又跑到那个延时任务去了。
如果0优先级没有任务的话,对不起,飞了
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
这个任务块根本就没初始化

void  OS_Sched (void)
{

    INT8U      y;


    OS_ENTER_CRITICAL();
    if ((OSIntNesting == 0) && (OSLockNesting == 0)) { /* Sched. only if all ISRs done & not locked    */
        y             = OSUnMapTbl[OSRdyGrp];          /* Get pointer to HPT ready to run              */
        OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
        if (OSPrioHighRdy != OSPrioCur) {              /* No Ctx Sw if current task is highest rdy     */
            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
            OSCtxSwCtr++;                              /* Increment context switch counter             */
            OS_TASK_SW();                              /* Perform a context switch                     */
        }
    }
    OS_EXIT_CRITICAL();
}

出0入0汤圆

 楼主| 发表于 2009-6-15 23:07:00 | 显示全部楼层
【1楼】 ralfak
调用 OSStart();之后就永远不反回了,你这么干只会跑飞了,跑飞的原因是就绪表里面没有任务,而其他任务处于阻塞中。
-----------------------------------------------------------------------------------------------------------------

为什么调用 OSStart();之后就永远不反回了。
原因是调用OSStart()的时候,没有保护本身断点信息,就切换任务里了,任务之间无论怎么切换,都不可能切回来了。

我的做法是,OSStart()第一次切换任务时,把断点信息记录到Idle Task的TCB里,当再次切换到Idle Task时,自动就切换回断点了。
任务切换对OSStart()来说,就好像只是发生了一次中断。任务切换回来断点在函数OSStart()里,继续执行从OSStart()返回,进入后面的while(1)循环。

因为OSStart()会保护断点信息到Idle Task的TCB里,前面Idle Task初始化不必分配任何有效堆栈,后面保护断点信息到IDLE TASK的TCB的时候,会把前面的初始值覆盖掉。

void  OSStart (void)
{
    INT8U y;
    INT8U x;


    if (OSRunning == FALSE) {
        y             = OSUnMapTbl[OSRdyGrp];        /* Find highest priority's task priority number   */
        x             = OSUnMapTbl[OSRdyTbl[y]];
        OSPrioHighRdy = (INT8U)((y << 3) + x);
           
        OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run    */
        
        OSTCBCur      = OSTCBPrioTbl[OS_IDLE_PRIO];  //当前任务是空闲任务,即主函数
        
        CRITICAL()   //临界段
        {
             OSRunning=1;
             OSCtxSw();  //任务切换,当任务再次切换回来,从这里继续向后执行
        }
    }
}

出0入0汤圆

发表于 2009-6-16 17:41:27 | 显示全部楼层
那你的意思还是需要IDLE的堆栈,既然都要堆栈了,那不跟有一个IDLE任务一样么。
你单独在main函数中做死循环,还要单独写一段初始化主函数堆栈的代码,要将主函数的要跳转执行的PC压入堆栈,至于其他的都不用关心了。实际效果与IDLE没任何差别。相反还添加了第一次压主函数进堆栈的任务。
还得在代码上标记一个lable吧,不知道管不管用

出0入0汤圆

 楼主| 发表于 2009-6-16 18:17:39 | 显示全部楼层
“那你的意思还是需要IDLE的堆栈,既然都要堆栈了,那不跟有一个IDLE任务一样么。”
----------------------------------------------------------------------------
如果有单独的IDLE TASK,就必须给IDLE TASK分配堆栈。
IDLE TASK的堆栈和主函数的堆栈是两个不同的堆栈。

如果去掉IDLE TASK,由主函数代替,那么只需要主函数的堆栈就行了。



“你单独在main函数中做死循环,还要单独写一段初始化主函数堆栈的代码,要将主函数的要跳转执行的PC压入堆栈,至于其他的都不用关心了。实际效果与IDLE没任何差别。相反还添加了第一次压主函数进堆栈的任务。”
---------------------------------------------------------------------------------
其实主主函数断点压入堆栈,是任务切换自动完成的。

主函数本身就是任务,我称主函数任务。
当主函数任务已经在运行,再初始化主函数任务上下文和上下文指针没有意义。
当主函数任务切换到其他任务,OS会自动保护主函数任务的断点上下文并记录上断点上下文指针,
当再次切换到主函数任务,从这个断点上下文指针恢复断点上下文。

出0入0汤圆

发表于 2009-6-16 18:49:36 | 显示全部楼层
---------------------------------------------------------------------------------  
其实主主函数断点压入堆栈,是任务切换自动完成的。

可以这样理解。
一般的OS,是由主函数先完成一个和多个任务的初始上下文堆栈,然后跳到某个任务开始运行。
任务在运行之前,必须初始化上下文堆栈。

现在假设已经在某个任务中运行了,那么这个任务的上下文堆栈还需要初始化吗?
不需要。任务切换的时候自动维护上下文堆栈。

当把主函数当作IDLE TASK运行时,

___________________________________________________________________________
前后台系统是不需要初始化
但是UC/OS你必须初始化
因为任务调度器确定任务运行的位置,
你都没有告诉调度器我这儿还运行着一个任务。
调度器又怎么能找得到你这个任务。

出0入0汤圆

发表于 2009-6-16 18:54:30 | 显示全部楼层
讨论这样的话题没有任何意义,其实没有IDLE TASK只有一个意义,就是让系统待机,省电,如果不是朝着这个方向进行的话,干也白干。
主函数系统自身分配个10几个字节的堆栈足够了,完成各种子程序的跳转的保护操作,函数基本不用保护,直接采用naked属性即可,我看3个字节就够了(128K以上flash需要3字节PC指针)
超过3个字节都是浪费。

出0入0汤圆

 楼主| 发表于 2009-6-16 19:52:58 | 显示全部楼层
直接采用naked属性即可,我看3个字节就够了(128K以上flash需要3字节PC指针) ,超过3个字节都是浪费。
---------------------------------------------------------------------------
主函数难道不需要初始化OS,初始化OS难道不需要函数调用,返回?3字节楼上说笑了。


其实没有IDLE TASK只有一个意义,就是让系统待机,省电,如果不是朝着这个方向进行的话,干也白干。
------------------------------------------------------------------------------------------------
楼上这话太绝对了。
记得FreeRTOS的协程调度就是放在空闲任务的。

出0入0汤圆

 楼主| 发表于 2009-6-16 20:02:16 | 显示全部楼层
前后台系统是不需要初始化
但是UC/OS你必须初始化
因为任务调度器确定任务运行的位置,
你都没有告诉调度器我这儿还运行着一个任务。
调度器又怎么能找得到你这个任务。

-----------------------------------------------------------
当任务还没有运行时(一次都没有),必须初始化任务入口(上下文和上下文指针),使任务第一次运行从这里开始。
但是当任务已经在运行,还需要初始化始化任务入口吗?
不用。当任务切换出去的时候,OS会自动保护任务的断点上下文,并记录到上下文指针。
当任务再次切换回来,从断点上下文指针恢复断点上下文。

这里,任务初始化和任务入口初始化时两个不同的概念。
任务当然要初始化,
但是主函数任务初始化不需要初始化任务入口。因为主函数任务已经在运行。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-5-20 10:57

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

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