μC/ OS III Version: v3.03.01
μC/ CPU Version: v1.29.01
μC/ LIB Version: v1.37.00
FOR: NXP LPC1768 CPU
首先贴出app.c中的main()函数的代码:
int main (void)
{
OS_ERR err;
CPU_Init();
BSP_Init(); /* Initialize BSP functions */
Mem_Init();
OSInit(&err); /* Initialize "uC/OS-III, The Real-Time Kernel" */
OSTaskCreate((OS_TCB *)&App_TaskStartTCB, /* Create the start task */
(CPU_CHAR *)"App Task Start",
(OS_TASK_PTR ) App_TaskStart,
(void *) 0,
(OS_PRIO ) APP_CFG_TASK_START_PRIO,
(CPU_STK *)&App_TaskStartStk[0],
(CPU_STK )(APP_CFG_TASK_START_STK_SIZE / 10u),
(CPU_STK_SIZE) APP_CFG_TASK_START_STK_SIZE,
(OS_MSG_QTY ) 0,
(OS_TICK ) 0,
(void *) 0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
#if (OS_TASK_NAME_EN > 0u)
OSTaskNameSet(APP_CFG_TASK_START_PRIO, "Start", &err);
#endif
OSStart(&err); /* Start multitasking (i.e. give control to uC/OS-III). */
while(DEF_ON){ /* Should Never Get Here */
};
}
完成Startup文件的工作后,代码将从main()函数开始,下面将逐一对其中的函数进行讲解。
1. CPU_Init()
共完成3个工作:
CPU_TS_Init(); /*时间戳初始化*/
CPU_IntDisMeasInit(); /*测试关闭时间功能初始化*/
CPU_NameInit(); /*CPU名字初始化(清零)*/
2. BSP_Init()
主要做的的硬件相关的板级驱动初始化,例如时钟配置,引脚配置,中断配置等,每块控制板的结构不同,初始化过程也不尽相同,所以做系统移植时改动最多的地方就在这里。
3. Mem_Init()
Mem_Init()是库文件lib_mem.c中的一个初始化函数,如果程序中使用uC/LIB的话,需要调用初始化函数。其主要做的工作是Initialize heap memory pool和Initialize memory pool table。
4. OSInit(&err)
初始化OS内核使用到的函数和全局变量,下面给出了未受宏定义限制的部分初始化内容(相对来说比较重要):
首先初始化钩子函数(这个函数我还没使用过):
OSInitHook();
然后初始化各个全局变量:
OSIntNestingCtr = (OS_NESTING_CTR)0; /*清除中断嵌套计数器*/
OSRunning = OS_STATE_OS_STOPPED; /*声明多任务未开始*/
OSSchedLockNestingCtr = (OS_NESTING_CTR)0; /*清除调度锁计数器*/
OSTCBCurPtr = (OS_TCB *)0; /*TCB相关的指针初始化*/
OSTCBHighRdyPtr = (OS_TCB *)0;
OSPrioCur = (OS_PRIO)0; /*优先级相关的指针初始化*/
OSPrioHighRdy = (OS_PRIO)0;
OSPrioSaved = (OS_PRIO)0;
然后是各个函数的初始化:
OS_PrioInit(); /*优先级bitmap表初始化*/
OS_RdyListInit(); /*就绪列表初始化*/
OS_TaskInit(p_err); /*任务初始化*/
OS_IdleTaskInit(p_err); /*空闲任务初始化*/
OS_TickTaskInit(p_err); /*Tick任务初始化*/
OSCfg_Init(); /*系统配置初始化*/
- OS_PrioInit():初始化了优先级表,代码如下:
for (i = 0u; i < OS_PRIO_TBL_SIZE; i++) { OSPrioTbl[i] = (CPU_DATA)0; }
优先级表是一个数组,在32位的环境下,每一个bit对应一个优先级,所以一个数组成员即可表示32个优先级,此时OS_PRIO_TBL_SIZE定义为1;如果需要支持64个优先级,只需要两个数组成员,OS_PRIO_TBL_SIZE定义为2即可。
- OS_RdyListInit():初始化OSRdyList[]数组,代码如下:
for (i = 0u; i < OS_CFG_PRIO_MAX; i++) { p_rdy_list = &OSRdyList[i]; p_rdy_list->NbrEntries = (OS_OBJ_QTY)0; p_rdy_list->HeadPtr = (OS_TCB *)0; p_rdy_list->TailPtr = (OS_TCB *)0; }
数组的大小由宏OS_CFG_PRIO_MAX决定,从OSRdyList[0]到OSRdyList[OS_CFG_PRIO_MAX-1],每一个成员数记录不同优先级的任务,数组的成员为OS_RDY_LIST类型的结构体,每个结构体包含有NbrEntries(个数),HeadPtr(头指针),TailPtr(尾指针)。当有多个同一优先级任务时,结构体中NbrEntries记录任务数量,每个相同优先级的任务以双向链表的方式连接。
-
OS_TaskInit():
OSTaskQty = (OS_OBJ_QTY )0; /*任务数量初始化*/ OSTaskCtxSwCtr = (OS_CTX_SW_CTR)0; /*上下文转换计数器初始化*/
对任务相关的全局变量进行初始化。
-
OS_IdleTaskInit(p_err):
OSIdleTaskCtr = (OS_IDLE_CTR)0; OSTaskCreate((OS_TCB *)&OSIdleTaskTCB, (CPU_CHAR *)((void *)"uC/OS-III Idle Task"), (OS_TASK_PTR)OS_IdleTask, (void *)0, (OS_PRIO )(OS_CFG_PRIO_MAX - 1u), (CPU_STK *)OSCfg_IdleTaskStkBasePtr, (CPU_STK_SIZE)OSCfg_IdleTaskStkLimit, (CPU_STK_SIZE)OSCfg_IdleTaskStkSize, (OS_MSG_QTY )0u, (OS_TICK )0u, (void *)0, (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS), (OS_ERR *)p_err);
对空闲任务计数器初始化,并创建空闲任务,其任务优先级为最低。所有进入延时(DLY)状态的任务都将转向执行空闲任务,在空闲任务执行时可进行相应的低功耗处理。
-
OS_TickTaskInit(p_err):
OSTickCtr = (OS_TICK)0u; /*Tick计数器初始化*/ OSTickTaskTimeMax = (CPU_TS)0u; /*最大Tick任务时间初始化*/ OS_TickListInit(); /*初始化Tick列表(时基列表)*/ OSTaskCreate((OS_TCB *)&OSTickTaskTCB, (CPU_CHAR *)((void *)"uC/OS-III Tick Task"), (OS_TASK_PTR )OS_TickTask, (void *)0, (OS_PRIO )OSCfg_TickTaskPrio, (CPU_STK *)OSCfg_TickTaskStkBasePtr, (CPU_STK_SIZE)OSCfg_TickTaskStkLimit, (CPU_STK_SIZE)OSCfg_TickTaskStkSize, (OS_MSG_QTY )0u, (OS_TICK )0u, (void *)0, (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS), (OS_ERR *)p_err);
Tick任务初始化时定义初始化了一个Tick列表(时基列表)
for (i = 0u; i < OSCfg_TickWheelSize; i++) { p_spoke = (OS_TICK_SPOKE *)&OSCfg_TickWheel[i]; p_spoke->FirstPtr = (OS_TCB *)0; p_spoke->NbrEntries = (OS_OBJ_QTY )0u; p_spoke->NbrEntriesMax = (OS_OBJ_QTY )0u; }
处于延时任务和等待时间有超时限制的任务都会从就绪列表中移除,然后插入时基列表中;后面创建的"uC/OS-III Tick Task"任务的优先级为2,Tick任务在每次的systick系统时钟中断都会进入到OS_TickTsak函数,记录tick的全局变量都会更新,插入在时基列表中的任务TCB记录的tick同样会更新,如果任务的延时时间结束或者超时到期,就会从时基列表移除,插入就绪列表。
-
OSCfg_Init():这个函数没有什么功能,只是用于确保未优化应用程序中未使用的调试变量,不做过多赘述。
5. OSTaskCreate(&App_TaskStartTCB,...)
创建在启动OS开始时需要执行的第一个任务"App Task Start",其任务优先级与空闲任务相同为2。
在后面执行任务时所做的工作首先对systick系统时钟进行初始化,并创建用户需要执行的任务,代码如下:
static void App_TaskStart (void *p_arg)
{
OS_ERR os_err;
(void)p_arg; /* See Note #1 */
BSP_Start(); /* Start BSP and tick initialization */
#if (OS_TASK_STAT_EN > 0)
OSStatInit(); /* Determine CPU capacity */
#endif
App_ObjCreate(); /* Create Applicaiton kernel objects */
App_TaskCreate(); /* Create Application tasks */
while (DEF_TRUE) { /* Task body, always written as an infinite loop. */
LED_TOGGLE();
OSTimeDly(1000, OS_OPT_TIME_DLY, &os_err);
}
}
创建用户任务完成后可将此任务删除。
6. OSStart(&err)
OSStart()函数中,主要做了以下工作:
if (OSRunning == OS_STATE_OS_STOPPED) {
OSPrioHighRdy = OS_PrioGetHighest(); /*找到已经就绪的最高的优先级*/
OSPrioCur = OSPrioHighRdy; /*当前优先级等于最高的优先级*/
OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
OSTCBCurPtr = OSTCBHighRdyPtr; /*将当前TCB指针指向最高优先级的任务TCB*/
OSRunning = OS_STATE_OS_RUNNING;
OSStartHighRdy(); /*执行目标特定代码以启动任务*/
*p_err = OS_ERR_FATAL_RETURN; /*OSStart()不会返回*/
}
函数首先寻找到当前就绪任务的最高优先级,然后将当前的TCB指针指向任务,准备执行。
至此,OS准备工作结束,在执行OSStartHighRdy()后,OS将获得CPU的控制权,启动实时系统和多任务处理。
QQ:956599264
欢迎交流