原创 菜鸟学uC/OS_II(7)

2008-9-12 10:07 4341 6 6 分类: MCU/ 嵌入式

菜鸟学uC/OS_II(7)<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


By <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />Norman


2008-7-14


 


实验


 


书看了一遍了,借助例程的文件,在PC上的移植也基本上弄懂了,不过感觉编写上比较生疏,决定花一些时间来熟悉一下uCOS_II的编程,并且做一做任务管理、通信等等方面的功能试验,以期对uCOS_II更加熟悉,对其内核调度等功能有更深的感性认识。


 


实验一:


 


实验内容:创建一个任务,改任务以1秒为间隔,在DOS窗口下显示给定字符


源程序及分析:


这个程序实现比较简单,不用详细分析了,只是利用程序来熟悉一下如何开始一个任务。


 


#include "includes.h"


#define TASK_STK_SIZE 512


 


OS_STK M_TaskStk[TASK_STK_SIZE];       /*首先定义并初始化数据结构相关*/


INT16S key;        /*按键缓冲区*/


INT16U x = 30,y = 6;   /*显示位置*/


void M_Task(void* data);      /*声明任务入口函数*/


 


void main()


{


char* s_M = "M";       /*赋值全局变量*/


OSInit();    /*@1@初始化内核*/


PC_DOSSaveReturn();


PC_VectSet(uCOS,OSCtxSw);       /*@2@*/


OSTaskCreate(M_Task,s_M,&M_TaskStk[TASK_STK_SIZE - 1],0);                 /*@3@这里我当时没有给出“-1,出现了乱码,要十分注意堆栈问题*/


OSStart();  /*@5@开始多任务之前必须创建至少一个任务*/


}


 


void M_Task(void* pdata)


{


#if OSCRITICAL_METHOD == 3


           OS_CPU_SR cpu_sr;


#endif



pdata = pdata;     /*这句话虽然可以不要,因为这里用到了pdata,但是作为习惯添上比较好吧,反正影响不大,但是多耗一个指令时间*/



/*初始化屏幕,一般将其写在另一个函数中比较好,这就是编程风格,尽量让主函数简洁,一目了然;只是这里程序比较简单,所以我没有另外写*/


PC_DispStr( 0,  0, "                         uC/OS-II, The Real-Time Kernel                         ", DISP_FGND_WHITE + DISP_BGND_BLUE + DISP_BLINK);


PC_DispStr( 0,  1, "                                     Norman                                     ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  2, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  3, "                                  EXPERIMENT #1                                 ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  4, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  5, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  6, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  7, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  8, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  9, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 10, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 11, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 12, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 13, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 14, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 15, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 16, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 17, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 18, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 19, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 20, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 21, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 22, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 23, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 24, "                            <-PRESS 'ESC' TO QUIT->                             ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY + DISP_BLINK);



OS_ENTER_CRITICAL();  /*@4@设置时钟中断和频率*/


PC_VectSet(0x08,OSTickISR);


PC_SetTickRate(OS_TICKS_PER_SEC);


OS_EXIT_CRITICAL();


OSStatInit();       /*一定要在这里初始化统计函数——第一个任务中*/


 


for(;;)


{


           if(x > 50)


           {


                    x = 30;


                    y += 2;


           }


           PC_DispChar(x,y,*(char*)pdata,DISP_BGND_BLACK + DISP_FGND_WHITE);


           x += 1;


           if(PC_GetKey(&key) == TRUE)


           {


                    if(key == 0x1B)


                    {


                             PC_DOSReturn();


                    }


           }


           OSTimeDlyHMSM(0,0,0,200);


}


}


 


实验二:


 


实验内容:使用一个布尔变量来模拟信号量。


源程序及分析:


此程序使用了一个布尔量的值来作为任务间的通信标志:只有当flag = 1的时候,任务才能够对共享的资源进行访问,任务得以继续运行。


本程序设计了两个任务:任务1优先级为5,运行时间需要400ticks;任务2优先级为6,需要200ticks。他们共同访问一个资源signal


我发现,优先级如果反过来,更能够体现这个保护机制。


#include "includes.h"


#define TASK_STK_SIZE 1024


OS_STK TaskStartStk[TASK_STK_SIZE];


OS_STK Task_1_Stk[TASK_STK_SIZE];


OS_STK Task_2_Stk[TASK_STK_SIZE];


 


char* signal = "Original Data";


INT16S key;


BOOLEAN flag;


INT16U y1 = 6,y2 = 6;


 


void taskStart(void* pdata);


void task_1(void* pdata);


void task_2(void* pdata);


 


static  void  TaskStartDispInit(void);


 


void main(void)


{


flag = 1;


OSInit();


 


PC_DOSSaveReturn();


PC_VectSet(uCOS,OSCtxSw);


 


OSTaskCreate(taskStart,signal,&TaskStartStk[TASK_STK_SIZE-1],0);      /*一般也就是这个结构了比较简洁明了*/



OSStart();


}


 


void taskStart(void* pdata)    /*在必须创建的任务中创建多任务并作一定初始化;当然并不一定都需要这样*/


{


#if OS_CRITICAL_METHOD == 3


           OS_CPU_SR cpu_sr;


#endif



pdata = pdata;



TaskStartDispInit();     /*初始化显示*/



OS_ENTER_CRITICAL();


PC_VectSet(0x08,OSTickISR);


PC_SetTickRate(OS_TICKS_PER_SEC);


OS_EXIT_CRITICAL();



OSStatInit();       /*统计任务初始化*/



OSTaskCreate(task_1,pdata,&Task_1_Stk[TASK_STK_SIZE-1],5);


OSTaskCreate(task_2,pdata,&Task_2_Stk[TASK_STK_SIZE-1],6);




for(;;)


{


           OSTimeDly(100);        /*第一个任务完成了使命,在本程序中,它再也不需要了,不过,这里没有删除它而是让它一直延迟*/


}


}


 


void task_1(void* pdata)


{


pdata = pdata;


for(;;)


{


           if(flag)        /*任务一要访问signal了,首先它要去判断是不是能够访问*/


           {


                    flag = 0;


                    signal = "task_1 gets the resource!";


                    if(y2 >20)


                    {


                             y1 = 6;


                             y2 = 6;


                             TaskStartDispInit();


                    }


                    PC_DispStr(0,++y1,signal,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);


                    flag = 1;      /*访问完成之后,将资源置为可用,别的任务就可以去访问了*/


           }


          


           if(PC_GetKey(&key) == TRUE)


           {


                    if(key == 0x1B)


                    {


                             PC_DOSReturn();


                    }


           }


           OSTimeDly(400);


}


}


 


 


void task_2(void* pdata)        /*同任务一*/


{


pdata = pdata;


for(;;)


{


           if(flag)


           {


                    flag = 0;


                    signal = "task_2 gets the resource!";


                    if(y2 >20)


                    {


                             y1 = 6;


                             y2 = 6;


                             TaskStartDispInit();


                    }


                    PC_DispStr(40,++y2,signal,DISP_BGND_LIGHT_GRAY+DISP_FGND_BLUE);


                    flag = 1;


           }


          


           if(PC_GetKey(&key) == TRUE)


           {


                    if(key == 0x1B)


                    {


                             PC_DOSReturn();


                    }


           }


           OSTimeDly(200);


}


}


 


static  void  TaskStartDispInit(void)    /*显示*/


{


PC_DispStr( 0,  0, "                         uC/OS-II, The Real-Time Kernel                         ", DISP_FGND_WHITE + DISP_BGND_BLUE + DISP_BLINK);


PC_DispStr( 0,  1, "                                     Norman                                     ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  2, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  3, "                                  EXPERIMENT #2                                 ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  4, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  5, "                                  Original Data                                 ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  6, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  7, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  8, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0,  9, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 10, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 11, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 12, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 13, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 14, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 15, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 16, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 17, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 18, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 19, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 20, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 21, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 22, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 23, "                                                                                ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY);


PC_DispStr( 0, 24, "                            <-PRESS 'ESC' TO QUIT->                             ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY + DISP_BLINK);


}


 


实验结果:


两个任务按照自己的运行时间运行,似乎没有什么干扰,保护了共享资源。


可以修改优先级去试验前面的猜想<>


 


实验三:


 


试验内容:二值信号量。使用二值信号量来实现实验一的功能,并作一些试探的试验,确定信号量的功能。


源程序及分析


前面实验的程序我发现了几个问题:


首先是,taskStart任务一直在做延时,似乎很浪费,后来才发现,它可以用来返回DOS环境,这样一来,其他两个任务也就不用劳神去干这个事情了。而且,如果两个任务被阻塞而无法运行,岂不是回不去了?


其次是,两个任务的时间正好两倍,是否有些情况不能验证?<待分析>


所以,我将程序修改如下:


#include "includes.h"


 


#define TASK_STK_SIZE 1024     /*按照一般的流程将所需要的数据结构定义、初始化等*/


 


OS_STK TaskStartStk[TASK_STK_SIZE];


OS_STK Task_1_Stk[TASK_STK_SIZE];


OS_STK Task_2_Stk[TASK_STK_SIZE];


 


char* signal = "Original Data";


INT16S key;


INT16U y1 = 6,y2 = 6;


OS_EVENT *flag;


 


void taskStart(void* pdata);


void task_1(void* pdata);


void task_2(void* pdata);


 


static  void  TaskStartDispInit(void);


 


void main(void)    /*main函数的一般结构*/


{


OSInit();


 


PC_DOSSaveReturn();


PC_VectSet(uCOS,OSCtxSw);



flag = OSSemCreate(1);         /*创建工作一般都放在这里*/


OSTaskCreate(taskStart,signal,&TaskStartStk[TASK_STK_SIZE-1],0);



OSStart();  /*开始多任务*/


}


 


void taskStart(void* pdata)    /*第一个任务必须创建,做创建其他任务、初始化等工作*/


{


#if OS_CRITICAL_METHOD == 3


           OS_CPU_SR cpu_sr;


#endif



pdata = pdata;



TaskStartDispInit();



OS_ENTER_CRITICAL();


PC_VectSet(0x08,OSTickISR);


PC_SetTickRate(OS_TICKS_PER_SEC);


OS_EXIT_CRITICAL();



OSStatInit();



OSTaskCreate(task_1,pdata,&Task_1_Stk[TASK_STK_SIZE-1],5);


OSTaskCreate(task_2,pdata,&Task_2_Stk[TASK_STK_SIZE-1],6);




for(;;)         /*作返回判断工作*/


{


           if(PC_GetKey(&key) == TRUE)


           {


                    if(key == 0x1B)


                    {


                             PC_DOSReturn();


                    }


           }


           OSTimeDly(10);


}


}


 


void task_1(void* pdata)


{


INT8U* err;


pdata = pdata;


for(;;)


{


           OSSemPend(flag,0,err);         /*等待信号量*/


           signal = "task_1 gets the resource!";


           if(y2 >20)


           {


                    y1 = 6;


                    y2 = 6;


                    TaskStartDispInit();


           }


           PC_DispStr(0,++y1,signal,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);


           OSSemPost(flag);         /*释放信号量*/


          


           OSTimeDly(400);


}


}


 


void task_2(void* pdata)


{


INT8U* err;


pdata = pdata;


for(;;)


{


           OSSemPend(flag,0,err);


           signal = "task_2 gets the resource!";


           if(y2 >20)


           {


                    y1 = 6;


                    y2 = 6;


                    TaskStartDispInit();


           }


           PC_DispStr(40,++y2,signal,DISP_BGND_LIGHT_GRAY+DISP_FGND_BLUE);


           OSSemPost(flag);


                            


           OSTimeDly(200);


}


}


 


static  void  TaskStartDispInit(void)    /**/


 


实验结果:


同实验二的结果是一致的。


为了更全面观测信号量,我做了以下改动的试验:


1)  屏蔽任务1OSSemPost()


2)  屏蔽任务2OSSemPost()


3)  将两个任务中OSSemPost()都屏蔽


4)  修改OSSemPend()有限等待时间,然后重复上面三个步骤


5)  修改优先级并重复上述四个步骤


6)  同步试验:


任务2运行时间比较短,为了让任务2运行与任务1同步,我们可以这样:


修改任务2等待时间为任务1运行时间;并且让任务1不调用OSSemPost()释放信号量。


这样的话,任务一虽然运行完成了,但是由于它没有释放信号量,信号量不可用,那么任务1和任务2下次运行都需要等待,而任务2运行时间比较短,它想去得到信号量,但是没有了,只好挂起——此时任务1是一直在等待任务2释放信号量——等到挂起时限到,任务2自动运行,处理自己的事情并释放信号量,此时,由于任务1得知信号量可用,优先级高的它就又立刻运行了。


实验结果显示这些分析是比较合理的。但是,我个人认为可能有些不太能够证明的地方:任务处理的是一个打印的事件,好像很快就处理完了,延时是让自己挂起,让其他任务运行,而不是自己占用了CPU。这一点我一时也想不怎么明白,放在这里看以后能够解决心中之惑否。


7)其他:实验中改了很多参数来看结果,不过很多都忘了记下。


 


 


(待续)


 


 


 


 


 


 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
6
关闭 站长推荐上一条 /3 下一条