1 项目需求
设计一个反应时间测试系统,用于测量两名队友(队友A和队友B)看到LED亮起后按下按钮的响应时间,并在数码管上显示。每个人进行8次测试,然后计算平均响应时间,并比较两个队友的结果,显示哪一方赢得了比赛。
1.1 组件及功能定义
- 数码管: 用于显示每次测试的响应时间,两名队友共用。
- LED: 每次测试时,相应测试轮次的LED灯亮起作为指示。第一次测试亮起L1,第二次亮起L2,依此类推,直至第八次测试亮起L8。
- RGB三色灯: 指示当前测试的队友。RGB1代表队友A,RGB2代表队友B。
- 绿色:测试过程中
- 蓝色:完成8次测试
- 红色:完成平均
- 白色:比赛结果。白色高亮表示获胜,白色暗淡表示失败。
- 开关SW1: 用于切换测试队友。拨到上面测试队友A,拨到下面测试队友B。
轻触按键:
- K1:启动
- K2:响应
- K3:平均
- K4:比较
1.2 游戏规则
- 按下“启动”按钮后,两个7段显示屏立即设置为全0。然后,在随机的时间段(大约1到10秒)之后,相应测试轮次的“立即反应”LED亮起,并启动毫秒计时器,数码管开始显示计时器值(以毫秒为单位递增)。
- “立即反应”LED亮起后,队友必须尽快按下“响应”按钮来停止计时器。 停止的计时器将包含“立即反应”LED亮起和按钮按下之间的毫秒数,并且该时间将显示在数码管上。
- 再次按下“启动”按钮将清除计时器并开始新的测试。
- 重复单个反应时间测量八次,每一个测试,相应的8个LED中的一个亮起,并将八个测量的反应时间值存储在临时保持寄存器中。
- 按下“平均”按钮可平均8次的测量值,并将平均后的数值显示在数码管上,8个LED全部亮起。
- 切换队友 - 将SW1的状态改变,重复测试8次,并平均八次的测试结果。
- 按下“比较”按钮,通过RGB三色灯指示哪个队友获胜(平均用时最短),并在数码管上显示相应的响应时间。
这些功能将确保系统能够准确测量和比较两名队友的反应时间,并给出比赛结果。
2 完成的功能及达到的性能
2.1 数码管显示功能
7段数码管显示每次测试的反应时间。当轮到某位玩家且参考LED亮起时,显示玩家的反应时间,即玩家按下按钮的时间。由于我们只有两个7段数码管,只能显示两位数,因此我添加了一个功能来更精确地显示反应时间。该功能如下:当显示的反应时间以毫秒为单位且不超过99毫秒时,显示的值不添加任何点“。”。
但是,当值超过99毫秒时,会添加一个点“。”到显示的值中,表示实际显示的值不是XX毫秒,而是XX0毫秒。例如,如果反应时间是200毫秒,则显示将显示“12。”。
此外,如果反应时间超过999毫秒,则会显示两个点“。”以及该值。这表示实际显示的值是“X.Y.”,其中X表示秒数,Y表示百分之一秒。例如,对于1秒123毫秒的反应时间,显示将显示“1.2.”。
2.2 LED指示功能
游戏当前状态由两种类型的LED指示。首先,简单的红色LED表示玩家应该反应的时刻,而RGB LED反映了整个游戏的状态。
关于红色LED,总共有8个,每个对应一个测试。在测试过程中,这些LED依次点亮,一个接一个地,以指示测试编号。例如,如果是第三个测试,第三个红色LED将点亮,而其他LED保持熄灭。两名玩家共享相同的8个红色LED进行测试。
至于RGB LED,有两组,分别用于每个玩家。它们显示五种不同的状态:
- 绿色表示相应的玩家当前正在接受测试。
- 蓝色表示玩家已完成所有8次测试。
- 红色表示玩家已经计算出其8次测试的平均反应时间。
- 明亮的白色表示玩家是游戏的赢家。
- 暗淡的白色表示玩家是失败者。
2.3 按键操作功能
- 启动按钮(K1)启动测试并清零数码管。
- 响应按钮(K2)记录响应时间。
- 平均按钮(K3)计算并显示平均响应时间。
- 比较按钮(K4)比较两名队友的平均响应时间。
2.4 SW1开关功能
用于切换测试队友,确保测试的公正性和准确性。
2.5 测试规则实现
测试的顺序如下。首先,在游戏开始之前,开关SW1应该处于下位,表示第一个玩家。一旦满足这个条件,当玩家按下K1按钮时,测试就开始了。按下K1后,第一个红色LED点亮之前会有1到10秒的随机延迟。从这一刻开始,直到完成所有8次测试,RGB1 LED保持绿色,表示玩家1正在接受测试。
随着红色LED的点亮,当前的反应时间会持续显示在7段数码管上。当玩家按下K2按钮时,计时器精确停止,并且他们的反应时间会在7段数码管上显示。要继续测试,玩家需要再次按下K1进行下一次测试。这个循环会重复,直到完成所有8次测试。
一旦玩家1完成了所有8次测试,RGB1 LED会变成蓝色。
如果玩家想要计算平均反应时间,他们必须确保SW1开关处于低位,然后按下K3按钮进行计算。玩家1还可以选择等待玩家2完成测试,然后再计算平均值。但是,平均值计算无法开始,直到玩家2完成了他们的8次测试。此外,SW1应该选择需要计算平均值的玩家。
玩家1完成了所有8次测试后,SW1应该切换到高位选择玩家2。完成后,玩家2可以以与玩家1相同的方式开始测试。唯一的区别是,关于玩家2的当前状态将显示在RGB2 LED上。对于两个玩家的测试过程,测试红色LED保持不变。
一旦所有玩家完成了测试并计算了平均值,按下K4按钮即可显示赢家。赢家的RGB LED将变为明亮的白色,而失败者的RGB LED也将是白色,但比赢家的亮度要低。
3 实现思路
- 实现按钮去抖动的模块。
- 实现我们的计数器模块。
- 实现控制7段数码管显示的模块。
- 实现控制RGB LED的模块。
- 实现游戏控制的主模块。
- 实现一个模块,用于将所有模块连接在一起。
4 实现过程
4.1 程序流程图
4.2 按钮去抖动的模块
这个 Verilog 模块用于去抖按钮,这在数字系统中是一个至关重要的任务,以确保可靠的信号解释。在接收原始按钮信号和时钟输入后,该模块利用内部计数器来测量自上次按钮状态改变以来经过的时间。与时钟信号同步运行,计数器在每个时钟周期增加。它监视当前按钮状态是否与先前去抖状态匹配;如果是,则将计数器重置为零,表示状态未改变。然而,如果按钮状态不同,并且计数器达到预定阈值——这里设置为 120000 个时钟周期,相当于 12MHz 时钟下的 1 毫秒——模块会更新去抖按钮信号以反映当前按钮状态。这种机制确保了按钮信号的任何瞬态波动被过滤掉,从而确保了下游数字处理的稳定和准确的输入检测。
// Module for debouncing buttons
module Debouncer (
input wire button,
input wire clk,
output reg debounced_button
);
// Internal registers
reg [23:0] counter; // Adjusted for 12MHz clock
// Synchronous process to debounce the button
always @(posedge clk) begin
// Increment counter
counter <= counter + 1;
// Check if button state changed
if (button == debounced_button) begin
counter <= 0;
//debounced_button <= button;
end else if (counter == 120000) begin // Adjusted for 12MHz clock, 1ms check
debounced_button <= button;
end
end
endmodule
4.3 计数器模块
这个 Verilog 模块在我们的项目中扮演着至关重要的角色,它是一个精确的毫秒计数器,专门针对我们数字系统的特定时序要求而设计。与系统时钟精确同步,该模块逐步跟踪经过的毫秒数,确保了对关键游戏机制执行所必需的精确时间准确性。该模块的输出设计考虑周到,每 4 位表示时间的一个单独数字,最大时间跨度为 99,999 毫秒。除了其计时功能外,该模块还无缝处理复位信号,初始化时迅速将计数器重置为零,以确保在整个游戏过程中保持一致可靠的行为。
// Module for counting milliseconds
module Counter (
input clk,
input wire rst,
input wire hold,
output reg [19:0] milliseconds //max is 99 999ms
);
// Timer counter logic
always @(posedge clk or posedge rst or negedge rst) begin
if (rst) begin
milliseconds <= 0;
end
else if (!hold) begin
if (milliseconds[3:0] == 9) begin
milliseconds[3:0] <= 0;
if (milliseconds[7:4] == 9) begin
milliseconds[7:4] <= 0;
if (milliseconds[11:8] == 9) begin
milliseconds[11:8] <= 0;
if (milliseconds[15:12] == 9) begin
milliseconds[15:12] <= 0;
if (milliseconds[19:16] == 9) begin
milliseconds[19:16] <= 0;
end
else milliseconds[19:16] <= milliseconds[19:16] + 1'b1;
end
else milliseconds[15:12] <= milliseconds[15:12] + 1'b1;
end
else milliseconds[11:8] <= milliseconds[11:8] + 1'b1;
end
else milliseconds[7:4] <= milliseconds[7:4] + 1'b1;
end
else milliseconds[3:0] <= milliseconds[3:0] + 1'b1;
end
else milliseconds <= milliseconds;
end
endmodule
4.4 实现控制7段数码管显示的模块
这个名为 DisplayController 的 Verilog 模块在我们的项目中扮演着关键的角色,负责管理七段显示器上数值的显示。该模块经过设计以适应我们的特定显示需求,接收代表要显示的十进制值的输入数据以及控制信号,用于启用或禁用小数点。然后,它生成两个输出,seg_out_tens 和 seg_out_ones,分别对应于十位和个位数字的七段输出。此外,该模块提供 dot_out 信号以控制显示器上的小数点段。 该模块初始化了一组预定义的七段显示器模式,用于表示从 0 到 9 的每个数字,确保数字值的准确表示。它根据输入数据动态分配这些显示模式,确保为十位和个位数字选择适当的模式。如果输入数据在 0 到 9 的范围内,该模块从 seg_patterns 数组中检索相应的显示模式,并分别将它们分配给 seg_out_tens 和 seg_out_ones 输出。在输入数据超出此范围以指示显示应关闭的情况下,该模块将两个输出信号都设置为零,有效地关闭了显示器。
module DisplayController (
input [7:0] data, // Decimal value to display
input [1:0] dot, //Enabling dots
output reg [7:0] seg_out_tens, // Seven-segment output for the first digit, tens
output reg [7:0] seg_out_ones, // Seven-segment output for the second digit, ones
output wire [1:0] dot_out
);
// Define seven-segment display patterns for each digit
reg [7:0] seg_patterns [0:9];
assign dot_out = dot;
// Initialize seven-segment display patterns
initial begin // GFE_DCBA
seg_patterns[0] = 8'b0011_1111; // 0
seg_patterns[1] = 8'b0000_0110; // 1
seg_patterns[2] = 8'b0101_1011; // 2
seg_patterns[3] = 8'b0100_1111; // 3
seg_patterns[4] = 8'b0110_0110; // 4
seg_patterns[5] = 8'b0110_1101; // 5
seg_patterns[6] = 8'b0111_1101; // 6
seg_patterns[7] = 8'b0000_0111; // 7
seg_patterns[8] = 8'b0111_1111; // 8
seg_patterns[9] = 8'b0110_1111; // 9
end
// Assign seven-segment patterns based on digits
always @(*) begin
//dot_out <= dot;
if(data[7:4] < 10 && data[3:0] < 10) begin
if(data[7:4] == 0) begin
seg_out_tens = 8'b0000_0000; //off
end
else begin
seg_out_tens = seg_patterns[data[7:4]];
end
seg_out_ones = seg_patterns[data[3:0]];
end
else begin //turning the display OFF
seg_out_tens = 8'b0000_0000;
seg_out_ones = 8'b0000_0000;
end
end
endmodule
4.5 控制RGB LED的模块
这个 Verilog 模块,RGB_Controller,在我们的项目中起着至关重要的作用,负责根据指定的强度级别控制 RGB LED 的输出。该模块经过设计,能够与我们的系统时钟无缝接口,接收表示 RGB LED 的红、绿和蓝色分量强度级别的输入强度值,每个分量的范围从 0 到 255。 在模块内部,初始化了一个用于 PWM 调光的计数器 pwm_counter,用于调节 LED 的亮度。在每个时钟信号的正边沿操作时,该模块根据提供的强度值动态调整 RGB LED 的输出。 RGB LED 控制逻辑采用 PWM 调光来独立调节每个颜色分量的亮度。通过将 pwm_counter 值与红、绿和蓝色的强度值进行比较,模块确定每个颜色分量是否应该点亮。如果 pwm_counter 值小于相应的强度值,表示达到了期望的亮度级别,则 LED 保持开启状态;否则,它将关闭。 总的来说,该模块确保对 RGB LED 输出进行精确控制,允许根据我们项目视觉界面的特定要求动态调整颜色强度级别。通过其高效的 PWM 调光机制,该模块实现了不同亮度级别之间的平滑过渡,提升了我们项目整体视觉体验的质量。
// Module for controlling RGB LED
module RGB_Controller (
input clk,
input [23:0] intensity, // Intensity of red[23:16] green[15:8] and blue[7:0], max 255
output reg [2:0] rgb_led // RGB LED output
);
// Counter for PWM dimming
reg [7:0] pwm_counter = 0;
// RGB LED control logic using PWM dimming
always @(posedge clk) begin
pwm_counter <= pwm_counter + 1;
// Compare PWM counter with intensity values for each color
// If PWM counter is less than the intensity value, LED is on,
// otherwise LED is off.
rgb_led[2] <= (pwm_counter < intensity[23:16]) ? 1'b0 : 1'b1; //RED
rgb_led[1] <= (pwm_counter < intensity[15:8]) ? 1'b0 : 1'b1; //GREEN
rgb_led[0] <= (pwm_counter < intensity[7:0]) ? 1'b0 : 1'b1; //BLUE
end
endmodule
4.6 游戏控制的主模块
这个名为"Game"的 Verilog 模块是我们项目的核心控制器,负责管理游戏流程并协调各种功能。该模块与时钟信号同步运行,响应各种输入信号,组织游戏的不同状态,确保游戏过程平稳,并实现准确的数据处理。
在核心部分,该模块由多个状态组成的状态机,包括初始设置、测试启动、响应处理、平均计算、比较和结束等状态。每个状态都经过精心设计,以处理特定的游戏事件,并在它们之间实现无缝的转换。
在初始化或复位时,该模块初始化内部变量,并准备系统进行游戏。然后,它等待开始信号,表示测试阶段的开始。在此阶段,模块会在启动每个测试之前生成随机延迟,模拟真实世界的反应情景。
随着游戏的进行,该模块监视玩家的响应,计算反应时间,并相应地更新游戏状态。它动态调整 LED 指示灯和显示输出,为玩家和观众提供实时反馈,增强游戏体验。
此外,该模块还包括用于计算平均反应时间的功能,促进玩家之间的公平比较。一旦所有测试完成,它根据反应时间的平均值确定获胜者,并点亮相应的 LED 来指示结果。
总的来说,该模块是我们项目的骨干,确保了高效的游戏控制、准确的数据处理和引人入胜的用户体验。其坚固的设计和全面的功能使其成为实现我们项目目标的关键组成部分。
module Game (
input clk,
input rst,
input start_button,
input response_button,
input average_button,
input compare_button,
input team_switch,
input [19:0]ms,
output reg [7:0] display,
output reg [1:0] dot,
output reg [23:0] rgb1,
output reg [23:0] rgb2,
output reg [7:0] led_out,
output reg rst_counter,
output reg hold
);
// Define game states
parameter INITIAL_STATE = 4'd0;
parameter PENDING_STATE = 4'd1;
parameter START_STATE = 4'd2;
parameter WAITING_RESPONSE_STATE = 4'd3;
parameter RESPONSE_STATE = 4'd4;
parameter TESTING_DONE_STATE = 4'd5;
parameter SWITCHING_STATE = 4'd6;
parameter AVERAGE_STATE = 4'd7;
parameter ALL_DONE_STATE = 4'd8;
parameter COMPARE_STATE = 4'd9;
reg NotFirstIni = 0; // 0 means it is the first initialisation, even when writing 1 here, the value still 0 till around 100ms later
reg [23:0] iniCounter = 0;
// Internal signals
reg [3:0] state=0; // State
reg [2:0] test_num; // Test number counter, 0->7
reg player_tested; // Player tested indicator
reg [15:0] player_A_avg; // Average response time for player A
reg [15:0] player_B_avg; // Average response time for player B
reg [3:0] random_delay; // Random delay for starting test
reg player_A_Done;
reg player_B_Done;
reg average_A_Done;
reg average_B_Done;
wire [15:0] times;
assign times = ms[15:12]*12'd1000 + ms[11:8]*8'd100 + ms[7:4]*4'd10 + ms[3:0];
//pseudo-random numbers generator
reg [3:0] rand_out;
always @(posedge clk) begin
if(!NotFirstIni)
rand_out = { {3{1'b0}}, 1'b1 };
rand_out <= {rand_out[2:0], rand_out[3] ^ rand_out[0]}; // Feedback based on polynomial
end
always @(posedge clk) begin
//For elimnating the startup error
if(!NotFirstIni) begin
state = INITIAL_STATE;
iniCounter = iniCounter + 1'd1;
if(iniCounter==24'd1200000) begin
NotFirstIni = 1;
end
end
//Button press detection
if (rst) begin
state = INITIAL_STATE;
end
else if((!start_button) & (state==PENDING_STATE) ) begin
//Green light for test state
if(!player_tested)
rgb1 = {8'd0, 8'd255, 8'd0}; // Green
else
rgb2 = {8'd0, 8'd255, 8'd0}; // Green
random_delay = rand_out%10 + 1; // Random delay between 1s and 10s
//Counter ON
rst_counter = 0;
hold = 0;
state = START_STATE;
end
else if(!response_button & (state==WAITING_RESPONSE_STATE)) begin
state = RESPONSE_STATE;
end
else if(!average_button & (state==SWITCHING_STATE) ) begin
state = AVERAGE_STATE;
end
else if(!compare_button & (state==ALL_DONE_STATE)) begin
state = COMPARE_STATE;
end
// Game state machine
if (state == INITIAL_STATE)begin
//Turn OFF RGB and LEDs
rgb1 = {8'd0, 8'd0, 8'd0};
rgb2 = {8'd0, 8'd0, 8'd0};
led_out = 8'b1111_1111;
//Turn OFF display
display = {4'd10,4'd10}; //Values more than 9 turns off the display
dot = 2'b00;
//RESET data
test_num = 0;
player_A_avg = 0;
player_B_avg = 0;
player_A_Done = 0;
player_B_Done = 0;
average_A_Done = 0;
average_B_Done = 0;
player_tested = 0;
//Reset and pause the counter
rst_counter = 1;
hold = 1;
if(!team_switch)
state = PENDING_STATE;
end
else if(state == PENDING_STATE) begin
//Nothing to do
end
else if(state == START_STATE) begin
//Turn off LEDs
led_out = 8'b1111_1111;
//OFF display
display = {4'd10,4'd10}; //Values more than 9 turns off the display
dot = 2'b00;
//Waiting the random time before going to next step
if ( ((ms[19:16]*10) + ms[15:12]) == random_delay) begin
//Counter OFF and reset
rst_counter = 1;
hold = 1;
//Tuning ON the corresponding LED
case (test_num)
0: led_out = 8'b1111_1110; // L1
1: led_out = 8'b1111_1101; // L2
2: led_out = 8'b1111_1011; // L3
3: led_out = 8'b1111_0111; // L4
4: led_out = 8'b1110_1111; // L5
5: led_out = 8'b1101_1111; // L6
6: led_out = 8'b1011_1111; // L7
7: led_out = 8'b0111_1111; // L8
endcase
state = WAITING_RESPONSE_STATE;
end
end
else if(state == WAITING_RESPONSE_STATE) begin
//Counter ON
rst_counter = 0;
hold = 0;
//Display the time,
// No dots means XX ms
//One dot mean XX0 ms
//Two dots mean X s X00 ms
if(ms[15:12]==0) begin
if(ms[11:8]==0) begin
display = ms[7:0];
end else begin
display = ms[11:4];
dot = 2'b01;
end
end else begin
display = ms[15:8];
dot = 2'b11;
end
if(ms[15:12]==3) begin //If 3sec without response, take 3sec and continue
state = RESPONSE_STATE;
end
end
else if(state == RESPONSE_STATE) begin
hold = 1; //Stop counting
if(player_tested == 0)
player_A_avg = player_A_avg + times;
else
player_B_avg = player_B_avg + times;
//Reset counter
rst_counter = 1;
if(test_num == 3'd7) begin //All 7 test done
state = TESTING_DONE_STATE;
test_num = 0;
end else begin
test_num = test_num + 1;
state = PENDING_STATE;
end
end
else if(state == TESTING_DONE_STATE) begin
if(!player_tested & !player_A_Done) begin
//Blue light for all 8 test done state
rgb1 = {8'd0, 8'd0, 8'd255}; // Blue
//Player A done
player_A_Done = 1;
state = SWITCHING_STATE;
end else if(player_tested & !player_B_Done) begin
//Blue light for all 8 test done state
rgb2 = {8'd0, 8'd0, 8'd255}; // Blue
//Player B done
player_B_Done = 1;
state = SWITCHING_STATE;
end
end
else if(state == SWITCHING_STATE) begin
if(team_switch & player_A_Done ) begin
player_tested = 1;
if(!player_B_Done)
state = PENDING_STATE;
end else if(!team_switch & player_B_Done) begin
player_tested = 0;
end
end
else if(state == AVERAGE_STATE) begin
state = SWITCHING_STATE;
if (player_A_Done & (!player_tested) & (!average_A_Done)) begin
player_A_avg = player_A_avg/8;
//Red light for average state
rgb1 = {8'd255, 8'd0, 8'd0}; // Red
average_A_Done = 1;
end else if(player_B_Done & player_tested & (!average_B_Done)) begin
player_B_avg = player_B_avg/8;
//Red light for average state
rgb2 = {8'd255, 8'd0, 8'd0}; // Red
average_B_Done = 1;
//state = SWITCHING_STATE;
end else if(average_A_Done&average_B_Done) begin
state = ALL_DONE_STATE;
end
end
else if(state == ALL_DONE_STATE) begin
//Nothing to do
end
else if(state == COMPARE_STATE) begin
if(player_A_avg < player_B_avg) begin
//Winner brighter white
rgb1 = {8'd255, 8'd255, 8'd255}; // White
//Looser
rgb2 = {8'd50, 8'd50, 8'd50}; // Light Gray
end
else begin
//Winner brighter white
rgb2 = {8'd255, 8'd255, 8'd255}; // White
//Looser
rgb1 = {8'd50, 8'd50, 8'd50}; // Light Gray
end
state = ALL_DONE_STATE;
end
else begin
state = INITIAL_STATE;
end
end
endmodule
4.7 连接模块
/* Verilog model created from schematic TopModule.sch -- Mar 13, 2024 01:35 */
module TopModule( CLK, dots, K1, K2, K3, K4, LEDs, ONES, RGB1, RGB2, RST, SW1,
TENS );
input CLK;
output [1:0] dots;
input K1;
input K2;
input K3;
input K4;
output [7:0] LEDs;
output [7:0] ONES;
output [2:0] RGB1;
output [2:0] RGB2;
input RST;
input SW1;
output [7:0] TENS;
wire [19:0] ms;
wire [23:0] rgb_wire1;
wire [23:0] rgb_wire2;
wire [7:0] display;
wire [1:0] dota;
wire N_1;
wire N_2;
wire N_3;
wire N_4;
wire N_5;
wire kHz_1;
wire rst_counter;
wire hold;
Game I14 ( .average_button(N_3), .clk(CLK), .compare_button(N_2),
.display(display[7:0]), .dot(dota[1:0]), .hold(hold),
.led_out(LEDs[7:0]), .ms(ms[19:0]), .response_button(N_4),
.rgb1(rgb_wire1[23:0]), .rgb2(rgb_wire2[23:0]), .rst(RST),
.rst_counter(rst_counter), .start_button(N_5), .team_switch(N_1) );
Debouncer I13 ( .button(SW1), .clk(CLK), .debounced_button(N_1) );
Debouncer I12 ( .button(K4), .clk(CLK), .debounced_button(N_2) );
Debouncer I11 ( .button(K3), .clk(CLK), .debounced_button(N_3) );
Debouncer I10 ( .button(K2), .clk(CLK), .debounced_button(N_4) );
Debouncer I9 ( .button(K1), .clk(CLK), .debounced_button(N_5) );
RGB_Controller I5 ( .clk(CLK), .intensity(rgb_wire2[23:0]), .rgb_led(RGB2[2:0]) );
RGB_Controller I6 ( .clk(CLK), .intensity(rgb_wire1[23:0]), .rgb_led(RGB1[2:0]) );
Divider I1 ( .clk(CLK), .output_frequency(kHz_1) );
DisplayController I7 ( .data(display[7:0]), .dot(dota[1:0]),
.dot_out(dots[1:0]), .seg_out_ones(ONES[7:0]),
.seg_out_tens(TENS[7:0]) );
Counter I3 ( .clk(kHz_1), .hold(hold), .milliseconds(ms[19:0]),
.rst(rst_counter) );
endmodule // TopModule
这段 Verilog 代码是通过使用 Lattice Diamond 软件创建的原理图生成的。这个原理图代表了名为 "TopModule" 的顶层模块,该模块集成了各种子模块,用于实现所需的功能。该模块包括诸如时钟信号(CLK)、按钮输入(K1、K2、K3、K4)、复位(RST)和开关(SW1)等输入,以及 LED 显示(LEDs、ONES、TENS)、RGB LED 输出(RGB1、RGB2)和点阵显示(dots)等输出。
为了创建这个 Verilog 代码,每个子模块都是单独设计并添加到原理图中的。这些子模块包括用于按钮去抖动(Debouncer)、控制 RGB LED(RGB_Controller)、分频时钟频率(Divider)、控制显示(DisplayController)和计算毫秒数(Counter)的模块。每个子模块都根据所需的功能进行相互连接,确保不同组件之间的正确通信和协调。
例如,"Game" 模块编排了整个游戏逻辑,而 "Debouncer" 模块处理各种按钮的去抖动。"RGB_Controller" 模块管理 RGB LED 的亮度,而 "Counter" 模块精确计算毫秒数。这些模块在顶层的 "TopModule" 中被实例化,其中的互连定义确保了整个系统的正确功能。
这段 Verilog 代码作为原理图设计的结构表示,有助于将其综合和实现到硬件平台上,以进行实际的部署和系统测试。
5 未来的计划建议
在这个项目中,我们成功实现了最初的目标,这对我来说是一次学习 FPGA 实现的丰富经历。然而,我对这个项目的兴趣引发了进一步的探索,使我设想了对现有产品的几项改进。其中一个重要的改进是自动化平均计算和玩家得分比较过程,消除了为这些任务专门设计的按钮的需求。这种简化只留下了启动按钮和反应时间按钮,简化了用户界面。此外,加入一个外部 LED 可以提高反应信号的可见性,克服了板载小型 LED 的局限性。另一个增强功能是集成 LCD 或 OLED 屏幕,提升显示界面,从而使游戏体验更具吸引力。此外,通过这种显示升级可以扩展游戏以容纳超过两名玩家。为了提高用户舒适度和可访问性,可以集成更大的外部按键,确保在游戏过程中的易用性。最后,设计并 3D 打印一个定制外壳,用于容纳所有电子元件,进一步提升产品的美观度和完整感。这些拟议的改进承诺提升产品的功能性、可用性和整体吸引力。