北京邮电大学电路实验中心
<数字电路与逻辑设计实验(下)>
实
验
报
告
班 级: xxx
学 院: xxx
实 验 室: xxx
审阅教师:
姓名(班内序号): xxx
学 号: xxx
实验时间: xxx
评定成绩:
目录
一、任务要求 2
1.基本要求 2
2.提高要求 2
二、系统设计 2
1.设计思路 2
2.总体框图 4
3.分块设计 5
(1)分频器模块 5
(2)4×4键盘输入模块 5
(3)数码管显示模块 6
(4)8×8 LED点阵显示模块 6
(5)LCD液晶屏显示模块 6
(6)中心模块 6
三、仿真波形及波形分析 6
1.分频器模块 6
2.4×4键盘输入模块 7
3.数码管显示模块 7
4.8×8 LED点阵显示模块 8
5.LCD液晶屏显示模块 8
6.中心模块 8
四、源程序 9
1.分频器模块 9
2.4×4键盘输入模块 9
3.数码管显示模块 11
4.8×8 LED点阵显示模块 12
5.LCD液晶屏显示模块 19
6.中心模块 23
五、功能说明及资源利用情况 26
六、故障及问题分析 27
七、总结和结论 27
本电路可供甲乙二人进行猜拳游戏。通过不同的按键控制,选择多种出拳方式,显示猜 拳的结果,实现猜拳游戏,防止了作弊的可能。
1、甲乙双方各用 4×4 键盘中的三个按键模拟“石头”、“剪刀”、“布”,一个按键为“确 认”。4×4 键盘第一行为甲,第二行为乙;
2、裁判用 4×4 键盘第三行的一个按键模拟“开”,一个按键为“准备”,一个按键为“复 位”;
3、裁判宣布“准备”后,甲乙双方分别选择出拳方式并确认;
4、裁判“开”以后,用点阵的左右三列同时显示甲乙双方的猜拳选择(如下图所示), 并用两个数码管显示甲乙的猜拳比分;
图 1甲“布”,乙“剪刀”;甲“剪刀”,乙“石头”
5、猜拳游戏为五局三胜制。若甲乙双方出拳一致,则比分保持不变,双方重新出拳;
6、比赛结束后,用 8×8 点阵显示甲乙获胜方;
7、复位后游戏重新开始。
1、点阵显示增加游戏开机动画、结束动画;
2、为游戏增加音效;
3、在 LCD1602 液晶屏上显示甲乙双方的猜拳比分;
4、自拟其他功能。
本电路分为6个模块,分别是中心模块(包含状态机)、8×8 LED点阵显示模块、数码管显示模块、LCD液晶屏显示模块、4×4键盘输入模块、分频器模块,各模块使用VHDL语言设计,顶层连接使用Quartus II原理图设计。
分频器模块负责将50MHz时钟分成低频信号,供其他模块使用。中心模块负责读取4×4键盘输入模块的输入,并控制状态机和其他模块的输出显示。8×8 LED点阵显示模块负责接收中心模块的信号,显示相应的图案。数码管显示模块和LCD液晶屏显示模块负责接收中心模块的信号,显示比分。4×4键盘输入模块负责读取键盘输入,并将其输出到中心模块。
图 2系统流程图
图 3逻辑框图
图 4 BDF原理图
输入clkin为50MHz时钟,输出clkout为1KHz时钟,作为中心模块、8×8 LED点阵显示模块、数码管显示模块、4×4键盘输入模块的时钟信号。
4×4键盘输入模块负责读取键盘输入,并将其输出到中心模块。输出KBcol为4位二进制信号,是键盘的遍历扫描信号。输入KBrow为4位二进制信号,是键盘的检测信号。输出resultout为5位二进制信号,是4×4键盘输入模块所检测出的所按的按键,其中第一位代表键盘按下,后四位用二进制数表示所按的按键。
数码管显示模块负责接收中心模块的信号,显示比分。输入A、B分别为2位二进制信号,代表甲、乙的得分。输出cat为8位二进制信号,控制8个数码管的使能端。输出disp为7位二进制信号,控制数码管所显示的图案。
8×8 LED点阵显示模块负责接收中心模块的信号,显示相应的图案。输入A、B分别为2位二进制信号,代表甲、乙的出拳结果,其中“11”表示甲或乙获胜,显示结束动画。输入en为点阵的使能端,start为开机动画控制信号。输出row为8位二进制信号,是点阵的扫描信号。输出colr为8位二进制信号,是红色点阵的数据信号。输出colg为8位二进制信号,是绿色点阵的数据信号。
LCD液晶屏显示模块负责接收中心模块的信号,显示比分。时钟clk直接使用50MHz信号。输入rst为LCD液晶屏模块的复位信号,输入A、B分别为2位二进制信号,代表甲、乙的得分。输出rs、en、rw、data_out为LCD液晶屏的控制和数据信号。
中心模块负责读取4×4键盘输入模块的输入,并控制状态机和其他模块的输出显示。输入KB为5位二进制信号,是4×4键盘输入模块所检测出的所按的按键。输出LEDen控制LED点阵模块的使能端,LEDstart为LED点阵模块的开机动画控制信号。输出LEDA、LEDB分别为2位二进制信号,代表甲、乙的出拳结果,其中“11”表示甲或乙获胜,显示结束动画。输出DISPA、DISPB分别为2位二进制信号,代表甲、乙的得分。
分频比太大,不易仿真。
图 5 4×4键盘输入模块仿真
模块为时钟下降沿有效,resultout[4]为有按键按下的信号,resultout[0..3]为按下的按键。仿真中遍历了所有按键的情况,在resultout中对应有16~31的所有情况(没有按顺序)。在中心模块编写时,考虑了防抖的问题,检测到按下多次按键与按下一次按键的效果相同,所以在此模块中没有必要加入防抖。
图 6数码管显示模块仿真
时钟clk为‘0’时,DISP7点亮,显示甲的得分,时钟clk为‘1’时,DISP6点亮,显示乙的得分。输入A、B遍历了甲、乙得分的所有结果,对应disp为数码管的显示,‘~’状态表示0分,‘0’状态表示1分,‘m’状态表示2分,‘y’状态表示3分。
图 7 8×8 LED点阵显示模块仿真
此模块状态太多,只仿真了部分状态。输入A、B的‘0’-‘2’状态分别代表石头、剪刀、布,‘3’状态代表甲或乙获胜。输出colr为甲的出拳结果,colg为乙的出拳结果。
此模块使用50MHz信号,不易仿真。实现功能与数码管显示模块类似。
图 8中心模块仿真
此模块状态太多,只仿真了部分状态。仿真中模拟按下了3个按键,第一个是裁判的“准备”键,按键抬起后结束开机动画,进入选手输入状态,LEDen和LEDstart都变为‘0’。第二个是乙按下“剪刀”(甲默认出“布”),按键抬起后LEDB的信号发生变化。第一个是裁判的“开”键,按键抬起后结算双方出拳结果,给乙+1分(DISPB),同时显示双方出拳结果,LEDen变为‘1’。
library ieee;
use ieee.std_logic_1164.all;
entity fenpinqi12 is
port( clkin:in std_logic; --时钟信号输入
clkout:out std_logic); --时钟信号输出
end fenpinqi12;
architecture aroneMHZ of fenpinqi12 is
signal data:integer range 0 to 24999;
signal Q:std_logic;
begin
process(clkin)
begin
if rising_edge(clkin) then --检测输入时钟上升沿
if(data=24999) then --此句为你想要的分频比,data=0,1,2,3,4.......9的分频比为1,2,3,,,10
data<=0;
Q<=not Q;
else
data<=data+1;
end if;
end if;
clkout<=Q;
end process;
end aroneMHZ;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY KBcontroller IS
PORT(
clk:IN STD_LOGIC; --时钟
KBcol:OUT STD_LOGIC_VECTOR(0 TO 3); --扫描信号
KBrow:IN STD_LOGIC_VECTOR(0 TO 3); --检测信号
resultout:OUT STD_LOGIC_VECTOR(4 DOWNTO 0) --检测结果
);
END KBcontroller;
ARCHITECTURE behavioral OF KBcontroller IS
signal temp:INTEGER RANGE 0 TO 3;
signal result:STD_LOGIC_VECTOR(4 DOWNTO 0);
BEGIN
P1:PROCESS(temp)
BEGIN
IF (clk'event and clk='0') THEN
CASE temp IS --检测键盘输入结果
WHEN 0=>
CASE KBrow IS
WHEN "0111"=> result<="11111";
WHEN "1011"=> result<="11110";
WHEN "1101"=> result<="11101";
WHEN "1110"=> result<="11100";
WHEN OTHERS=> result<="00000";
END CASE;
WHEN 1=>
CASE KBrow IS
WHEN "0111"=> result<="11011";
WHEN "1011"=> result<="11010";
WHEN "1101"=> result<="11001";
WHEN "1110"=> result<="11000";
WHEN OTHERS=> result<="00000";
END CASE;
WHEN 2=>
CASE KBrow IS
WHEN "0111"=> result<="10111";
WHEN "1011"=> result<="10110";
WHEN "1101"=> result<="10101";
WHEN "1110"=> result<="10100";
WHEN OTHERS=> result<="00000";
END CASE;
WHEN 3=>
CASE KBrow IS
WHEN "0111"=> result<="10011";
WHEN "1011"=> result<="10010";
WHEN "1101"=> result<="10001";
WHEN "1110"=> result<="10000";
WHEN OTHERS=> result<="00000";
END CASE;
WHEN OTHERS=> NULL;
END CASE;
END IF;
resultout<=result;
END PROCESS P1;
P2:process(clk)
begin
IF (clk'event and clk='1') THEN --模4计数器,对应键盘的4列
IF temp=3 THEN
temp<=0;
ELSE
temp<=temp+1;
END IF;
END IF;
END PROCESS P2;
P3:process(temp)
begin
CASE temp IS --键盘扫描输出
WHEN 0=> KBcol<="1110";
WHEN 1=> KBcol<="1101";
WHEN 2=> KBcol<="1011";
WHEN 3=> KBcol<="0111";
WHEN OTHERS=> KBcol<="1111";
END CASE;
END PROCESS P3;
END behavioral;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY DISPshow IS
PORT(
clk:IN STD_LOGIC; --时钟
A:IN STD_LOGIC_VECTOR(1 DOWNTO 0); --甲的得分
B:IN STD_LOGIC_VECTOR(1 DOWNTO 0); --乙的得分
disp:OUT STD_LOGIC_VECTOR(0 To 6); --显示内容
cat:OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); --数码管使能
END DISPshow;
ARCHITECTURE behavioral OF DISPshow IS
BEGIN
P3:process(clk,A,B)
variable dispA:STD_LOGIC_VECTOR(0 To 6);
variable dispB:STD_LOGIC_VECTOR(0 To 6);
begin
CASE A IS --将甲得分变为数码管显示信号
WHEN "00"=> dispA:="1111110";--0
WHEN "01"=> dispA:="0110000";--1
WHEN "10"=> dispA:="1101101";--2
WHEN "11"=> dispA:="1111001";--3
WHEN OTHERS=> dispA:="0000000";
END CASE;
CASE B IS --将乙得分变为数码管显示信号
WHEN "00"=> dispB:="1111110";--0
WHEN "01"=> dispB:="0110000";--1
WHEN "10"=> dispB:="1101101";--2
WHEN "11"=> dispB:="1111001";--3
WHEN OTHERS=> dispB:="0000000";
END CASE;
CASE clk IS --时钟为‘0’时显示甲,时钟为‘1’时显示乙,相当于扫描
WHEN '0'=> disp<=dispA; cat<="01111111";
WHEN '1'=> disp<=dispB; cat<="10111111";
WHEN OTHERS=> disp<="0000000"; cat<="11111111";
END CASE;
END PROCESS P3;
END behavioral;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY LEDshow IS
PORT(
clk:IN STD_LOGIC;--时钟
en:IN STD_LOGIC;--使能端
A:IN STD_LOGIC_VECTOR(1 DOWNTO 0); --甲的出拳
B:IN STD_LOGIC_VECTOR(1 DOWNTO 0); --乙的出拳
start:IN STD_LOGIC;--开始动画控制
colr:OUT STD_LOGIC_VECTOR(7 DOWNTO 0); --红色数据信号
colg:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);--绿色数据信号
row:OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); --扫描信号
END LEDshow;
ARCHITECTURE behavioral OF LEDshow IS
signal temp:INTEGER RANGE 0 TO 8;
signal temp1:INTEGER RANGE 0 TO 5;
signal data:integer range 0 to 249;
signal clk_2Hz,Q:STD_LOGIC;
signal A0:STD_LOGIC_VECTOR(0 to 7);
signal A1:STD_LOGIC_VECTOR(0 to 7);
signal A2:STD_LOGIC_VECTOR(0 to 7);
signal A3:STD_LOGIC_VECTOR(0 to 7);
signal A4:STD_LOGIC_VECTOR(0 to 7);
signal A5:STD_LOGIC_VECTOR(0 to 7);
signal A6:STD_LOGIC_VECTOR(0 to 7);
signal A7:STD_LOGIC_VECTOR(0 to 7);
signal B0:STD_LOGIC_VECTOR(7 DOWNTO 0);
signal B1:STD_LOGIC_VECTOR(7 DOWNTO 0);
signal B2:STD_LOGIC_VECTOR(7 DOWNTO 0);
signal B3:STD_LOGIC_VECTOR(7 DOWNTO 0);
signal B4:STD_LOGIC_VECTOR(7 DOWNTO 0);
signal B5:STD_LOGIC_VECTOR(7 DOWNTO 0);
signal B6:STD_LOGIC_VECTOR(7 DOWNTO 0);
signal B7:STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
P1:PROCESS(clk_2Hz)
BEGIN
if start='0' then
if A="00" then--甲出布
A0<="00000000"; A1<="00000000"; A2<="11100000"; A3<="11100000";
A4<="11100000"; A5<="11100000"; A6<="00000000"; A7<="00000000";
elsif A="01" then--甲出剪刀
A0<="00000000"; A1<="00000000"; A2<="00100000"; A3<="11000000";
A4<="11000000"; A5<="00100000"; A6<="00000000"; A7<="00000000";
elsif A="10" then--甲出石头
A0<="00000000"; A1<="00000000"; A2<="01000000"; A3<="11100000";
A4<="11100000"; A5<="01000000"; A6<="00000000"; A7<="00000000";
else
case temp1 is--甲获胜,显示动画
when 0 =>--显示“甲”
A0<="11111110";
A1<="10010010";
A2<="11111110";
A3<="10010010";
A4<="11111110";
A5<="00010000";
A6<="00010000";
A7<="00010000";
when 1 =>--显示“获”
A0<="00101000";
A1<="11111110";
A2<="10101000";
A3<="01001010";
A4<="10111110";
A5<="01101000";
A6<="10101100";
A7<="01110010";
when 2 =>--显示“胜”
A0<="11100100";
A1<="10110100";
A2<="11111111";
A3<="10100100";
A4<="11111111";
A5<="10100100";
A6<="10100100";
A7<="10111111";
when 3 =>--显示笑脸
A0<="00111100";
A1<="01000010";
A2<="10000001";
A3<="10100101";
A4<="10000001";
A5<="10100101";
A6<="01011010";
A7<="00111100";
when 4 =>--显示笑脸
A0<="00111100";
A1<="01000010";
A2<="10000001";
A3<="10100101";
A4<="10000001";
A5<="10100101";
A6<="01011010";
A7<="00111100";
when 5=>--显示空白
A0<="00000000"; A1<="00000000"; A2<="00000000"; A3<="00000000";
A4<="00000000"; A5<="00000000"; A6<="00000000"; A7<="00000000";
when others=>NULL;
end case;
end if;
if B="00" then--乙出布
B0<="00000000"; B1<="00000000"; B2<="00000111"; B3<="00000111";
B4<="00000111"; B5<="00000111"; B6<="00000000"; B7<="00000000";
elsif B="01" then--乙出剪刀
B0<="00000000"; B1<="00000000"; B2<="00000100"; B3<="00000011";
B4<="00000011"; B5<="00000100"; B6<="00000000"; B7<="00000000";
elsif B="10" then--乙出石头
B0<="00000000"; B1<="00000000"; B2<="00000010"; B3<="00000111";
B4<="00000111"; B5<="00000010"; B6<="00000000"; B7<="00000000";
else
case temp1 is--乙获胜,显示动画
when 0 =>--显示“乙”
B0<="11111100";
B1<="00000100";
B2<="00001000";
B3<="00010000";
B4<="00100000";
B5<="01000001";
B6<="10000001";
B7<="11111111";
when 1 =>--显示“获”
B0<="00101000";
B1<="11111110";
B2<="10101000";
B3<="01001010";
B4<="10111110";
B5<="01101000";
B6<="10101100";
B7<="01110010";
when 2 =>显示“胜”
B0<="11100100";
B1<="10110100";
B2<="11111111";
B3<="10100100";
B4<="11111111";
B5<="10100100";
B6<="10100100";
B7<="10111111";
when 3 =>--显示笑脸
B0<="00111100";
B1<="01000010";
B2<="10000001";
B3<="10100101";
B4<="10000001";
B5<="10100101";
B6<="01011010";
B7<="00111100";
when 4 =>--显示笑脸
B0<="00111100";
B1<="01000010";
B2<="10000001";
B3<="10100101";
B4<="10000001";
B5<="10100101";
B6<="01011010";
B7<="00111100";
when 5 =>--显示空白
B0<="00000000"; B1<="00000000"; B2<="00000000"; B3<="00000000";
B4<="00000000"; B5<="00000000"; B6<="00000000"; B7<="00000000";
when others => NULL;
end case;
end if;
if A="11" then--显示获胜动画时另一个颜色为空白
B0<="00000000"; B1<="00000000"; B2<="00000000"; B3<="00000000";
B4<="00000000"; B5<="00000000"; B6<="00000000"; B7<="00000000";
elsif B="11" then
A0<="00000000"; A1<="00000000"; A2<="00000000"; A3<="00000000";
A4<="00000000"; A5<="00000000"; A6<="00000000"; A7<="00000000";
end if;
else--显示开机动画
B0<="00000000"; B1<="00000000"; B2<="00000000"; B3<="00000000";
B4<="00000000"; B5<="00000000"; B6<="00000000"; B7<="00000000";
case temp1 is--红色的“start”字样
when 0 =>--显示‘s’
A0<="00000000";
A1<="00111000";
A2<="01000100";
A3<="01000000";
A4<="00111000";
A5<="00000100";
A6<="01000100";
A7<="00111000";
when 1 =>--显示‘t’
A0<="00000000";
A1<="01111100";
A2<="00010000";
A3<="00010000";
A4<="00010000";
A5<="00010000";
A6<="00010000";
A7<="00010000";
when 2 =>--显示‘a’
A0<="00000000";
A1<="00010000";
A2<="00101000";
A3<="01000100";
A4<="01000100";
A5<="01111100";
A6<="01000100";
A7<="01000100";
when 3 =>--显示‘r’
A0<="00000000";
A1<="01111000";
A2<="01000100";
A3<="01000100";
A4<="01111000";
A5<="01010000";
A6<="01001000";
A7<="01000100";
when 4 =>--显示‘t’
A0<="00000000";
A1<="01111100";
A2<="00010000";
A3<="00010000";
A4<="00010000";
A5<="00010000";
A6<="00010000";
A7<="00010000";
when others => NULL; --显示空白
-- A0<="00000000";
-- A1<="00000000";
-- A2<="00000000";
-- A3<="00000000";
-- A4<="00000000";
-- A5<="00000000";
-- A6<="00000000";
-- A7<="00000000";
end case;
end if;
END PROCESS P1;
P2:process(clk)
begin
if en='1' then
IF (clk'event and clk='1') THEN--模8计数器,用于扫描点阵
IF temp>=7 THEN
temp<=0;
ELSE
temp<=temp+1;
END IF;
END IF;
else
temp<=8;--使能端为0,则不扫描
end if;
END PROCESS P2;
P4:process(clk)
begin
if rising_edge(clk) then--分频器,分出2Hz的信号,用于动画显示
if(data=249) then --此句为你想要的分频比,data=0,1,2,3,4.......9的分频比为1,2,3,,,10
data<=0;
Q<=not Q;
else
data<=data+1;
end if;
end if;
clk_2Hz<=Q;
end process P4;
P5:process(clk_2Hz)
begin
IF (clk_2Hz'event and clk_2Hz='1') THEN--模6计数器,用于动画显示
IF temp1>=5 THEN
temp1<=0;
ELSE
temp1<=temp1+1;
END IF;
END IF;
END PROCESS P5;
P3:process(temp)
begin--点阵扫描显示进程
CASE temp IS
WHEN 0=> colr<=A0; colg<=B0; row<="01111111";
WHEN 1=> colr<=A1; colg<=B1; row<="10111111";
WHEN 2=> colr<=A2; colg<=B2; row<="11011111";
WHEN 3=> colr<=A3; colg<=B3; row<="11101111";
WHEN 4=> colr<=A4; colg<=B4; row<="11110111";
WHEN 5=> colr<=A5; colg<=B5; row<="11111011";
WHEN 6=> colr<=A6; colg<=B6; row<="11111101";
WHEN 7=> colr<=A7; colg<=B7; row<="11111110";
WHEN OTHERS=> colr<="00000000"; colg<="00000000"; row<="11111111";
END CASE;
END PROCESS P3;
END behavioral;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY show IS PORT
(rst,clk: IN STD_LOGIC; --复位、时钟
A:IN STD_LOGIC_VECTOR(1 DOWNTO 0); --甲的得分
B:IN STD_LOGIC_VECTOR(1 DOWNTO 0); --乙的得分
rs, en, rst_out, sec_out: OUT STD_LOGIC;
rw: OUT STD_LOGIC;
data_out: OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END show;
ARCHITECTURE fwm OF show IS
TYPE states IS (pause,hold, func_set, dis_on,mode_set,set_ddram1,write_ddram1,set_ddram2,write_char1,write_char2,write_char3,
write_char4,write_char5, write_char6,write_char7,write_char8,write_char9,write_char10,write_char11,write_char12,
write_char13,write_char14,write_char15,return_home,toggle_e,rst1,rst2,rst3,dis_off,dis_clr);
SIGNAL state, n_state: states; --
--SIGNAL data_out: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL s0,s1,m0,m1,h0,h1,t0,t1 : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL clk_400Hz, clk_100Hz : STD_LOGIC;
SIGNAL temp:STD_LOGIC;
TYPE ram IS ARRAY (0 TO 15)OF STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL ram1:ram:=(X"20",X"20",X"20",X"20",X"41",X"3A",X"30",X"20",X"20",X"42",X"3A",X"30",X"20",X"20",X"20",X"20"); --显示比分“A:0 B:0”
signal stop_out:std_logic;
BEGIN rst_out <= NOT rst; sec_out <= s0(0); --
--data_out <= data_out WHEN rw = '0' ELSE "ZZZZZZZZ"; -- 设置LCD的数据线为三态数据线
PROCESS(clk,rst) --50MHz分频到400Hz
VARIABLE cnt1: INTEGER RANGE 0 TO 62500;
BEGIN
IF rst='0' THEN cnt1:=0;
clk_400Hz<='0';
ELSIF clk'EVENT AND clk = '1' THEN
IF cnt1 < 62500 THEN cnt1 := cnt1 + 1;
ELSE cnt1 := 0;
clk_400Hz <= NOT clk_400Hz;
END IF; END IF;
END PROCESS;
PROCESS(clk_400Hz) --50MHz分频到400Hz
BEGIN
case A is--修改甲的得分显示
when "00"=> ram1(6)<=X"30";
when "01"=> ram1(6)<=X"31";
when "10"=> ram1(6)<=X"32";
when "11"=> ram1(6)<=X"33";
when others=> NULL;
end case;
case B is--修改乙的得分显示
when "00"=> ram1(11)<=X"30";
when "01"=> ram1(11)<=X"31";
when "10"=> ram1(11)<=X"32";
when "11"=> ram1(11)<=X"33";
when others=> NULL;
end case;
END PROCESS;
PROCESS (clk_400Hz, rst)
VARIABLE cnt : INTEGER RANGE 0 TO 16;
VARIABLE cnt2 :INTEGER RANGE 0 TO 199;
BEGIN
IF rst = '0' THEN state <=rst1;
data_out <= X"38";
n_state <= rst2;
en <= '1';
rs <= '0';
rw <= '0';
ELSIF clk_400Hz'EVENT AND clk_400Hz = '1' THEN --产生秒脉冲100Hz信号,调试时采用100Hz
--IF stop ='1' THEN state<=pause;
--END IF;
CASE state IS --LCD控制
WHEN rst1 => en <= '1';
rs <= '0';rw <= '0';
data_out <= X"38";
state <= toggle_e;
n_state <= rst2;--设置功能:8位,两行,5×7
WHEN rst2 => en <= '1';
rs <= '0';rw <= '0';
data_out <= X"38";
state <= toggle_e;
n_state <= rst3;--设置功能:8位,两行,5×7
WHEN rst3 => en <= '1';
rs <= '0';rw <= '0';
data_out <= X"38";--001 1000
state <= toggle_e;
n_state <= func_set;--设置功能:8位,两行,5×7,可靠复位
WHEN func_set => en <= '1';
rs <= '0';
rw <= '0';
data_out <= X"38";
state <= toggle_e;
n_state <= dis_off;
WHEN dis_off => en <= '1';
rs <= '0';rw <= '0';
data_out <= X"08";
state <= toggle_e;
n_state <= dis_clr; --显示控制:显示关,光标关
WHEN dis_clr => en <= '1';
rs <= '0';
rw <= '0';
data_out <= X"01";
state <= toggle_e;
n_state <= dis_on;--清屏
WHEN dis_on => en <= '1';
rs <= '0';
rw <= '0';
data_out <= X"0C";
state <= toggle_e;
n_state <= mode_set;--显示控制:显示开,光标关
WHEN mode_set => en <= '1';
rs <= '0';rw <= '0';
data_out <= X"06";
state <= toggle_e;
n_state <= set_ddram1;--显示模式:自动增地址,光标右移
WHEN set_ddram1 => en <='1';
rs<='0';
rw<='0';
data_out<=X"80";
state <= toggle_e;
n_state<=write_ddram1;
WHEN write_ddram1=>en<='1';
rs<='1';
rw<='0';
data_out<=ram1(cnt)(7 DOWNTO 0);
state <= toggle_e;
cnt:=cnt+1; --将ram1的15个byte写入ADDRAM
IF cnt=16
THEN n_state<=return_home;
END IF;
WHEN return_home => en <= '1';
rs <= '0';
rw <= '0';
data_out <= "11000000";
state <= toggle_e;
n_state <= set_ddram1;--返回写地址到第一行第一列位置
WHEN toggle_e => en <= '0';
state <= hold;--en下降沿
WHEN hold => state <= n_state; --保持
WHEN pause=>en<='0';
state <= toggle_e;
when others=>NULL;
END CASE;
END IF;
END PROCESS;
END fwm;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY main IS
PORT(
clk:IN STD_LOGIC;--时钟
LEDen:OUT STD_LOGIC;--LED点阵使能端
KB:IN STD_LOGIC_VECTOR(4 DOWNTO 0);--键盘
LEDA:OUT STD_LOGIC_VECTOR(1 DOWNTO 0):="00"; --甲的出拳
LEDB:OUT STD_LOGIC_VECTOR(1 DOWNTO 0):="00";--乙的出拳
DISPA:OUT STD_LOGIC_VECTOR(1 DOWNTO 0):="00"; --甲的得分
DISPB:OUT STD_LOGIC_VECTOR(1 DOWNTO 0):="00";--乙的得分
LEDstart:OUT STD_LOGIC--开机动画控制
);
END main;
ARCHITECTURE behavioral OF main IS
type state_type is(S0,S1,S2,S3);
signal temp:state_type:=s0;
signal finish:STD_LOGIC:='0';
signal change:STD_LOGIC:='0';
signal goalA:INTEGER RANGE 0 TO 3:=0;
signal goalB:INTEGER RANGE 0 TO 3:=0;
signal answerA:INTEGER RANGE 0 TO 3:=0;
signal answerB:INTEGER RANGE 0 TO 3:=0;
signal confirmA:STD_LOGIC:='0';
signal confirmB:STD_LOGIC:='0';
BEGIN
P1:process(clk)--状态机进程
begin
IF (clk'event and clk='1') THEN
case temp is
--reset
when s0 =>if (KB="10010") then temp<=s1;--change<='0';--按下“准备”进入ready状态
end if;
--ready
when s1 =>if (KB="10110") then temp<=s2;--change<='1'; --按下“开”进入show状态
elsif (KB="11110") then temp<=s0;--change<='0'; --按下“复位”进入reset状态
end if;
--show
when s2 =>if (finish='0' and KB="10010") then temp<=s1;--change<='0'; --按下“准备”进入ready状态
elsif finish='1' then temp<=s3;--change<='0'; --游戏结束,进入end状态
elsif (KB="11110") then temp<=s0;--change<='0'; --按下“复位”进入reset状态
end if;
--end
when s3 =>if (KB="11110") then temp<=s0;--change<='0'; --按下“复位”进入reset状态
end if;
when others => temp<=s0;--change<='0';
end case;
end if;
END PROCESS P1;
P2:process(clk,goalA,goalB)--输出控制进程
begin
IF (clk'event and clk='1') THEN
case temp is
when s0 =>--reset状态,显示开始动画
answerA<=0;
answerB<=0;
confirmA<='0';
confirmB<='0';
finish<='0';
LEDen<='1';
LEDstart<='1';
change<='0';
when s1 =>--ready状态
change<='0';
LEDstart<='0';
LEDen<='0';
case KB is--检测甲乙的出拳
when "10000" =>if confirmA='0' then answerA<=0;end if;--布
when "10100" =>if confirmA='0' then answerA<=1;end if;--剪刀
when "11000" =>if confirmA='0' then answerA<=2;end if;--石头
when "11100" =>confirmA<='1';--按下确认
when "10001" =>if confirmB='0' then answerB<=0;end if;
when "10101" =>if confirmB='0' then answerB<=1;end if;
when "11001" =>if confirmB='0' then answerB<=2;end if;
when "11101" =>confirmB<='1'; --按下确认
when others => NULL;
end case;
when s2 =>--show状态,显示出拳结果
change<='1';
LEDen<='1';
LEDstart<='0';
if (goalA>=3 or goalB>=3) then--赢三局,游戏结束
finish<='1';
end if;
confirmA<='0';
confirmB<='0';
when s3 =>--end状态
change<='0';
LEDen<='1';
LEDstart<='0';
if KB="11010" then--按下“结果”键,显示获胜方的获胜动画
if goalA>=3 then
answerA<=3;
else answerB<=3;
end if;
end if;
when others => NULL;
end case;
case goalA is--显示得分
when 0 => DISPA<="00";
when 1 => DISPA<="01";
when 2 => DISPA<="10";
when 3 => DISPA<="11";
when others => NULL;
end case;
case goalB is--显示得分
when 0 => DISPB<="00";
when 1 => DISPB<="01";
when 2 => DISPB<="10";
when 3 => DISPB<="11";
when others => NULL;
end case;
case answerA is--显示出拳
when 0 => LEDA<="00";
when 1 => LEDA<="01";
when 2 => LEDA<="10";
when 3 => LEDA<="11";
when others => NULL;
end case;
case answerB is--显示出拳
when 0 => LEDB<="00";
when 1 => LEDB<="01";
when 2 => LEDB<="10";
when 3 => LEDB<="11";
when others => NULL;
end case;
end if;
END PROCESS P2;
P3:process(temp,change)--计算得分的进程
begin
if (temp=s0) then--reset状态清零
goalA<=0;
goalB<=0;
elsif (change'event and change='1') then
if(temp=s2) then
case answerB is--判断获胜方并加分
when 0 =>
if answerA=2 then goalB<=goalB+1;end if;
if answerA=1 then goalA<=goalA+1;end if;
when 1 =>
if answerA=0 then goalB<=goalB+1;end if;
if answerA=2 then goalA<=goalA+1;end if;
when 2 =>
if answerA=1 then goalB<=goalB+1;end if;
if answerA=0 then goalA<=goalA+1;end if;
when others => NULL;
end case;
end if;
end if;
END PROCESS P3;
END behavioral;
此工程实现了全部的基本要求、提高要求的1和3(动画和LCD显示)。验收时包含提高要求的程序出现了一点问题(现在已经解决),因此只验收了基本要求。
资源利用情况如下:
图 9资源利用情况
验收时,只包含基本要求,资源利用情况如下:
图 10资源利用情况2
1.增加动画和LCD显示模块时,出现问题,只有甲获胜会加分,乙获胜不加分。经过仿真发现问题是电路需要反应时间导致时钟沿不匹配。解决方法是修改了时钟沿。
2.设计4×4键盘输入模块时,发现检测不到按键信号。后来发现是扫描与检测的端口接反了。
经过逻辑分析,编写VHDL代码,然后调试,进行波形仿真,最后下载到实验板实现,一系列工序之后,成功实现了本实验。我认识到进行数字电路实验,理论分析是十分重要的一环,只有逻辑分析透彻无误,才能用语言进行描述,进而用硬件实现。这次实验让我对VHDL这样一门硬件描述语言有了更加深刻的认识。编写硬件描述代码,必须使用与编写软件完全不同的思想。编写硬件描述代码,不仅要符合基本编程语言的规范,更应该时时刻刻联系实现功能的硬件,理解时序和组合的关系,理解同步和异步的差异,理解进程和信号的流程等等,这样才能使写出的代码效率更高。在这学期数字电路实验中,我在实验操作能力有所提升的同时也更深的理解了数字电路与逻辑设计的理论知识,也体会到了数字电路的强大功能。
本文来源:https://www.2haoxitong.net/k/doc/50fc7bc3fc0a79563c1ec5da50e2524de518d0e9.html
文档为doc格式