关闭

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

标签: uC-OS-II入门
381人阅读 评论(0) 收藏 举报
分类:
                                                                               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》,邵贝贝译。

0
0

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:27366次
    • 积分:551
    • 等级:
    • 排名:千里之外
    • 原创:15篇
    • 转载:0篇
    • 译文:0篇
    • 评论:4条
    文章分类
    最新评论