1、基于 ARM9的贪吃蛇游戏 摘要 本课程设计 是使用我们学习过的嵌入式系统的有关知识,在 ARM9 嵌入式硬件开发平台和 C/OS-II的软件开发框架下,实现一个还有 AD转换,按键, LCD等硬件功能的实时多任务的简单贪吃蛇的设计。 文中首先 C/OSII 系统和 ARM9进行了介绍,然后对设计要求进行分析,给出了系统总体上设计,并对各个功能模块进行了介绍,紧接着给出了 系统软件设计,最后介绍了系统的调试方法和测试结果 。 关键词: C/OS ARM9 嵌入式 贪吃蛇 一 开发环境简介 1、 C /OS-II 操作系统 C/OS -II是一种可移植的,可植入 ROM的,可裁剪的,抢占式的,实
2、时多任务操作系统内核。它被广泛应用于微处理器、微控制器 和数字信号处理器。 uC/OS-II 只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。没有提供输入输出管理,文件系统,网络等额外的服务。但由于 uC/OS-II良好的可扩展性和源码开放,这些非必须的功能完全可以由用户自己根据需要分别实现。 uC/OS-II目标是实现一个基于优先级调度的抢占式的实时内核,并在这个内核之上提供最基本的系统服务,如信号量,邮箱,消息队列,内存管理,中断管理等 C/OS-II 是专门为计算机的嵌入式应用设计的, 绝大部分代码是用 C 语言编写的。 CPU
3、 硬件相关部分是用汇编语言编写的、总量约 200 行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的 CPU 上。 C /OS-II 中最多可以支持 64 个任务,分别对应优先级 0 63,其中 0 为最高优先级。 63 为最低级,系统保留了 4 个最高优先级的任务和 4 个最低优先级的任务,所有用户可以使用的任务数有 56 个,每个任务都有不同的优先级,用户在创建任务的时候定义该任务的优先级。 C/OS 操作系统中每个任务可以有 5 种状态:休眠态、就绪态、运行态、等待或挂起状态、中断态,在任一个时候,任务的状态一定是 这 5 种状态之一。任务在等待消息、邮箱或者信号量等事件的
4、到来的时候会进入挂起状态,当任务接到消息以后,则处于就绪状态。 uC/OS-II的时间管理是通过定时中断来实现的,该定时中断一般为 10毫秒或 100毫秒发生一次,时间频率取决于用户对硬件系统的定时器编程来实现。中断发生的时间间隔是固定不变的,该中断也成为一个时钟节拍。 uC/OS-II 要求用户在定时中断的服务程序中,调用系统提供的与时钟节拍相关的系统函数,例如中断级的任务切换函数,系统时间函数。 在 ANSI C 中是使用 malloc 和 free 两个函数来动态分配和释放内存。但在嵌入式实时系统中,多次这样的操作会导致内存碎片,且由于内存管理算法的原因, malloc 和 free 的
5、执行时间也是不确定。 uC/OS-II 中把连续的大块内存按分区管理。每个分区中包含整数个大小相同的内存块,但不同分区之间的内存块大小可以不同。用户需要动态分配内存时,系统选择一个适当的分区,按块来分配内存。释放内存时将该块放回它以前所属的分区,这样能有效解决碎片问题,同时执行时间也是固定的。 对一个多任务的操作系统来说,任务间的通信 和同步是必不可少的。uC/OS-II中提供了 4 种同步对象,分别是信号量,邮箱,消息队列和事件。所有这些同步对象都有创建,等待,发送,查询的接口用于实现进程间的通信和同步。 uC/OS-II 采用的是可剥夺型实时多任务内核。可剥夺型的实时内核在任何时候都运行就
6、绪了的最高优先级的任务。 uC/os-II的任务调度是完全基于任务优先级的抢占式调度,也就是最高优先级的任务一旦处于就绪状态,则立即抢占正在运行的低优先级任务的处理器资源。为了简化系统设计, uC/OS-II 规定所有任务的优先级不同,因为任务的优先级也同时唯 一标志了该任务本身。 随着信息化技术的发展和数字化产品的普及,以计算机技术、芯片技术和软件技术为核心的嵌入式系统再度成为当前研究和应用的热点。 对功能、可靠性、成本、体积和功耗严格要求的嵌入式系统一般由嵌入式微处理器、外围硬件设备、嵌入式操作系统以及用户的应用程序等四个部分组成,其中嵌入式微处理器和嵌入式操作系统分别是其硬件和软件的核心
7、。 ARM处理器由于其具有小体积、低功耗、低成本、高性能等特点,广泛应用在 16/32 位嵌入式 RISC 解决方案中,几乎占有嵌入式微处理器市场分额的 75% ,本文选定三星 公司生产的一款基于 ARM920T 核的高性能低功耗SOC芯片 S3C2410 作为移植方案的硬件平台。市场上主流的嵌入式实时操作系统有 Vxworks、 pSos、 WinCE、 Linux 等,基于实时性、成本以及开发难度方面的考虑,我们选择 uC/OS II 开放源代码的嵌入式实时操作系统。 采用基于 ARM9 的 S3C2410 嵌入式微处理器,可以使系统具备高性能的运算能力的同时便于与各种外设连接扩展,简化了
8、硬件设计,维持小型化的同时降低了系统成本。 uC/OS II 作为一个源代码公开的操作系统,在具体应用中稳定可靠,并且支 持 uIP TCP/IP 协议栈、 ucGUI 等,可扩展性强,功能强大。本系统采 ARM9+uC/OS II 开发设计,具有精度高、运行稳定、实时性好、抗干扰能力强、性价比高的特点,可以在各种工业场合中广泛应用,达到了设计的初衷 。 2、 试验箱基本硬件信息 1 S3C2410-S Core 小板:采用 S3C2410X 处理器, 64M NANDFLASH 64RAM。 2 Double 100M EtherNet网卡:均由 AX88796 构成,采用现有电路但分配不同
9、地址。 3 4 HOST / 1 DEVICE USB 接口:主 USB 口扩展为 4个,由 AT43301 构成 USB HUB,其中电源管理用 MIC2525。 USB 从口保持处理器本身的 1个。 4 3 UART/IrDA:保持 2个 RS232 串口,增加 1个 RS485 串口, 1个 IrDA 收发器,均从处理器的 UART2 引出。 5 168Pin EXPORT:有一个 168Pin 扩展卡插槽,并去掉已经被主板上各模块占用的资源。网卡部分还在局部总线上,其余电路包括 168Pin 扩展槽都在外部总线。 6 LCD:兼容多种 LCD,可采用 5 寸 256 色屏或 8 寸 1
10、6bit 真彩屏,同时预留一个 24bit 接口。可以支持板外 8bit 或 24bit 屏。 7 TouchScr:采用 ADS7843,预备了直接用 2410 内部 ADC 构成的转换电路接口 8 AUDIO:采用 UDA1341,具有放音、录音等功能。 9 PS2 KEYPAD:使用 ATMEGA8 单片机控制 2个 PS2 接口和 板载 17键小键盘。两个PS2 可接 PC 键盘和鼠标。 10 LED:使用 ZLG7290 只驱动 8 只小数码管。同时可作 IIC 总线实验。 11 POWER SUPPLY、 RESET、 RTC 等必须资源。 12 ADC: 板载 3个电位器和选择跳
11、线,同时在板上设模拟电压输入专用接口。 13 IDE/CF 卡插座:支持 2.5 英尺的笔记本硬盘读写和 IDE 模式下的 CF 卡读写。 14 PCMCIA 和 SD 卡插座:由 EPM3128A100 CPLD 实现。 15 IC 卡插座。由 ATMEGA8 单片机控制。 16 DC/STEP 电机。步进电机采用 74HC573 扩展 IO,软件形成时序来控制。同时剩余 IO 可以控制 CAN 等电路,以节省 CPU 的 GPIO 资源。 17 CAN BUS:设置 1个 CAN 口,采用 MCP2510 和 TJA1050。 18 Double DA:设置两个 DAC 端口,采用 MAX
12、504 接 SPI 总线。 19 GPRS/GPS 扩展板不做在主板上,单独设计扩展板。注意 GPS 的 RS232 需要增加 MAX3232芯片来转换为 TTL 才能引到 168Pin 插座上。 3 、 ADS1.2 集成开发环境 ADS1.2 ADS 是 ARM 公司的 集成开发环境, 他的功能非常强大。 ADS 包括了四个模块分别是: SIMULATOR; C 编译器; 实时调试器;应用函数库。ADS1.2 提供完整的 WINDOWS 界面开发环境。 C 编译器效率极高,支持 c 以及 c+,使工程师可以很方便的使用 C语言进行开发。提供软件模拟仿真功能,使没有 Emulators 的学
13、习者也能够熟悉 ARM 的指令系统。配合 FFT-ICE使用, ADS1.2 提供强大的实时调试跟踪功能 ,片内运行情况尽在掌握。ADS1.2 需要硬件支持才能发挥强大功能。目前支持的硬件调试器有Multi-ICE 以及兼容 Multi-ICE 的调试工具如 FFT-ICE。 ADS 由命令行开发工具, ARM 实时库, GUI 开发环境 (Code Warrior 和AXD),适用程序和支持软件组成。有了这些部件,用户就可以为 ARM系列的RISC 处理器编写和调试自己的开发应用程序了。 二 系统设计要求 贪吃蛇游戏是一款经典的小游戏,它的原型是 1976 年, Gremlin 平台推出了一
14、款经典街机游戏 Blockade。 真正走红的是该游戏 随诺基亚手机走向世界 。本课程设计 有关贪吃蛇的 功能描述: 1、 可以通过嵌入式平台的键盘控制游戏,键盘中起作用的是方向键( 2,4,6,8)和 回车键,方向键控制蛇的上下左右运动,回车键控制游戏的继续和暂停。 2、 贪吃蛇由若干 连续 黄色 方块构成,程序中随机出现一些 “ 食物 ” (用蓝色的方块表示 ),贪吃蛇通过吃“食物”增加自身的长度并增加相应的分值。 3、 游戏分三个关口,第一关没有障碍物,第二关有 2 个障碍物,第三关有四个障碍物 。 4、 贪吃蛇撞到矩形边界,障碍物或者自己身体的一部分,游戏即结束,重新开始 。 5、 为
15、了增加难度,加入 AD 转换器用于控制蛇的运动速度,这也是本设计的创新点 。 6、 贪吃蛇每吃一个食物分数会增加,屏幕上显示得分 和 游戏所用时间。 三 系统总体设计 本设计需要创建两个任务, 系统结构框图如图 3-1 所示, 任务状态切换如 图3-2 所示 。具体的任务流程和任务所要完成的功能如下: 在系统启动后,同时创建两个任务,任务一 main_task 和 任务二 snake_task。任务 一 主要功能是等待键盘消息,有键盘消息的时候判断是什么键盘,并对相应的变量重新赋值。任务 二主要 功能是控制并在屏幕上显示蛇的移动和速度,并完 图 3-1 系统结构框图 图 3-2 任务切换框图
16、任务一,任务二就绪 是否有键盘消息 任务一挂起 任务二运行 任务二挂起 任务一运行 系统初始化 任务一 任务二 等待键盘消息 控制蛇移动 AD采样 LCD显示 图 3-3 系统主任务流程框图 成对分数 , 游戏等级和其他相关参数的记录和显示。任务一为主任务,在创建任务的时候,赋给它的优先级别 比任务二 高,所以任务一优先运行,任务二处于就绪状态,因为任务一主要是等待键盘消息,在无键盘消息的时候,任务一被挂起,这时候任务二进入运行状态。 1、 任务一程序流程框图 如图 3-3所示 , 该任务完成对键盘消息的接收,识别,并改变相应变量 2、任务二流程图: 如图 3-4 所示, 主要功能是控制 蛇的
17、速度 并在屏幕上显示蛇的移动,并完成对分数、游戏等级、和 游戏用时 的记录和显示。 四 系统具体 功能 的 实现 1 初 始化 初始化 包括了硬件初始化 和软件初始化 。硬件初始化主要有 AD 转换器的初始化, LCD 的初始化,串口初始化, ARM 目标板的初始化等,软件初始化 包括了系统初始化,游戏初始化 。系统初始化包括了任务的建立,信号量的创建,变量的创建,系统文件初始化,初始化绘图设备上下文,系统实时时钟的初始化和函数的声明等,游戏的初始化,包括了有关参数属性的初始化化和游戏界面的初始化。 硬件初始化: #define ADCCON_FLAG (0x1Type=TP_SkHead;
18、xNode-isBlock=1; HeadNode=xNode; UpdateNextNode(xNode,Left); xNode-PreDir=Left; /Snake Body xNode= xNode-Type=TP_SkBody; xNode-isBlock=1; UpdateNextNode(xNode,Left); xNode-PreDir=Left; /Snake Tail xNode= xNode-Type=TP_SkTail; xNode-isBlock=1; TailNode=xNode; UpdateNextNode(xNode,Left); xNode-PreDir=
19、Left; RandCake(); 2 判断蛇是否吃到食物 判断蛇是否吃到食物的方法比较简单,只要判断蛇头的 属性是否和下一个节点的属性 一样。吃到食物后改变响应的游戏参数,并要让蛇的节数多 三 节,这时候要让变量 lenadd加 3, 并且还要对蛇补画上一节,本设计采用补上蛇头的方法,要注意根据此时蛇的运动方向来确定新蛇头的坐标。,以后食物产生子程序能够判断食物已经被蛇“吃到”了,要重新产生食物。 if(HeadNode-Type=TP_Cake) score+; if(score=5) flag1=1; else if (score=10) flag2=1; LenToAdd+=CakeL
20、ength; RandCake(); 3 判断游戏是否结束 (1) 蛇头撞到蛇身 判断蛇是否撞到蛇身的方法可以从蛇头开始依次开始判断蛇头 的属性是否和下一个方块的属性相同 ,一样的话即表明蛇撞到蛇身了,此时游戏结束。 (2)蛇头撞到游戏界面边框 判断蛇是否撞到边框的方法,只要比较蛇头的 属性 是不是同时边框的 属性一样,一样的话,即表明蛇撞到边框,游戏结束。 If ( HeadNode - isBlock ) nRet = 1;/Hit a Block goto SnakeStep_End; 4 蛇移动功能 这部分功能是游戏的主体,实现蛇移动的方式是首先擦除蛇尾,擦除的方发是 改变蛇尾的属性
21、, 通过调用绘图上下文设备, 蛇尾就变成白色底色不可见,然后从蛇尾开始,依次 改变下一个节点的属性 。例如刚开始蛇是 5 节,这时候依次把第 2 四节 的属性 给第 1 节;把第 3 节(即蛇头)的 属性 给第 2 节;把第 4 四节的 属性 给第 3 节;把第 4 节(即蛇头)的 属性 给第 3 节;把第 5 节(即蛇头)的属性 给第 4 节。擦除蛇尾和转移坐标这两个顺序不能颠倒。这时候蛇头的 属性 和第 4 节的 属性是一样的,这时候需要判断蛇的方向变量 的值,根据 蛇的方向变量的值补画上蛇头。 If ( LenToAdd != 0) LenToAdd -; else TailNode -
22、 Type= TP_Space; TailNode - IsBlock = 0; DrawPoint ( TailNode ); /old tail TailNode = TailNode - Next; TailNode - Type = TP_SkTail; DrawPoint ( TailNode ); /new tail HeadNode- Type = TP_SkBody; /old head DrawPoint ( HeadNode ); HeadNode - Next - PreDir = HeadNode - Dir; /save predir HeadNode = HeadN
23、ode - Next; /new head 5 食物的产生 食物的产生主要要注意食物产生之前,我们必须要判断画面上面是已经存在食物,如有已经存在食物了,就不再产生食物,如果食物被蛇吃到了,那就要重新画上食物。本设计是 通过在每次吃完食物后调用随机产生食物函数 ,另外还要保证食物不能超出蛇的活动界面,并要保证食物能被蛇吃到,所以需要指定食物坐标的范围,被通过舍去食物坐标个位的方法保证食物坐标是整十,这样就能被蛇吃到。本设计用一个矩形方框来代表食物,所以通过上面介绍的方法产生食物坐标后,对应在该坐标的位置画上一个矩形方框。 void RandCake (void) /Get a new rand
24、cake position INT32U x,y; While (1) X = rand () %W_XSize; Y = rand () %W_YSize; if( !WorldArrayyx.isBlock ) break; CakeNode = CakeNode - Type = TP_Cake; DrawPoint ( CakeNode ); 5、监听键盘动作 : 任务通过等待消息而处于挂起状态,当任务接到消息以后,则处于就绪状态,然后开始判断所接受到的这个消息是不是需要处理,如果是执行相应的处理函数,最后,删除所接收到的消息,继续挂起等待下一条消息。 void Main_Task (
25、 void *Id ) POSMSG pMsg=0;/定义消息结构 ClearScreen ();/清屏 WorldSem = OSSemCreate (1); GameRun = OSSemCreate (1); Pdc = CreateDC (); SetLCDUpdata ( pdc , FALSE ); /消息循环 For ( ; ; ) pMsg = WaitMessage ( 0);/等待消息 switch ( pMsg - Message) case OSM_KEY:/键盘消息 onKey ( pMsg - WParam , pMsg - LParam ); break; DeleteMessage ( pMsg );/删除消息 DestoryDC(pdc); 6 AD 控制蛇速度 在每次蛇前进一步后,通过刷新 LCD 屏幕来显示画面和相关参数,紧接着占用系统信号量,占用的时间是同过当前游戏的关口和调用 AD 采样函数来确定的额,游戏关口越高,蛇的前进速度越快, AD采样值越小,蛇的前进速度越快。 OSTimeDly ( GetSpeed (gamelevel);