名称:羽毛球计分器Basys3开发板verilog代码带设计报告
软件:VIVADO
语言:VHDL
代码功能:
羽毛球计分器
1、计分器可以同时显示2位选手的分数,每个选手的分数通过1bit的输入按键信号控制,按一次加一分,一共2个按键对应2个不同的分数。/
2、分数最高为21分,谁先达到21分则获胜,比赛结束,同时通过LED显示获胜的选手。
3、分数通过7段数码管显示,一共4个数码管,其中2个显示选手1的分数,另外2个显示选手2的分数,
4、分数达到21分后显示持续5秒后自动清零,或者有复位信号也会清零
FPGA代码Verilog/VHDL代码资源下载:www.hdlcode.com
本代码已在Basys3开发板验证,开发板如下,其他开发板可以修改管脚适配:
羽毛球计分器设计报告(节选)
一、摘要
本题目要求设计使用VHDL语言设计一个羽毛球计分器,计分器可以同时显示2位选手的分数,每个选手的分数通过1bit的输入按键信号控制,按一次加一分,一共2个按键对应2个不同的分数。分数最高为21分,谁先达到21分则获胜,比赛结束,同时通过LED显示获胜的选手。分数通过7段数码管显示,一共4个数码管,其中2个显示选手1的分数,另外2个显示选手2的分数,分数达到21分后显示持续5秒后自动清零,或者有复位信号也会清零。通过这个计分器可以用来在羽毛球比赛中计分。
二、概述
本报告设计的是一个羽毛球计分器,可记录并显示2个选手分数,每个选手的分数通过1bit的输入按键信号控制,按一次加一分,一共2个按键对应2个不同的分数。分数最高为21分,谁先达到21分则获胜,比赛结束,同时通过LED显示获胜的选手。分数通过7段数码管显示,一共4个数码管,其中2个显示选手1的分数,另外2个显示选手2的分数,分数达到21分后显示持续5秒后自动清零,或者有复位信号也会清零。
本工程代码一共可以分为3个模块,分别为顶层模块badminton_scoreboard、计分模块badminton_score和显示模块display。其中计分模块根据按键控制对应选手的分数,按一次加1分,加到21分获胜并不再增加,并且需要控制获胜后的led指示灯和获胜后持续5秒后返回初始状态。显示模块用于将计分模块的二进制分数转换为便于数码管显示的BCD码分数,然后控制数码管的位选信号和段选信号分别显示AB两组选手的分数(分为个位和十位显示)。顶层模块调用计分模块和显示模块,将计分模块的分数输入到显示模块,其他信号连接到外部IO接口。
三、顶层模块
顶层模块badminton_scoreboard的实体定义如下:
entity badminton_scoreboard is
Port ( clk : in STD_LOGIC;
bit_sel : out STD_LOGIC_VECTOR (3 downto 0);
seg_sel : out STD_LOGIC_VECTOR (7 downto 0);
reset : in STD_LOGIC;
player_A_point : in STD_LOGIC;
player_B_point : in STD_LOGIC;
win_A_led : out STD_LOGIC;
win_B_led : out STD_LOGIC);
end badminton_scoreboard;
顶层模块输入包括时钟clk信号,复位reset信号,2个按键player_A_point和player_B_point。输出为2个led灯win_A_led和win_B_led,2个数码管控制信号bit_sel和seg_sel ,其中bit_sel为4bit,控制当前显示哪个数码管,seg_sel为8bit信号,控制当前点亮的数码管的显示值,通过bit_sel信号的时分复用可以使4个数码管同时显示不同的值。顶层模块调用计分模块和显示模块,用于将两个模块连接,代码如下:
--call Scoring module
U_badminton_score: badminton_score
PORT MAP(
clk =>clk,
reset =>reset,--reset
player_A_point =>player_A_point,--player_A_point key
player_B_point =>player_B_point,--player_B_point key
score_A =>score_A,----A score
score_B =>score_B,----B score
win_A_led =>win_A_led,--A win LED
win_B_led =>win_B_led--B win LED
);
--call Display module
U_display: display
PORT MAP(
clk =>clk,
score_A =>score_A,--A score
score_B =>score_B,--B score
bit_sel =>bit_sel,--Digital tube position selection
seg_sel =>seg_sel--Digital tube section selection
);
首先调用Scoreboard模块,可以得到2个选手的分数,即score_1信号和score_2信号,再调用数码管显示模块segment_display,将score_1信号和score_2信号输入到segment_display模块中,最终通过7segment_display的bit_select和lednum_select信号进行显示。
四、计分模块
计分模块的输入包括时钟clk信号,复位reset信号,2个按键player_A_point和player_B_point。输出为2个led灯LED_1和LED_2,和2个分数信号score_1和score_2。
实体定义如下:
--Scoring module
ENTITY badminton_score IS
PORT (
clk : IN STD_LOGIC;
reset : IN STD_LOGIC;--reset
player_A_point : IN STD_LOGIC;--player_A_point key
player_B_point : IN STD_LOGIC;--player_B_point key
score_A : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);----A score
score_B : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);----B score
win_A_led : OUT STD_LOGIC;--A win LED
win_B_led : OUT STD_LOGIC--B win LED
);
END badminton_score;
为了控制按键按下后加一分,可以通过一个process进程,判断按键是否按下然后控制分数加1,但是由于按键信号相对于时钟信号是一个持续时间很长的信号,所以需要将按键信号缩短为只持续一个时钟周期的信号,可以通过检测按键上升沿实现。实现方法如下:
Basys3板子上一个有4个数码管,四个数码管有4个位选信号控制当前点亮哪个数码管,然后4个数码管共用8位段选信号。因此需要通过时分复用的方式依次点亮4个数码管才能同时显示4个数字。Basys3板子上的数码管位选为低电平选中,即低电平时显示,高电平时不显示。段选信号也是低电平点亮,高电平熄灭。如下图所示,图中可以看到,若要显示数字0,需要将ABCDF全部点亮,G和DP不点亮,因此,按DP,G,F,E,D,C,B,A的顺序就是11000000。即十六进制的C0。
设计代码如下:
PROCESS (clk)
BEGIN
五、Testbench
Testebnch用于产生仿真测试激励,即模拟顶层模块的输入时钟、复位、按键A、按键B
等信号,观察输出的信号是否正确。由于testbench是一个模拟输入,所以实体可以是空的,如下:
entity test is
-- Port ( );
end test;
然后调用顶层模块
u_badminton_scoreboard:badminton_scoreboard
Port MAP(
clk =>clk,
bit_sel =>bit_sel,
seg_sel =>seg_sel,
reset =>reset,
player_A_point =>player_A_point,
player_B_point =>player_B_point,
win_A_led =>win_A_led,
win_B_led =>win_B_led
);
根据要求,模拟的时钟信号为1KHz,如下,500us高电平和500us低电平:
PROCESS
BEGIN
clk <= '0';
WAIT FOR 500 us;
clk <= '1';
WAIT FOR 500 us;
END PROCESS;
根据计分器的实际功能,设计激励信号为:先复位,使代码初始化,然后重复按下10次player_A_point按键,模块A选手赢得10分,然后重复按下10次player_B_point按键,模块B选手赢得10分,最后再重复按下12次player_A_point按键,模块A选手赢得12分。使A分数可以达到21,以观察得到21分后的信号变化,对应的testebnch代码如下:
六、仿真图结果
使用上述testbench仿真,分别看计分模块和数码管显示模块。
1.计分模块仿真
下图为计分模块的仿真图
上图中,reset信号为高电平后,score_A和score_B均为0,表示复位,分数清零。
随后player_A_point信号和player_B_point分别交替产生10个个高电平脉冲,AB对应的分数也由0依次变为10。然后只有player_A_point信号继续再来12个高电平脉冲。A的分数继续增长达到21后,在来高电平脉冲分数不再增加。并且在A分数为21后,win_LED_A拉高,表示A获胜。并且一直持续了5秒后自动清零。从上面两个仿真图可以看到计分模块实现了模块对应功能,仿真正确。
2. 数码管显示模块仿真
下图中score_A、score_B是输入的8位二进制分数,d2表示分数A的十位,d2表示分数B的个位,c2表示分数score_B的十位,c1表示score_B的个位。图中当score_A为19时,对应d2=1,d1=9,十位和个位均正确。
下图中bit_sel依次产生低电平信号,选通对应数码管。当数码管显示0时段选信号seg_sel等于十六进制的C0。显示1时为十六进制F9。图中当score_A等于1、score_B等于0时,数码管应该显示01,00,故对应的编码值为,C0,F9,C0,C0,与仿真图一致。故数码管显示模块仿真正确。
七、综合即实现结果
对代码进行综合实现,结果如下图所示
资源消耗LUT为113,FF为104,IO为18,BUFG为1.
八、结论
本设计使用VHDL设计了羽毛球计分器,系统分为3个部分,分别为顶层模块、计分模块、显示模块。顶层模块调用计分模块和显示模块,用于将两个模块连接,使其组合到一起。经过testbench仿真,计分模块完成了根据按键控制对应选手的分数,并且需要控制获胜后的led指示灯和获胜后持续5秒后返回初始状态。显示模块完成了将计分模块的分数转换为数码管显示的内容。最终仿真结果表明程序实现了网球计分器的全部功能。
部分代码展示:
LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all; --Scoring module ENTITY badminton_score IS PORT ( clk : IN STD_LOGIC; reset : IN STD_LOGIC;--reset player_A_point : IN STD_LOGIC;--player_A_point key player_B_point : IN STD_LOGIC;--player_B_point key score_A : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);----A score score_B : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);----B score win_A_led : OUT STD_LOGIC;--A win LED win_B_led : OUT STD_LOGIC--B win LED ); END badminton_score; ARCHITECTURE behave OF badminton_score IS SIGNAL player_A_point_temp1 : STD_LOGIC := '0'; SIGNAL player_A_point_temp2 : STD_LOGIC := '0'; SIGNAL player_B_point_temp1 : STD_LOGIC := '0'; SIGNAL player_B_point_temp2 : STD_LOGIC := '0'; SIGNAL A_point_add : STD_LOGIC; SIGNAL B_point_add : STD_LOGIC; SIGNAL count : STD_LOGIC_VECTOR(15 DOWNTO 0) := "0000000000000000"; SIGNAL score_A_temp : STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL score_B_temp : STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL A_win_flag : STD_LOGIC:='0'; SIGNAL B_win_flag : STD_LOGIC:='0'; BEGIN score_A <= score_A_temp;--Output score A score_B <= score_B_temp;--Output score B --D trigger to synchronization of player_A_point PROCESS (clk) BEGIN IF (clk'EVENT AND clk = '1') THEN player_A_point_temp1 <= player_A_point; player_A_point_temp2 <= player_A_point_temp1; END IF; END PROCESS; --D trigger to synchronization of player_B_point PROCESS (clk) BEGIN IF (clk'EVENT AND clk = '1') THEN player_B_point_temp1 <= player_B_point; player_B_point_temp2 <= player_B_point_temp1; END IF; END PROCESS; A_point_add <= player_A_point_temp1 AND (NOT(player_A_point_temp2));--Rising edge of key A B_point_add <= player_B_point_temp1 AND (NOT(player_B_point_temp2));--Rising edge of key B --Time 5 seconds PROCESS (clk) BEGIN IF (clk'EVENT AND clk = '1') THEN IF (reset = '1') THEN--reset count <= "0000000000000000"; ELSIF (A_win_flag = '1' OR B_win_flag = '1') THEN--win flag for A or B count <= count + "0000000000000001";--count to 5 seconds ELSE count <= "0000000000000000"; END IF; END IF; END PROCESS; --Control A's score PROCESS (clk) BEGIN IF (clk'EVENT AND clk = '1') THEN IF (reset = '1') THEN score_A_temp <= "00000000"; A_win_flag<='0';--clera A flag ELSIF (count = "0001001110001000") THEN--if count=5000,clk =1KHz count for 5000 means 5seconds score_A_temp <= "00000000";--reset scoreA A_win_flag<='0';--clera A flag ELSIF (score_A_temp >= "00010101" and (score_A_temp-score_B_temp)>="00000010" and (score_A_temp>score_B_temp)) THEN--when score is more then 21 and bigger then 2 score_A_temp <= score_A_temp;--21 A_win_flag<='1';--A win flag ELSIF (A_point_add = '1') THEN--add key -- IF (score_A_temp >= "00010101" and (score_A_temp-score_B_temp)>="00000010" and (score_A_temp>score_B_temp)) THEN--when score is more then 21 and bigger then 2 -- score_A_temp <= score_A_temp;--21 -- A_win_flag<='1';--A win flag -- ELSE score_A_temp <= score_A_temp + "00000001";--increase one -- END IF; ELSE score_A_temp <= score_A_temp;--keep END IF; END IF; END PROCESS; --Control B's score PROCESS (clk) BEGIN IF (clk'EVENT AND clk = '1') THEN IF (reset = '1') THEN score_B_temp <= "00000000"; B_win_flag<='0';--clera B flag ELSIF (count = "0001001110001000") THEN--if count=5000,clk =1KHz count for 5000 means 5seconds score_B_temp <= "00000000";--reset score B B_win_flag<='0';--clera B flag ELSIF (score_B_temp >= "00010101" and (score_B_temp-score_A_temp)>="00000010" and (score_B_temp>score_A_temp)) THEN--when score is more then 21 and bigger then 2 score_B_temp <= score_B_temp;--when 21 keep 21 B_win_flag<='1';--B win flag ELSIF (B_point_add = '1') THEN--add key -- IF (score_B_temp >= "00010101" and (score_B_temp-score_A_temp)>="00000010" and (score_B_temp>score_A_temp)) THEN--when score is more then 21 and bigger then 2 -- score_B_temp <= score_B_temp;--when 21 keep 21 -- B_win_flag<='1';--B win flag -- ELSE score_B_temp <= score_B_temp + "00000001";--increase one -- END IF; ELSE score_B_temp <= score_B_temp;--keep END IF; END IF; END PROCESS;