前言
北邮数电实验三“接球小游戏”
数电实验验收已经结束了,实验报告也已经提交很久了,就把VHDL代码发到CSDN上分享一下,造福后来的学弟学妹,这也是我第一篇博客,以后也会分享一些单片机、PCB、FPGA之类的内容。
老师上学期没教状态机,自己也没自学这部分,所以用了多个模块然后接线,当时年级里传着一个大佬用状态机写的代码,看着很厉害,但是我感觉不好调试,就自己写了一份。
提示:代码仅供参考,请不要直接抄袭,看懂再用才是最好的,然后我的代码可能有问题,希望在评论里探讨呀
一、实验要求
基本要求:
1、 设计实现一个基于 8×8 双色点阵的接球游戏,其中接球板采用红色 LED 显示,小球采用绿色 LED 显示。数码管 DISP0 显示游戏分数、DISP1、DISP2 显示游戏时间。
2、 按下游戏开始键 BTN0 后,点阵显示 5 秒倒计时动画。动画结束后进入游戏界面。
3、 游戏示意过程参考图 1 中从①→⑦的顺序所示。在点阵顶部第 7 行的位置随机出现一个小球,并按照相应的列垂直落下,下落速度为 0.5 秒/行。接球板采用 3 个红色LED 进行显示并可以通过 BTN1、BTN2 按键控制接球板左右移动(左右移动时接球板要在点阵上显示完整)。如果球落下时碰到板(即小球到达点阵第 1 行,同时正好在接球板 3 个 LED 范围内)则游戏加 1 分,否则不加分,然后在点阵顶部重新随机出现新的小球。
4、游戏时间为 30 秒倒计时提醒。当在游戏时间内计满 5 分时游戏结束,点阵显示胜利动画,蜂鸣器演奏胜利音效;如果在游戏时间内未到达 5 分,游戏显示失败画面,蜂鸣器演奏相应音效。
提高要求:
1、增加游戏音效,当小球碰到接球板时,蜂鸣器发声;
2、 增加高级模式,当游戏达到 10 秒后,接球板变短(长度变为 2 个 LED);
3、 增加难度模式,该模式下,当小球从点阵顶部降落到第 5 行时,点阵顶部随机出现第二个小球;
4、 小球降落速度多档可调;
5、 自拟其他功能。创建的。
二、设计思路
一开始打算用状态机,一个实体写完,尝试过后发现太麻烦了,多个进程间的通信比较麻烦,也容易弄混,而且不好调试,就把点阵显示模块和模式选择模块用状态机的模板来写,把其他的功能分离开,将一个复杂的游戏机划分成多个简单模块的组合。模块间通过信号通信。
所有模块如下:
–1.M序列发生器 hwk7_02_M1
–2.分频器 hwk7_02_CLK_DIVISON
–3.防抖 hwk7_02_FD
–4.点阵显示 hwk7_02_POINTDISPLAY
–5.底板移动计数器 hwk7_02_movecount
–6.小球下落计数器 hwk7_02_fallpointcount
–7.模式选择切换控制器 hwk7_02_MODEL
–8.得分判断 hwk7_02_goal
–9.数码管显示 hwk7_02_goalSegmentDisplay
–10.蜂鸣器 hwk7_02_music
–0.顶层实体 game
其中有的模块可以利用上学期已有的代码,可以大大节约开发时间,也方便仿真和调试。
模块大体分为以下几类:输入→逻辑处理→输出。
输入为按键和时钟,以此延伸出按键防抖和分频器,因为小球的下落是随机的,所以还需要M序列发生器来产生随机信号。
逻辑处理主要是几个计数器和判断模块。模式选择器是用来调节各模块之间的同步问题,用不同的模式信号告诉一些需要切换状态的模块,你当前应该处于哪个状态。底板位置用一个三位的二进制信号x1表示,每隔一段就去扫描BTN1和BTN2组成的一个二维信号,10减一,01加一,其他不变。小球的位置用两个三位的二进制信号x0和y0表示,每隔一段时间y0+1,当y0到底时读取新的x0。得分判断就是当y0=7时,判断x0是否等于x1 | x1+1 | x1-1 即可,是的话就输出一个脉冲信号goal。
输出分三大块,点阵显示,蜂鸣器,数码管。里面点阵显示是最复杂的,大体逻辑如下图所示:
开机处于000状态,按下以后进入倒计时,然后游戏中,最后根据游戏结果显示胜利或者失败。蜂鸣器的输出先与goal做或运算,这样只要接到球就能输出一个声音,胜利或失败以后根据finial信号输出胜利或失败音效。数码管在close信号为1时,一直处于初始状态,当close为0时,开始倒计时,同时每输入一个脉冲goal,显示得分就+1。
三、设计系统框图
图中输入的speed[1]是接拨码开关,通过speed不同,控制小球下落速度不同,实现提高功能,速度可调。其它信号根据变量名都可以看出具体作用,这里就不一一解释了,详情可以看设计思路和源代码。
四、源代码
代码的注释挺多的,但有的地方为了加功能改了内容,没有改注释(因为懒:(,看的时候多看代码):
----------------------------------------------------------------------------------------
--题目 3 接球小游戏的设计与实现 by hwk
--基本要求: 基本功能全部完成
--1、 设计实现一个基于 8×8 双色点阵的接球游戏,其中接球板采用红色 LED 显示,小球采用绿色 LED 显示。
-- 数码管 DISP0 显示游戏分数、DISP1、DISP2 显示游戏时间。
--2、 按下游戏开始键 BTN0 后,点阵显示 5 秒倒计时动画。动画结束后进入游戏界面。
--3、 游戏示意过程参考图 1 中从①→⑦的顺序所示。在点阵顶部第 7 行的位置随机出现一个小球,并按照相应的列垂直落下,下落速度为 0.5 秒/行
-- 接球板采用 3 个红色LED 进行显示,并可以通过 BTN1、BTN2 按键控制接球板左右移动(左右移动时接球板要在点阵上显示完整)
-- 如果球落下时碰到板(即小球到达点阵第 1 行,同时正好在接球板 3 个 --LED 范围内)则游戏加 1 分
-- 否则不加分,然后在点阵顶部重新随机出现新的小球。
--4、 游戏时间为 30 秒倒计时提醒。当在游戏时间内计满 5 分时游戏结束,点阵显示胜利动画,蜂鸣器演奏胜利音效
-- 如果在游戏时间内未到达 5 分,游戏显示失败画面,蜂鸣--器演奏相应音效。
--提高要求:
--1、增加游戏音效,当小球碰到接球板时,蜂鸣器发声; √
--2、增加高级模式,当游戏达到 10 秒后,接球板变短(长度变为 2 个 LED); X
--3、增加难度模式,该模式下,当小球从点阵顶部降落到第 5 行时,点阵顶部随机出现第二个小球; X
--4、小球降落速度多档可调; √ SW(1) 00——11速度依次升高, 10为变速下降
--5、自拟其他功能。 X
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------
--1.M序列发生器 hwk7_02_M1
--2.分频器 hwk7_02_CLK_DIVISON
--3.防抖 hwk7_02_FD
--4.点阵显示 hwk7_02_POINTDISPLAY
--5.底板移动计数器 hwk7_02_movecount
--6.小球下落计数器 hwk7_02_fallpointcount
--7.模式选择切换控制器 hwk7_02_MODEL
--8.得分判断 hwk7_02_goal
--9.数码管显示 hwk7_02_goalSegmentDisplay
--10.蜂鸣器 hwk7_02_music
--0.顶层实体 game
--编译者邮箱:HeWenKang@bupt.edu.cn
-------------------------------------------------------------------------------------------------------------
----------------------------------------------
--名称:M序列发生器 hwk7_02_M1 1
--功能: 产生随机序列
--输入:时钟信号clkin和复位信号clear
--输出:4位随机序列 m
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY hwk7_02_M1 IS
PORT(clkin:IN STD_LOGIC;
clear:IN STD_LOGIC;
m:OUT STD_LOGIC_VECTOR(2 downto 0));
END ;
ARCHITECTURE a OF hwk7_02_M1 IS
SIGNAL temp1:STD_LOGIC_VECTOR(3 downto 0);
SIGNAL temp2:STD_LOGIC_VECTOR(2 downto 0);
BEGIN
PROCESS(clear,clkin)
BEGIN
IF clear='1' THEN
temp2<="000";
ELSIF(clkin'EVENT AND clkin='1')THEN
IF temp1="0000" THEN
temp1<="0001" ;
ELSE
temp1(0)<=temp1(0) xor temp1(3);
temp1(1)<=temp1(0);
temp1(2)<=temp1(1);
temp1(3)<=temp1(2);
END IF;
case temp1 is
when "0000"=> temp2<="000";-- 0
when "0001"=> temp2<="001";-- 1
when "0010"=> temp2<="010";-- 2
when "0011"=> temp2<="011";-- 3
when "0100"=> temp2<="100";-- 4
when "0101"=> temp2<="101";-- 5
when "0110"=> temp2<="110";-- 6
when "0111"=> temp2<="111";-- 7
when "1000"=> temp2<="000";-- 0
when "1001"=> temp2<="001";-- 1
when "1010"=> temp2<="010";-- 2
when "1011"=> temp2<="011";-- 3
when "1100"=> temp2<="100";-- 4
when "1101"=> temp2<="101";-- 5
when "1110"=> temp2<="110";-- 6
when "1111"=> temp2<="111";-- 7
when others=> temp2<="111";
end case;
END IF;
END PROCESS ;
m<=temp2;
END a;
----------------------------------------------
--名称:分频器 2
--功能: 产生其它频率的时钟信号
--输入clkin 1MHz
--输出:clk_out_10Hz, clk_out_1Hz, clk_out_2Hz
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY hwk7_02_CLK_DIVISON IS
PORT(clkin:IN STD_LOGIC;
clk_out_10Hz, clk_out_1Hz, clk_out_2Hz :OUT STD_LOGIC
);
END ;
ARCHITECTURE a OF hwk7_02_CLK_DIVISON IS
signal count_10Hz :integer range 0 to 2000000;
signal count_1Hz :integer range 0 to 1000000;
signal count_2Hz :integer range 0 to 500000;
BEGIN
p1:process(clkin)
BEGIN
if rising_edge(clkin) then
if count_10Hz =100000 then
count_10Hz<=0;
elsif count_1Hz = 1000000 then
count_1Hz<=0;
elsif count_2Hz = 250000 then
count_2Hz<=0;
else
count_10Hz<=count_10Hz + 1;
count_1Hz<=count_1Hz + 1;
count_2Hz<=count_2Hz + 1;
end if;
end if;
end process p1;
p2:process(count_10Hz,clkin)
begin
if rising_edge(clkin) then
if count_10Hz<50000 then
clk_out_10Hz <= '0';
else clk_out_10Hz <= '1';
end if;
end if;
end process p2;
p3:process(count_1Hz,clkin)
begin
if rising_edge(clkin) then
if count_1Hz<500000 then
clk_out_1Hz <= '0';
else clk_out_1Hz <= '1';
end if;
end if;
end process p3;
p4:process(count_2Hz,clkin)
begin
if rising_edge(clkin) then
if count_2Hz<125000 then
clk_out_2Hz <= '0';
else clk_out_2Hz <= '1';
end if;
end if;
end process p4;
END a;
----------------------------------------------
--名称:按键防抖 3
--功能:计数实现按键防抖,按下高电平
--输入:BTN0,BTN1,BTN2,clkin,goal 其中clkin为1Mhz,BTN接外部键盘,goal是内部模块间信号
--输出:FDBTN0,FDBTN1,FDBTN2,fdgoal
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY hwk7_02_FD IS
PORT(clkin , BTN0 , BTN1 ,BTN2, goal:IN STD_LOGIC;
FDBTN0 , FDBTN1 ,FDBTN2,fdgoal:OUT STD_LOGIC
);
END ;
ARCHITECTURE a OF hwk7_02_FD IS
signal count_0 :integer range 0 to 10000;
signal count_1 :integer range 0 to 10000;
signal count_2 :integer range 0 to 10000;
signal count_3 :integer range 0 to 10000;
BEGIN
p1:process(clkin, BTN0)
BEGIN
if BTN0 = '1' then
if rising_edge(clkin) then
if count_0 =10000 then
count_0<=count_0;
else count_0<=count_0+1;
end if;
if count_0<10000 then FDBTN0 <= '0';
else FDBTN0 <= '1';
end if;
end if;
else
count_0<=0;
FDBTN0 <= '0';
end if;
end process p1;
p2:process(clkin, BTN1)
BEGIN
if BTN1 = '1' then
if rising_edge(clkin) then
if count_1 =10000 then
count_1<=count_1;
else count_1<=count_1+1;
end if;
if count_1<10000 then FDBTN1 <= '0';
else FDBTN1 <= '1';
end if;
end if;
else
count_1<=0;
FDBTN1 <= '0';
end if;
end process p2;
p3:process(clkin, BTN2)
BEGIN
if BTN2 = '1' then
if rising_edge(clkin) then
if count_2 =10000 then
count_2<=count_2;
else count_2<=count_2+1;
end if;
if count_2<10000 then FDBTN2 <= '0';
else FDBTN2 <= '1';
end if;
end if;
else
count_2<=0;
FDBTN2 <= '0';
end if;
end process p3;
p4:process(clkin, goal)
BEGIN
if goal = '1' then
if rising_edge(clkin) then
if count_3 =10000 then
count_3<=count_3;
else count_3<=count_3+1;
end if;
if count_3<10000 then fdgoal <= '0';
else fdgoal <= '1';
end if;
end if;
else
count_3<=0;
fdgoal <= '0';
end if;
end process p4;
END a;
----------------------------------------------
--名称:点阵显示 4 4
--功能:模式选择000,实现倒计时动画001,胜利动画010,失败动画011,游戏动画100
-- model输入进某个状态,就先让model_out输出该状态以保持
-- 该状态结束以后再用model_out输出下一状态
--输入:x0[2],y0[2],x1[2],model[2],clkin_1Hz,clkin(1M Hz)
--输出:col_red[7],col_green[7],row[7],model_out
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY hwk7_02_POINTDISPLAY IS
PORT(X0:IN STD_LOGIC_VECTOR(2 DOWNTO 0);
Y0:IN STD_LOGIC_VECTOR(2 DOWNTO 0);
X1:IN STD_LOGIC_VECTOR(2 DOWNTO 0);
MODEL :IN STD_LOGIC_VECTOR(2 DOWNTO 0);
MODEL_out :out STD_LOGIC_VECTOR(2 DOWNTO 0);
clkin: IN STD_LOGIC;
clkin_1Hz: IN STD_LOGIC;
col_red:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
col_green:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
row:OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END ;
ARCHITECTURE a OF hwk7_02_POINTDISPLAY IS
signal count_row :integer range 0 to 8;
signal time_count :integer range -1 to 5;
begin
p1:process(model,clkin_1Hz) --5秒倒计时进程
begin
if model ="001" then
if rising_edge(clkin_1Hz) then
time_count<=time_count-1;
end if;
else
time_count<=5;
end if;
end process;
p2:process(model,clkin) --点阵扫描进程
begin
if rising_edge(clkin) then
count_row<=count_row+1;
if count_row = 8 then
count_row<=0;
end if;
end if;
end process;
p3:process(MODEL,clkin,clkin_1Hz,x0,y0,x1)
begin
if MODEL ="000" then -- 模式选择待完成,应在1处显示绿灯
col_red<="00000000";
col_green<="00000001";
row<="11111110";
end if;
if MODEL ="001" then --开场5秒倒计时 状态001 结束后跳到状态100
MODEL_out <="001";
case time_count is
when 0 => MODEL_out <="100";
when 1 => case count_row is
when 0 => col_green<="00000000"; row<="01111111";
when 1 => col_green<="00001000"; row<="10111111";
when 2 => col_green<="00001000"; row<="11011111";
when 3 => col_green<="00001000"; row<="11101111";
when 4 => col_green<="00001000"; row<="11110111";
when 5 => col_green<="00001000"; row<="11111011";
when 6 => col_green<="00001000"; row<="11111101";
when 7 => col_green<="00000000"; row<="11111110";
when others => col_green<="00000000"; row<="11111111";
end case;
when 2 => case count_row is
when 0 => col_green<="00000000"; row<="01111111";
when 1 => col_green<="00111100"; row<="10111111";
when 2 => col_green<="00100000"; row<="11011111";
when 3 => col_green<="00111100"; row<="11101111";
when 4 => col_green<="00000100"; row<="11110111";
when 5 => col_green<="00111100"; row<="11111011";
when 6 => col_green<="00000000"; row<="11111101";
when 7 => col_green<="00000000"; row<="11111110";
when others => col_green<="00000000"; row<="11111111";
end case;
when 3 => case count_row is
when 0 => col_green<="00000000"; row<="01111111";
when 1 => col_green<="00111100"; row<="10111111";
when 2 => col_green<="00100000"; row<="11011111";
when 3 => col_green<="00111100"; row<="11101111";
when 4 => col_green<="00100000"; row<="11110111";
when 5 => col_green<="00111100"; row<="11111011";
when 6 => col_green<="00000000"; row<="11111101";
when 7 => col_green<="00000000"; row<="11111110";
when others => col_green<="00000000"; row<="11111111";
end case;
when 4 => case count_row is
when 0 => col_green<="00000000"; row<="01111111";
when 1 => col_green<="00001001"; row<="10111111";
when 2 => col_green<="00001001"; row<="11011111";
when 3 => col_green<="00111111"; row<="11101111";
when 4 => col_green<="00001000"; row<="11110111";
when 5 => col_green<="00001000"; row<="11111011";
when 6 => col_green<="00001000"; row<="11111101";
when 7 => col_green<="00000000"; row<="11111110";
when others => col_green<="00000000"; row<="11111111";
end case;
when 5 =>
case count_row is
when 0 => col_green<="00000000"; row<="01111111";
when 1 => col_green<="00111100"; row<="10111111";
when 2 => col_green<="00000100"; row<="11011111";
when 3 => col_green<="00111100"; row<="11101111";
when 4 => col_green<="00100000"; row<="11110111";
when 5 => col_green<="00111100"; row<="11111011";
when 6 => col_green<="00000000"; row<="11111101";
when 7 => col_green<="00000000"; row<="11111110";
when others => col_green<="00000000"; row<="11111111";
end case;
when others => col_green<="00000000"; row<="11111111";
end case;
end if;
if MODEL ="010" then --胜利动画,绿色笑脸 状态010
MODEL_out <="010"; col_red<="00000000";
case count_row is
when 0 => col_green<="00000000"; row<="01111111";
when 1 => col_green<="01000010"; row<="10111111";
when 2 => col_green<="00000000"; row<="11011111";
when 3 => col_green<="01000010"; row<="11101111";
when 4 => col_green<="00100100"; row<="11110111";
when 5 => col_green<="00011000"; row<="11111011";
when 6 => col_green<="00000000"; row<="11111101";
when 7 => col_green<="00000000"; row<="11111110";
when others => col_green<="00000000"; row<="11111111";
end case;
end if;
if MODEL ="011" then --失败动画,红色哭脸 状态011
MODEL_out <="011"; col_green<="00000000";
case count_row is
when 0 => col_red<="00000000"; row<="01111111";
when 1 => col_red<="01000010"; row<="10111111";
when 2 => col_red<="00000000"; row<="11011111";
when 3 => col_red<="00011000"; row<="11101111";
when 4 => col_red<="00100100"; row<="11110111";
when 5 => col_red<="01000010"; row<="11111011";
when 6 => col_red<="00000000"; row<="11111101";
when 7 => col_red<="00000000"; row<="11111110";
when others => col_green<="00000000"; row<="11111111";
end case;
end if;
if MODEL ="100" then --游戏中 状态100 结束以后跳到状态010或者011
MODEL_out <="100";
CASE count_row IS
when 0 => if y0 ="000" then
CASE x0 IS
when "000"=> col_green<="10000000";
when "001"=> col_green<="01000000";
when "010"=> col_green<="00100000";
when "011"=> col_green<="00010000";
when "100"=> col_green<="00001000";
when "101"=> col_green<="00000100";
when "110"=> col_green<="00000010";
when "111"=> col_green<="00000001";
WHEN OTHERS =>col_green<="00000000";
end case;
row<="01111111";
else row<="11111111";
end if;
when 1 => if y0 ="001" then
CASE x0 IS
when "000"=> col_green<="10000000";
when "001"=> col_green<="01000000";
when "010"=> col_green<="00100000";
when "011"=> col_green<="00010000";
when "100"=> col_green<="00001000";
when "101"=> col_green<="00000100";
when "110"=> col_green<="00000010";
when "111"=> col_green<="00000001";
WHEN OTHERS =>col_green<="00000000";
end case;
row<="10111111";
else row<="11111111";
end if;
when 2 => if y0 ="010" then
CASE x0 IS
when "000"=> col_green<="10000000";
when "001"=> col_green<="01000000";
when "010"=> col_green<="00100000";
when "011"=> col_green<="00010000";
when "100"=> col_green<="00001000";
when "101"=> col_green<="00000100";
when "110"=> col_green<="00000010";
when "111"=> col_green<="00000001";
WHEN OTHERS =>col_green<="00000000";
end case;
row<="11011111";
else row<="11111111";
end if;
when 3 => if y0 ="011" then
CASE x0 IS
when "000"=> col_green<="10000000";
when "001"=> col_green<="01000000";
when "010"=> col_green<="00100000";
when "011"=> col_green<="00010000";
when "100"=> col_green<="00001000";
when "101"=> col_green<="00000100";
when "110"=> col_green<="00000010";
when "111"=> col_green<="00000001";
WHEN OTHERS =>col_green<="00000000";
end case;
row<="11101111";
else row<="11111111";
end if;
when 4 => if y0 ="100" then
CASE x0 IS
when "000"=> col_green<="10000000";
when "001"=> col_green<="01000000";
when "010"=> col_green<="00100000";
when "011"=> col_green<="00010000";
when "100"=> col_green<="00001000";
when "101"=> col_green<="00000100";
when "110"=> col_green<="00000010";
when "111"=> col_green<="00000001";
WHEN OTHERS =>col_green<="00000000";
end case;
row<="11110111";
else row<="11111111";
end if;
when 5 => if y0 ="101" then
CASE x0 IS
when "000"=> col_green<="10000000";
when "001"=> col_green<="01000000";
when "010"=> col_green<="00100000";
when "011"=> col_green<="00010000";
when "100"=> col_green<="00001000";
when "101"=> col_green<="00000100";
when "110"=> col_green<="00000010";
when "111"=> col_green<="00000001";
WHEN OTHERS =>col_green<="00000000";
end case;
row<="11111011";
else row<="11111111";
end if;
when 6 => if y0 ="110" then
CASE x0 IS
when "000"=> col_green<="10000000";
when "001"=> col_green<="01000000";
when "010"=> col_green<="00100000";
when "011"=> col_green<="00010000";
when "100"=> col_green<="00001000";
when "101"=> col_green<="00000100";
when "110"=> col_green<="00000010";
when "111"=> col_green<="00000001";
WHEN OTHERS =>col_green<="00000000";
end case;
row<="11111101";
else row<="11111111";
end if;
when 7 => col_green<="00000000"; row<="11111110";
CASE x1 IS
when "000"=> col_red<="11100000";
when "001"=> col_red<="11100000";
when "010"=> col_red<="01110000";
when "011"=> col_red<="00111000";
when "100"=> col_red<="00011100";
when "101"=> col_red<="00001110";
when "110"=> col_red<="00000111";
when "111"=> col_red<="00000111";
WHEN OTHERS =>col_red<="00000000";
end case;
when others => col_green<="00000000";col_red<="00000000"; row<="11111111";
end case;
end if;
end process ;
END a;
----------------------------------------------
--名称:底板移动计数器 5
--功能:实现底板移动
--输入:BTN1,BTN2
--输出:x[2]
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY hwk7_02_movecount IS
PORT(
clkin:IN STD_LOGIC;
btn:IN STD_LOGIC_VECTOR(1 downto 0);
x1:OUT STD_LOGIC_VECTOR(2 downto 0));
END ;
ARCHITECTURE a OF hwk7_02_movecount IS
signal temp: integer range 0 to 5;
BEGIN
p1: PROCESS(clkin)
BEGIN
if rising_edge(clkin) then
if (btn="01") then
if temp =0 then
temp<=0;
else temp<=temp-1;
end if;
elsif (btn="10") then
if temp =5 then
temp<=5;
else temp<=temp+1;
end if;
end if;
end if;
end process;
p2: process(temp)
begin
case temp is
when 0 => x1<= "001";
when 1 => x1<= "010";
when 2 => x1<= "011";
when 3 => x1<= "100";
when 4 => x1<= "101";
when 5 => x1<= "110";
end case;
END PROCESS ;
END a;
----------------------------------------------
--名称:小球下落计数器 6
--功能:实现小球下落
--输入:M[2],clk_2hz
--输出:x[2]
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY hwk7_02_fallpointcount IS
PORT(
clkin,clear: IN STD_LOGIC;
clkin_2Hz: IN STD_LOGIC;
speed:IN STD_LOGIC_VECTOR(1 downto 0);
M:IN STD_LOGIC_VECTOR(2 downto 0);
x0:OUT STD_LOGIC_VECTOR(2 downto 0);
y0:OUT STD_LOGIC_VECTOR(2 downto 0));
END ;
ARCHITECTURE a OF hwk7_02_fallpointcount IS
SIGNAL temp1: STD_LOGIC_VECTOR(2 downto 0);
SIGNAL temp2: integer range 0 to 30;
BEGIN
PROCESS(clkin_2Hz,clear)
BEGIN
if (clear='1') then
temp2<=0;
elsif rising_edge(clkin_2Hz) then
case speed is
when "00" =>
if temp2>=27 then
temp1<=M;temp2<=0;
else temp2<=temp2+1;
end if;
when "01" =>
if temp2>=27 then
temp1<=M;temp2<=0;
else temp2<=temp2+2;
end if;
when "10" =>
if temp2>=27 then
temp1<=M;temp2<=0;
else temp2<=temp2+3;
end if;
when "11" =>
if temp2>=27 then
temp1<=M;temp2<=0;
else temp2<=temp2+4;
end if;
when others =>
if temp2>=27 then
temp1<=M;temp2<=0;
else temp2<=temp2+2;
end if;
end case;
x0<=temp1;
case temp2 is
when 0|1|2|3 => y0<="000";
when 4|5|6|7 => y0<="001";
when 8|9|10|11 => y0<="010";
when 12|13|14|15 => y0<="011";
when 16|17|18|19 => y0<="100";
when 20|21|22|23 => y0<="101";
when 24|25|26|27 => y0<="110";
when others => y0<="111";
end case;
end if;
END PROCESS ;
END a;
----------------------------------------------
--名称: 模式选择器 7
--功能:实现模式选择 模式选择000,实现倒计时动画001,胜利动画010,失败动画011,游戏动画100,
--输入:BTN0,BTN1,BTN2
--输出:MODEL[2]
--编译者邮箱:HeWenKang@bupt.edu.cn MODEL_out <="100";
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY hwk7_02_MODEL IS
PORT( BTN0 , BTN1 ,BTN2:IN STD_LOGIC;
MODEL_in:in STD_LOGIC_VECTOR(2 DOWNTO 0);
MODEL:OUT STD_LOGIC_VECTOR(2 DOWNTO 0);
finish:in STD_LOGIC_VECTOR(1 DOWNTO 0);
close: out STD_LOGIC
);
END ;
ARCHITECTURE a OF hwk7_02_MODEL IS
begin
p1: process(btn0,model_in,finish)
begin
if btn0 ='1' then
MODEL<="001";
elsif model_in ="100" and finish = "10" then
MODEL<="010";
elsif model_in ="100" and finish = "01" then
MODEL<="011";
else
model<=model_in;
end if;
end process;
p2: process(btn0,model_in,finish)
begin
if model_in ="100" then
close<='0';
else
close<='1';
end if;
end process;
END a;
----------------------------------------------
--名称: 得分判断模块 8
--功能:实现得分判断,如果得分,则输出一个高电平
--输入:x0[2],y0[2],x1[2]
--输出:goal
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY hwk7_02_goal IS
PORT( MODEL :IN STD_LOGIC_VECTOR(2 DOWNTO 0);
clkin: IN STD_LOGIC;
goal:out STD_LOGIC;
x0:in STD_LOGIC_VECTOR(2 downto 0);
y0:in STD_LOGIC_VECTOR(2 downto 0);
x1:in STD_LOGIC_VECTOR(2 downto 0));
END ;
ARCHITECTURE a OF hwk7_02_goal IS
begin
p1: process(clkin)
begin
if rising_edge(clkin) then
case model is
when "100" =>
if (y0="110") then
if x0=x1-1 or x0=x1 or x0=x1+1 then
goal <='1';
end if;
else
goal <='0';
end if;
when others =>
goal <='0';
end case;
end if;
end process;
end a;
----------------------------------------------
--名称: 数码管计分模块 9
--功能:实现得分计数,当收到一个高电平,数码管显示数字+1
--输入:goal, clk, clear, clk_1hz
--输出:seg[7],cat[7],finish[1]
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
Library ieee;
Use ieee.std_logic_1164.all;
ENTITY hwk7_02_goalSegmentDisplay IS
PORT(clk,clk_1Hz, close: in std_logic;
goal:in std_logic;
finish: out std_logic_vector(1 downto 0);
number: OUT STD_LOGIC_VECTOR(6 downto 0);
cat: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END hwk7_02_goalSegmentDisplay;
ARCHITECTURE a OF hwk7_02_goalSegmentDisplay IS
signal i ,time_high,time_low: STD_LOGIC_VECTOR(3 DOWNTO 0);
signal finish_signal,finish_signal1: std_logic_vector(1 downto 0);
signal point_count: integer range 0 to 3;
BEGIN
p1:PROCESS(goal,close,clk,clk_1Hz,time_high,time_low)
begin
if close ='1' then
i<="0000";finish_signal<="00";
elsif rising_edge(goal) then
if i="0100" then
finish_signal<="10";
else i<=i+1;
end if;
end if;
end process;
p2: PROCESS(point_count,goal,close,clk,clk_1Hz,time_high,time_low)
begin
if close ='1' then
time_high<="0011";time_low<="0000";finish_signal1<="00";
elsif rising_edge(clk_1Hz) then
if(time_low="0000" and time_high="0000") then
finish_signal1<="01";
elsif(time_low="0000" ) then
time_low<="1001";time_high<=time_high-1;
else time_low<=time_low-1;
end if;
end if;
case point_count is
when 0 =>
case i is
WHEN "0000" =>number<="1111110";cat<="11111110";--0
WHEN "0001" =>number<="0110000";cat<="11111110";--1
WHEN "0010" =>number<="1101101";cat<="11111110";--2
WHEN "0011" =>number<="1111001";cat<="11111110";--3
WHEN "0100" =>number<="0110011";cat<="11111110";--4
WHEN "0101" =>number<="1011011";cat<="11111110";--5
WHEN "0110" =>number<="1011111";cat<="11111110";--6
WHEN "0111" =>number<="1110000";cat<="11111110";--7
WHEN "1000" =>number<="1111111";cat<="11111110";--8
WHEN "1001" =>number<="1111011";cat<="11111110";--9
WHEN OTHERS =>number<="0000000";cat<="11111111";--other
end case;
when 1 =>
case time_high is
WHEN "0000" =>number<="1111110";cat<="11011111";--0
WHEN "0001" =>number<="0110000";cat<="11011111";--1
WHEN "0010" =>number<="1101101";cat<="11011111";--2
WHEN "0011" =>number<="1111001";cat<="11011111";--3
WHEN "0100" =>number<="0110011";cat<="11011111";--4
WHEN "0101" =>number<="1011011";cat<="11011111";--5
WHEN "0110" =>number<="1011111";cat<="11011111";--6
WHEN "0111" =>number<="1110000";cat<="11011111";--7
WHEN "1000" =>number<="1111111";cat<="11011111";--8
WHEN "1001" =>number<="1111011";cat<="11011111";--9
WHEN OTHERS =>number<="0000000";cat<="11111111";--other
end case;
when 2 =>
case time_low is
WHEN "0000" =>number<="1111110";cat<="11101111";--0
WHEN "0001" =>number<="0110000";cat<="11101111";--1
WHEN "0010" =>number<="1101101";cat<="11101111";--2
WHEN "0011" =>number<="1111001";cat<="11101111";--3
WHEN "0100" =>number<="0110011";cat<="11101111";--4
WHEN "0101" =>number<="1011011";cat<="11101111";--5
WHEN "0110" =>number<="1011111";cat<="11101111";--6
WHEN "0111" =>number<="1110000";cat<="11101111";--7
WHEN "1000" =>number<="1111111";cat<="11101111";--8
WHEN "1001" =>number<="1111011";cat<="11101111";--9
WHEN OTHERS =>number<="0000000";cat<="11111111";--other
end case;
WHEN OTHERS =>number<="0000000";cat<="11111111";--other
end case;
end process;
p3: process (clk)
begin
if rising_edge(clk) then
point_count <= point_count + 1;
if point_count=3 then
point_count<=0;
end if;
end if;
end process;
finish<=finish_signal or finish_signal1;
END a;
----------------------------------------------
--名称: 蜂鸣器模块 10
--功能:接球响一下,胜利音调上升,失败音调下降
--输入:goal,finish, clk_in
--输出:music
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY hwk7_02_music IS
PORT(
clk_in:IN STD_LOGIC;
goal:IN STD_LOGIC;
model:IN STD_LOGIC_vector(2 downto 0);
music:OUT STD_LOGIC);
END hwk7_02_music;
ARCHITECTURE a OF hwk7_02_music IS
SIGNAL tmp:INTEGER RANGE 0 TO 2000;
SIGNAL clktmp:STD_LOGIC;
SIGNAL tmp2:INTEGER RANGE 0 TO 300000;
SIGNAL clktmp2:STD_LOGIC;
SIGNAL fp:INTEGER RANGE 0 TO 20000;
SIGNAL q_temp: INTEGER RANGE 0 TO 144;
signal music_win,music_lose: STD_LOGIC;
BEGIN
PROCESS(fp,clk_in) --Changeable div
BEGIN
IF clk_in'event AND clk_in='1' THEN
IF tmp >= fp/2 THEN
tmp<=0; clktmp<=NOT clktmp;
ELSE
tmp<=tmp+1;
END IF;
END IF;
END PROCESS;
PROCESS(clk_in) --0.5S div
BEGIN
IF clk_in'event AND clk_in='1' THEN
IF tmp2=83333 THEN
tmp2<=0; clktmp2<=NOT clktmp2;
ELSE
tmp2<=tmp2+1;
END IF;
END IF;
END PROCESS;
PROCESS(clktmp2,model)
BEGIN
IF model="100" THEN
q_temp<=0 ;
ELSIF(clktmp2'event AND clktmp2='1' and model="010")THEN
IF q_temp =7 THEN --wait for finish
q_temp<=7 ;
ELSE
q_temp<=q_temp+1;
END IF;
ELSIF(clktmp2'event AND clktmp2='1' and model="011")THEN
IF q_temp =64 THEN --wait for finish
q_temp<=64 ;
ELSE
q_temp<=q_temp+8;
END IF;
END IF;
END PROCESS;
PROCESS(q_temp,clk_in)
BEGIN
if rising_edge(clk_in) then
case q_temp is
when 0|56 => fp<=5000;
when 1|48 => fp<=1911;
when 2|40 => fp<=1703;
when 3|32 => fp<=1517;
when 4|24 => fp<=1412;
when 5|16 => fp<=1276;
when 6|8 => fp<=1136;
when others => fp<=5000;
end case;
end if;
END PROCESS;
p1:process(clk_in)
begin
if rising_edge(clk_in) then
if(goal='1') then
music<='1';
elsif (model="010") then
music<=clktmp;
elsif (model="011") then
music<=clktmp;
else
music<='0';
end if;
end if;
end process;
END a;
----------------------------------------------
--名称:接球小游戏顶层设计 0
--功能:根据按键完成点阵接球小游戏
--输入:1MHz,BTN0,BTN1,BTN2
--输出:点阵显示, 数码管 ,蜂鸣器
--编译者邮箱:HeWenKang@bupt.edu.cn
----------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY game IS
PORT
(btn0:IN STD_LOGIC;
btn1:IN STD_LOGIC;
btn2:IN STD_LOGIC;
clk_1M:IN STD_LOGIC;
speed:IN STD_LOGIC_VECTOR(1 downto 0);
col_red:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
col_green:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
row:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
music:OUT STD_LOGIC;
segnumber:OUT STD_LOGIC_VECTOR(6 DOWNTO 0);
cat:OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END game;
ARCHITECTURE a OF game IS
COMPONENT hwk7_02_M1 IS
PORT(clkin:IN STD_LOGIC;
clear:IN STD_LOGIC;
m:OUT STD_LOGIC_VECTOR(2 downto 0));
END COMPONENT;
COMPONENT hwk7_02_CLK_DIVISON IS
PORT(clkin:IN STD_LOGIC;
clk_out_10Hz, clk_out_1Hz, clk_out_2Hz :OUT STD_LOGIC
);
END COMPONENT;
COMPONENT hwk7_02_FD IS
PORT(clkin , BTN0 , BTN1 ,BTN2,goal:IN STD_LOGIC;
FDBTN0 , FDBTN1 ,FDBTN2,fdgoal:OUT STD_LOGIC
);
END COMPONENT;
COMPONENT hwk7_02_POINTDISPLAY IS
PORT(X0:IN STD_LOGIC_VECTOR(2 DOWNTO 0);
Y0:IN STD_LOGIC_VECTOR(2 DOWNTO 0);
X1:IN STD_LOGIC_VECTOR(2 DOWNTO 0);
MODEL :IN STD_LOGIC_VECTOR(2 DOWNTO 0);
MODEL_out :out STD_LOGIC_VECTOR(2 DOWNTO 0);
clkin: IN STD_LOGIC;
clkin_1Hz: IN STD_LOGIC;
col_red:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
col_green:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
row:OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END COMPONENT;
COMPONENT hwk7_02_movecount IS
PORT( clkin:IN STD_LOGIC;
btn:IN STD_LOGIC_VECTOR(1 downto 0);
x1:OUT STD_LOGIC_VECTOR(2 downto 0));
END COMPONENT;
COMPONENT hwk7_02_MODEL IS
PORT( BTN0 , BTN1 ,BTN2:IN STD_LOGIC;
MODEL_in:in STD_LOGIC_VECTOR(2 DOWNTO 0);
MODEL:OUT STD_LOGIC_VECTOR(2 DOWNTO 0);
finish:in STD_LOGIC_VECTOR(1 DOWNTO 0);
close: out STD_LOGIC
);
END COMPONENT;
COMPONENT hwk7_02_fallpointcount IS
PORT( clear,clkin: IN STD_LOGIC;
clkin_2Hz: IN STD_LOGIC;
speed:IN STD_LOGIC_VECTOR(1 downto 0);
M:IN STD_LOGIC_VECTOR(2 downto 0);
x0:OUT STD_LOGIC_VECTOR(2 downto 0);
y0:OUT STD_LOGIC_VECTOR(2 downto 0));
END COMPONENT;
COMPONENT hwk7_02_goal IS
PORT( clkin: IN STD_LOGIC;
goal:out STD_LOGIC;
MODEL :IN STD_LOGIC_VECTOR(2 DOWNTO 0);
x0:in STD_LOGIC_VECTOR(2 downto 0);
y0:in STD_LOGIC_VECTOR(2 downto 0);
x1:in STD_LOGIC_VECTOR(2 downto 0));
END COMPONENT;
COMPONENT hwk7_02_goalSegmentDisplay IS
PORT(clk,clk_1Hz, close: in std_logic;
goal:in std_logic;
finish: out std_logic_vector(1 downto 0);
number: OUT STD_LOGIC_VECTOR(6 DOWNTO 0);
cat: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END COMPONENT;
COMPONENT hwk7_02_music IS
PORT(
clk_in:IN STD_LOGIC;
goal:IN STD_LOGIC;
model:IN STD_LOGIC_vector(2 downto 0);
music:OUT STD_LOGIC);
END COMPONENT;
SIGNAL m_signal: STD_LOGIC_VECTOR(2 DOWNTO 0);
SIGNAL clk_10Hz_signal,clk_1Hz_signal,clk_2Hz_signal: STD_LOGIC;
SIGNAL FDBTN0_signal , FDBTN1_signal ,FDBTN2_signal,fdgoal_signal:STD_LOGIC;
SIGNAL x0_signal,y0_signal,x1_signal,MODEL_signal,MODEL_out_signal: STD_LOGIC_VECTOR(2 DOWNTO 0);
SIGNAL goal_signal,close_signal: STD_LOGIC;
SIGNAL finish_signal: STD_LOGIC_vector(1 downto 0);
BEGIN
G1:hwk7_02_M1 PORT MAP(clkin=>clk_1M,clear=>FDBTN0_signal,m=>m_signal);
G2:hwk7_02_CLK_DIVISON PORT MAP(clkin=>clk_1M,clk_out_10Hz=>clk_10Hz_signal, clk_out_1Hz=>clk_1Hz_signal, clk_out_2Hz=>clk_2Hz_signal);
G3:hwk7_02_FD PORT MAP(goal=>goal_signal,fdgoal=>fdgoal_signal,clkin=>clk_1M , BTN0=>btn0 , BTN1=>btn1 , BTN2=>btn2, FDBTN0=>FDBTN0_signal , FDBTN1=>FDBTN1_signal ,FDBTN2=>FDBTN2_signal);
G4:hwk7_02_POINTDISPLAY PORT MAP(x0=>x0_signal,y0=>y0_signal,x1=>x1_signal,MODEL=>MODEL_signal,MODEL_out=>MODEL_out_signal,clkin=>clk_1M,clkin_1Hz=>clk_1Hz_signal,col_red=>col_red,col_green=>col_green,row=>row);
G5:hwk7_02_movecount PORT MAP(clkin=>clk_10Hz_signal,btn(0)=>FDBTN1_signal,btn(1)=>FDBTN2_signal,x1=>x1_signal);
G6:hwk7_02_fallpointcount PORT MAP(speed=>speed,clear=>FDBTN0_signal,clkin=>clk_1M,clkin_2Hz=>clk_2Hz_signal,M=>m_signal,x0=>x0_signal,y0=>y0_signal);
G7:hwk7_02_MODEL PORT MAP(finish=>finish_signal ,model_in=>model_out_signal,btn0=>FDBTN0_signal,btn1=>FDBTN1_signal,btn2=>FDBTN2_signal,MODEL=>MODEL_signal,close=>close_signal);
G8:hwk7_02_goal PORT MAP(model=>model_signal,clkin=>clk_1M,x0=>x0_signal,y0=>y0_signal,x1=>x1_signal,goal=>goal_signal);
G9:hwk7_02_goalSegmentDisplay PORT MAP(clk=>clk_1M,clk_1hz=>clk_1hz_signal,close=>close_signal,goal=>goal_signal,finish=>finish_signal,number=>segnumber,cat=>cat);
G10:hwk7_02_music PORT MAP(goal=>fdgoal_signal,clk_in=>clk_1M,model=>model_out_signal,music=>music);
END;
五、遇到的问题和解决办法
问题:小球跳格下落,每次下落两行
解决办法: 在分频器的代码外嵌套了一个上升沿的判断语句,如下面红色部分所示。
p4:process(count_2Hz,clkin)
begin
if rising_edge(clkin) then
if count_2Hz<125000 then
clk_out_2Hz <= ‘0’;
else clk_out_2Hz <= ‘1’;
end if;
end if;
end process p4;
问题:验收时老师指出,小球下落未到最后一行,到了倒数第二行就重新到第0行了。
解决办法: 在小球位矢计数器和点阵显示模块中加入最后一行的代码,代码格式和前几行格式一样,只要复制就行。
问题:底板位矢计数器中,两个进程中无法对同一个信号进行赋值。
解决办法:加一个扫描信号,以它为敏感信号建立一个进程。将输入的按键信号合并为一组二进制信号,当扫描到btn为01或者10时,对底板的位矢进行+1或者-1。
六、总结
这次实验时间跨度很大,大二下的实验,因为疫情原因只能在家用做仿真,回学校才拿到器件开始做实物实验,不过因祸得福,我的Quartus使用的熟练度有了很大提升。
回学校用了实物以后才知道实物电路和仿真的差距有多大,很多问题都是用仿真软件时难以发现的。也在实验中通过烧录发现问题,解决问题,也是需要不断的实验来积累自己的经验的。
这个实验做起来到最后还是有一些遗憾的吧,没有把所有的提高功能做完,一个是因为每周六要上课,学校压缩课时没有太多课余时间,二个是因为数电实验验收前一阵子恰好赶上期中考试,但是在写代码的时候预留了部分接口,给之后提高留了空间,等学期结束,可以把提高的部分自己给写完。
原本挺讨厌实验课的,觉得实验中遇到的问题很“玄学”,很多问题是需要经验积累的,不去踩这个坑就很难知道这个问题,就很难意识到问题。数字电路的问题没有C代码那样容易被发现。但是一旦有了经验,知道问题在哪,调起来还是很快的。做了这次接球小游戏实验,我对数电实验没有原来那么厌恶或者说畏惧了,掌握了很多调试的方法,比如说将其分块分别测试,看仿真的波形,这些方法都是需要经验去积累和自行领会的。感谢这次实验机会吧,也感谢老师的答疑和帮助,谢谢!