搜档网
当前位置:搜档网 › VHDL课程设计之打地鼠游戏报告-含代码

VHDL课程设计之打地鼠游戏报告-含代码

题目:VHDL课程设计之打地鼠游戏

专业:信息工程

班级:电联

学生姓名:

提交日期:2015年03月05日

目录

一、设计任务与要求 (3)

二、总体框图 (3)

2.1 总体框图 (3)

2.2 设计思路及各模块功能 (3)

2.2.1 设计思路 (3)

2.2.2 各模块功能 (3)

三、选择器件 (4)

四、模块功能实现 (7)

4.1 分频器模块 (7)

4.2 随机数产生模块1 (8)

4.3 随机数产生模块2 (9)

4.4 键盘控制模块 (10)

4.5 计分器模块 (14)

4.6 LCD1602 地鼠显示模块 (15)

4.7 数码管显示模块 (17)

五、总体设计电路图 (18)

六、游戏说明书 (18)

6.1 前言 (18)

6.2 运行说明 (18)

6.3 评分规则 (18)

七、心得体会 (19)

一、设计任务与要求

设计一个挑战反应速度的“打地鼠”游戏机。要求:地鼠随机出现在任何位置,以按键代表锤子,击中地鼠,一旦击中,数码管计分器分数增加。按复位键重新开始游戏。

二、总体框图

2.1、打地鼠游戏机的总体框图如下图所示:

电路设计总体框图

2.2、设计思路及各模块功能:

2.2.1设计思路:

产生伪随机数使地鼠随机出现,外接LCD1602显示地鼠随机出现的位置,以一个特殊字符表示地鼠。游戏者按下按键,与地鼠出现的位置代表的伪随机数进行比较,若一致,计分器进行加分。按下ESC键进行复位,利用50MHz分频作为基本信号源。

2.2.2各模块功能介绍:

——分频器模块

将50MHz的信号源分别分频为游戏所需频率的时钟信号1Hz。

——伪随机数产生模块

产生伪随机数,使得地鼠出现位置随机。

——计分模块

接收来自键盘控制模块的信号,正确一次加一分。

——LCD显示模块

在1HZ时钟信号下,根据产生的伪随机数使得2*16的LCD屏上随机出现代表地鼠的字符。

——键盘控制模块

玩家按下地鼠出现的位置可能对应的按键,按键地址与地鼠出现的位置对应的伪随机进行比较,若一致,输出一个为‘1’的correct信号。

——计分模块

接收来自键盘控制模块的信号,正确一次加一分。

——数码管显示模块

通过数码管,将计分模块的计分结果显示出来。

三、器件选择

设计开发软件:Quartus2 8.1/9.0

主芯片:

1. FPGA芯片: EP2C8Q208C8

EP2C8Q208C8:含8,256 Les; 165,888 RAM bits; 2个PLL;18 Multipliers;139个I/O口

2.配置芯片: EPCS1 / EPCS4 FPGA串行配置芯片含1 M bit Flash / 4 M bit Flash EP2C5Q208C8:配置EPCS1EP2C8Q208C8:配置EPCS4

3. FLASH: AM29LV160DB 16M bit(2 M×8 Bit/1 M×16 Bit)

4. SRAM: IS61LV25616 256K×16 Bit

5. I2C存储器电路: 24LC16B 16K bit(8 Blocks×256×8 Bit)

6. SPI存储器电路: 93LC46B 1K bit(64×16 Bit)

7.有源晶振: 50 MHz

8.电源芯片: LM1117-3.3V、LM1117-1.5V

9.调试接口: AS、JTAG调试接口

10.核心板尺寸:100mm×79mm

外接LCD1602显示屏

工业字符型液晶,能够同时显示16x02即32个字符。(16列2行)

注:为了表示的方便,后文皆以1表示高电平,0表示低电平。

1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。

1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。

市面上字符液晶大多数是基于HD44780液晶芯片的,控制原理是完全相同的,因此基于HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液晶。

2管脚功能

1602采用标准的16脚接口,其中:

第1脚:GND为电源地

第2脚:VCC接5V电源正极

第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会产生“鬼影”,使用时可以通过一个10K 的电位器调整对比度)。

第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。

第5脚:RW为读写信号线,高电平(1)时进行读操作,

以51为例的简单原理图

低电平(0)时进行写操作。

第6脚:E(或EN)端为使能(enable)端,高电平(1)时读取信息,负跳

变时执行指令。

第7~14脚:D0~D7为8位双向数据端。第15~16脚:空脚或背灯电

源。15脚背光正极,16脚背光负极。

特性

3.3V或5V工作电压,对比度可调

内含复位电路

提供各种控制命令,如:清屏、字符闪烁、光标闪烁、显示移位等多种功能有80字节显示数据存储器DDRAM

内建有192个5X7点阵的字型的字符发生器CGROM

8个可由用户自定义的5X7的字符发生器CGRAM

特征应用

微功耗、体积小、显示内容丰富、超薄轻巧,常用在袖珍式仪表和低功耗应用系统中。

操作控制

注:关于E=H脉冲——开始时初始化E为0,然后置E为1。

外接PS/2键盘进行控制

四、功能模块

4.1 分频器模块

分频器模块接收晶振提供的50MHz时钟信号,通过计数将其分频为1s的时钟脉冲信号并输出。

输出秒脉冲的VHDL程序如下:

LIBRARY IEEE;

USE IEEE.std_logic_1164.ALL;

use ieee.std_logic_unsigned.all;

ENTITY divider IS

PORT(

clk:IN STD_LOGIC;

rst_n:IN STD_LOGIC;

clk_1HZ:BUFFER STD_LOGIC

);

END divider;

ARCHITECTURE behav OF divider IS

BEGIN

PROCESS(clk,rst_n)

VARIABLE count:INTEGER range 0 TO 50000000;

BEGIN

IF rst_n='0' THEN

count:=0;

ELSIF clk'event AND clk='1' THEN

IF count=25000000 THEN

count:=0;

clk_1HZ<=NOT clk_1HZ;

ELSE

count:=count+1;

END IF;

END IF;

END PROCESS;

END behav;

4.2 随机数产生模块1

以下程序为产生4位伪随机数的代码,取ram为一个4位数,将第1位和第4位进行同或得结果feedback,将ram的前3位和feedback合并取代原来4位的ram,新的ram即是得到的一个伪随机数,不停的反复就可得到一组序列为16的伪随机数。这个伪随机数产生器的伪随机数传递给LCD显示屏。

Library IEEE ;

use IEEE.std_logic_1164.all ;

use IEEE.std_logic_arith.all ;

entity bee is

port (

clk : in std_logic ;

reset : in std_logic ;

data_out : out UNSIGNED(3 downto 0)

);

end bee ;

architecture rtl of bee is

signal feedback : std_logic ;

signal ram : UNSIGNED(3 downto 0) ;

begin

feedback <= ram(3) xnor ram(0) ;

latch_it : process(clk,reset)

begin

if (reset = '1') then

ram <= (others => '0') ;

elsif (clk = '1' and clk'event) then

ram <= ram(2 downto 0) & feedback ;

end if;

end process;

data_out <= ram(3 downto 0);

end RTL;

4.3 随机数产生模块2

原理同随机数产生模块1,产生的伪随机数传递给键盘控制模块。

Library IEEE ;

use IEEE.std_logic_1164.all ;

use IEEE.std_logic_arith.all ;

entity lai2 is

port (

clk : in std_logic ;

reset : in std_logic ;

data_out : out UNSIGNED(3 downto 0)

);

end lai2 ;

architecture rtl of lai2 is

signal feedback : std_logic ;

signal ram : UNSIGNED(3 downto 0) ;

begin

feedback <= ram(3) xnor ram(0) ;

latch_it : process(clk,reset)

begin

if (reset = '1') then

ram <= (others => '0') ;

elsif (clk = '1' and clk'event) then

ram <= ram(2 downto 0) & feedback ;

end if;

end process;

data_out <= ram(3 downto 0);

end RTL;

4.4 键盘控制模块

根据得到伪随机产生模块传递的信号num1,将此时按下的按键地址与伪随机数所代表的0地址进行比较,若一致,则输出为‘1’的correct信号给下面的计分器模块。

library IEEE;

use IEEE.std_logic_1164.all;

use IEEE.std_logic_arith.all;

use IEEE.std_logic_unsigned.all;

entity ps2scan is

port( clk: in STD_LOGIC;

rst_n: in STD_LOGIC;

num1: in std_logic_vector(3 downto 0);

ps2k_clk: in STD_LOGIC;

ps2k_data: in STD_LOGIC;

LCD_Data:in std_logic_vector (8 downto 0);

correct:out std_logic;

signal resss:out std_logic;

led: out STD_LOGIC_VECTOR (5 downto 0)

);

end entity ps2scan;

architecture ps2receive of ps2scan is

signal ps2k_clk_r: STD_LOGIC_VECTOR (2 downto 0);

signal neg_ps2k_clk: STD_LOGIC;

signal temp_data: STD_LOGIC_VECTOR (7 downto 0);

signal num: STD_LOGIC_VECTOR (3 downto 0);

signal ps2_byte_r: STD_LOGIC_VECTOR (7 downto 0);

signal count:std_logic_vector(3 downto 0);

begin

---------------

process(clk,rst_n)

begin

if (rst_n = '0') then

ps2k_clk_r <= "000";

elsif (clk'event AND clk = '1') then

ps2k_clk_r <= ps2k_clk_r(1 downto 0) & ps2k_clk;

end if;

end process;

----------------------

neg_ps2k_clk <= '1' when ps2k_clk_r(2 downto 1) = "10" else '0';

----------------------

process(clk,rst_n)

begin

if (rst_n = '0') then

num <= x"0";

temp_data <= x"00";

elsif (clk'event AND clk = '1') then

if (neg_ps2k_clk = '1') then

num <= num+1;

case num is

when x"1" => temp_data(0) <= ps2k_data;

when x"2" => temp_data(1) <= ps2k_data;

when x"3" => temp_data(2) <= ps2k_data;

when x"4" => temp_data(3) <= ps2k_data;

when x"5" => temp_data(4) <= ps2k_data;

when x"6" => temp_data(5) <= ps2k_data;

when x"7" => temp_data(6) <= ps2k_data;

when x"8" => temp_data(7) <= ps2k_data;

when others => null;

end case;

end if;

if (num = x"b") then

num <= x"0";

end if;

end if;

end process;

-------------------

process(clk,rst_n)

VARIABLE count1:INTEGER range 0 TO 1;

begin

if (rst_n = '0') then

ps2_byte_r <= x"00";

elsif (clk'event AND clk = '1') then

if (num = x"b") then

ps2_byte_r <= temp_data;

end if;

end if;

end process;

------------------- process(ps2_byte_r)

begin

--correct<='0';

if (ps2_byte_r=x"29") then resss<='0';

else

case num1 is

when "0000"=>--0

if(ps2_byte_r=x"6b") then

correct<='1';

else correct<='0';

end if;

when "0001"=>--1

if(ps2_byte_r=x"74") then

correct<='1';

else correct<='0';

end if;

when "0010"=>--2

if(ps2_byte_r=x"73") then

correct<='1';

else correct<='0';

end if;

when "0011"=>--3

if(ps2_byte_r=x"74") then

correct<='1';

else correct<='0';

end if;

when "0100"=>--4

if(ps2_byte_r=x"69") then

correct<='1';

else correct<='0';

end if;

when "0101"=>--5

if(ps2_byte_r=x"79") then

correct<='1';

else correct<='0';

end if;

when "0110"=>--6

if(ps2_byte_r=x"73") then

correct<='1';

else correct<='0';

when "0111"=>--7

if(ps2_byte_r=x"73") then correct<='1';

else correct<='0';

end if;

when "1000"=>--8

if(ps2_byte_r=x"79") then correct<='1';

else correct<='0';

end if;

when "1001"=>--9

if(ps2_byte_r=x"69") then correct<='1';

else correct<='0';

end if;

when "1010"=>--10

if(ps2_byte_r=x"74") then correct<='1';

else correct<='0';

end if;

when "1011"=>--11

if(ps2_byte_r=x"6b") then correct<='1';

else correct<='0';

end if;

when "1100"=>--12

if(ps2_byte_r=x"72") then correct<='1';

else correct<='0';

end if;

when "1101"=>--13

if(ps2_byte_r=x"73") then correct<='1';

else correct<='0';

end if;

when "1110"=>--14

if(ps2_byte_r=x"7a") then correct<='1';

else correct<='0';

end if;

when others=>null;

resss<='1';

end if;

end process;

end architecture ps2receive;

4.5 计分器模块

判断得到来自键盘控制模块的correct信号是否为1,来确定计分器是否需要加1,并实现在数码管上显示出来。

library ieee;

use ieee.std_logic_1164.all;

use ieee.std_logic_unsigned.all;

ENTITY grade IS

PORT(

-- clk_1:IN STD_LOGIC;

clk_1HZ : in std_logic;

rst_n : in std_logic;

correct: in std_logic;

-- light : buffer std_logic_vector(2 downto 0);

seg_en : buffer std_logic;

clr: buffer std_logic;

seg_data : buffer std_logic_vector(15 downto 0)

);

END grade;

architecture behav of grade is

signal cnt : std_logic_vector(3 downto 0);

signal tim : std_logic_vector(3 downto 0):="1111";

begin

process (clk_1HZ,rst_n)

begin

if (clk_1HZ'event and clk_1HZ='1') then

--clr <= '1';

if correct='1' then

cnt<=cnt+1;

end if;

if (cnt>"1001") then

seg_data <= "000000000001"&( cnt-"1010");

else

seg_data <= "000000000000"&cnt;

end if;

end if;

end process;

end behav;

4.6 LCD1602 地鼠显示模块

首先分频得到一个5Hz的时钟信号,LCD在5Hz时钟信号的驱动下,完成五步操作,第一步,设置8位格式,第二步,整体显示,关光标,光标闪烁,第三步,清屏,第四步,根据得到来自伪随机数产生模块的伪随机数信号numin,读地址,移动光标位置,第五步,在光标位置写特殊字符,代表地鼠出现。

library ieee;

use IEEE.std_logic_1164.all;

use ieee.std_logic_unsigned.all;

entity lcdd is

port(clk, reset: in std_logic;

numin:in std_logic_vector(3 downto 0);

LCD_Data: buffer std_logic_vector(8 downto 0);

en: out std_logic;

rw: out std_logic;

judge: out std_logic_vector(8 downto 0);

LCD_Clk: buffer std_logic

);

end lcdd;

architecture gongneng of lcdd is

signal s : integer range 0 to 5000000;

begin

--50MHz to 5Hz

process(clk, reset)

begin

if reset = '0' then

LCD_Clk <= '0';

s <= 0;

elsif clk'event and clk = '1' then

if s = 5000000 then

s <= 0;

LCD_Clk <= not LCD_Clk;

else

s <= s + 1;

end if;

end if;

end process;

rw <='0';

en <= LCD_Clk;

process(LCD_Clk)

variable cnt1:std_logic_vector(2 downto 0):="000";

begin

if Reset='0'then

LCD_Data<="000000001"; -- Resetzanting

--LCD_Data[8..0], 其中LCD_Data[8]对应1602的RS,--LCD_Data[7..0]对应1602的八根数据线

elsif rising_edge(LCD_Clk) then

if cnt1<"101" then cnt1:=cnt1+1;

else cnt1:="001";

end if;

case cnt1 is

when "001"=>LCD_Data<="000111000";

when "010"=>LCD_Data<="000001100";

when "011"=>LCD_Data<="000000001";

when "100"=>

case numin is

when "0000"=>LCD_Data<="010000010";

---3

when "0001"=>LCD_Data<="010001100";

---13

when "0010"=>LCD_Data<="010000111";

--8

when "0011"=>LCD_Data<="010001100";

--13

when "0100"=>LCD_Data<="011000010";

--2.3

when "0101"=>LCD_Data<="011001100";

---2.13

when "0110"=>LCD_Data<="011000111";

--2.8

when "0111"=>LCD_Data<="010000111";

---8

when "1000"=>LCD_Data<="011001100";

--2.13

when "1001"=>LCD_Data<="011000010";

---2.3

when "1010"=>LCD_Data<="010001100";

--l3

when "1011"=>LCD_Data<="010000010";

---3

when "1100"=>LCD_Data<="011000111";

--2.8

when "1101"=>LCD_Data<="010000111";

---8

when "1110"=>LCD_Data<="011001100";

--2.13

when "1111"=>LCD_Data<="011000010";

---2.3

when others=>null;

end case;

when "101"=>LCD_Data<="111101111";

when others=>null;

end case;

end if;

end process;

process(LCD_Data)

begin

if (LCD_Data(8 downto 7)="01")then

judge<=LCD_Data;

end if;

end process;

end gongneng;

4.7 数码管显示模块

Seg.v数码管驱动程序,具体分数显示在计分模块代码中实现。

五、总体设计电路图

总体电路原理图如下图所示:

实物图:

总体图:

LCD显示图:

六游戏说明书

6.1前言:

地鼠欢乐地上窜下跳,在六个洞口不时探出身来,调皮的孩子用小锤左敲右击却仿佛总也打不到,地鼠从不记仇,为你计分,为你加油。打打地鼠,释放压力,呆萌地鼠陪你一起换个心情!

6.2 运行说明:

通电即可开始游戏,地鼠出现位置成2*3的阵列,玩家只需在允许的0.2s反应时间内按下键盘1-6的数字按键,按对即可得分,数码管上即可显示出来,游戏初步最高得分为16,之后便回归零计分。在游戏过程中,可按下键盘空白键以暂停游戏,之后按下任意键,即可继续游戏,也可以按下ESC键随时重新开始游戏。

6.3 评分规则:

在允许的反应时间内按对地鼠出现位置对应的按键,即可获取加分。

七、心得体会

我们选取的是一个比较经典的课程设计题目——打地鼠游戏,如果只是单纯

的在开发板上实现功能比较简单,所以我们小组采取的方法是增加LCD显示器和键盘做外设,以增加功能完善度,也更好的锻炼我们学以致用的能力。

课设的开始,小组成员间一起讨论、设想了游戏该具备的功能,每个功能对应着程序的一个或多个模块。讨论的结果是,功能主要分为打地鼠和计分,其中地鼠的随机性出现,以产生的伪随机数来实现,所以相应的程序里面应该包括分频器模块、随机数产生模块、键盘控制模块、计分器模块、LCD屏地鼠显示模块、数码管显示模块。纸上得来终觉浅,绝知此事要躬行,设想总是美好的,要真正实现好,还是得在编程上下一番功夫。我们把程序的零碎部分先编好,在不断的调试与修改中,将每个模块先分开独立实现。但是,设计的过程不是一帆风顺的,当将每个独立完成好的模块整体拼接烧录在开放板中时,却还是有问题出现,只得从各个模块的各个输出去检测问题的存在原因,从而解决问题。让我们明白了,细节决定成败,整体也绝不是个体的简单叠加。在把各个模块连接起来,也要瞻前顾后,注意整体的关系。做好的成果,也需要再进行调试和改进,设计没有最好,只有更好。只有不断的完善,才能得到我们预期的结果。

在这次课程设计中,遇到问题,解决问题的波折过程,锻炼了我们将学到的知识运用到实践中的能力!

相关主题