uc/os-ii学习

经典教程:嵌入式实时操作系统uc/os-ii Jean J.Labrosse著 邵贝贝等译


1. 从主函数开始

int main (void)
{
    init();//一些硬件的初始化
    
    InstallInterruptHandler((unsigned int) OSTickISR, (unsigned int) 0x18);//Timer 1 Interrupt Level 8 指定定时器中断中断号
    InstallInterruptHandler((unsigned int) OSCtxSw, (unsigned int) 0x80);//Context Switch 指定上下文切换陷阱
    InitialiseSystemTimer(ACTIVE_TICK_TIMER);

    OSInit(); /* Initialize uC/OS-II*/

    OSTaskCreate(FirstTestTask, (void *)0, &FirstTestTaskStk[TEST_STK_SIZE - 1], APP_TASK_ONE_PRIO);//创造任务1,给出任务1的地址、堆栈大小和优先级
    OSTaskCreate(SecondTestTask, (void *)0, &SecondTestTaskStk[TEST_STK_SIZE - 1], APP_TASK_TWO_PRIO);
    OSStart();  /* Start multitasking   */
    return 0;
}

其中重要的有三个函数OSInit() OSTskCreate() OSStart():

1.1.OSInit()

void  OSInit (void)
{
    OSInitHookBegin();                                           /* Call port specific initialization code   */
    OS_InitMisc();                                               /* Initialize miscellaneous variables       */
    OS_InitRdyList();                                            /* Initialize the Ready List                */
    OS_InitTCBList();                                            /* Initialize the free list of OS_TCBs      */
    OS_InitEventList();                                          /* Initialize the free list of OS_EVENTs    */
#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
    OS_FlagInit();                                               /* Initialize the event flag structures     */
#endif
#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u)
    OS_MemInit();                                                /* Initialize the memory manager            */
#endif
#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u)
    OS_QInit();                                                  /* Initialize the message queue structures  */
#endif
    OS_InitTaskIdle();                                           /* Create the Idle Task                     */
#if OS_TASK_STAT_EN > 0u
    OS_InitTaskStat();                                           /* Create the Statistic Task                */
#endif
#if OS_TMR_EN > 0u
    OSTmr_Init();                                                /* Initialize the Timer Manager             */
#endif
    OSInitHookEnd();                                             /* Call port specific init. code            */
#if OS_DEBUG_EN > 0u
    OSDebugInit();
#endif
}

其中hook为钩子函数,是作者留给开发人员的发挥空间,可以在这里完成一些开发人员想做的事情,比如初始化自己的硬件。条件编译“开关”都在ucos_ii.h中,可以在这里对内核进行“剪裁”,决定保留什么功能,去除什么功能。

在OSInit中最重要的是三个部分:就绪表、任务块、事件块。

1.1.1就绪表

每个任务有自己的优先级0~63。处于就绪态的任务会在就绪表的相应位置1。

如果一个任务的优先级为8=00001000,即OSRdyGrp=YYY=001,OSRdyTbl[001]=XXX=000

每个任务的优先级都会分成两部分分别记录在OSRdyGrp和OSRdyTbl中。


当就绪表中的值是一定的,则有且仅有唯一一个最小值(优先级最高的任务),如当第7/22/30位置一,则最小值为7。

在就绪表中找到优先级最高的任务:

y = OSUnMapTbl[OSRdyGrp];
x = OSUnMapTbl[OSRdyTbl[y]];
prio = (y<<3) + x;

OSUnMapTbl为:

若某时刻OSRdyGrp为0x68,OSRdyTbl为0xE4。则

3 = OSUnMapTbl[0x68];
2 = OSUnMapTbl[0xE4];
26 = (3<<3) + 2;//最高优先级任务为26

1.1.2任务控制块

以下为任务控制块精简版本:

typedef struct os_tcb {
    OS_STK          *OSTCBStkPtr;           /* Pointer to current top of stack                         */
    struct os_tcb   *OSTCBNext;             /* Pointer to next     TCB in the TCB list                 */
    struct os_tcb   *OSTCBPrev;             /* Pointer to previous TCB in the TCB list                 */

    INT32U           OSTCBDly;              /* Nbr ticks to delay task or, timeout waiting for event   */
    INT8U            OSTCBStat;             /* Task      status                                        */
    INT8U            OSTCBStatPend;         /* Task PEND status                                        */
    INT8U            OSTCBPrio;             /* Task priority (0 == highest)                            */

    INT8U            OSTCBX;                /* Bit position in group  corresponding to task priority   */
    INT8U            OSTCBY;                /* Index into ready table corresponding to task priority   */
    OS_PRIO          OSTCBBitX;             /* Bit mask to access bit position in ready table          */
    OS_PRIO          OSTCBBitY;             /* Bit mask to access bit position in ready group          */

} OS_TCB;

一旦任务建立,一个任务控制块就被赋值。当任务的CPU使用权被剥夺,uc/os-ii用它来保存该任务的状态。OS_TCB全部驻留在RAM中。

在ucos初始化时,所有任务控制块OS_TCB都被连接成单向空任务链表,然后OSTCBFreeList的值调整为指向链表下一个空的任务控制块。一旦任务被删除,任务控制块就还给空任务链表。


任务链表初始化:

static  void  OS_InitTCBList (void)
{
    INT8U    ix;
    INT8U    ix_next;
    OS_TCB  *ptcb1;
    OS_TCB  *ptcb2;

    OS_MemClr((INT8U *)&OSTCBTbl[0],     sizeof(OSTCBTbl));      /* Clear all the TCBs                 */
    OS_MemClr((INT8U *)&OSTCBPrioTbl[0], sizeof(OSTCBPrioTbl));  /* Clear the priority table           */
    for (ix = 0u; ix < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1u); ix++) {    /* Init. list of free TCBs     */
        ix_next =  ix + 1u;
        ptcb1   = &OSTCBTbl[ix];
        ptcb2   = &OSTCBTbl[ix_next];
        ptcb1->OSTCBNext = ptcb2;
#if OS_TASK_NAME_EN > 0u
        ptcb1->OSTCBTaskName = (INT8U *)(void *)"?";             /* Unknown name                       */
#endif
    }
    ptcb1                   = &OSTCBTbl[ix];
    ptcb1->OSTCBNext        = (OS_TCB *)0;                       /* Last OS_TCB                        */
#if OS_TASK_NAME_EN > 0u
    ptcb1->OSTCBTaskName    = (INT8U *)(void *)"?";              /* Unknown name                       */
#endif
    OSTCBList               = (OS_TCB *)0;                       /* TCB lists initializations          */
    OSTCBFreeList           = &OSTCBTbl[0];
}

1.1.3事件控制块

事件控制块ECB是用于实现以下功能函数的基本数据结构:信号量管理、互斥型信号量管理、消息邮箱管理以及消息队列管理。

typedef struct os_event {
    INT8U    OSEventType;                    /* Type of event control block (see OS_EVENT_TYPE_xxxx)    事件类型*/
    void    *OSEventPtr;                     /* Pointer to message or queue structure                   等待任务所在的组*/
    INT16U   OSEventCnt;                     /* Semaphore Count (not used if other EVENT type)          计数器(当事件是信号量的时候)*/
    OS_PRIO  OSEventGrp;                     /* Group corresponding to tasks waiting for event to occur 指向消息或者消息队列的指针*/
    OS_PRIO  OSEventTbl[OS_EVENT_TBL_SIZE];  /* List of tasks waiting for event to occur                等待任务列表*/

#if OS_EVENT_NAME_EN > 0u
    INT8U   *OSEventName;
#endif
} OS_EVENT;
每个信号量、互斥型信号量、消息邮箱以及消息队列都应分配到一个事件控制块ECB。

1.2.OSTaskCreate()

通过将任务的地址和其他参数如优先级传递到此函数中来建立任务。

1.3.OSStart()

void OSStart(void){

if (OSRunning == OS_FALSE) { OS_SchedNew(); /* Find highest priority's task priority number */ OSPrioCur = OSPrioHighRdy; OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run */ OSTCBCur = OSTCBHighRdy; OSRunning = 1; OSStartHighRdy(); /* Execute target specific code to start task */ } }

在这里完成最高优先级查找和开始执行最高优先级任务。


两个用户任务的定义:

void FirstTestTask (void *pdata)
{
	pdata = pdata;
	InitiateTimer(ACTIVE_TICK_TIMER);
	while(1)
	{
		get_status_for_ucos();//用户任务
		
		OSTimeDly(10);//任务延时10个时钟节拍
	}
}
void SecondTestTask (void *pdata)
{
	pdata = pdata;
	InitiateTimer(ACTIVE_TICK_TIMER);
	while(1)
	{
		get_vector_for_ucos();
		OSTimeDly(15);//任务延时15个时钟节拍
	}
}


2. 系统的基本运作

在任务开始运行之后,每遇到任务的“OSTimeDly”,任务就进入等待状态。在这个函数中会调用OS_Sched()函数进行任务调度,重新寻找就绪列表中的最高优先级任务,并调用OS_TASK_SW()函数,出发陷阱,开始任务切换。

3.系统移植

与处理器相关的代码只有OS_CPU.H,OS_CPU_A.ASM,OS_CPU_C.C。

OS_CPU.H中包含临界区的实现方式。

OS_CPU_A.ASM中实现OSStartHighRdy()使就绪态任务中优先级最高的任务开始运行,OSCtxSw()任务切换,OSIntCtxSw()和OSTickISR()提供节拍定时中断。

OS_CPU_C.C中实现任务堆栈初始化以及所有钩子函数(可以不写)。

猜你喜欢

转载自blog.csdn.net/u012824853/article/details/80824642