菜鸟学uC/OS_II(8)<?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-15
实验<续>
实验四:
实验内容:消息邮箱的使用
源程序及分析:
实验使用消息邮箱,任务2给任务1发送递增的数值,任务1接收到就显示出来。
这个实验是昨天晚上写好的,但是由于中间调试没有达到预期结果,任务1不是接收到多条重复信息,就是一条都接不到,所以拖到今天。最后发现的问题是:发送缓冲区必须是一个局部变量,否则接受任务就会永远挂起;具体原因(若有大虾看到,帮小弟分析一把),我想不太明白,反正做成局部变量就可以了。
#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];
INT16S key;
INT16U i="0";
INT16U y1 = 6,y2 = 6;
OS_EVENT *MB_Str; /*声明*/
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);
MB_Str = OSMboxCreate((void*)0); /*创建工作一般都放在这里*/
OSTaskCreate(taskStart,(void*)0,&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;
char* msg;
char* str = "Task_1 gets a msg:";
pdata = pdata;
for(;;)
{
msg = OSMboxPend(MB_Str,0,err); /*等待消息,这里需要一个局部变量msg*/
if(y2 > 20 || y1 > 20)
{
y1 = 6;
y2 = 6;
TaskStartDispInit();
}
y1++;
PC_DispStr(0,y1,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
PC_DispStr(18,y1,msg,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSTimeDly(20);
}
}
void task_2(void* pdata)
{
INT8U* err;
char* str = "Task_2 sends a msg:";
char* send;
pdata = pdata;
for(;;)
{
sprintf(send,"%d",i++);
OSMboxPost(MB_Str,send); /*发送一个消息,也需要一个局部变量*/
if(y2 > 20 || y1 > 20)
{
y1 = 6;
y2 = 6;
TaskStartDispInit();
}
y2++;
PC_DispStr(40,y2,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_BLUE);
PC_DispStr(59,y2,send,DISP_BGND_LIGHT_GRAY+DISP_FGND_BLUE);
OSTimeDly(400);
}
}
static void TaskStartDispInit(void)<略>
实验五:
实验内容:利用消息队列进行任务间通信
源程序及分析:
本程序设计三个任务:taskServe作为消息队列服务器,向消息队列发送递增数据;task_1和task_2两个任务从消息队列中读取数据并作显示。
taskServe任务向消息队列发送消息比较快,而两个消费者读取消息比较慢,所以理论上可以观测FIFO和LILO方式的不同结果。
但是:
疑惑:为什么使用OSQPost()和OSQPostFront()效果是一样的?郁闷,OS_CFG中也没有做特殊配置嘛!为什么就不行呢?难道说2.52版本没有FIFO?结果都是LILO嘛!
#include "includes.h"
#define TASK_STK_SIZE 1024 /*按照一般的流程将所需要的数据结构定义、初始化等*/
#define N_MSGS 32 /**/
OS_STK TaskStartStk[TASK_STK_SIZE];
OS_STK Task_S_Stk[TASK_STK_SIZE];
OS_STK Task_1_Stk[TASK_STK_SIZE];
OS_STK Task_2_Stk[TASK_STK_SIZE];
INT16S key;
INT16U i="0";
void* MsgQGrp[N_MSGS]; /*消息队列需要一个消息数组,其实是分配存储空间*/
INT16U y1 = 6,y2 = 6;
OS_EVENT *MQ_Str; /*声明*/
void taskStart(void* pdata);
void taskServe(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);
MQ_Str = OSQCreate(&MsgQGrp[0],N_MSGS); /*创建工作一般都放在这里*/
OSTaskCreate(taskStart,(void*)0,&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(taskServe,pdata,&Task_S_Stk[TASK_STK_SIZE-1],4);
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 taskServe(void* pdata)
{
char* send;
OS_Q_DATA* Q_Data;
for(;;)
{
sprintf(send,"%d",i++);
OSQPostOpt(MQ_Str,send,OS_POST_OPT_NONE); /*消息队列服务器???*/
OSQQuery(MQ_Str,Q_Data);
if(Q_Data->OSNMsgs == 32)
{
OSQFlush(MQ_Str);
i = 0;
}
OSTimeDly(50);
}
}
void task_1(void* pdata)
{
INT8U* err;
char* msg;
char* str = "Task_1 gets a msg:";
pdata = pdata;
for(;;)
{
msg = OSQPend(MQ_Str,0,err); /**/
if(y2 > 20 || y1 > 20)
{
y1 = 6;
y2 = 6;
TaskStartDispInit();
}
y1++;
PC_DispStr(0,y1,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
PC_DispStr(18,y1,msg,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSTimeDly(200);
}
}
void task_2(void* pdata)
{
INT8U* err;
char* str = "Task_2 gets a msg:";
char* msg;
pdata = pdata;
for(;;)
{
msg = OSQPend(MQ_Str,0,err); /**/
if(y2 > 20 || y1 > 20)
{
y1 = 6;
y2 = 6;
TaskStartDispInit();
}
y2++;
PC_DispStr(40,y2,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_BLUE);
PC_DispStr(59,y2,msg,DISP_BGND_LIGHT_GRAY+DISP_FGND_BLUE);
OSTimeDly(200);
}
}
static void TaskStartDispInit(void)<略>
实验结果:
改了很多地方:发送方式,等待时间,延迟时间等等,不行就是不行,这个FIFO默认都不行……
实验六:
实验内容:互斥信号量的使用——创建三个任务,三个任务都要访问同一个资源,创建互斥信号量来保护这个资源。
源程序:
#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];
OS_STK Task_3_Stk[TASK_STK_SIZE];
INT16S key;
INT16U y = 6;
OS_EVENT *Mutex_Str; /*声明*/
void taskStart(void* pdata);
void task_1(void* pdata);
void task_2(void* pdata);
void task_3(void* pdata);
static void TaskStartDispInit(void);
void main(void) /*main函数的一般结构*/
{
INT8U* err;
OSInit();
PC_DOSSaveReturn();
PC_VectSet(uCOS,OSCtxSw);
Mutex_Str = OSMutexCreate(4,err); /*创建工作一般都放在这里*/
OSTaskCreate(taskStart,(void*)0,&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);
OSTaskCreate(task_3,pdata,&Task_3_Stk[TASK_STK_SIZE-1],7);
for(;;) /*作返回判断工作*/
{
if(PC_GetKey(&key) == TRUE)
{
if(key == 0x1B)
{
PC_DOSReturn();
}
}
OSTimeDly(10);
}
}
void task_1(void* pdata)
{
INT8U* err;
char* str;
pdata = pdata;
for(;;)
{
str = "Task_1 asks for mutex!";
y++;
PC_DispStr(0,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSMutexPend(Mutex_Str,0,err); /**/
if(y > 20)
{
y = 6;
TaskStartDispInit();
}
str = "Task_1 is running!";
y++;
PC_DispStr(0,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSTimeDly(150);
str = "Task_1 release mutex!";
y++;
PC_DispStr(0,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSMutexPost(Mutex_Str);
OSTimeDly(10);
}
}
void task_2(void* pdata)
{
INT8U* err;
char* str;
pdata = pdata;
for(;;)
{
str = "Task_2 asks for mutex!";
y++;
PC_DispStr(25,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSMutexPend(Mutex_Str,0,err); /**/
if(y > 20)
{
y = 6;
TaskStartDispInit();
}
str = "Task_2 is running!";
y++;
PC_DispStr(25,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSTimeDly(200);
str = "Task_2 release mutex!";
y++;
PC_DispStr(25,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSMutexPost(Mutex_Str);
OSTimeDly(10);
}
}
void task_3(void* pdata)
{
INT8U* err;
char* str;
pdata = pdata;
for(;;)
{
str = "Task_3 asks for mutex!";
y++;
PC_DispStr(50,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSMutexPend(Mutex_Str,0,err); /**/
if(y > 20)
{
y = 6;
TaskStartDispInit();
}
str = "Task_3 is running!";
y++;
PC_DispStr(50,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSTimeDly(250);
str = "Task_3 release mutex!";
y++;
PC_DispStr(50,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSMutexPost(Mutex_Str);
OSTimeDly(10);
}
}
static void TaskStartDispInit(void)
实验结果及分析:
1)
没有任务释放后没有添加延时模拟。但任务3饿死了……
“饥饿”就是由于在占先式内核中,高优先级任务一直不释放OS的使用权,致使低优先级的任务一直由于得不到使用权而无法运行。
那么,在程序中加入一个延时在释放信号量之后。
这里加了一个10ticks的延时。
2)
添加延时模拟之后更清楚,但是任务3还是饿死了……
难道是我加的延时太少了?少也能够交出OS了撒!
我生气了,加就加吧——我一口气给加到500ticks——
结果……
任务3真有东西吃了……
在500个ticks内,任务可能全部都在延迟,任务3就很有机会得到这个资源了。
3)
具体的时间是:首先根据任务优先级和任务运行时间的关系:任务1运行时间最短,因此需要高优先级;任务3运行时间最长,赋给最低的优先级。对于任务1,延迟300ticks;任务2延迟200ticks;任务3延迟100ticks。
这样的话,任务运行的时间也看得比较清楚:任务1运行次数多;任务3运行次数少。
如果延迟相同的时间,150ticks是最低值,否则任务3还是会饿死。
这难道是和任务运行时间有关系?任务1运行时间设置为150ticks的;不会吧?如果要这样才能够交出OS,那效率如何提高?OS作者本意该不会是这样的!
再次研究程序,我发现只要任务2延时150ticks以上任务3就不会饿死了……
分析起来是这样的:三个任务一开始都回去请求信号量。任务1优先级高,首先运行;任务1释放信号量的时候,任务2不请求,那么任务3就得以运行。
我看很多演示程序中都只建立了两个任务去请求一个共享资源。这样不好啊……
各位大虾拯救我吧……
实验七:
实验内容:事件标志的使用
源程序:
/*******************************************************************************/
/*********************************事件标志组实验********************************/
/************************************By Norman**********************************/
/************************************2008-7-15**********************************/
/****************该程序创建4个任务,任务1等待事件标志FlagsPtr发生***************/
#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];
OS_STK Task_3_Stk[TASK_STK_SIZE];
OS_STK Task_4_Stk[TASK_STK_SIZE];
INT16S key;
INT16U y = 6;
OS_FLAG_GRP *FlagsPtr; /*声明*/
void taskStart(void* pdata);
void task_1(void* pdata);
void task_2(void* pdata);
void task_3(void* pdata);
void task_4(void* pdata);
static void TaskStartDispInit(void);
void main(void) /*main函数的一般结构*/
{
INT8U* err;
OSInit();
PC_DOSSaveReturn();
PC_VectSet(uCOS,OSCtxSw);
FlagsPtr = OSFlagCreate((OS_FLAGS)0,err); /*创建工作一般都放在这里*/
OSTaskCreate(taskStart,(void*)0,&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);
OSTaskCreate(task_3,pdata,&Task_3_Stk[TASK_STK_SIZE-1],7);
OSTaskCreate(task_4,pdata,&Task_4_Stk[TASK_STK_SIZE-1],8);
for(;;) /*作返回判断工作*/
{
if(PC_GetKey(&key) == TRUE)
{
if(key == 0x1B)
{
PC_DOSReturn();
}
}
OSTimeDly(10);
}
}
void task_1(void* pdata)
{
INT8U* err;
char* str;
pdata = pdata;
for(;;)
{
str = "Task_1 asks is waiting!";
y++;
PC_DispStr(0,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSFlagPend(FlagsPtr,(OS_FLAGS)0x26,
OS_FLAG_WAIT_SET_ALL + OS_FLAG_CONSUME,0,err); /*等待事件标志组,注意OS_FLAG_CONSUME*/
if(y > 20)
{
y = 6;
TaskStartDispInit();
}
str = "Task_1 is running!";
y++;
PC_DispStr(0,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSTimeDly(10);
}
}
void task_2(void* pdata)
{
INT8U* err;
char* str;
pdata = pdata;
for(;;)
{
str = "Task_2 is running!";
if(y > 20)
{
y = 6;
TaskStartDispInit();
}
y++;
PC_DispStr(40,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSTimeDly(200);
str = "Task_2 sets 0x02!";
y++;
PC_DispStr(40,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSFlagPost(FlagsPtr,(OS_FLAGS)0x02,OS_FLAG_SET,err); /**/
OSTimeDly(200);
}
}
void task_3(void* pdata)
{
INT8U* err;
char* str;
pdata = pdata;
for(;;)
{
str = "Task_3 is running!";
if(y > 20)
{
y = 6;
TaskStartDispInit();
}
y++;
PC_DispStr(40,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSTimeDly(500);
str = "Task_3 sets 0x04!";
y++;
PC_DispStr(40,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSFlagPost(FlagsPtr,(OS_FLAGS)0x04,OS_FLAG_SET,err); /**/
OSTimeDly(200);
}
}
void task_4(void* pdata)
{
INT8U* err;
char* str;
pdata = pdata;
for(;;)
{
str = "Task_4 is running!";
if(y > 20)
{
y = 6;
TaskStartDispInit();
}
y++;
PC_DispStr(40,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSTimeDly(800);
str = "Task_4 sets 0x20!";
y++;
PC_DispStr(40,y,str,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
OSFlagPost(FlagsPtr,(OS_FLAGS)0x20,OS_FLAG_SET,err); /**/
OSTimeDly(200);
}
}
static void TaskStartDispInit(void)<略>
实验结果及分析:
1)FLAG_WAIT_SET_ALL + OS_FLAG_CONSUME
2)FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME
看起来实验结果同预期的效果是一样的。
注意到OS_FLAG_CONSUME这个选项,有了这个选项,任务1可以不停等待一个事件标志发生;如果任务只是等待这个事件标志发生一次,然后被遵循被唤醒之类的机制后一直运行,不加这个选项就可以了。
总结:
1)总的来说,熟悉了uC/OS_II的功能函数等的使用。下一步就是对其他处理器的移植和一些驱动程序的开发了。这些应该比前面学到要难,一步步来吧。
2)我在程序中没有做错误信息处理,这应该是一个很不好的习惯;在程序中,对于一些内核函数的调用应该处理其错误信息!
如:
err = OSTaskCreate(myTask,(void*)0,&myTask_Stk[Task_Stk_Size-1],7);
if(err = ?????)
{
err handler;
}
这样的程序才能够避免不必要的麻烦。
3)实验中有些问题需要解决。
唉,不写了,王小妹儿扭着要打牌,升级去了^_^
<待续>
文章评论(0条评论)
登录后参与讨论