贪吃蛇结题报告

代码

题目意义

这次微机实验,我们选择的题目是贪吃蛇街机小游戏。简单来讲就是使用微机试验台上的led点阵作为显示屏,配合计数操作显示得分情况,利用键盘进行IO操作的贪吃蛇小游戏。之所以选择这个题目是因为我想在有限的实验条件上极可能的做出一个比较有趣的项目。由此可见,此题目的意义就是探求自己在简陋的实验环境中做出复杂工程的能力,同时也是在检验自己在微机课程中所学到的知识是否扎实。

设计思想

  1. 图像显示
    使用led点阵将贪吃蛇的位置和食物的位置显示出来,首先我们必须提供一个底层的方法来方便地将led灯进行点亮,这就促使我们引入了缓存地概念(下面再说)和一个读取缓存地内容进行点亮灯的方法。
  2. 图像显示的缓存
    为了方便的进行led的显示,我门引入了缓存的概念,即将要显示的led点阵的信息以比特的形式存储在内存中,命名为red_buffer和green_buffer
  3. 图像操控
    为了方便的修改缓存中的信息,我们实现了一个函数将特定位置的额灯的颜色置红,值绿或者置暗。
  4. 中断
    使用8253产生定时中断为系统提供时间基准。
  5. IO输入
    由中断驱动进行IO操作,将键盘等的输入存入内存。
  6. 时分复用
    由于试验台上的输出端口不够用了,所以为了添加数码管功能,我们引入了时分复用的概念,即利用led点阵灭的那一瞬间将数码管点亮,这样既不会影响led点阵也可以实现点亮数码管。

采用的主要技术,遇到的难点和解决方法

  1. led点阵驱动
    led点阵驱动提供了make_it_red、make_it_green、make_it_dark等底层方法来供上层控制led点阵的缓冲区内容,而led点阵驱动的硬件交互部分又通过读取缓冲区的内容来按照用户设想的方式亮灯。

    1. 难点
      操作内存与硬件底层相衔接的问题。即如何方便的在软件层面上控制底层led亮。
    2. 解决方法
      引入了缓冲区的概念,系统存在两个led点阵的缓冲区,分别为ren_buffer和green_buffer,分别用来存储led点阵上灯亮的信息,这两个缓冲区都为8字节的数据,其中每一个比特控制每一个灯的亮的情况,利用这两个缓冲区就可以将led灯亮的信息存储在内存中,led底层控制模块只需要读取这两个内存区就可以将led点阵按预设的点亮了。
    3. 难点
      没有足够的端口点亮数码管
    4. 解决方法
      引用了时分复用的概念,将led点阵和数码管点亮的过程时分复用,解决了输出端口不够的问题。由于每一次led点阵点亮过后,存在一段时间led点阵的所有列信息为零,所以此时复用使用的8255PA连接数码管的段码显示,就可以利用有限的端口点亮数码管了。
  2. IO输入控制
    IO输入控制负责定时的读取外设的输入信息,并且将其信息存储到内存中的缓冲区。

    1. 难点
      如何定时的获取输入内容
    2. 解决方法
      使用8253设置定时中断连接在IRQ10上,由此可以实现定时的扫描键盘等外设的输入,键盘输入程序中使用BIOS提供的16号中断获取键盘输入数据。
    3. 难点
      如何在将外设的输入存储到内存中。
    4. 解决方法
      以键盘为例,在内存中开辟一个键盘输入的缓冲区,keyboard_input,其为16位的字,低1位到第9位存储了1-9按键是否被按下的信息。10-13存储WASD按键的信息。
  3. 时间同步
    程序需要一个全局的同步时间量来控制每一个模块进行同步操作。

    1. 难点
      如何获取当前时间呢。
    2. 解决方法
      在上文提到的额中断程序中加上时间量处理,即每一次中断将全局的时间同步量加一。
  4. 状态机
    整个程序就是一个巨大的状态机。

    1. 难点
      控制每一个状态的转换
    2. 解决方法
      使用一个缓冲区status来存储当前状态信息,程序利用该内存数据进行状态的转移。

实现的主要功能和系统结构

主要功能

  1. 状态机。
    整个程序就是一个巨大的状态机。使用一个缓冲区status来存储当前状态信息,程序利用该内存数据进行状态的转移。

  2. 键盘输入。
    读取键盘输入并存储

  3. 点亮数码管。
    将游戏的得分信息在使用数码管进行显示。

  4. 控制led点阵任一灯的亮暗。

  5. 控制led点阵按预定信息亮。

  6. 贪吃蛇主体程序

  7. 输入信息处理程序

  8. 时间同步程序

系统结构

时间同步程序为所有的程序提供一个时间的基本量,中断程序为负责定时读取输入和更新时间同步量,向上提供输入和同步,状态处理模块负责读取输入信息和状态信息进行状态的控制操作。在进入贪吃蛇主体程序之后,程序通过读取外设的输入信息控制贪吃蛇的移动,并通过贪吃蛇的逻辑控制来控制贪吃蛇的状态信息,并且实时的调用led点阵来动态显示贪吃蛇的位置以及使用数码管动态显示贪吃蛇得分信息。

相关技术说明

  1. 缓冲区
    程序的所有所欲信息和状态都存储在缓冲区中,功能之间上下游分别负责存入和读取改变缓冲区,由此来驱动程序的运行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    ;红色   颜色是通过列线进行输出的
    red_buffer byte 8 dup(0)
    ;绿色
    green_buffer byte 8 dup(0)
    ;infrared_input_buffer 存储红外线输入的缓冲区 每一个bit可以自由定义其含义
    infrared_input_buffer word 0
    ;keyboard_input_buffer 存储键盘输入的缓冲区 每一个bit可以自由定义其含义
    keyboard_input_buffer word 0
    ;Status buffer 状态缓冲区,用来存放程序运行的各种状态
    status_buffer word 0
    ;时间缓冲区,负责提供同步信息 由中断程序每隔10ms加一
    sync_time_buffer word 0
    ;蛇身位置 不包含蛇头 蛇的每一个位置需要两个字节,8*8*2=128B
    snake_body_buffer byte 128 dup(0)
    ;蛇身的长度,不包括蛇头,也是当前的分数
    snake_body_length word 0
    ;蛇头位置
    snake_head_position_x byte 0
    snake_head_position_y byte 0
    ;蛇尾位置
    snake_tail_position_x byte 0
    snake_tail_position_y byte 0
    ;食物位置
    food_x byte 0
    food_y byte 0
    ;是否吃了食物 0:没有 1:吃了
    food_eaten byte 0
    ;碰撞与否
    collision byte 0
    ;蛇的前近方向 2:上 0:下 2;左 1:右
    snake_direction byte 0
    ;保存原中断程序入口
    int_0b_seg word 0
    int_0b_off word 0
    ;蛇的时间量,每经过100个全局时间量 加一,即蛇每1s移动一次
    snake_time word 0
    ;数码管
    ledtb byte 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh,6fh
    ;得分(当前长度减去初始长度)存储 分别存储四个数码管的数字
    lednum byte 4 dup(0)
  2. 状态机。
    整个程序就是一个巨大的状态机。使用一个缓冲区status来存储当前状态信息,程序利用该内存数据进行状态的转移。

  3. IO输入控制
    IO输入控制负责定时的读取外设的输入信息,并且将其信息存储到内存中的缓冲区。
    使用8253设置定时中断连接在IRQ10上,由此可以实现定时的扫描键盘等外设的输入,键盘输入程序中使用BIOS提供的16号中断获取键盘输入数据。在内存中开辟一个键盘输入的缓冲区,keyboard_input,其为16位的字,低1位到第9位存储了1-9按键是否被按下的信息。10-13存储WASD按键的信息。

  4. led点阵驱动
    led点阵驱动提供了make_it_red、make_it_green、make_it_dark等底层方法来供上层控制led点阵的缓冲区内容,而led点阵驱动的硬件交互部分又通过读取缓冲区的内容来按照用户设想的方式亮灯。系统存在两个led点阵的缓冲区,分别为ren_buffer和green_buffer,分别用来存储led点阵上灯亮的信息,这两个缓冲区都为8字节的数据,其中每一个比特控制每一个灯的亮的情况,利用这两个缓冲区就可以将led灯亮的信息存储在内存中,led底层控制模块只需要读取这两个内存区就可以将led点阵按预设的点亮了。将led点阵和数码管点亮的过程时分复用,解决了输出端口不够的问题。由于每一次led点阵点亮过后,存在一段时间led点阵的所有列信息为零,所以此时复用使用的8255PA连接数码管的段码显示,就可以利用有限的端口点亮数码管了。

总结和体会

计算机领域的知识都是相通的,之前在操作系统学到了复用的概念于是在本次实验中就利用复用解决了输出端口不够的问题。还有缓冲区的概念和封装的和概念。程序将分散的功能封装为一个一个小模块,使得程序的调用更加方便了。缓冲区为个模块提供信息交互的通道。

计算机知识博大精深,要好好学习。不要沉迷于上层技术,其实底层原理是更加令人着迷的,只要学好了计算机的底层原理,使用计算机底层原理的方式进行思考问题往往会获得意想不到的结果。