基于μCOSII的贪吃蛇游戏嵌入式系统实现方案设计.docx
《基于μCOSII的贪吃蛇游戏嵌入式系统实现方案设计.docx》由会员分享,可在线阅读,更多相关《基于μCOSII的贪吃蛇游戏嵌入式系统实现方案设计.docx(23页珍藏版)》请在冰豆网上搜索。
基于μCOSII的贪吃蛇游戏嵌入式系统实现方案设计
西南石油大学
计算机科学与技术学院
嵌入式系统设计课程设计
设计题目:
基于μC/OS-II的贪吃蛇游戏
嵌入式系统实现方案设计
专业班级:
计算机科学学院2008级
(2)班
组员:
杨海威王坤
*********************************
设计时间:
2011/7/4~2011/7/8
设计地点:
明理楼B319
基于μC/OS-II的贪食蛇游戏设计
μC/OS-II实时操作系统简介
μC/OS-是一种免费公开源代码、结构小巧、具有可剥夺实时内核的实时操作系统。
μC/OS-II的前身是μC/OS,最早出自于1992年美国嵌入式系统专家JeanJ.Labrosse在《嵌入式系统编程》杂志的5月和6月刊上刊登的文章连载,并把μC/OS的源码发布在该杂志的BBS上。
μC/OS和μC/OS-II是专门为计算机的嵌入式应用设计的,绝大部分代码是用C语言编写的。
CPU硬件相关部分是用汇编语言编写的、总量约200行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的CPU上。
用户只要有标准的ANSI的C交叉编译器,有汇编器、连接器等软件工具,就可以将μC/OS-II嵌人到开发的产品中。
μC/OS-II具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点,最小内核可编译至2KB。
μC/OS-II已经移植到了几乎所有知名的CPU上。
严格地说μC/OS--II只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。
没有提供输入输出管理,文件系统,网络等额外的服务。
但由于μC/OS--II良好的可扩展性和源码开放,这些非必须的功能完全可以由用户自己根据需要分别实现。
一、方案论证
方案一
如图1.1所示,采用AT89C52和1602液晶显示。
AT89C52芯片是一款非常常用的芯片,具有32个IO口及多个定时器中断,添加外部ram后能够实现ucos-II的移植。
这里AT89C52作为主控芯片,实现多任务操作。
如1602不断刷新显示字符串,流水灯同时产生不同的变化。
图1.1系统框图
方案二
如图4.2所示,采用MSP430和KS0108的12864液晶显示。
MSP430系列是一个16位的、具有精简指令集的、超低功耗的混合型单片机。
KS0108是不带中文字库的128*64大液晶。
由这两个作为主要芯片,8个并行按键能实现基于ucos-II的贪食蛇游戏设计。
图4.2系统框图
方案三
如图所示,采用STC89C58RD+和ST7920的12864液晶显示
C58RD+有32KFLASH,256Bytes的片内RAM,1K的XRAM。
在资源方面完全满足ucos的移植,12864液晶采用带中文字库的ST7920芯片。
键盘由4*4矩阵键盘组成。
图1.3系统框图
方案对比
1、复杂度
从硬件来看最复杂的应该是方案一,需要扩展外部RAM存储器。
而且占用了一排通用IO口,造成了资源的浪费。
从软件来看最复杂的应该是方案二,MSP430虽然性能优越,但编程较为复杂,需要掌握更多的汇编指令。
2、实用性
显然第三种方案更为实用,需要的东西均为模块化设计,只需改动程序便可实现多种功能。
而方案二MSP430资源丰富,应该用于更为复杂的程序设计,在这里就有些大材小用了。
3、性价比
价格而言方案三与方案二基本差不多,主要是方案三采用国产的STC芯片价格更为实惠。
而方案二价格芯片价格较高,不适合做小游戏的开发。
综上所述,本课程设计采用方案三。
二、硬件系统设计
1、单片机最小系统
图2.1STC89C58RD+最小系统
2、12864液晶电路
液晶接口说明
1、VSS电源地
2、VDD电源正极
3、NC悬空
4、RS数据/命令选择端
5、RW读/写控制信号
6、E使能信号
7-14DataI/O
15、PSB串行/并行数据选择
16、NC空脚
17、/RST复位端
18、VOUT接10k到地
19、BLA背光正极
20、BLK背光负极
图2.212864液晶接口电路
3、矩阵键盘
采用4*4矩阵键盘
图2.3矩阵键盘
4、led闪烁电路
图2.4led闪烁电路
5、整体电路
见附录一
6、元器件清单
名称
数量
AT89C58RD+
1块
12864液晶模块
1块
电路基板
1块
按键
17个
40脚单片机底座
1个
排针20脚
1个
导线
若干
表2.1元器件清单
三、软件设计
1、程序框图
依据硬件系统设计,软件系统设计主要包括:
图3.1贪食蛇任务框图
图3.2ucos系统框图图3.3任务一框图
1、程序清单
见附录三
2、内核裁剪
未裁剪前:
ProgramSize:
data=40.1xdata=1744code=8561
裁剪内容:
修改OS_CPU.H文件:
#defineCPU_MAX_STK_SIZE0xF8改为0x28
修改OS_CFG.H文件:
#defineOS_MAX_TASKS10改为4
#defineOS_LOWEST_PRIO10改为4
裁剪后:
ProgramSize:
data=40.1xdata=1021code=8573
四、系统调试
1、软件调试
根据程序框图,写出对应的程序,在keilC中进行调试编译,生成.hex文件。
在Proteus中画出电路图,并装载上述生成的.hex文件,仿真观察结果,根据结果再对程序进行修改,调试,直到满意为止。
图4.1仿真电路图
2、硬件调试
2.1、检查元器件
在焊接之前应先检查各元器件的好坏。
按键:
按键有四个引脚,分为两对,每对之间是导通的,对角线上是断开的,按下按键时导通,则用万用表的二极管档逐一检查好坏。
2.2、排列元器件
由于本次课程设计采用的是万用板,元器件在电路上的排列要自己排列分布好,以为焊接减少不必要的麻烦。
2.3、焊接
在分布好元器件的格局后,开始焊接,先焊接单片机底座、排母、其它元器件。
焊接完元器件后即元器件分布在万用板上已定型。
然后根据电路图,用导线连接各引脚。
在用导线连接时应注意,导线焊接在元器件引脚上时剥皮部分长度要适中。
每焊完一个元器件都应该检查是否有错。
2.4、调试
按照电路图焊接完毕后,检查电路完毕后。
单片机和液晶先不装上去,接上电源,用万用表测试单片机和液晶的电源引脚,看其值是否正常,不正常检查电路调试直至正常。
以避免烧坏元器件。
完成以上步骤后,接上电源装上单片机和液晶,看是否实现功能。
如果出错,检查电路,调试,直至出现正确结果。
五、心得体会
本次课程设计与前几次的课程设计大有不同,第一次使用到了操作系统ucos。
这个操作系统虽然很小只有几K不到,但功能依然很强大。
Ucos_ii是开源免费的操作系统,而且流行使用已有快20年了,是一个学习资源丰富的操作系统。
此次ucos课程设计,学到的东西也很丰富,也很复杂。
就操作系统本身而言,移植就必须面临裁剪内核,只有对内核有一定的了解才可能深入的去裁剪一些不需要的模块,好在ucos_ii的移植性非常好,移植需要的代码一般情况下也就是三个主要的C程序,而需要的修改的部分也显得较为简单。
只需要修改一些数值,如#defineOS_MEM_EN0将0设置为1则表示启用该模块,为0则不使用该模块。
另外对于CPU堆栈空间的设定也是如此。
在实现多任务运行时,也有很多方面需要考虑到。
例如多任务的管理,毕竟CPU只有一个,怎样才能实现同时运行?
就需要了解每个任务的优先级的设定,该任务的运行时间,延时的分配。
这些都要先了解该操作系统才能进行的。
而在移植贪食蛇游戏就面临了12864芯片不同的情况。
已有的贪食蛇游戏是针对不带字库的12864编写的,而我的手上的12864却是带中文字库的。
首先在引脚连接方面就出现了不少情况,与一般的1602引脚接法不一样,VO可以悬空,但VOUT脚必须接10K电阻到地,否则液晶无法显示。
另外修改程序也花了很长一段时间,不过正是花费时间去考虑这些程序时才让我了解到一个大程序编写规则的重要性。
如果将每一个模块都像硬件设计那样分开模块,那么移植的时候只需要针对不同的芯片相应的改动程序即可。
所以在以后的编写程序中,规范化,模块化将是编程的重点。
六、参考文献
[1]JeanJLabrosse.嵌入式实时操作系统μC/OS-II[M].邵贝贝译.北京:
北京航空航天大学出版社,2003.
[2]任哲.嵌入式实时操作系统μC/OS-II原理及应用[M].北京:
北京航空航天大学出版社,2003.
[3]沈睿.μC/OS-Ⅱ在DSP2407上若干移植问题的研究[J].中国水运,2007,5(5):
:
43-44.
[4]马忠梅编著.单片机的C语言应用程序设计[M].北京:
北京航空航天出版社,2OO3.
[5]徐灵伟,刘飞.基于μC/OS-Ⅱ的嵌入式中断实现与扩展[C].北京:
中国控制与决策学会,2007:
999-1002
[6]ucos51移植心得,杨屹,巨龙公司系统集成开发部
七、附录
附录一
附录二
实物反面实物正面
附录三
#include"..\uc_os_II\includes.h"
OS_STKxdataTask1Stack[CPU_MAX_STK_SIZE];
OS_STKxdataTask2Stack[CPU_MAX_STK_SIZE];
sbitled1=P3^0;
voidTask1(voidxdata*ppdata)reentrant
{
ppdata=ppdata;
led1=0;
while
(1)
{
led1=~led1;
OSTimeDlyHMSM(0,0,0,500);
}
}
voidTask2(voidxdata*ppdata)reentrant
{
ppdata=ppdata;
while
(1)
{
snake12864();
OSTimeDlyHMSM(0,0,0,50);
}
}
voidInterruptInitial()
{
/*settimer.50ms,THTL=3cafwhencpuat12MHz*/
TMOD|=0x11;
TH0=0x70;
TL0=0x00;
/*TR0issetinOSStart()*/
ET0=1;
}
main()
{
InterruptInitial();
OSInit();
OSTaskCreate(Task1,(voidxdata*)0,&Task1Stack[0],2);
OSTaskCreate(Task2,(voidxdata*)0,&Task2Stack[0],3);
OSStart();
}
#include"..\driver\graphcode.h"
#include"..\driver\lcddriver.h"
#defineuintunsignedint
#defineucharunsignedchar
#defineup0x14
#definedown0x44
#defineleft0x28
#defineright0x22
#definequit0x11
ucharbdatasnake_flag;
sbitgameover=snake_flag^3;
sbitfood=snake_flag^2;
ucharnum=0;
uchartemp;
ucharidatasnake_len;
ucharxdatasnake[256][2];
ucharidatasnake_food[2];
uintmarker;
ucharno_counter;
voiddelayms(uintx)
{
uinti;
for(;x>0;x--)
for(i=0;i<1500;i++);
}
uchargetkey(void)
{
ucharcol_code,row_code;
P2=0xf0;
if(P2!
=0xf0)
{
delayms(5);
if(P2!
=0xf0)
{
row_code=0xfe;
while(row_code&0x10)
{
P2=row_code;
if(P2!
=row_code)
{
col_code=(P2&0xf0)|0x0f;
return((~row_code)|(~col_code));
}
elserow_code=(row_code<<1)|0x01;
}
}
}
return(0);
}
bitcompare(ucharx,uchary)
{
ucharcounter;
for(counter=0;counter{
if((snake[counter][0]==x)&&(snake[counter][1]==y))return(0);
}
return
(1);
}
voidset_food(void)
{
uchari,j;
bitcompare_flag;
i=TL0&0x3f;
j=TH0&0x3f;
if(i==0)i++;
if(i==0x4f)i--;
if(j==0x4f)j--;
if(j==0)j++;
do{
compare_flag=compare(i,j);
if(!
compare_flag)
{
i++;
j++;
if(i>63)i=1;
if(j>63)j=1;
}
}
while(!
compare_flag);
drawPoint(i,j,1);
snake_food[0]=i;
snake_food[1]=j;
food=1;
}
voidsnake_init(void)
{
marker=0;//分数初值
no_counter=0;//吃到的食物
snake_len=3;//蛇长度
drawPoint(31,30,1);//画蛇,位置
drawPoint(32,30,1);
drawPoint(33,30,1);
snake[0][0]=33;//数组中的量
snake[1][0]=32;
snake[2][0]=31;
snake[0][1]=30;
snake[1][1]=30;
snake[2][1]=30;
snake_flag=0x10;
drawRowLine(0,0,63,1);//横线
drawRowLine(0,63,63,1);
drawCollumLine(0,0,63,1);//竖线
drawCollumLine(63,0,63,1);
putstrxy(8,0,"score");//右框显示的内容
printf_number(8,1,0);
putstrxy(8,2,"按退出键");
putstrxy(8,3,"退出");
}
voidsnake_refresh()//刷新蛇
{
uchark;
for(k=snake_len;k>0;k--)
{
snake[k][0]=snake[k-1][0];
snake[k][1]=snake[k-1][1];
}
}
voidsnake_run(void)
{
uchari;
snake_refresh();
switch(snake_flag>>4)
{
case(0x08):
if(snake[0][1]==1)gameover=1;
elsesnake[0][1]--;
break;
case(0x04):
if(snake[0][1]==62)gameover=1;
elsesnake[0][1]++;
break;
case(0x02):
if(snake[0][0]==1)gameover=1;
elsesnake[0][0]--;
break;
case(0x01):
if(snake[0][0]==62)gameover=1;
elsesnake[0][0]++;
break;
default:
break;
}
for(i=(snake_len);i>0;i--)
{
if((snake[0][0]==snake[i][0])&&(snake[0][1]==snake[i][1]))
{
gameover=1;
break;
}
}
if(!
gameover)
{
if((snake[0][0]==snake_food[0])&&(snake[0][1]==snake_food[1]))
{
food=0;
snake_len++;
no_counter++;
marker=no_counter*100;
printf_number(8,1,marker);
}
else
{
drawPoint(snake[snake_len][0],snake[snake_len][1],0);
drawPoint(snake[0][0],snake[0][1],1);
}
}
if(no_counter>14)
gameover=1;
}
voidsnake_game(void)
{
ucharkey_code;
charlcdfill('');//显示清屏
putstrxy(4,0,"");
putstrxy(4,1,"贪吃蛇");
putstrxy(4,2,"by余世安");
putstrxy(2,3,"按任意键开始");
while(getkey()==0);
charlcdfill('');//显示清屏
snake_init();//初始化
do{
if(!
food)set_food();//设置食物
key_code=getkey();//判断按键
switch(key_code)
{
case0:
break;
caseup:
if((snake_flag&0xf0)==0x40)
break;
snake_flag=(snake_flag&0x0f)|0x80;
break;
casedown:
if((snake_flag&0xf0)==0x80)
break;
snake_flag=(snake_flag&0x0f)|0x40;
break;
caseleft:
if((snake_flag&0xf0)==0x10)
break;
snake_flag=(snake_flag&0x0f)|0x20;
break;
caseright:
if((snake_flag&0xf0)==0x20)
break;
snake_flag=(snake_flag&0x0f)|0x10;
break;
casequit:
charlcdfill('');//显示清屏
return;
default:
break;
}
snake_run();//游戏进行
delayms(10);//游戏速度
if(gameover&&(no_counter!
=15))
{
charlcdfill('');
glcdfill(0);
putstrxy(4,1,"GAMEOVER");
putstrxy(0,3,"按任意键重新开始");
while(getkey()==0);
return;
}
if(gameover&&(no_counter==15))
{
charlcdfill('');
glcdfill(0);
putstrxy(0,1,"Congratulation!
!
");
putstrxy(0,3,"按任意键重新开始");
while(getkey()==0);
return;
}
}
while
(1);}
voidsnake12864(void)
{
lcm_init();
charlcdfill('');//显示清屏
lcdgraphon();//开图形模式
GXPOS=0,GYPOS=0;
putimage(Img_1);
delayms(300);
glcdfill(0);//图形区域清屏
lcdgraphoff();//关图形模式
while
(1)
snake_game();
}