- 实验目的
- 掌握在 UCOsH操作系统下编写应用程序 的基本方法
- 实验内容
- 在移植好的UCOsII项 目中添加串口、LCD、 键盘的驱动程序
- 学习在UCOSII下 ,多应用任务的简单编程实例
- 实验设备
- EL-RAM-860教 学 实验 箱 ,PentiumII以上 的 PC机 ,仿 真 调试 电缆 ,串 口直 连 电 缆 。
- PC操 作 系统 WIN98或 WIN⒛00或 WINXP, ADs1.2集 成 开发环 坑 , 仿真 调试 驱动程 序 。
- 实验步骤
实验题目1:
- 在界面显示一个半径为20的红色圆圈,且该圆圈随着上、下、左、右键的按下往该方向平移6个单位。
- 当捕获回车按键后串口输出当前激活按键的值如"Left Button Pressed!"等
实验代码:
代码说明:
Main:此函数创建并启动了任务一,利用“邮箱”来进行多任务间的通信。
Task1:创建并启动了任务2,3,4,也是利用“邮箱” 来进行多任务间的通信。通过设置任务的优先级来控制任务的调度。
Task2:主要是控制LED灯的交替闪烁效果
Task3:主要是向超级终端中输出键盘上的按键值,代码只变动了输出内容。
Task4:是进行GUI任务,代码变动主要是改写此函数,函数编写代码已经进行了相关的注释。
void Task_4(void *pdata)
{ I32 number;INT8U Loop;for(;;) { number = GUI_WaitKey();Loop = TRUE;do{switch (number){case GUI_KEY_START: // 得到开始命令 Set_Color(GUI_BLUE);Fill_Rect(0,0,639,479); //画窗口的边框Set_Color(GUI_WHITE);Set_BkColor (GUI_BLUE); //设置窗口的背景颜色Fill_Rect(0,0,639,2); Fill_Rect(0,0,2,479);Fill_Rect(0,477,639,479);Fill_Rect(637,0,639,479); Set_Color(GUI_YELLOW);Set_Font (&CHINESE_FONT16);Disp_String (CN_start"这是一个多任务显示的例程"CN_end,50,30); Set_Color(GUI_RED); //画红色的圆,Fill_Circle (320, 240, 20); //圆心坐标、半径为20Loop = FALSE;number = 0;break;default: // 等待主任务发送的键值命令number = GUI_WaitKey(); Loop = TRUE;break;}}while(Loop==TRUE);do{switch (number) {case GUI_KEY_UP: //选择上移Set_Color(GUI_BLUE); //将原先的圆消失掉Fill_Rect(0,0,639,479); //重新绘制窗口Set_Color(GUI_WHITE);Set_BkColor (GUI_BLUE);Fill_Rect(0,0,639,2); //窗口的四条边框的绘制Fill_Rect(0,0,2,479);Fill_Rect(0,477,639,479);Fill_Rect(637,0,639,479);Set_Color(GUI_RED);if(y-20<=1){y=240; //如果圆要超过上边界,将圆设置到中心}else{y=y-6;}Fill_Circle(x, y, 20);Loop = TRUE;number = 0;break; case GUI_KEY_DOWN: //选择下移Set_Color(GUI_BLUE); //将原先的圆消失掉Fill_Rect(0,0,639,479); //重新绘制窗口Set_Color(GUI_WHITE);Set_BkColor (GUI_BLUE); Fill_Rect(0,0,639,2); //窗口的四条边框的绘制Fill_Rect(0,0,2,479);Fill_Rect(0,477,639,479);Fill_Rect(637,0,639,479);Set_Color(GUI_RED);if(y+20>=479){ //如果圆要超过下边界,将圆设置到中心y=240;}else{y=y+6;}Fill_Circle(x, y, 20); Loop = TRUE;number = 0;break;case GUI_KEY_RIGHT: //选择右移Set_Color(GUI_BLUE); //将原先的圆消失掉Fill_Rect(0,0,639,479); //重新绘制窗口Set_Color(GUI_WHITE); Set_BkColor (GUI_BLUE);Fill_Rect(0,0,639,2); //窗口的四条边框的绘制Fill_Rect(0,0,2,479);Fill_Rect(0,477,639,479);Fill_Rect(637,0,639,479);Set_Color(GUI_RED); //x为全局变量if(x+20>=639){ //如果圆要超过右边界x=320; //将圆心重新设置到中间}else{ x=x+6; //每一次右移,x值加6}Fill_Circle(x, y, 20); Loop = TRUE;number = 0; break; case GUI_KEY_LEFT: //选择左移 Set_Color(GUI_BLUE); //将原先的圆消失掉Fill_Rect(0,0,639,479); //重新绘制窗口Set_Color(GUI_WHITE);Set_BkColor (GUI_BLUE);Fill_Rect(0,0,639,2); //窗口的四条边框的绘制Fill_Rect(0,0,2,479);Fill_Rect(0,477,639,479); Fill_Rect(637,0,639,479);Set_Color(GUI_RED);if(x-20<=1){ //如果圆要超过左边界x=320; //将圆心重新设置到中间}else{ x=x-6;}Fill_Circle(x, y, 20);Loop = TRUE;number = 0;break;case GUI_KEY_ESCAPE: // 得到退出命令Set_Color(GUI_BLUE);Fill_Rect(0,0,639,479);Set_Color(GUI_WHITE);Fill_Rect(0,0,639,2);Fill_Rect(0,0,2,479);Fill_Rect(0,477,639,479);Fill_Rect(637,0,639,479);Loop = FALSE;number = 0;break; default: // 等待主任务发送的键值命令number = GUI_WaitKey();Loop = TRUE;break;}}while(Loop == TRUE);}
}
void Task_3(void *pdata)
{for(;;){if(key_number!=0xff){ Uart_Printf("key_number=%x Button Pressed!\n",key_number); //任务的干得活儿就是向超级终端发送内容key_number=0xff;OSTimeDly(30); //延时100个节拍}}
}
实验题目2:
在编写一个任务5,此任务中完成,设置其优先级为60,绘制一个圆,此圆的初始半径为2,然后扩大到50之后缩小为半径为2的圆。扩大的频率为LED灯闪烁的频率的1/2.
代码的实现:
在task1中创建并启动任务task5,在task2中设置让task2闪烁完一回,线程睡眠OSTimeDly(30); ,让低优先级的task5得到执行,task2中创建一个信号量,让task2运行两次,往信号量中扔一把钥匙,达到灯闪烁频率的1/2是圆扩大的频率,task5负责接受取出钥匙得到运行。
void Task_5(void *pdata)
{ I32 number;INT8U Loop;for(;;) { Key_P = OSMboxPend(Key_Mbox1, 0, &err); //取钥匙获取执行机会number = GUI_WaitKey();// 得到开始命令 Set_Color(GUI_BLUE);Fill_Rect(0,0,639,479); //画窗口的边框Set_Color(GUI_WHITE);Set_BkColor (GUI_BLUE); //设置窗口的背景颜色Fill_Rect(0,0,639,2); Fill_Rect(0,0,2,479);Fill_Rect(0,477,639,479);Fill_Rect(637,0,639,479); Set_Color(GUI_YELLOW);Set_Font (&CHINESE_FONT16);Disp_String (CN_start"这是一个多任务显示的例程"CN_end,50,30); R+=2; //此处R是全局变量If(R>50){R=2; //当圆半径到达了50时,圆半径回到2}Set_Color(GUI_RED); //画红色的圆,Fill_Circle (320, 240, R); //圆心坐标、半径为20Loop = FALSE;number = 0;
Loop = TRUE;number = GUI_WaitKey(); Loop = TRUE;}}
void Task_2(void *pdata)
{INT32U i,flag=0;K=1; //k是全局变量,控制代码执行两次往信号量里//面扔一把钥匙Key_Mbox1 = OSMboxCreate((void *)0);//创建信号量Key_Mbox1for(;;){k++;
If(k%2==0)
OSMboxPost(Key_Mbox1,&key_number);//往信号量Key_Mbox1仍钥匙OSTimeDly(30); if(flag==0){for(i=0;i<100000;i++);rGPGDAT = rGPGDAT&~(0x3<<8)|(0x1<<8);for(i=0;i<100000;i++);flag = 1;}else{for(i=0;i<100000;i++);rGPGDAT = rGPGDAT&~(0x3<<8)|(0x2<<8);for(i=0;i<100000;i++);flag = 0;}OSTimeDly(30); //延时30个节拍}
}
实验结果截图:
问题以及总结:
本次实验过程中绘制红心圆的时候往上移,左移、右移发现之前的圆不会消失,于是就造成了圆移动的过程中绘画成一条线,于是我就想到每次点击上下移动之前把原先这个圆给删除掉,但是GUI中又没有提供相关的函数,于是借鉴了一下别人的做法,每一移动触发之前,先把面板上的组件清空,把原先的窗口设置成白色,然后重新绘制窗口,这样之前的圆就消失了。
在任务二中,task5老是得不到机会运行,因为task5的优先级太低,而task2中总是在运行,导致低优先级的task5得不到机会运行,后来在老师的帮助下,将task任务线程睡眠,也就是延迟30个节拍,让task5得到机会能够运行。