名称:网球计分器设计VHDL代码VIVADO仿真(文末获取)
软件:VIVADO
语言:VHDL
代码功能:
网球计分器
计分器可以同时显示2位选手的分数,通过2个按键分别控制2个分数,按键按一次加对应分数,分数为0~4,采用7段数码管显示分数,0分时显示L,1分显示15,2分显示30,3分显示40,4分显示W。W表示获胜,获胜后分数不再变化,同时有LED指示灯指示对应选手获胜。获胜指示持续5秒后自动返回初始状态,即显示L。通过这个计分器可以用来在网球比赛中计分。
网球计分器设计报告
一、摘要
本设计使用VHDL语言设计了一个网球计分器,计分器可以同时显示2位选手的分数,通过2个按键分别控制2个分数,按键按一次加对应分数,分数为0~4,采用7段数码管显示分数,0分时显示L,1分显示15,2分显示30,3分显示40,4分显示W。W表示获胜,获胜后分数不再变化,同时有LED指示灯指示对应选手获胜。获胜指示持续5秒后自动返回初始状态,即显示L。通过这个计分器可以用来在网球比赛中计分。
二、概述
本报告设计的是一个网球计分器,计分器可以同时显示2位选手的分数,通过2个按键分别控制2个分数,按键按一次加对应分数,分数为0~4,采用7段数码管显示分数,0分时显示L,1分显示15,2分显示30,3分显示40,4分显示W。W表示获胜,获胜后分数不再变化,同时有LED指示灯指示对应选手获胜。获胜指示持续5秒后自动返回初始状态,即显示L。
设计代码时可以分为3个代码进行设计,分别为顶层模块Tennis_Scoreboard、计分模块Scoreboard、显示模块segment_display。顶层模块调用计分模块和显示模块,用于将两个模块连接,使其组合到一起。计分模块根据按键控制对应选手的分数,并且需要控制获胜后的led指示灯和获胜后持续5秒后返回初始状态。显示模块用于将计分模块的分数转换为数码管显示的内容,即0分时显示L,1分显示15,2分显示30,3分显示40,4分显示W。需要控制数码管的段选和位选信号。
三、顶层模块
顶层模块Tennis_Scoreboard的实体定义如下:
ENTITY Tennis_Scoreboard IS
PORT (
clk : IN STD_LOGIC;--clk
reset : IN STD_LOGIC;--reset
player1_key : IN STD_LOGIC;--player1 score add key
player2_key : IN STD_LOGIC;--player2 score add key
LED_1 : OUT STD_LOGIC;--player1 win LED
LED_2 : OUT STD_LOGIC;--player2 win LED
bit_select : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);--7segment_display bit_select
lednum_select : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)--7segment_display segment_select
);
END Tennis_Scoreboard;
顶层模块输入包括时钟clk信号,复位reset信号,2个按键player1_key和player2_key。输出为2个led灯LED_1和LED_2,2个数码管控制信号bit_select和lednum_select,其中bit_select为4bit,控制4个数码管的亮灭,lednum_select为8bit信号,控制每个数码管的显示值,通过这两个信号配合可以使4个数码管显示不同的值。下面是模块调用部分代码,调用计分模块和显示模块,用于将两个模块连接,使其组合到一起:
--call Scoreboard module
i_Scoreboard : Scoreboard
PORT MAP (
clk => clk,
reset => reset,
player1_key => player1_key,--player1 score add key
player2_key => player2_key,--player2 score add key
LED_1 => LED_1,--player1 win LED
LED_2 => LED_2,--player2 win LED
score_1 => score_1,--player1 score
score_2 => score_2 --player2 score
);
--call segment_display module
i_segment_display : segment_display
PORT MAP (
clk => clk,
reset => reset,
score_1 => score_1,--player1 score
score_2 => score_2,--player2 score
bit_select => bit_select,--7segment_display bit_select
lednum_select => lednum_select--7segment_display segment_select
);
首先调用Scoreboard模块,可以得到2个选手的分数,即score_1信号和score_2信号,再调用数码管显示模块segment_display,将score_1信号和score_2信号输入到segment_display模块中,最终通过7segment_display的bit_select和lednum_select信号进行显示。
四、计分模块
计分模块的实体定义如下:
ENTITY Scoreboard IS
PORT (
clk : IN STD_LOGIC;--clk
reset : IN STD_LOGIC;--reset
player1_key : IN STD_LOGIC;--player1 score add key
player2_key : IN STD_LOGIC;--player2 score add key
LED_1 : OUT STD_LOGIC;--player1 win LED
LED_2 : OUT STD_LOGIC;--player2 win LED
score_1 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);--player1 score
score_2 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)--player2 score
);
END Scoreboard;
输入包括时钟clk信号,复位reset信号,2个按键player1_key和player2_key。输出为2个led灯LED_1和LED_2,和2个分数信号score_1和score_2。
首先将按键信号通过D触发器打2拍,使按键同步于clk信号,如下:
代码见附件
再通过以下代码可以获取按键的上升沿,有了按键上升沿信号才可以用于计分
player1_en <= player1_key_buf0 AND NOT(player1_key_buf1);--Gets the rising edge of the player1_key
同理player2_key也是一样的操作最终也可以得到按键2的上升沿player2_en。
接下来就是计算分数,按键按下一次会产生一次上升沿信号,检测到上升沿后控制分数加1,当加到4以后不再增加,当有复位信号来时,将分数清零,对应代码如下:
代码见附件
同理,选手2的计分也是同样操作。
接下来需要控制LED显示获胜的选手,控制方法为判断分数是否达到4分若为4则控制led拉高,否则为低电平,同理在接收到复位信号后需要拉低led
LED2的控制代码亦同理。
根据要求,当一方获胜后,需要持续5秒后自动恢复到起始状态。因此需要设计一个计时电路,用于计时5秒。计时方法为当count_1或者count_2等于4时,开始每个clock计数一次,由于clk频率为1KHz,所以计数5s需要计数到5000,当计数到5000时,控制clear信号为高电平,该clear信号就可以用于控制计分清零。
代码见附件
到此计分模块就设计完成了。
五、数码管显示模块
数码管显示模块的实体定义如下:
ENTITY segment_display IS
PORT (
clk : IN STD_LOGIC;--clk
reset : IN STD_LOGIC;--reset
score_1 : IN STD_LOGIC_VECTOR(3 DOWNTO 0);--player1 score
score_2 : IN STD_LOGIC_VECTOR(3 DOWNTO 0);--player2 score
bit_select : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);--7segment_display bit_select
lednum_select : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)--7segment_display segment_select
);
END segment_display;
输入包括时钟clk信号,复位reset信号,2个分数信号score_1和score_2,输出为数码管的位选信号bit_select和段选信号lednum_select。其中bit_select为4bit,控制4个数码管的亮灭,lednum_select为8bit信号,控制每个数码管的显示值,通过这两个信号配合可以使4个数码管显示不同的值。
由于分数score是0~4的,因此首先需要将0~4转换为对应显示值,0分时显示L,1分显示15,2分显示30,3分显示40,4分显示W。为此定义了4个信号对应4个数码管显示的内容:
SIGNAL score_1_H : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";
SIGNAL score_1_L : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";
SIGNAL score_2_H : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";
SIGNAL score_2_L : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";
score_1_H表示分数1的高位,score_1_L表示分数1的低位,score_2_H表示分数2的高位,score_2_L表示分数2的低位。例如当score_1为2时,对应30分,所以高位score_1_H=3,低位score_1_L=0;这样就能在数码管上显示30字样。score_1对应转换代码如下:
代码见附件
score_1的转换代码如下:
代码见附件
由于数码管是共用段选信号,因此需要时分复用才能同时显示4个数字,以下代码实现了复用功能:
代码见附件
即通过计数器,将时间分为4段,每段显示对应位的数字。
有了显示值后,接下来需要控制数码管的段选和位选信号。根据Basys3的相关资料可知,Basys3板子上的数码管位选为低电平选中,即低电平时显示,高电平时不显示。段选信号也是低电平点亮,高电平熄灭。如下图所示,图中可以看到,若要显示数字0,需要将ABCDF全部点亮,G和DP不点亮,因此,按DP,G,F,E,D,C,B,A的顺序就是11000000。即十六进制的C0。
设计代码如下:
代码见附件
至此,数码管显示模块代码设计完成了。
六、Testbench
Testebnch用于产生仿真测试激励,即模拟输入时钟、复位、按键1、按键2等信号,观察输出的信号是否正确。由于testbench是一个模拟输入,所以实体可以是空的,如下:
ENTITY test_bench IS
END test_bench;
模拟的时钟信号为100MHz,如下,5ns高电平和5ns低电平:
--Generates the clock
PROCESS
BEGIN
clk <= '0';
WAIT FOR 5 ns;
clk <= '1';
WAIT FOR 5 ns;
END PROCESS;
模拟的复位和按键信号如下:
代码见附件
模拟过程为:先按下复位信号,将系统复位,延时一段时间后player1_key按下,然后再次按下player1_key,后按下player2_key,在按一次player2_key。完了再按3次player1_key。
七、仿真图结果
根据上述testbench运行仿真,可以分别看计分模块和数码管显示模块。
1.计分模块仿真
下图为计分模块的仿真图
上图中,reset信号为高电平后,score_1和score_2均为0,表示复位,分数清零。随后
player1_key信号有个高电平脉冲表示按键按键,对应的分数score_1随即变为1。再来一个player1_key信号后又变为2。score_2也一样,在两次player2_key信号后也变为2。随后player1_key信号又来了2次使score_1分数达到4。可以看到达到4后再按player1_key信号时分数已不再变化。且LED1变为高电平,指示player1获胜。
上图是计分模块的仿真图后半部分,图中可以看到LED1信号在time_5s_cnt计数到5000后变为低电平,表示持续5秒后回到初值状态。
从上面两个仿真图可以看到计分模块实现了模块对应功能,仿真正确。
2. 数码管显示模块仿真
上图为数码管显示模块仿真图,图中reset为高电平时显示C0,表示显示0。图中可以看到score_1_H表示分数1的高位,score_1_L表示分数1的低位,score_2_H表示分数2的高位,score_2_L表示分数2的低位。图中当score_1为2时,对应30分,所以高位score_1_H=3,低位score_1_L=0,与设计一致。
上图中bit_select依次产生低电平信号,选通对应数码管。当数码管显示0时段选信号lednum_select等于十六进制的C0。显示L时为十六进制C7,显示W时为十六进制C1。图中当score_1等于4、score_2等于2时,数码管依次显示的值为,C1,C1,B0,C0。对应实际观察到的是W30,即选手1获胜,选手2是30分显示正确。
八、结论
本设计使用VHDL设计了网球计分器,系统分为3个部分,分别为顶层模块Tennis_Scoreboard、计分模块Scoreboard、显示模块segment_display。顶层模块调用计分模块和显示模块,用于将两个模块连接,使其组合到一起。经过testbench仿真,计分模块完成了根据按键控制对应选手的分数,并且需要控制获胜后的led指示灯和获胜后持续5秒后返回初始状态。显示模块完成了将计分模块的分数转换为数码管显示的内容,即0分时显示L,1分显示15,2分显示30,3分显示40,4分显示W。最终仿真结果表明程序实现了网球计分器的全部功能。
附录:
所有代码粘贴,略过,后期可以自己粘贴。
1. 工程文件
2. 程序文件
3. 程序编译
4. Testbench
5. 仿真图
部分代码展示:
LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all; ENTITY Scoreboard IS PORT ( clk : IN STD_LOGIC;--clk reset : IN STD_LOGIC;--reset player1_key : IN STD_LOGIC;--player1 score add key player2_key : IN STD_LOGIC;--player2 score add key LED_1 : OUT STD_LOGIC;--player1 win LED LED_2 : OUT STD_LOGIC;--player2 win LED score_1 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);--player1 score score_2 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)--player2 score ); END Scoreboard; ARCHITECTURE behave OF Scoreboard IS SIGNAL count_1 : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";----player1 score count SIGNAL count_2 : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0000";----player2 score count SIGNAL clear : STD_LOGIC := '0';--score clear signal SIGNAL cnt_rst : STD_LOGIC; SIGNAL player1_key_buf0 : STD_LOGIC; SIGNAL player2_key_buf0 : STD_LOGIC; SIGNAL player1_key_buf1 : STD_LOGIC; SIGNAL player2_key_buf1 : STD_LOGIC; SIGNAL player1_en : STD_LOGIC; SIGNAL player2_en : STD_LOGIC; --count for 5 seconds SIGNAL time_5s_cnt : STD_LOGIC_VECTOR(31 DOWNTO 0) := "00000000000000000000000000000000"; BEGIN score_1 <= count_1;----player1 score count output score_2 <= count_2;----player2 score count output cnt_rst <= reset OR clear;--External reset or reset after 5 seconds --Trigger key synchronization PROCESS (clk) BEGIN IF (clk'EVENT AND clk = '1') THEN player1_key_buf0 <= player1_key; player1_key_buf1 <= player1_key_buf0; END IF; END PROCESS; --Trigger key synchronization PROCESS (clk) BEGIN IF (clk'EVENT AND clk = '1') THEN player2_key_buf0 <= player2_key; player2_key_buf1 <= player2_key_buf0; END IF; END PROCESS; player1_en <= player1_key_buf0 AND NOT(player1_key_buf1);--Gets the rising edge of the player1_key player2_en <= player2_key_buf0 AND NOT(player2_key_buf1);--Gets the rising edge of the player2_key --score count of player1 PROCESS (clk, cnt_rst) BEGIN IF (cnt_rst = '1') THEN count_1 <= "0000"; ELSIF (clk'EVENT AND clk = '1') THEN IF (player1_en = '1') THEN IF (count_1 = "0100") THEN--It doesn't increase after 4 count_1 <= "0100"; ELSE count_1 <= count_1 + "0001";--Press the key to increase the score END IF; ELSE count_1 <= count_1; END IF; END IF; END PROCESS;
源代码
点击下方的公众号卡片获取