目录
练习 1 任务的创建 ........................................................................................................... 1
练习 2 任务的挂起和恢复 ............................................................................................... 3
练习 3 任务加锁解锁 ....................................................................................................... 5
练习 4 任务删除 ............................................................................................................... 6
练习 5 钩子函数 ............................................................................................................... 8
练习 6 信号量的使用 ....................................................................................................... 9
练习 7 未使用互斥型信号量的反例 ............................................................................ 11
练习 8 使用互斥型信号量解决优先级反转的例子 .................................................... 13
练习 9 使用邮箱的例子 ................................................................................................. 15
练习 10 使用消息队列 .................................................................................................. 17
练习 11 信号量集的使用 ............................................................................................... 19
练习 12 内存分配 ........................................................................................................... 20
μC/OS-II 在 LPC2000 系列处理器上的移植 ............................................................................... 23
.1 移植过程 ............................................................................................................................ 24
.2 移植相关文件介绍 ............................................................................................................ 24
.2.1 Vectors.s 向量表 ..................................................................................................... 24
.2.2 Init.s 启动代码 ......................................................................................................... 25
.2.3 os_cpu_a.s ................................................................................................................ 27
.2.4 Target.c 硬件初始化 ................................................................................................ 27
.2.5 OS_CFG.H 配置文件 .............................................................................................. 27
.3 任务切换的过程 ................................................................................................................ 28
练习 1 任务的创建
TaskStart 任务中创建两个任务 myTask 和 yourTask。当程序运行后,任务 myTask 在显
示器上显示一个字符“M”;yourTask 则是在显示器上显示字符 “Y”。
主要实验代码如下:
//声明任务堆栈
OS_STK myTask[TASK_STK_SIZE];
OS_STK yourTask[TASK_STK_SIZE];
OS_STK StartTask[TASK_STK_SIZE];
void StartTask (void *pdata);
void mytask(void *pdata);
void yourtask(void *pdata);
int main()
{
/*初始化部分,初始化各种硬件以及 ucos */
TargetInit();
OSInit();
/*创建起始任务*/
OSTaskCreate(StartTask, NULL, &StartTask[TASK_STK_SIZE-1], 3);
/*启动 ucos*/
OSStart();
}
void StartTask (void *pdata)
{ pdata = pdata;
T0TCR = 1; /*开启时钟节拍中断*/
uart1printf("startTask is on");
/*创建两个任务*/
OSTaskCreate(mytask, NULL, &myTask[TASK_STK_SIZE-1],4);
OSTaskCreate(yourtask, NULL, &yourTask[TASK_STK_SIZE-1], 5);
for(;;)
{
OSTimeDly(10); //系统延时函数,其实这里可以将该任务杀死,TaskDel
}
}
void mytask(void *pdata)
{
pdata = pdata;
for(;;)
{ uart1printf("M");
OSTimeDly(10);
}
}
void yourtask(void *pdata)
{
pdata = pdata;
for(;;)
{ uart1printf("Y");
OSTimeDly(10);
}
}
本实验在 keil3 编译环境、proteus 仿真环境下通过串口即可完成,看到的显示结果在串
口 2 窗口中如下:因为 myTask 和 yourTask 延时同样的时间,所以显示是交替显示。
图任务切换结果
本实验中 OSTimeDly 是系统提供的延时函数,各任务在完成了自己的工作后要主动交出
CPU 使用权,调用 OSTimeDly 函数将任务状态置为等待态,使得其他就绪任务可以获得 CPU
使用权。
练习 2 任务的挂起和恢复
修改上练习 1 应用程序的任务 yourTask 。要求任务 yourTask 运行 3 次后,挂起任务
myTask;任务 yourTask 运行 5 次后,恢复任务 myTask。
本实验和三个函数有关:OSTimeDly()、 OSTimeTick()、OSTaskResume()。
OSTimeDly()在 OS_time.c 中,为任务延时,记录任务延时节拍。
OSTimeTick()在 OS_time.c 中,为时钟节拍函数,负责将延时的任务每来一个时钟节拍
后延时数减 1。该函数不会使被挂起的任务延时时间到而进入就绪态。若延时、挂起双重等
待态的任务延时时间到了,该函数的处理是将延时时间再次调整为 1(OSTCBDly=1)并且
依然是处于挂起等待状态。只有 OSTaskResume()将任务挂起恢复后,时钟节拍才会减为零,
任务处于就绪态。
OSTaskResume()在 os_task.c 中,恢复挂起,将 OSTaskSuspend 函数引起的任务挂起解
除。只会将任务状态的“挂起位”清除。
于是在使用 OSTaskResume 后虽然是要解除 mytask 的挂起,但是由于 mytask 的
OSTCBDly 不为 0,所以要等到下个时钟节拍才被唤醒。这种情况可使用单步调试来跟踪。
代码部分清单如下,和实验 1 比,只是修改了 yourtask,并且使用了全局变量 INT8U
times=0。
void yourtask(void *pdata)
{
pdata = pdata;
for(;;)
{
if(times==2)
{
OSTaskSuspend(4);
}
if(times==4)
{
OSTaskResume(4);
}
times+=1;
uart1printf("Y");
OSTimeDly(10);
}
}
运行结果见图 4-11。
分析
定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析
如下:
startTask is on//首先 TaskStart 任务显示 startTask is on 并换行,创建任务 mytask 和 yourtask。
M//mytask 打印 M,优先级高于 Yourtask
Y//yourtask 打印 Y,这是 Y 任务第 1 次运行,进入该任务代码时 times=0
M//mytask 打印 M
Y//yourtask 打印 Y,这是 Y 任务第 2 次运行,进入该任务时 times=1
M// mytask 打印 M
Mytask is suspended//任务 Y 第 3 次运行,所以进入该任务时 times=2,首先打印 Mytask is
suspended 显示挂起了任务 Mytask
Y//任务 Yourtask 打印 Y
Y//任务 Yourtask 打印 Y,任务 Y 第 4 次运行,所以进入该任务时 times=3
Mytask is Resumed//任务 Y 第 5 次运行,所以进入该任务时 times=4,唤醒任务 mytask,在
唤醒任务的时候,虽然是要进行任务调度的,但是由于此时虽然 OSTaskResume 中
ptcb->OSTCBStat &= ~OS_STAT_SUSPEND将任务状态从挂起态解除,但是由于任务mytask
的 OSTCBDly 依然是 1,所以实际上 mytask 不被立刻调用。
YM//任务 Yourtask 打印 Y,在其即将打印换行的时候,时钟节拍来临了,此时 mytask 被唤
醒,所以本行显示了 M,接着 Mytask 打印换行,并且交出 CPU 使用权,此时 yourtask 接续
运行,也是要打印换行,这样串口中显示的情况是打印了一个空行,原因就在于此
而后 Mytask 和 Yourtask 又继续正常执行了。
图任务挂起恢复练习实验结果
练习 3 任务加锁解锁
除 startTask 任务外,有 MyTask、YourTask 两个任务,当任务 MyTask 运行 2 次时,用
函数 OSSchedLock()对调度器进行加锁;而当任务 Task1 运行到第 4 次时,再用函数
OSSchedUnlock()对调度器进行解锁,并运行该程序。
MyTask 部分代码清单如下:
times+=1;//全局变量
if (times==2)
{
OSSchedLock(); //锁调度器
}
if (times==4)
{
OSSchedUnlock(); //解锁调度器
}
实验结果见图 4-12,分析如下:
startTask is on//首先 TaskStart 任务显示 startTask is on 并换行,创建任务 mytask 和 yourtask。
M//mytask打印M,优先级高于Yourtask,这是M任务第1次运行,进入该任务代码时 times=0,
但是在进入 if 条件判断前,已经把 times 加 1 了,所以条件判断之前 times=1。
Y//yourtask 打印 Y
M// mytask 打印 M,这是 M 任务第 2 次运行,在进入 if 条件判断前,times=2,所以调用
OSSchedLock 函数,阻止任务切换,Yourtask 不会被唤醒了。但是此时由于任务调度无效,
所以 mytask 实际上一直被 delay 着,未处于就绪状态,而不得以“被运行”。
M// mytask 打印 M,这是 M 任务第 3 次运行,在进入 if 条件判断前,times=3。
Y// yourtask 打印 Y,看似不合理,其实是有道理的,再次执行任务 mytask 时,times=4,此
时调用 OSSchedUnlock()解锁,任务得以切换, starttask 变为了最高就绪的任务,接着由于
mytask 一直处于延时,yourtask 占用 CPU 使用权。
而后又恢复正常。
该实验的结论就是调度器上锁后未就绪的任务被“逼迫”运行!因为上锁后 OSSched()不进
行任务调度了。
图加锁解锁实验结果
练习 4 任务删除
假定 yourtask 是被删除方,mytask 是请求删除方,完成任务 myTask 删除任务 yourTask。
部分代码清单如下:
void mytask(void *pdata)
{
char* s="MyTask:i want to delete yourtask\r";//定义要显示的字符
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
pdata = pdata;
for(;;)
{
times+=1;
if (times==2)
{
uart1printf(s);
while( OSTaskDelReq( 5 ) != OS_TASK_NOT_EXIST )
{
OSTimeDly(1); //延时一个时钟节拍
}
}
uart1printf("M\r");
OSTimeDly(10);
}
}
void yourtask(void *pdata)
{
char *s1="YouTask:i want to delete myself\r";
char *s2="YouTask:i have detelted myself\r";
pdata = pdata;
for(;;)
{
if( OSTaskDelReq(OS_PRIO_SELF ) == OS_TASK_DEL_REQ )
{
uart1printf(s1);
OSTimeDly(5);
uart1printf(s2);
OSTaskDel( OS_PRIO_SELF );
}
uart1printf("Y\r");
OSTimeDly(10);
}
}
实验结果见图 4-13。分析结果:mytask 在第二次运行时候,调用 OSTaskDelReq 删除
优先级是 5 的 yourtask,但是 mytask 只是不断查询删除的结果,删除的过程由 yourtask 通过
OSTaskDel( OS_PRIO_SELF )自行完成,但是 mytask 在调用 OSTaskDelReq 过程中已经给
yourtask 的删除标志置位了,yourtask 在运行过程中检测到了置位标志,则在适合的阶段给
自己删除。
图任务删除试验结果
练习 5 钩子函数
熟悉钩子函数的用法,例如在 OSTimeTickHook 中激活某个任务显示的内容。部分主要
代码如下:
void mytask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
pdata = pdata;
for(;;)
{
uart1printf("M\r");
OSTimeDly(10);
}
}
void yourtask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
pdata = pdata;
for(;;)
{
if(InterKey)
{
uart1printf("y\r");
InterKey=FALSE;
}
OSTimeDly(10);
}
}
Yourtask 显示内容是要在 InterKey 为“TRUE”时可以显示,那么什么时候 InterKey 为真由
时钟节拍的次数控制如下:
void OSTimeTickHook (void)
{
if(InterCtr == 100)
{
InterKey = TRUE;
InterCtr = 0;
}
InterCtr++;
}
由此实验结果如图所示,yourtask 显示“y”一次就表明时钟节拍来了 100 次。
图 HOOK 函数的作用
练习 6 信号量的使用
试编写一个应用程序,其中有一个函数 Fun()和两个任务 MyTask 和 YourTask。应用程
序中的两个任务都可以调用函数 Fun(),但不能同时调用。
分析该问题相当于约束某个共享资源的使用。题中说明共享资源的数量为 1,于是可以
建立只有一个信号量的事件来约束共享资源的使用。任务申请该信号量通过 OSSemPend()
完成,任务使用后释放信号量通过 OSSemPost()完成。部分代码如下:
OS_EVENT *pevent_Sem; //指向信号量事件的指针
int main()
{
/*初始化部分,初始化各种硬件以及 ucos */
TargetInit();
OSInit();
pevent_Sem = OSSemCreate (1);//可用信号量数目为 1
/*创建起始任务*/
OSTaskCreate(TaskStart, NULL, &StartTask[TASK_STK_SIZE-1], 3);
/*启动 ucos*/
OSStart();
}
void mytask(void *pdata)
{
INT8U err;
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
pdata = pdata;
for(;;)
{
uart1printf("My pend \r");
OSSemPend(pevent_Sem,0,&err); //请求信号量
Fun(); //调用函数 Fun( )
OSSemPost(pevent_Sem); //发送信号量
uart1printf("My post\r");
OSTimeDly(100);
}
}
void yourtask(void *pdata)
{
INT8U err;
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
pdata = pdata;
for(;;)
{
uart1printf("Your pend\r");
OSSemPend(pevent_Sem,0,&err); //请求信号量 ,无限等待
Fun(); //调用函数 Fun( )
OSSemPost(pevent_Sem); //发送信号量
uart1printf("Your post\r");
OSTimeDly(100);
}
}
void Fun(void)
{
uart1printf("Fun is running\r");
}
图 申请释放信号量实验效果
练习 7 未使用互斥型信号量的反例
下面是一个使用信号量实现独占式访问共享资源而出现了任务优先级反转的应用程序
实例。请运行该程序并分析它的运行结果。 主要应用程序代码如下:
int main()
{
/*初始化部分,初始化各种硬件以及 ucos */
TargetInit();
OSInit();
pevent_Sem = OSSemCreate (1);//可用信号量数目为 1
/*创建起始任务*/
OSTaskCreate(TaskStart, NULL, &StartTask[TASK_STK_SIZE-1], 3);
/*启动 ucos*/
OSStart();
}
void TaskStart(void *pdata)
{
pdata = pdata;
T0TCR = 1; /*开启时钟节拍中断*/
uart1printf("startTask is on\r");
/*创建两个任务*/
OSTaskCreate(mytask, NULL, &myTask[TASK_STK_SIZE-1],4);
OSTaskCreate(yourtask, NULL, &yourTask[TASK_STK_SIZE-1], 5);
OSTaskCreate(hertask, NULL, &herTask[TASK_STK_SIZE-1], 6);
for(;;)
{
OSTimeDly(10);
}
}
void mytask(void *pdata)
{
INT8U err;
pdata = pdata;
for(;;)
{
OSTimeDlyHMSM(0, 0, 2, 0); //等待 2 秒
uart1printf("mytask pend sem \r");
OSSemPend(pevent_Sem,0,&err); //请求信号量
uart1printf("mytask is running \r");
uart1printf("mytask post sem\r");
OSSemPost(pevent_Sem); //发送信号量
OSTimeDly(200);
}
}
void yourtask(void *pdata)
{
pdata = pdata;
for(;;)
{
uart1printf("Yourtask is running\r");
OSTimeDly(200);
}
}
void hertask (void *pdata)
{
static INT32U hertask_counter;
INT8U err;
pdata = pdata;
for (;;)
{
uart1printf("hertask pend sem \r");
OSSemPend(pevent_Sem,0,&err); //请求信号量
uart1printf("hertask is running \r");
for(hertask_counter;hertask_counter<4000000;++hertask_counter)//说明该任务很长
时间后才释放信号量
{
;
}
hertask_counter = 0;
uart1printf("hertask post sem\r");
OSSemPost(pevent_Sem); //发送信号量
OSTimeDly(200);
}
}
实验结果如下:
图 未使用互斥信号量的反例
简单分析:首先起始任务建立 mytask、yourtask、hertask 三个任务后,按照优先级 mytask
先运行,mytask 因为延时,于是 yourtask 运行,而后 hertask 运行,申请信号量,使用共享
资源较长时间。期间 yourtask 多次醒来,则中断 hertask 运行而运行,而 mytask 的延时 2s
时间也在 hertask 长时间占用共享资源的过程中结束,mytask 开始申请信号量,无奈因为
hertask 没有释放信号量,mytask 就算有多么高的优先级也不能强制获得信号量,mytask 只
有等待,等待低优先级的 hertask 主动是否信号量,这样 yourtask 这类不使用信号量,不需
要获得共享资源的任务就先于 mytask 这类受独占信号量约束的高优先级任务而运行,这绝
对不是我们期待的,那么就有了互斥型信号量的使用价值。
练习 8 使用互斥型信号量解决优先级反转的例子
现在使用互斥型信号量的相关函数解决实验 7 中优先级反转的问题。
部分代码如下:
int main()
{
…
pevent_Sem = OSMutexCreate (1,&err);//提升到的优先级为 1
…
}
void TaskStart(void *pdata)
{
…
OSTaskCreate(mytask, NULL, &myTask[TASK_STK_SIZE-1],4);
OSTaskCreate(yourtask, NULL, &yourTask[TASK_STK_SIZE-1], 5);
OSTaskCreate(hertask, NULL, &herTask[TASK_STK_SIZE-1], 6);
…
}
void mytask(void *pdata)
{
…
for(;;)
{
OSTimeDlyHMSM(0, 0, 2, 0); //等待 2 秒
uart1printf("mytask pend sem \r");
OSMutexPend(pevent_Sem,0,&err); //请求信号量
uart1printf("mytask is running \r");
uart1printf("mytask post sem\r");
OSMutexPost(pevent_Sem); //发送信号量
OSTimeDly(200);
}
}
void yourtask(void *pdata)
{
…
for(;;)
{
uart1printf("Yourtask is running\r");
OSTimeDly(200);
}
}
void hertask (void *pdata)
{
…
for (;;)
{
uart1printf("hertask pend sem \r");
OSMutexPend(pevent_Sem,0,&err); //请求信号量
uart1printf("hertask is running \r");
for(hertask_counter;hertask_counter<4000000;++hertask_counter)//说明该任务很长
时间后才释放信号量
{
;
}
hertask_counter = 0;
uart1printf("hertask post sem\r");
OSMutexPost(pevent_Sem); //发送信号量
OSTimeDly(200);
}
}
图 互斥型信号量例子
分析:起始任务启动后建立三个任务,mytask 延时那么 yourtask 先显示,接下来 hertask 申
请信号量,显示运行,期间 yourtask 演示时间到打断 hertask 进行显示,而后 hertask 接续运
行,当 mytask 申请互斥信号量时,还是没有获得,因为低优先级的 hertask 未释放,但此时
mytask 是通过使用互斥型信号量的方式来申请信号量,于是 hertask 占有信号量的任务优先
级被临时提高,提高到不能被 yourtask 这类任务打断,那么 hertask 迅速运行结束,交出信
号量,让高优先级的任务尽快运行。
练习 9 使用邮箱的例子
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
一个应用程序,该程序有两个任务 MyTask 和 YourTask。在任务 MyTask 中用一个
变量记录任务 MyTask 的运行次数,并将其作为消息用邮箱发给任务 YourTask,且由任务
YourTask 显示出来。 这个变量不通过全局方式实现,当运行次数有变化时则通过消息邮箱
方式传送。部分代码如下:
OS_EVENT * pevent_box; // 消息邮箱指针
int main()
{
…
pevent_box = OSMboxCreate(NULL);//提升到的优先级为 1
…
}
void mytask(void *pdata)
{
INT16U MytaskRunCnt='0';
pdata = pdata;
for(;;)
{
MytaskRunCnt++;
uart1printf("mytask send mailbox \r");
OSMboxPost(pevent_box,&MytaskRunCnt );
OSTimeDly(300);
}
}
void yourtask(void *pdata)
{
INT8U err;
INT8U *ReceiveBuffer=NULL;
pdata = pdata;
for(;;)
{
ReceiveBuffer=OSMboxPend(pevent_box,0,&err );
uart1printf("mytask runs ");
uart1printf(ReceiveBuffer);
uart1printf(" times ");
uart1printf("\r");
OSTimeDly(200);
}
}
实验结果如图所示:
图邮箱的实验
实验结果分析: mytask负责发送邮件,邮件内容为mytask运行的次数,即MytaskRunCnt
的内容,为了正常在屏幕上打印,所以 MytaskRunCnt 初值设置为’0’,即 0x30。随后 yourtask
读取邮箱内容,将邮箱消息打印到屏幕上。“Mytask runs X times”就是 yourtask 显示的
内容。
练习 10 使用消息队列
编写一个应用消息队列进行通信的应用程序,要求 starttask 做消息队列发送,mytask、
yourtask 分别请求消息,starttask 在发现消息队列为空后,再向消息队列中装入消息。编写、
运行该程序并观察其运行结果。部分代码如下:
#define N_MESSAGES 7 //定义消息队列长度
OS_EVENT *pevent_q; // 消息队列指针
void *MsgGrp[N_MESSAGES]; //消息指针数组
OS_Q_DATA qdata; //查询消息时用到的结构
int main()
{
/*初始化部分,初始化各种硬件以及 ucos */
TargetInit();
OSInit();
pevent_q= OSQCreate (&MsgGrp[0],N_MESSAGES); //创建消息队列
/*创建起始任务*/
OSTaskCreate(TaskStart, NULL, &StartTask[TASK_STK_SIZE-1], 3);
/*启动 ucos*/
OSStart();
}
void TaskStart(void *pdata)
{
char* pmsg;
pdata = pdata;
T0TCR = 1; /*开启时钟节拍中断*/
uart1printf("startTask is on\r");
/*创建任务*/
OSTaskCreate(mytask, NULL, &myTask[TASK_STK_SIZE-1],4);
OSTaskCreate(yourtask, NULL, &yourTask[TASK_STK_SIZE-1], 5);
OSQFlush(pevent_q);
for(;;)
{
OSQQuery (pevent_q, &qdata);
if(qdata.OSNMsgs == 0)
{
pmsg="this is no 1 message!\r";
OSQPostFront(pevent_q,pmsg); //向消息队列插入一个消息
pmsg="this is no 2 message!\r";
OSQPostFront(pevent_q,pmsg); //向消息队列插入一个消息
pmsg="this is no 3 message!\r";
OSQPostFront(pevent_q,pmsg); //向消息队列插入一个消息
pmsg="this is no 4 message!\r";
OSQPostFront(pevent_q,pmsg); //向消息队列插入一个消息
pmsg="this is no 5 message!\r";
OSQPostFront(pevent_q,pmsg); //向消息队列插入一个消息
pmsg="this is no 6 message!\r";
OSQPostFront(pevent_q,pmsg); //向消息队列插入一个消息
pmsg="this is no 7 message!\r";
OSQPostFront(pevent_q,pmsg); //向消息队列插入一个消息
}
OSTimeDly(100);
}
}
void mytask(void *pdata)
{
INT8U* pmsg;
INT8U err;
pdata = pdata;
for(;;)
{
uart1printf("mytask pend q ");
pmsg=OSQPend(pevent_q,0,&err); //请求消息队列
uart1printf(pmsg);
OSTimeDly(300);
}
}
void yourtask(void *pdata)
{
INT8U* pmsg;
INT8U err;
pdata = pdata;
for(;;)
{
uart1printf("yourtask pend q ");
pmsg=OSQPend(pevent_q,0,&err); //请求消息队列
uart1printf(pmsg);
OSTimeDly(300);
}
}
实验结果如图所示:
图 消息队列实验
简单分析,starttask 在消息队列为空的时候创建 7 条消息,mytask 和 yourtask 相继申请消息,
由于消息插入使用的是后进先出的方式,于是第一次取走的消息是最后插入的 no7 号
message。
练习 11 信号量集的使用
设计一个有 3 个任务的应用程序,这 3 个任务分别叫做 MyTask、YourTask 和 HerTask。
要求用一个信号量集来控制 MyTask 的运行,即任务 YourTask 发送一个信号,任务 HerTask
发送一个信号,当这两个任务都发了信号之后,MyTask 才能运行。
部分代码如下:
OS_FLAG_GRP *pflaggrp; //信号量集标志组指针
int main()
{
……
pflaggrp = OSFlagCreate (0,&err); //创建信号量集
}
void mytask(void *pdata)
{
……
for(;;)
{
uart1printf("mytask pend flags\r");
OSFlagPend( //请求信号量集
pflaggrp,
(OS_FLAGS)3, //请求第 0 位和第 1 位信号 0000 0011
OS_FLAG_WAIT_SET_ALL, //第 0 位和第 1 位信号都为 1 为有效
0,&err
);
uart1printf("mytask is running\r");
OSTimeDly(300);
}
}
void yourtask(void *pdata)
{
……
for(;;)
{
OSTimeDly(300);
uart1printf("yourtask send flag\r");
//隔了一会才发送信号量集 给第 1 位发信号 00000010,信号置 1
OSFlagPost(
pflaggrp, (OS_FLAGS)2, OS_FLAG_SET, &err );
OSTimeDly(300);
}
}
void hertask(void *pdata)
{
……
for(;;)
{
uart1printf("hertask send flag\r");
//发送信号量集 给第 0 位发信号 0000 0001 信号置 1
OSFlagPost( pflaggrp, (OS_FLAGS)1,OS_FLAG_SET, &err);
OSTimeDly(300);
}
}
图 信号量集使用实验结果
练习 12 内存分配
设计一个含有 3 个任务的应用程序,这 3 个任务分别是 MyTask、YourTask 和 HerTask。
在应用程序中创建一个动态内存分区,该分区有6个内存块,每个内存块的长度为8个字节。
应用程序的任务 HerTask 在任务运行后请求一个内存块,随后就释放它。任务 MyTask 也在
任务运行后请求一个内存块,但是要在任务 MyTask 运行 3 次后,才释放它所申请的内存块。
任务 YourTask 也在任务运行后请求一个内存块,但是不释放它所申请的内存块。
为了了解内存分区变化的情况,编写代码来观察已被使用内存块的个数。
部分代码如下:
OS_MEM *pBuffer; //定义内存控制块指针
INT8U Part[6][4]; //划分分区及内存块
INT8U *pBlk;
OS_MEM_DATA MemInfo;
INT8U s[20];
INT8U Times=0;
int main()
{
……
pBuffer = OSMemCreate(Part,6,4,&err); //创建内存分区
}
void TaskStart(void *pdata)
{
……
OSTaskCreate(mytask, NULL, &myTask[TASK_STK_SIZE-1],4);
OSTaskCreate(yourtask, NULL, &yourTask[TASK_STK_SIZE-1], 5);
OSTaskCreate(hertask, NULL, &herTask[TASK_STK_SIZE-1], 6);
……
}
void mytask(void *pdata)
{
……
for(;;)
{
uart1printf("mytask\r");
pBlk=OSMemGet ( //请求内存块
pBuffer, //内存分区的指针
&err //错误信息
);
OSMemQuery (
pBuffer, //待查询的内存控制块的指针
&MemInfo
);
uart1printf("used memory number: ");
sprintf(s,"%d\r",MemInfo.OSNUsed);
uart1printf(s);
if(Times>2)
{
OSMemPut ( //释放内存块
pBuffer, //内存分区的指针
pBlk //待释放内存块的指针
);
}
Times++;
OSTimeDly(400);
}
}
void yourtask(void *pdata)
{
……
for(;;)
{
uart1printf("yourtask \r");
pBlk=