任务介绍
1、在内存空间开辟了一片区域,供 4 个任务共享读写。1 个任务在写内存时,其它任务不能读写。多个任务可以同时读该内存区域数据。键盘按键 1-4 分别是 task1、task2、task3、task4 的写控制键,键盘按键 5-8 分别是 task1、task2、task3、task4 的读控制键。每按下一次写控制键,在共享区域的数据加 1,超过 99 变为 0,显示“写倒计时“在屏幕上。按下读控制键时,对应的读任务读取共享区域的数据并显示数据。一个任务的写控制键按下且“写倒计时”未结束时,其它任务的写控制键不能写,同时所有的读控制键也不能读,如果此时有读写动作(按下相应的按键),屏幕应显示报警。--------------采用消息邮箱机制完成此实验。一次读或写任务持续时间 5 秒。
代码实现:
```c
#include "includes.h"
#define TASK_STK_SIZE 512 //任务堆栈长度
#define TIME 5 //eat_time -> TIME - j
#define col 10
OS_STK StartTaskStk[TASK_STK_SIZE]; //定义任务堆栈区
OS_STK PhilosStk[4][TASK_STK_SIZE]; //利用二维数组来创建五个任务堆栈
INT8U PhilosID[]={1,2,3,4}; //用数组来存储五位哲学家的序号
INT16S key; //用于退出uCOS_II的键
INT16S key1[] = {0x1B,0x31,0x32,0x33,0x34}; //检测输入
INT16S key2[] = {0x1B,0x35,0x36,0x37,0x38};
INT16S wait_ticks;
//用于循环遍历的变量
INT8U Intpart[5][4]; //3个块的分区
INT8U *IntBlkPtr; //定义内存块的指针,这是全局变量呀!
char *msg1 = "can"; //这种定义在全局变量区的可以这样定义,可以不用字符数组
char *msg2 = "can't";
OS_MBOX_DATA *p;
OS_MEM *IntBuffer; //块的指针。
BOOLEAN getKey; //用于获取键值的变量
OS_EVENT *StrBox; //创建一个消息邮箱指针
void StartTask(void *data);
void Task(void *data);
void my_write(INT8U id);
void my_read(INT8U id);
/************************主函数*********************************************/
void main (void)
{
INT8U err;
char temp[50];
PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK);
OSInit(); //初始化uCOS_II
PC_DOSSaveReturn(); //保存Dos环境
PC_VectSet(uCOS, OSCtxSw); //安装uCOS_II中断
//创建一个消息邮箱
StrBox = OSMboxCreate(msg1); //初始化消息是可以写
IntBuffer = OSMemCreate(Intpart,5,4,&err); //管理分区
OSTaskCreate(StartTask,0,&StartTaskStk[TASK_STK_SIZE - 1],3);
OSStart();
}
//*****************************StartTask********************************************
void StartTask(void *pdata)
{
char s1[100]; //必须先分配好内存,这样不会跑飞
INT8U err1,i;
pdata=pdata;
OS_ENTER_CRITICAL();
PC_VectSet(0x08, OSTickISR);
PC_SetTickRate(OS_TICKS_PER_SEC);
OS_EXIT_CRITICAL();
OSStatInit();
//请求一个内存块
IntBlkPtr = OSMemGet(IntBuffer,&err1); //获得一块内存
*(IntBlkPtr+1) = 0; //首先赋初值,不用它了
//创建4个任务
for(i=0;i<4;i++)
{
OSTaskCreate(Task,(void *)&PhilosID[i],&PhilosStk[i][TASK_STK_SIZE - 1],i+6);
}
for(; ;)
{
getKey = PC_GetKey(&key); //实时获取按键值
if(key==key1[0]) //退出程序
{
PC_DOSReturn();
}
sprintf(s1,"%x",key);
PC_DispStr(col,0,s1,DISP_BGND_BLACK+DISP_FGND_WHITE); //打印了键值
OSTimeDly(1); //为了能够实时获取按键值
}
}
void Task(void *pdata)
{
char *s1= "write ok",*s2 = "read ok",*s3 = "wating for operation! ";
char *s4 = "You can't read now! ";
char *s5 = "You can't operate now! ";
INT8U err1,err2; //这样先分配内存不会跑飞!!!
char *sr;
char *sr2;
char ss[50];
INT8U PhID;
PhID = *(INT8U *)pdata; //哲学家序号
for(;;)
{
if (key == key1[PhID]) //&& cnt ==0
{
sr = OSMboxPend(StrBox,1,&err1); //我要保证一定能读取到
if(strcmp(sr,msg1) == 0) //这是可以写
{
OSMboxPost(StrBox,msg2); //马上就给它写上不能再读写了
if(*(IntBlkPtr+1)<9)
{
*(IntBlkPtr+1) += 1;
}
else
{
*(IntBlkPtr+1) = 0;
}
my_write(PhID);
}
else
{
OSMboxPost(StrBox,msg2); //如果是不能操作的话,也要马上写上不能操作,后面的任务才能判断
PC_DispStr(col,PhID+10,s5,DISP_BGND_BLACK+DISP_FGND_WHITE);
OSTimeDly(200*TIME-wait_ticks);
}
}
else if(key == key2[PhID])
{
sr2 = OSMboxPend(StrBox,1,&err2); //我要保证一定能读取到
if(strcmp(sr2,msg1) == 0) //这个表示可以读
{
OS_ENTER_CRITICAL();
OSMboxPost(StrBox,msg1);//马上写上可以读,告诉其他任务
OS_EXIT_CRITICAL();
my_read(PhID);
}
else
{
OSMboxPost(StrBox,msg2); //不能读就还是写上不能读
//if_operate = 1;
PC_DispStr(col,PhID+10,s5,DISP_BGND_BLACK+DISP_FGND_WHITE);
OSTimeDly(200*TIME-wait_ticks);
}
}
else
{
PC_DispStr(col,PhID+10,s3,DISP_BGND_BLACK+DISP_FGND_WHITE);
OSTimeDly(1); //这里必须是1或者2,其他数字都是不行的!!!!
}
}
}
void my_write(INT8U id)
{
char ss[100];
INT8U err;
for(wait_ticks=0;wait_ticks<TIME*200;wait_ticks++)
{
sprintf(ss,"task_%d is writing, count down: %d ",id,(TIME-wait_ticks/200));
PC_DispStr(col,id+10,ss,DISP_BGND_BLACK+DISP_FGND_WHITE);
OSTimeDly(1);
}
OSMboxPend(StrBox,1,&err); //在这里pend后,邮箱无论如何都为空,那就不用下面判断了
OSMboxPost(StrBox,msg1);
}
void my_read(INT8U id)
{
char ss[100];
INT8U err;
INT8U i;
for(i=0;i<5;i++)
{
sprintf(ss,"task_%d read the number is: %d count down: %d",id,*(IntBlkPtr+1),5-i); //我也不知道为啥第一个内存单元不能用,它的数据总是不对
PC_DispStr(col,id+10,ss,DISP_BGND_BLACK+DISP_FGND_WHITE);
OSTimeDly(200);
}
}