网球计分器设计VHDL代码VIVADO仿真

名称:网球计分器设计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;
源代码

点击下方的公众号卡片获取

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值