【zz】μC/OS-II内核架构解析

原文转自:http://blog.ednchina.com/windy123/1969777/message.aspx

 

1. uC/OS-II文件结构

 

 

2. uC/OS-II组成部分

 

    uC/OS-II大致可以分成系统核心(包含任务调度)、任务管理、时间管理、多任务同步与通信、内存管理、CPU移植等部分。

 

    (1) 核心部分(OSCore.c) :uC/OS-II处理核心,包括初始化、启动、中断管理、时钟中断、任务调度及事件处理等用于系统基本维持的函数。

 

    (2) 任务管理(OSTask.c) :包含与任务操作密切相关的函数,包括任务建立、删除、挂起及恢复等,uC/OS II以任务为基本单位进行调度。

 

    (3) 时钟部分(OSTime.c) :uC/OS-II中最小时钟单位是timetick(时钟节拍),其中包含时间延迟、时钟设置及时钟恢复等与时钟相关的函数。

 

    (4) 多任务同步与通信(OSMbox.c, OSQ.c, OSSem.c, OSMutex.c, OSFlag.c):包含事件管理函数,涉及Mbox、msgQ、Sem、Mutex、Flag等。

 

    (5) 内存管理部分(OSMem.c):主要用于构建私有的内存分区管理机制,其中包含创建memPart、申请/释放memPart、获取分区信息等函数。

 

    (6) CPU接口部分:uC/OS-II针对特定CPU的移植部分,由于牵涉到SP等系统指针,通常用汇编语言编写,包括任务切换、中断处理等内容。

 

3. uC/OS-II任务状态

 

      在uC/OS-II中,一个任务就是一个线程,该任务可以认为CPU完全属于它自己。任务有自己的堆栈和CPU寄存器,并且被赋予一定的优先级。任务可能处于睡眠、就绪、运行、等待或中断服务状态之一。

 

 

 

4. uC/OS-II与VxWorks的比较

 

 

 

【专题】uC/OS-II内核架构解析(3)---uC/OS-II系统核心

 

主要包含在C源文件OS_CORE.C中。

 

1. uC/OS-II任务调度

 

(1) uC/OS-II调度算法

 

      uC/OS-II采用基于优先级的调度算法,总是选择当前处于就绪状态的优先级最高的任务进行调度。uC/OS-II是可抢占性的强实时性OS,在完成中断后允许进行新的任务调度。

 

      uC/OS-II有两种调度方式:任务级任务调度、中断级任务调度。

 

(2) 任务就绪表

 

      INT8U const OSUnMapTbl[256] = {…};

 

      OS_EXT INT8U OSRdyGrp;

 

      OS_EXT INT8U OSRdyTbl[OS_RDY_TBL_SIZE];

 

  • 添加就绪任务至就绪表;
  • 从就绪表删除就绪任务;
  • 查找最高优先级就绪任务OS_SchedNew();

 

(3) 任务级任务调度

 

      指在非中断返回时进行任务调度,一般发生在当前任务因时间延迟或等待某事件而阻塞或被挂起,或有更高优先级的任务处于就绪状态。

 

      任务的基本信息:

 

  • CPU的PC寄存器:任务当前执行的位置;
  • CPU的通用寄存器:任务当前执行涉及的临时数据;
  • CPU的状态寄存器:存储当前CPU的状态。

 

      任务级任务切换:从一个任务直接切换至另一个任务,不涉及CPU状态的切换,OS_TASK_SW()既保存当前任务上下文,又恢复新任务上下文。

 

      过程:OS_Sched() -> OS_SchedNew() -> OS_TASK_SW()

 

 

 

 

 

 

(4) 中断级任务调度  

 

 

 

 

 

 

 

 

 

 

      中断级任务切换:在中断处理完成后,通过OSIntExit()判断是否有更高优先级就绪任务。如果有,调用OSIntCtxSW()恢复新任务上下文。注意:在中断处理中,已经保存了被中断任务的上下文,所以这里仅仅恢复。

 

      过程:OSIntExt() –> OSIntEnter() -> ISR –> OSIntExit() -> OSIntCtxSW()

 

(5) 调度器上锁与解锁

 

      uC/OS-II提供调度器锁定功能,在锁定期间不能进行任务调度。uC/OS-II使用全局变量OSLockNesting标识是否锁定了任务调度器。

 

  • OS_EXT INT8U OSLockNesting;
  • void OSSchedLock(void);
  • void OSSchedUnlock(void);

 

(6) 中断管理函数

 

      在中断处理中,不允许进行任务管理、事件管理及任务调度等操作。uC/OS-II通过全局变量OSIntNesting标识当前是否处于中断状态。在所有任务及事件管理的程序中,都有对OSIntNesting进行判断的语句。

 

  • void OSIntEnter(void);
  • void OSIntExit(void);

 

 

 

(7) 中断相关问题

 

  • OS_ENTER_CRITICAL()
  • OS_EXIT_CRITICAL()

 

    关中断使得uC/OS-II能够同时避免有其他任务或中断服务进入临界代码段。调用uC/OS-II功能函数时,中断总应当是开着的。

 

  • uC/OS-II如何禁止调度?
  • 在中断中允许调度吗?为什么?
  • uC/OS-II如何屏蔽中断?

 

2. uC/OS-II系统启动

 

      uC/OS-II首先调用OSInit()进行初始化,然后创建任务(此时还未启动系统,仅仅为其分配资源),然后调用OSStart()启动系统,将CPU控制权交给uC/OS-II,OS根据任务优先级选择由哪个任务开始执行,或创建新的任务。

 

(1) 初始化函数OSInit()

 

      OSInit()主要完成初始化操作,包括初始化全局变量(在OS_InitMisc()中)、任务就绪表、TCB、ECB、FCB、内存单元、消息队列,并创建空闲任务。如果有必要,创建统计任务。

 

  • OS_InitMisc();                  //初始化部分全局变量
  • OS_InitRdyList();             //初始化任务就绪表
  • OS_InitTCBList();            //初始化空闲TCB链表
  • OS_InitEventList();          //初始化ECB链表
  • OS_FlagInit();                  //初始化事件组标志结构
  • OS_MemInit();                 //初始化内存管理
  • OS_QInit();                      //初始化消息队列
  • OS_InitTaskIdle();            //创建空闲任务
  • OS_InitTaskStat();            //创建统计任务

 

 

 

 

 

      uC/OS-II初始化了5个空的数据结构缓冲区,每个缓冲区都是单向链表,允许uC/OS-II从缓冲区中迅速取得或释放一个缓冲区中的元素。

 

 

 

     uC/OS-II调用OSInit()后的变量与数据结构 如下图所示:

 

 

 

 

(2) 启动函数OSStart()

 

      OSStart()在一切准备就绪且需要首先创建的任务都被创建后,启动uC/OS-II。它从就绪表中查找最高优先级就绪任务,并恢复其上下文开始执行。

 

      过程:OSStart() -> OS_SchedNew() -> OSStartHighRdy()

 

      问题:任务第一次被调用时,哪来的上下文供其恢复呢 ?创建任务时,调用了OSTaskStkInit()初始化任务堆栈,可此函数中没有涉及任务的上下文呀?

 

      uC/OS-II调用OSStart()后的变量和数据结构 如下图所示:

 

 

(3) 统计任务OSTaskStat

 

     
OSTaskStat用于计算CPU利用率。设置OS_CFG.H中的OS_TASK_STAT_EN为1,创建统计任务,在系统启动后一直处于就绪状
态。刚开始时,空闲任务运行1S,为计算CPU利用率提供一个基准值,并保存在统计任务的堆栈中,这个值不会改变除非重新启动CPU。此后空闲任每次被其
它任务抢去CPU时,它里面的计数器就会直接记录下CPU空闲的时间。

 

3. uC/OS-II系统时钟

 

      任何实时系统的时钟硬件设备每隔一段时间(一个系统tick)产生一个硬件中断,OS接收到该中断后,更新时间计数器,更新所有对时钟依赖的程序代码,从而维持系统有序稳定的运行。

 

      主要包含在C源文件OS_TIME.C中。

 

  • #define OS_TICKS_PER_SEC 100     //系统时钟中断间隔
  • OS_EXT volatile INT32U OSTime;      //系统运行的时间值

 

   

 

  • void OSTimeTick(void);                         //时钟中断服务程序
  • void OSTimeDly(INT16U ticks);           //延迟指定时钟节拍
  • INT8U OSTimeDlyHMSM(…);             //延迟指定时间长度
  • INT8U OSTimeDlyResume(prio);  //恢复等待(时延/阻塞)任务
  • INT32U OSTimeGet(void);                   //读取当前时间
  • void OSTimeSet(INT32U ticks);            //设置当前时间

 

4. uC/OS-II事件管理

 

(1)   事件控制块

 

  • INT8U OSEventType;                           //事件类型
  • void *OSEventPtr;                                //指向MBox或Queue
  • INT16U OSEventCnt;                           //信号量计数器(注:Mutex)
  • INT8U OSEventGrp;                            //事件等待组标志
  • INT8U OSEventTbl[];                          //时间任务等待表
  • INT8U OSEventName[];                      //时间名称

 

(2) ECB管理机制

 

  • OS_EXT OS_EVENT *OSEventFreeList;   //空闲ECB链表指针
  • OS_EXT OS_EVENT OSEventTbl[];       //ECB结构体数组

 

(3) ECB管理函数

 

  • OS_InitEventList():初始化ECB;
  • OS_EventWaitListInit():在创建事件时调用,初始化ECB任务等待表;
  • OS_EventTaskRdy():在事件发生时调用,修改此事件中最高优先级任务的TCB成员变量,在任务就绪表中添加此任务,将相应信息传递给该任务TCB,并将此任务从事件的任务等代表中删除;
  • OS_EventTaskWait():在申请资源失败而暂停当前任务时被调用,将任务从任务就绪表中删除,并添加到事件的任务等代表中;
  • OS_EventTO():在事件等待超时时调用,将此任务从事件的任务等代表中删除,并修改该任务的TCB成员变量;

 

【专题】uC/OS-II内核架构解析(4)---uC/OS-II任务管理

 

1. C可执行代码结构

 

 

 

    (1)代码段.text:存放CPU执行的机器指令,通常.text是可共享且只读的。

 

    (2)数据段.data:.rodata(常量数据)、.rwdata(已初始化全局变量、静态变量)。

 

    (3)未初始化数据段.bss:未初始化的全局变量、静态变量。

 

    (4)栈.stack:存放函数参数、局部变量及任务切换时的上下文。

 

    (5)堆.heap:用于动态内存分配。

 

2. 任务结构

 

 

 

      在uC/OS-II中,任务是事件运行和管理的基本单元。一个uC/OS-II任务至少包含程序代码、栈和TCB,还可选择性使用相当于堆的动态内存空间。程序运行时,uC/OS-II中的任务相当于可执行代码(可单独运行的单元)。

 

      uC/OS-II任务的各部分如何管理???

 

3. 任务栈

 

  • 任务栈数据类型:typedef unsigned short OS_STK
  • 任务栈增长方向:#define OS_STK_GROWTH 0/1
  • 任务栈基本功能:???

 

4. 任务控制块

 

(1) TCB描述

 

      主要用来存储任务的当前属性。(问:任务第一次被调度时,该如何运行 ?)

 

(2) TCB主要成员

 

  • 任务栈空间位置:OSTCBStkPtr、OSTCBStkBottom、OSTCBStkSize;
  • 任务通信与同步:OSTCBEventPtr、OSTCBMsg;
  • 任务事件组标志:OSTCBFlagNode、OSTCBFlagsRdy;
  • 任务等待/阻塞:OSTCBDly、OSTCBPendTO;
  • 任务当前状态:OSTCBStat;
  • 任务优先级:OSTCBPrio;

 

(3)TCB全局变量

 

  • OS_EXT OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];
  • OS_EXT OS_TCB OSTCBPrioTbl[OS_LOWEST_PRIO + 1];
  • OS_EXT OS_TCB *OSTCBFreeList;
  • OS_EXT OS_TCB *OSTCBList;
  • OS_EXT OS_TCB *OSTCBHighRdy;
  • OS_EXT OS_TCB *OSTCBCur;

 

5. 任务状态切换

 

 

 

6. 任务管理函数

 

  OS_TASK.C:11个函数

 

  • OSTaskCreate();
  • OSTaskCreateExt();
  • OSTaskDel();
  • OSTaskDelReq();
  • OSTaskChangePrio();
  • OSTaskSuspend();
  • OSTaskResume();
  • OSTaskNameGet();
  • OSTaskNameSet();
  • OSTaskStkChk();
  • OS_TaskStkClr();
  • OSTaskQuery();

 

【专题】uC/OS-II内核架构解析(5)---uC/OS-II通信与同步

 

1. 消息邮箱Mbox

 

      Mbox用于多任务间单一消息的传递,uC/OS-II使用ECB管理Mbox的基本信息,OSEventPtr指向创建Mbox时指定的内存空间。事件的创建由具体的事件管理程序实现。主要包含在C源文件OS_MBOX.C中。

 

  • OS_EVENT *OSMboxCreate(void *msg);
  • void *OSMboxPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);
  • void *OSMboxAccept(OS_EVENT *pevent);
  • INT8U OSMboxPost(OS_EVENT *pevent, void *msg);
  • INT8U OSMboxPostOpt(OS_EVENT *pevent, void *msg, INT8U opt);
  • OS_EVENT *OSMboxDel(OS_EVENT *pevent, INT8U opt, INT8U *err);
  • INT8U OSMboxQuery(OS_EVENT *pevent, OS_MBOX_DATA *);

 

 

 

 

 

 

2. 消息队列msgQ

 

(1) msgQ基本内容

 

      msgQ是uC/OS-II任务间通信的机制,可实现多条消息传递,即可以同时存储多条消息。uC/OS-II使用循环队列管理机制。主要包含在C源文件OS_Q.C中。

 

      msgQ管理:使用指针数组存储所有消息的位置;使用QCB标识指针数组中消息的基本信息;使用ECB管理整个msgQ。QCB在编译时分配空间,即当前系统中可用的msgQ个数是预先设置的,系统运行时不能修改。

 

 

 

(2) msgQ全局变量

 

  • OS_EXT OS_Q *OSQTbl[OS_MAX_QS];   //QCB结构体数组
  • OS_EXT OS_Q *OSQFreeList;                    //空闲QCB头指针
  • typedef struct os_q{                                //消息队列控制块

 

      struct os_q *OSQPtr;        //用于构建空闲QCB链表

 

      void **OSQStart;              //指向msgQ指针数组的起始位置

 

      void **OSQEnd;               //指向msgQ指针数组的结束位置

 

      void **OSQIn;    //指向msgQ指针数组下一个可以插入消息的位置

 

      void **OSQOut; //指向msgQ指针数组下一个可以读出消息的位置

 

      INT16U OSQSize;            //msgQ指针数组的大小

 

      INT16U OSQEntries;              //msgQ指针数组当前可以读取的消息个数

 

              }OS_Q;

 

 

 

(3) msgQ管理函数

 

  • OS_EVENT *OSQCreate(void **start, INT16U size);
  • INT8U OSQPost(OS_EVENT *pevent, void *msg); //发送消息到队尾
  • INT8U OSQPostFront(OS_EVENT *pevent, void *msg);      //msg至队首
  • INT8U OSQPostOpt(OS_EVENT *pevent, void *msg, INT8U opt);
  • void *OSQPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);
  • void *OSQAccept(OS_EVENT *pevent, INT8U *err);
  • OS_EVENT *OSQDel(OS_EVENT *pevent, INT8U opt, INT8U *err);
  • INT8U OSQQuery(OS_EVENT *pevent, OS_Q_DATA*);
  • INT8U OSQFlush(OS_EVENT *pevent);

 

 

 

(4) msgQ几个问题

 

      uC/OS-II中,什么是事件 ?事件是uC/OS-II管理任务间同步与通信的机制。

 

      事件是处理事件的对象感兴趣的,能够感知或捕获到一种事件状态的改变。

 

3. 信号量Sem

 

      Sem主要用来实现任务间同步及标识某类资源的可用个数,即某个特定资源可供多少任务同时使用。主要包含在C源文件OS_SEM.C中。

 

  • OS_EVENT *OSSemCreate(INT16U cnt);
  • void OSSemPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);
  • INT16U OSSemAccept(OS_EVENT *pevent);
  • INT8U OSSemPost(OS_EVENT *pevent);
  • OS_EVENT *OSSemDel(OS_EVENT *pevent, INT8U opt, INT8U *err);
  • INT8U OSSemQuery(OS_EVENT *pevent, OS_SEM_DATA*);
  • void OSSemSet(OS_EVENT *pevent, INT16U cnt, INT8U *err);

 

 

 

4. 互斥锁Mutex

 

(1) Mutex基本原理

 

      Mutex用来实现对资源的排他性访问,可能引起优先级反转。任何任务在占有某个互斥锁事件时,都不能阻塞等待其它任何事件,否则会造成死锁。主要包含在C源文件OS_MUTEX.C中。

 

      优先级反转是指,低优先级任务占有高优先级任务运行所需的资源,而使高优先级不得不等低优先级任务把资源释放才能执行。

 

      uC/OS-II使用ECB管理Mutex,其成员变量OSEventCnt:高8位存储Mutex被使用时提供给任务的prio;低8位在没有任务占有Mutex时为0xFF,否则为占有任务的prio。

 

      优先级反转优先级反转避免 分别如下图所示:

 

 

 

 

 

(2) 提升/恢复优先级

 

    a) 提升Mutex拥有者任务的优先级的相关操作:

 

  • 如果该任务原来处于就绪状态,则从就绪表中将其删除;如果该任务正在等待某个事件,则从该事件的任务等待表中将其删除;
  • 修改拥有Mutex的TCB,将其OSTCBPrio修改为欲提升的优先级;
  • 如果该任务处于就绪状态,则将提升的优先级加载到任务就绪表中;如果该任务未就绪且正在等待某个事件,则将提升的优先级添加到该事件的任务等待表中,并修改TCB中OSTCBEventPtr;
  • 修改TCB中与优先级相关的成员变量。

 

    b) 恢复Mutex拥有任务的优先级的相关操作:

 

  • 从任务就绪表中删除提升过的优先级值,修改当前TCB中与优先级相关的所有成员变量;
  • 再次保留提升的优先级值控制块入口,避免将其分配给其它任务。

 

(3)Mutex管理函数

 

  • #define  OS_MUTEX_KEEP_LOWER_8   0x00FF
  • #define  OS_MUTEX_KEEP_UPPER_8   0xFF00
  • #define  OS_MUTEX_AVAILABLE      0x00FF

 

 

 

  • OS_EVENT *OSMutexCreate(INT8U prio, INT8U *err);
  • void OSMutexPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);
  • INT8U OSMutexAccept(OS_EVENT *pevent, INT8U *err);
  • INT8U OSMutexPost(OS_EVENT *pevent);
  • OS_EVENT *OSMutexDel(OS_EVENT*, INT8U opt, INT8U *err);
  • INT8U OSMutexQuery(OS_EVENT*, OS_MUTEX_DATA*);

 

 

5. 事件组标志Flag

 

(1) Flag基本原理

 

      uC/OS-II提供事件组标志实现多事件管理。Flag只是使用0/1来表示某个事件是否发生过,而不能直接被用来传递数据和消息。可以选择性地设置一个Flag最多可以管理的任务同步状态。主要包含在C源文件OS_FLAG.C中。

 

 

 

(2) Flag数据结构

 

  • #define OS_FLAGS_NBITS 8/16/32     //定义OS_FLAGS的位数
  • FCB结构体:

 

   typedef struct os_flag_grp{

 

          INT8U OSFlagType;                        //事件类型

 

          void *OSFlagWaitList;                      //指向等待的任务链表

 

          OS_FLAGS OSFlagFlags;               //信号列表

 

          INT8U OSFlagName[OS_FLAG_NAME_SIZE];

 

    }OS_FLAG_GRP;

 

  • 事件标志等待链表结点

 

   typedef struct os_flag_node{

 

          void *OSFlagNodeNext;

 

          void *OSFlagNodePrev;

 

          void *OSFlagNodeTCB;

 

          void *OSFlagNodeFlagGrp;          //指向此任务所等待的事件组标志

 

          OS_FLAGS OSFlagNodeFlags;     //等待的事件

 

          INT8U OSFlagNodeWaitType;       //等待方式

 

    }OS_FLAG_NODE;

 

  • OS_EXT OS_FLAG_GRP OSFlagTbl[OS_MAX_FLAGS];
  • OS_EXT OS_FLAG_GRP *OSFlagFreeList;
  • OS_FLAG_GRP *OSFlagCreate(OS_FLAGS flags, INT8U *err);
  • OS_FLAGS OSFlagPend(OS_FLAG_GRP *pgrp, OS_FLAGS flags,

 

(3) Flag管理函数

 

  • INT8U wait_type, INT16U timeout, INT8U *err);
  • static void OS_FlagBlock(OS_FLAG_GRP *pgrp,

 

            OS_FLAG_NODE *pnode,

 

            OS_FLAGS flags,

 

            INT8U wait_type,    //挂起任务,

 

            INT16U timeout);     //直到等待的事件或超时

 

              类似于:OS_EventTaskWait();

 

  • void OS_FlagUnlink(OS_FLAG_NODE *pnode);   //等待超时删除结点

 

      类似于:OS_EventTO();

 

  • OS_FLAGS OSFlagAccept(OS_FLAG_GRP *pgrp,

 

            OS_FLAGS flags,

 

            INT8U wait_type,

 

            INT8U *err);

 

  • OS_FLAGS OSFlagPost(OS_FLAG_GRP *pgrp,

 

            OS_FLAGS flags,

 

            INT8U opt,

 

            INT8U *err);

 

  • static BOOLEAN OS_FLAGTaskRdy(OS_FLAG_NODE *pnode,

 

            OS_FLAGS flags_rdy);

 

  • OS_FLAG_GRP *OSFlagDel(OS_FLAG_GRP*, INT8U opt, INT8U *err);
  • OS_FLAGS OSFlagPendGetFlagsRdy(void);    //获取任务就绪标志
  • OS_FLAGS OSFlagQuery(OS_FLAG_GRP*, INT8U *err);
  • INT8U OSFlagNameGet(OS_FLAG_GRP*, INT8U *pname, INT8U *err);
  • void OSFlagNameSet(OS_FLAG_GRP*, INT8U *pname, INT8U *err);

 

 

 

6. Task就绪状态 判断???

 

    a) OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX != 0

 

        如:函数OSMutexPend()

 

    b) (ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY

 

        如:函数OSTimeTick()

 

    c) ptcb->OSTCBStat == OS_STAT_RDY

 

        如:函数OS_EventTaskRdy()

 

 

【专题】uC/OS-II内核架构解析(6)---uC/OS-II内存管理

 

1. memPart基本原理

 

    uC/OS-II根据需要将内存空间分成多个内存分区,每个内存分区由具有相同大小的内存块(Block)组成。主要包含在C源文件OS_MEM.C中。

 

  • OS_EXT OS_MEM OSMemTbl[OS_MAX_MEM_PART];
  • OS_EXT OS_MEM *OSMemFreeList;
  • memPart控制块结构体:

 

  typedef struct os_men{

 

        void *OSMemAddr;                 //首地址

 

        void *OSMemFreeList;            //分区中空闲空间的起始地址

 

        INT32U OSMemBlkSize;         //分区中块成员空间大小

 

        INT32U OSMemNBlks;           //块结构数量

 

        INT32U OSMemNFree;           //剩余空闲块个数

 

        INT8U OSMemName[];

 

  }OS_MEM;

 

 

 

2. memPart管理函数

 

  • OS_MEM *OSMemCreate(void *addr, INT32U nblks,

 

            INT32U blksize, INT8U *err);

 

 

  • void *OSMemGet(OS_MEM *pmem, INT8U *err); //申请内存分区块
  • INT8U OSMemPut(OS_MEM *pmem, void *pblk); //释放内存分区块
  • INT8U OSMemQuery(OS_MEM *pmem, OS_MEM_DATA*);
  • INT8U OSMemNameGet(OS_MEM *pmem, INT8U *pname, INT8U *err);
  • INT8U OSMemNameSet(OS_MEM *pmem, INT8U *pname, INT8U *err);

 

 

3. memPart几个问题

 

    (1)能不能一次申请1B的堆空间

 

    (2)uC/OS-II在申请栈空间和堆空间时有什么不同

【专题】uC/OS-II内核架构解析(7)---uC/OS-II应用开发

 

1. 应用开发步骤

 

    (1) 包含uC/OS-II的总头文件includes.h;

 

    (2) 定义任务栈的大小和任务栈;

 

    (3) 分配任务优先级;

 

    (4) 实现任务功能;

 

    (5) 调用OSInit()函数初始化uC/OS-II的数据结构;

 

    (6) 创建用户任务,启动uC/OS-II;

 

2. 编写任务函数

 

    用户任务函数必须是无限循环,程序执行流由OS内核改变。在执行完用户代码后最好调用系统服务,主动把CPU使用权让给有需要的任务。

 

    模式一

 

      void YourTask(void *pdata)

 

      {

 

        for(;;)

 

    {  

 

      /*用户代码*/

 

      调用uC/OS II的服务;

 

      OSMboxPend();

 

      OSQPend();

 

      OSSemPend();

 

      OSTimeDlyHMSM();

 

      /*用户代码*/

 

    }

 

    }

 

 

 

    模式二 (自删除任务)

 

    void YourTask(void *pdata)

 

  {   

 

    /*用户代码*/

 

    OSTaskDel(OS_PRIO_SELF);

 

  } //这种任务运行完后就自我删除了。

 

3. 堆栈设计扩展

 

    方法:中断堆栈和任务堆栈分开设计

 

   
原因:uC/OS-II占用RAM主要用于任务TCB、任务堆栈等方面,任务堆栈大是由于硬件设计中没有把中断堆栈和任务堆栈分开,造成了考虑任务堆栈大
小时,不仅要计算任务中局部变量和函数嵌套层数,还要考虑中断的最大嵌套层数,导致大量RAM被浪费。可以把中断堆栈和任务堆栈分开设计,这样计算任务堆
栈时,就不需要把中断处理(包括中断嵌套)中的内存占用计算到任务堆栈中,只需计算每个任务本身需要的内存大小即可。

 

4. 一些借鉴经验

 

    (1) 编写中断程序时,有条件的情况下尽量使用汇编语言,这样可以避免一些编译器自身的操作,减少指针调整次数。

 

    (2) 用C编写ISR时,有时要调用汇编函数,其中一些压栈的PC可能破坏堆栈结构,这就要调整堆栈,保证正确的格式。

 

    (3)由于uC/OS-II中断处理原始设计中可能不调整SP,需要在调用OSIntExit()返回后,判断程序是否处于中断嵌套状态。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值