uC/OS-II学习笔记(1)

原创 2015年07月08日 10:14:01
                                                                               by WC 7.9.2015

本文假设读者对uC/OS-II和多任务知之甚少,但有一定的C语言和单片机基础。为的是为了从0开始学习uC/OS-II。流程图如下图示:
这里写图片描述

1## 范例1 ##
范例1程序结果
范例一演示uC/OC-II的多任务处理能力。共有10个任务在屏幕上面随机的位置显示一个0~9的数字。每个任务只显示同一个数字。其包含了13个任务,在运行窗口的左下角增加了两个内部任务。注意:context switch指CPU寄存器内容的切换,其实就是任务切换。

LI.1 TEXT.C

#include "includes.h"                                                                        【1】                 
#define  TASK_STK_SIZE           512       /* Size of each task's stacks (# of WORDs)  */    【2】    
#define  N_TASKS                 10       /* Number of identical tasks                 */    【3】                  
OS_STK        TaskStk[N_TASKS][TASK_STK_SIZE];        /* Tasks stacks                  */    【4】 
OS_STK        TaskStartStk[TASK_STK_SIZE];                                                   【5】
char          TaskData[N_TASKS];                  /* Parameters to pass to each task   */    【6】     
OS_EVENT     *RandomSem;
说明:在程序的最后加了索引【?】,L1.1【1】表示程序L.1.1标号1地方的代码.

L1.1【1】:所有的头文件都放在了主控头文件includes.h中,这样写结构简单。后面需要时会继续讲解LI.1中的内容,先看main函数。
L1.1【2】:任务堆栈长度。
L1.1【3】:该程序任务的个数。
L1.1【4】:堆栈空间。
L1.1【5】:栈顶。
L1.1【6】:定义一个数组,存放0~9的ASCII字符。

LI.2 TEXT.C,main()

void  main (void)
{
 PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK);    /* Clear the screen         */1】             
 OSInit();                                            /* Initialize uC/OS-II      */2】            
 PC_DOSSaveReturn();                          /* Save environment to return to DOS*/3】  
 PC_VectSet(uCOS, OSCtxSw);                   /* Install uC/OS-II's context switch vector*/4】
 RandomSem = OSSemCreate(1);                /* Random number semaphore        */5】
 OSTaskCreate(TaskStart, (void *)0, &TaskStartStk[TASK_STK_SIZE - 1], 0);                    【6】
 OSStart();                                  /* Start multitasking             */7】
}

L1.2【1】:清空屏幕,PC_DispClrScr(INT8U colur),也可以通过定义DISP_FGND_X来指定任意一种颜色.
L1.2【2】:在使用uC/OS-II提供的功能之前,必须调用OSInint()函数。该函数建立了两个任务,空闲任务——在其他任 务未就绪时运行;统计任务——计算CPU的利用率。
L1.2【3】:PC_DOSSaveReturn()允许程序开始多任务前,保存重要寄存器的值,以保证uC/OS-II能够正常返回没有运行之前的DOS环境。必须在设定uC/OS-II的环境切换中断向量之前调用。
L1.2【4】:PC_VectSet( INT8U vect,void *(pisr)(void) )用于设定中断向量表的内容,vect:中断向量值,介于0~255的数值。pisr:中断/异常处理程序地址。eg:PC_VectSet(64,InterruptHandler)
L1.2【5】:调用OSSemCreate(INT16U cnt)函数建立一个信号量,用于保护产生的随机数。cnt为信号量的初始值,当cnt=0,该信号量表示等待一个事件或者多个事件的发生。当cnt=1时,两个任务Task1和Task2对一个公共资源进 行互斥访问。该程序中,信号量初值设置为1.
L1.2【6】:建立了一个叫做TaskStart的任务。这个任务有4个参数:第1个参数是指向该任务代码的指针,在这里指的是 TaskStart(),第2个参数是一个指向任务初始化数据的指针,这里不需要任何初始化数据,所以传递一个空(NULL)指针,第3个参数是任务的堆栈栈顶TOS(Top-of-Stack),在这个例子中,堆栈空间被定义为TaskSt- artStk。第4个参数为优先级,0为最高优先级。
L1.2【7】:调用OSStart()函数,将控制权给uC/OS-II内核,开始执行多任务。在启动OSStart()函数之前,至少要先建立一个任务。OSStart()函数将判断哪一个任务的优先级最高,最先运行优先级最高的任务。

LI.3 TEXT.C,TaskStart()

void  TaskStart (void *pdata)
{
#if OS_CRITICAL_METHOD == 3         /* Allocate storage for CPU status register */           【0】
    OS_CPU_SR  cpu_sr;
#endif
    char       s[100];
    INT16S     key;

    pdata = pdata;                         /* Prevent compiler warning             */1】

    TaskStartDispInit();                   /* Initialize the display               */2】

    OS_ENTER_CRITICAL();                                                                     【3】
    PC_VectSet(0x08, OSTickISR);           /* Install uC/OS-II's clock tick ISR    */4】
    PC_SetTickRate(OS_TICKS_PER_SEC);      /* Reprogram tick rate                  */5】
    OS_EXIT_CRITICAL();                                                                      【6】
    OSStatInit();                          /* Initialize uC/OS-II's statistics     */7】

    TaskStartCreateTasks();               /* Create all the application tasks      */8for (;;)                                                                                 【9】
     {   
        TaskStartDisp();                   /* Update the display                   */10if (PC_GetKey(&key) == TRUE)       /* See if key has been pressed          */11】
        {                     
            if (key == 0x1B)               /* Yes, see if it's the ESCAPE key      */12】
            {                             
                PC_DOSReturn();             /* Return to DOS                       */13】
            } 
        }

        OSCtxSwCtr = 0;                     /* Clear context switch counter        */14】
        OSTimeDlyHMSM(0, 0, 1, 0);          /* Wait one second                     */15】
    }  
}

L1.3【1】:假装使用了pdata,以避免某些编译器的警告,该程序没有实际意思。并且pdata是当任务建立传递过来的一个指针,这个例子指向空指针。
L1.3【2】:初始化屏幕显示。
L1.3【3】:关中断。uC/OS-II需要先关中断,在放置代码段,在重新开中断。在这里解释一个名词:临界段,就是不可被中断的代码段,例如常见的入栈出栈等操作就不能被中断。uC/OS-II是一个实时内核,需要关闭中断进入和开中断退出临界段。
L1.3【4】:设置中断向量
L1.3【5】:PC_SetTickRate(INT16U freq)将PC的时钟节拍从标准值18.20648改变为freq,OS_TICKS_PER_SEC为200
L1.3【6】:开中断,必须和关中断成对使用。
L1.3【7】:计算处理器在运行所用任务时实际CPU使用率。
L1.3【8】:来创建更多的任务,在这里即N_TASKS个任务,先分析TaskStartCreateTasks()的代码,如下所示。

LI.4 TEST.C,TaskStartCreateTasks()

/*
                                            CREATE TASKS
*/

static  void  TaskStartCreateTasks (void)
{
    INT8U  i;
    for (i = 0; i < N_TASKS; i++)      /* Create N_TASKS identical tasks           */1】
     {                       
        TaskData[i] = '0' + i;          /* Each task will display its own letter    */2】
        OSTaskCreate(Task, (void *)&TaskData[i], &TaskStk[i][TASK_STK_SIZE - 1], i + 1);     【3】
    }
}

L1.4【1】:循环建立了N_TASKS(即10)个相同的任务Task()。
L1.4【2】:初始化一个数组,包含0~9的ASCII字符 [见L1.1【5】]。
L1.4【3】:建立了一个叫做Task的任务。这个任务有4个参数:第1个参数是指向该任务代码的指针,在这里指的是 Task(),第2个参数是一个指向任务初始化数据的指针,第3个参数是任务的堆栈栈顶TOS(Top-of-Stack),在这个例子中栈顶为TaskStk[N_TASKS][TASK_STK_SIZE] [见L1.1【5】]。第4个参数为优先级,因为优先级0已经被任务TaskStart()占用了,新建立的任务将使用1~10的优先级。
注:在每个任务建立的时候,uC/OS-II判断新建立的任务是否比建立它们的任务优先级高。如果高,则这个新建立的任务将立即开始运行。这这个范例中,建立新任务的TaskStart()任务具有最高的优先级0,所以这些新建立的任务暂时不能运行。

继续分析L1.3
L1.3【9】:每一个任务都是无限的循环。
L1.3【10】:在DOS窗口的底部,显示建立任务的个数、当前CPU利用率、任务切换次数等相关信息。
L1.3【11】:检测是否有按键按下。
L1.3【13】:判断是否按下Esc键,如果按下,则返回DOS环境。
L1.3【14】:如果没有按下,记录任务切换次数的全局变量OSCtxSwCtr被清零,以便更新为下一个1S内发生的任务切换次数。
L1.3【15】:通过调用OSTimeDlyHMSM(),TaskStrat()任务将自身挂起1S。HMSM代表时(hour),分(miunte),秒(second)及毫秒(millisecond),这是传递给OSTimeDlyHMSM()的参数。当TaskStrat()任务将自身挂起1S,uC/OC-II开始调度,找到下一个最高优先级的就绪任务,在本例中就是优先级为1的Task()任务。注意:若没有OSTimeDlyHMSM()或其他类似的函数,TaskStrat()将是一个真正的无限循环,其他任务没有运行的机会。

LI.5 TEST.C,Task()

void  Task (void *pdata)
{
    INT8U  x;
    INT8U  y;
    INT8U  err;

    for (;;)                                                                                 【1】
    {
        OSSemPend(RandomSem, 0, &err);   /* Acquire semaphore to perform random numbers   */ 【2】
        x = random(80);                  /* Find X position where task number will appear */ 【3】
        y = random(16);                  /* Find Y position where task number will appear */ 【4】
        OSSemPost(RandomSem);            /* Release semaphore                             */ 【5】
                                         /* Display the task number on the screen         */ 
        PC_DispChar(x, y + 5, *(char *)pdata, DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);       【6】
        OSTimeDly(1);                    /* Delay 1 clock tick                            */ 【7】
    }
}

L1.5【1】:每一个任务是一个无限循环。
L1.5【2】:Task()任务首先检查RandomSem信号量,这个信号量用来防止多个任务同时访问产生随机数的函数。OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err),等待一个信号量函数(信号量指针、允许等待的时钟节拍、代码错误指针)。pevent:指向事件控制块结合目标信号量的指针;timeout:定时超时选项(以时钟节拍为单位),如果这个值为0,代表任务将无限期地等待信号量。在此程序中,信号量在建立时被初始化为1,并且没有其他的任务使用该信号量,所有Task()任务立刻得到该信号量并继续运行。如果该信号量被其他任务占用,uC/OS-II将挂起这个任务并开始调度,找到下一个就绪任务中优先级最高的;err:指向错误代码的消息指针。
L1.5【3】:产生一个0~79(含79)的数值。这个值用来确定在屏幕上面显示字符的X方向的位置。
L1.5【4】:产生一个0~75(含75)的数值。这个值用来确定在屏幕上面显示字符的Y方向的位置。
L1.5【5】:释放信号量。
L1.5【6】:PC_DispChar(INT8U x,INT8U y,INT8U c,INT8U color)用来表示在(x,y)坐标处显示色彩组合为color的字符c,为了避免影响底部的其他信息,y加了5行的偏移量。
L1.5【7】:通过调用OSTimeDly(),通知uC/OS-II该任务本次运行已经结束,可以让下一个最高优先级的就绪任务运行。参数1表示延时一个时钟节拍,在200Hz情况下就是5ms。

注:本人这个系列的学习笔记参考于《嵌入式实时操作系统uC/OS-II》,邵贝贝译。

版权声明:本文为博主原创文章,未经博主允许不得转载。

uC/OS-II内核架构解析---uC/OS-II通信与同步

1. 消息邮箱Mbox       Mbox用于多任务间单一消息的传递,uC/OS-II使用ECB管理Mbox的基本信息,OSEventPtr指向创建Mbox时指定的内存空间。事件的创建由具体的...
  • softn
  • softn
  • 2016年07月12日 22:09
  • 1292

uC/OS-II 一些函数简介

以前搞硬件的经验,最近突然翻出来了。分享给大家;主要讲解uC/OS-II常用函数;虽说现在转行软件了,但是感觉之前搞硬件的经验还真是很有用对于理解底层等很有帮助。比如这里对于操作系统还是有点用的;好了...
  • peace1213
  • peace1213
  • 2015年07月25日 15:10
  • 2143

uC/OS-II学习笔记--任务

uC/OS-II中的任务1 任务的基本概念uC/OS-II操作系统内核的主要任务就是对任务进行管理和调度。 在设计一个较为复杂的应用程序时,通常把一个大型任务分解成多个小任务,这样可以将问题分而治之...
  • hxszk
  • hxszk
  • 2017年02月23日 15:23
  • 194

uc/os-ii操作系统笔记

操作系统是应用程序与硬件的之间的接口,只有硬件构成的电脑成为裸机,操作系统的功能主要是对计算机的资源进行管理。 主要的功能:   1.处理器的管理,主要两项工作:一是对中断的管理,二是对处理器的工...
  • hello_world6
  • hello_world6
  • 2016年09月09日 21:30
  • 840

uC/OS-II 应用程序基本结构

 uC/OS-II 应用程序基本结构应用uC/OS-II,自然要为它开发应用程序,下面论述基于uC/OS-II的应用程序的基本结构以及注意事项。每一个uC/OS-II应用至少要有一个任务。而每一个任务...
  • silenceee
  • silenceee
  • 2006年11月11日 11:32
  • 1679

【UC/OS-II】一、STM32平台移植教程

因为一开始就讲STM32的UC/OS-ii的移植对于不了解系统的小白来说可能看不懂,但我的开发平台是基于STM32的,所以又不得不先说明移植教程,所以在这里建议不懂的可以去网上先下个可运行的STM32...
  • qq_22520215
  • qq_22520215
  • 2017年06月13日 11:20
  • 366

UC/OS-II学后总结

/************************************************************************时间:2009.1.3    开发平台:SMart A...
  • yeqishi
  • yeqishi
  • 2009年10月21日 00:09
  • 6420

uc/os-ii事件控制块

任务间的同步依赖于任务间的通信。在μC/OS-II中,使用信号量、互斥信号量、消息邮箱、消息队列、事件标志组这些被称作事件的中间环节来实现任务之间的通信的。为了把描述事件的数据结构统一起来,μC/OS...
  • fillthesky
  • fillthesky
  • 2015年07月02日 16:21
  • 335

UC/OS-II功能介绍、要点记录

UC/OS-II功能介绍、要点记录 通过不断地学习和实验UC/OS-II,终于在五一前在ARM平台上实现了多任务的创建、调度运行、挂起,任务间信号量、互斥型信号量、邮箱、消息队列和事件标识组方式下的...
  • shuju345
  • shuju345
  • 2015年08月17日 11:59
  • 724

关于uc/os-ii在c51上的移植总结

ucos 在 51单片机上的移植
  • u013562393
  • u013562393
  • 2016年05月23日 12:02
  • 455
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:uC/OS-II学习笔记(1)
举报原因:
原因补充:

(最多只允许输入30个字)