⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 functionforucos.txt

📁 This the brief for the common function in uCOS system. Valid for elementary user.
💻 TXT
📖 第 1 页 / 共 2 页
字号:
#endif

#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN
    void          *OSTCBMsg;           //
#endif    

    INT16U         OSTCBDly;           //任务延时节拍
    INT8U          OSTCBStat;          //任务状态,当它等于OS_STAT_READY时,任务进入就绪态
    INT8U          OSTCBPrio;          //任务优先级

    INT8U          OSTCBX;             //例如任务的优先级为25,    则OSTCBX=25%8=1
    INT8U          OSTCBY;             //OSTCBY=25%8=3
    INT8U          OSTCBBitX;          //

    INT8U          OSTCBBitY;          //对应的位数
    
#if OS_TASK_DEL_EN    
    BOOLEAN        OSTCBDelReq;        //
#endif
} OS_TCB;

第六章:OS的核心运转过程 (1)空闲任务的建立及运行过程
μC/OS /sherlock_lai 发表于2008-01-16, 21:56 
OS是如何运转起来的?(一般情况下,不考虑系统的一些配置被修改).

1.系统变量常量配置

在程序的最开头,先定义你需要的任务的堆栈大小,优先级,此时CPU已经将系统的一些变量,常量储存于实际物理地址了(例如任务堆栈)

#define  .....

...

2.运行到OSInit();

首先是一个主函数,CPU运行第一个函数OSInit();在这里,CPU初始化一些系统变量的值,例如一些任务记数器等.

然后创建两个基本的任务:空闲任务(CPU闲置时就连续运行此任务),统计任务(统计空闲任务,以便计算CPU的使用率).

void Main(void)
{
 OSInit(); 
 OSTaskCreate(Main_Task, (void *)0, (OS_STK *)&Main_Stack[TASK_STACK_SIZE-1],  Main_PRIO); 
 OSStart(); 
} 

2.0 初始化一个任务控制快单向链表, .OSTCBNext=下一个,      OSTCBFreeList为第一个,如果这个链表被取出一个,则OSTCBFreeList指向空链表里的第一个       

2.1 建立空闲任务的过程

2.11 OSTaskStkInit 根据任务函数入口,传递的参数,栈顶,选择项,4个参数决定物理栈顶指针,这个栈里还有其他参数,比如PC值,这些参数都保存在这个物理栈里,在任务开始运行时,将这些值取出,而当任务因为某种原因中断了,则保存这些值,这样下次就能从中断的那个状态再次运行这个任务.

初始化堆栈,从栈顶依次压入,任务函数入口,各个寄存器,这样恢复任务的时候先恢复各个寄存器,最后才将任务函数入口压入PC,从而运行任务

2.12 OSTCBInit 初始化一个任务控制块

将各个参数填入这个控制块,并且生成一个双向任务链表,每次初始化的任务控制块将会添加入链表的左端,这个双向链表在时钟节拍中会用到.

最后在就绪表里将此任务对应的位置一,表示这个任务已经就绪了.

2.13 如果以上都成功了,则任务记数器+1. 接下来会检查OSRunning,如果它为0,说明系统还未运行,这样空闲任务就建立了,等待OSStart 函数开始运行系统,如果OSRunning 为1,说明系统已经运行,这样就执行一次任务调度,任务调度的作用是,如果刚刚建立的任务优先级最高,就运行这个任务. 以下分析任务调度函数

2.131 OSSched 如果任务调度的条件成立,则将就绪表里优先级最高的任务赋予OSPrioHighRdy(等待运行里优先级最高的任务)(这个地方有个疑问:在这个地方运行完后,OSPrioHighRdy和OSPrioRdy会变成什么) 如果这个最高优先级的任务还没运行,那么任务切换计数器+1,执行OS_TASK_SW 任务切换函数. 接下来解析任务切换函数功能

2.1311 OS_TASK_SW  保存处理器的值,将当前任务的堆栈指针保存到当前任务的OS_TCB, (第一次运行OS,这个TCB是否为空闲任务的TCB?) , OSTCBCur , OSPrioCur 赋予最高优先级任务,堆栈指针赋予最高优先级任务指针,将堆栈中的内容恢复,执行中断返回指令,这样就运行了最高优先级任务了,这里就是空闲任务. (疑问:第一次的堆栈有何作用?还是本来就没用?)

2.2 建立完空闲任务,这时空闲任务就运行了,这里又有个疑问,此时系统的最高优先级任务为空闲任务,那么当空闲任务挂起进行任务调度时,那么会运行的不会又是空闲任务? 还是没有跳会到主程序流程? 可能空闲任务里保存了两块堆栈,主流程堆栈和自身的堆栈. 这里不是很理解...不管先,继续往下走,假设系统跳回到任务建立那,接下来也就是要建立统计任务了.


第六章:OS的核心运转过程 (2)始终节拍函数,统计任务
μC/OS /sherlock_lai 发表于2008-01-06, 22:19 
OSTickISR 时钟节拍函数

时钟一到,保存寄存器值,当前的堆栈指针SP赋予OSTCBCur.OSTCBStkPtr,调用OSTimeTick() 

OSTimeTick 节拍服务函数

将每个TCB中的.OSTCBDly-1,如果OSTCBDly为0了,任务原先也没有被挂起,就将任务置为就绪态,如果原先被挂起,就先将OSTCBDly为1.  这里有条语句ptcb=OSTCBList ,OSTCBList是?

接着恢复处理器寄存器的值,返回原先的状态.

前面提出的疑问这里突然也得到解决, 因为第一次建立空闲函数,此时OSRUNNING还是为0,所以还不会出现程序在空闲任务处循环的情况,因为空闲任务根本不会运行,这里程序会继续往下走,建立统计任务

OSTaskStat




第七章:函数解析:OSTimeTick
μC/OS /sherlock_lai 发表于2008-01-08, 20:31 
void OSTimeTick (void)   //这个节拍服务函数是在OSTickISR函数中调用的,目的是在时钟节拍到来时,检查每个任务的任务控制块中的.OSTCBDly-1后是否为0,如果是,那么表明这个任务刚才是挂起的状态,此时应改变为就绪态
{
    OS_TCB *ptcb;


    OSTimeTickHook();                                      //
    ptcb = OSTCBList;                                      //时钟节拍到来时,将控制块双向链表的第一个控制块取出(并不是节拍之前运行的任务)
    while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {              //空闲任务处于控制块双向链表的最后一个,如果取出的控制块为空闲任务的控制块,那么已经取到最后一个了,就结束

      //        OS_ENTER_CRITICAL();
        if (ptcb->OSTCBDly != 0) {                         //
            if (--ptcb->OSTCBDly == 0) {                   //

                if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) {    //检查任务是否处于强制挂起状态,如果是,那再挂起一个时钟节拍,否则就将它就绪

                    OSRdyGrp               |= ptcb->OSTCBBitY; 

                    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                } else {                                       //
                    ptcb->OSTCBDly = 1;                        //

                }                                              //
            }
        }
        ptcb = ptcb->OSTCBNext;                            //下一个任务控制块
 //        OS_EXIT_CRITICAL();
    }
    //    OS_ENTER_CRITICAL();                                   //
    OSTime++;           //节拍计数器+1
    //    OS_EXIT_CRITICAL();
}

第八章:函数解析:OSTaskStat
μC/OS /sherlock_lai 发表于2008-01-08, 21:01 
void OSTaskStat (void *pdata)  //统计任务的目的是计算CPU利用率。CPU空闲时会不停的运行空闲任务,只要得到空闲任务运行次数的全局变量,就能统计出CPU利用率
{
    INT32U run;
    INT8S  usage;
    
    
    pdata = pdata;                               //
    while (OSStatRdy == FALSE) {    //等待统计任务就绪
        OSTimeDly(2 * OS_TICKS_PER_SEC);             //
    }
    for (;;) {
        OS_ENTER_CRITICAL();
        OSIdleCtrRun = OSIdleCtr;                //获得统计任务运行次数(1秒内)
        run          = OSIdleCtr;
        OSIdleCtr    = 0L;                       //清零,必要的,为下一秒的统计做准备
        OS_EXIT_CRITICAL();
        if (OSIdleCtrMax > 0L) {
            usage = (INT8S)(100L - 100L * run / OSIdleCtrMax);  //计算百分比
            if (usage > 100) {
                OSCPUUsage = 100;
            } else if (usage < 0) {
                OSCPUUsage =   0;
            } else {
                OSCPUUsage = usage;
            }
        } else {
            OSCPUUsage = 0;
        }
        OSTaskStatHook();                        //
        OSTimeDly(OS_TICKS_PER_SEC);             //挂起一秒,统计任务一秒运行一次    }
} 
第九章:函数解析:OSStart
μC/OS /sherlock_lai 发表于2008-01-08, 22:07 
void OSStart (void)   //执行这个函数OS就开始运行了
{
    INT8U y;
    INT8U x;


    if (OSRunning == FALSE) 
    {
        y             = OSUnMapTbl[OSRdyGrp];        //取出优先级最高的任务
        x             = OSUnMapTbl[OSRdyTbl[y]];
        OSPrioHighRdy = (INT8U)((y << 3) + x);
        OSPrioCur     = OSPrioHighRdy;
        OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy]; //
        OSTCBCur      = OSTCBHighRdy;
        OSStartHighRdy();                            //OSRunning=TRUE,得到要将要运行的最高优先级任务的指针,恢复任务栈内的寄存器和PC值,开始执行任务。疑问:AMR7移植的OS里,这个函数中为什么不包含OSRunning=TRUE这条指令????
    }
}

执行这个函数后,空闲任务开始不停运行,到了第一个时钟节拍,CPU首先将任务双向链表里的任务的延迟变量都-1,然后将延迟变量为0的任务就绪,接着看处于就绪态的优先级最高的任务是否运行,如果没有,就运行这个任务。然后系统到了第二个时钟节拍,第三个.....一直做这样的循环,这样就保证优先级最高的任务得以第一时间运行。

一般情况下,UCOS的核心运转过程就是这样一个循环。

第十章:函数解析:OSTickISR,OSIntExit,OSIntCtxSw
μC/OS /sherlock_lai 发表于2008-01-08, 22:43 
这个函数涉及寄存器的操作。以下是示意性代码(引用邵贝贝一书)。

保存处理器寄存器;

调用OSIntEnter()或者直接给OSIntNesting加1;

if(OSIntNesting==1)

{

OSTCBCur->OSTCBStkPtr=Stack Pointer;

}

给产生中断的设备清中断;

重新允许中断(可选);

OSTimeTick();  //给延时到的任务就绪态

OSIntExit();  //这个函数与OSSched 差不多,都是将最高级任务置为就绪态

恢复处理器寄存器;

执行中断返回指令;

}

void OSIntExit (void)
{
  //    OS_ENTER_CRITICAL();
    if ((--OSIntNesting | OSLockNesting) == 0)   //
        OSIntExitY    = OSUnMapTbl[OSRdyGrp];
        OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
        if (OSPrioHighRdy != OSPrioCur) 
            OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy]; //在这里得到新的OSTCBHighRdy参数
            OSCtxSwCtr++;                        
            OSIntCtxSw();                //这个函数与OSCtxSw差不多

        }
    }
    //    OS_EXIT_CRITICAL();
}

void OSIntCtxSw(void)

{

OSTCBCur->OSTCBStkPtr=堆栈指针;

OSTCBCur=OSTCBHighRdy;

OSPrioCur=OSPrioHighRdy;   //恢复OSTCBCur参数

堆栈指针=OSTCBHighRdy->OSTCBStkPtr;

将任务堆栈中的内容恢复;

执行中断返回指令;

}

第十一章:关于OSRunning的问题
μC/OS /sherlock_lai 发表于2008-01-09, 12:41 
UCOS的源代码中要求在OSStartHighRdy中加入OSRunning=TRUE的代码,但是我用的那个ARM7移植的OSSTartHighRdy并没有这段代码,这会带来什么问题?

首先,OSRunning这个变量在创建任务函数OSTaskCreate中有用到,如果OSRunning为TRUE,则执行OSSched,OSSched的功能就是将就绪表中优先级任务最高的任务取出,然后进行任务切换。也就是说,如果在OSStartHighRdy中没有OSRunning=TRUE的代码,在创建任务的时候,如果创建的任务的优先级为最高,那么它并不能得到马上运行。但实际上这也没多大关系,因为当时钟节拍到来的时候,时钟节拍依次调用了OSTimeTick(节拍服务函数)和OSIntExit。后者与OSSched是极其相似的,它们的作用也一样。这样,在节拍到来时,还是会进行任务切换,只不过刚创建的优先级最高的任务相当于延时了一个节拍运行而已。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -