题目
使用SystemVerilog实现一个数字钟。
要求:
(1)能够显示时分秒;
(2)能够设置开始时间;
(3)使用你自己的7段数码管显示译码电路实现;
(4)可以使用动态显示方法实现;
(5)依据实现的其他附加功能,酌情加分:秒表、倒计时、闹钟…
(6)需要在Basys3 FPGA开发板上实现
解决方案
本解决方案参考@Hellsegamosken的[SystemVerilog] 基于 FPGA 的数字钟设计,并在其基础上进行修改。
clock.sv
module clock
(
input logic clk_pre,TU, TL, TC, TD,TR,
input logic T1, T2, T3, T4, T15, T16,
output logic [10:0] segments,
output logic alarm_light, down_light,ontime_light
);
// Control signals for different modes
logic mode1, mode2, mode3, mode4;
// Display variables for digits A and B
logic [3:0] disp_A0, disp_A1, disp_B0, disp_B1;
// Clock variables
logic [3:0] h0 = 4'b0000, h1 = 4'b0000, m0 = 4'b0000, m1 = 4'b0000, s0 = 4'b0000, s1 = 4'b0000;
// Alarm variables
logic [3:0] ah0 = 4'b0000, ah1 = 4'b0000, am0 = 4'b0000, am1 = 4'b0000, as0 = 4'b0000, as1 = 4'b0000;
// Countdown variables
logic [3:0] dh0 = 4'b0000, dh1 = 4'b0000, dm0 = 4'b0000, dm1 = 4'b0000, ds0 = 4'b0000, ds1 = 4'b0000;
// Stopwatch variables
logic [3:0] ch0 = 4'b0000, ch1 = 4'b0000, cm0 = 4'b0000, cm1 = 4'b0000, cs0 = 4'b0000, cs1 = 4'b0000;
integer disp_pos = 0,set_pos = 0;
logic clk_sec = 1'b0, clk_centi = 1'b0, clk_disp = 1'b0;
// Enumeration for different modes
typedef enum integer {
MAIN, ALARM, COUNT, DOWN,ONTIME} ModeType;
// Enumeration for display control
typedef enum logic {
LOW, HIGH} DispType;
// Enumeration for hand control
typedef enum logic {
OFF, ON} HandType;
ModeType mode = MAIN;
DispType DISP = LOW;
logic hand = OFF;
integer alarm_time = 0, down_time = 0,ontime_time=0;
logic down_sig = 1'b1, alarm_sig = 1'b1, ontime_sig = 1'b1, counting = 1'b0;
// Control module
// Temporary variables to handle button debouncing
logic tmpU1, tmpU2, tmpU3, UP;
logic tmpL1, tmpL2, tmpL3, LEFT;
logic tmpR1, tmpR2, tmpR3, RIGHT;
logic tmpC1, tmpC2, tmpC3, CENTER;
logic tmpD1, tmpD2, tmpD3, RESET;
// Eliminate button debounce
always_ff @ (posedge clk_centi) begin
tmpU3 <= tmpU2;
tmpU2 <= tmpU1;
tmpU1 <= TU;
tmpL3 <= tmpL2;
tmpL2 <= tmpL1;
tmpL1 <= TL;
tmpR3 <= tmpR2;
tmpR2 <= tmpR1;
tmpR1 <= TR;
tmpC3 <= tmpC2;
tmpC2 <= tmpC1;
tmpC1 <= TC;
tmpD3 <= tmpD2;
tmpD2 <= tmpD1;
tmpD1 <= TD;
end
// Decode input signals to determine current mode and other information
always_comb begin
if (T16) hand = ON;
else hand = OFF;
if (T1) begin mode = ALARM; {
mode1, mode2, mode3, mode4} = 4'b1000; end
else if (T2) begin mode = COUNT; {
mode1, mode2, mode3, mode4} = 4'b0100; end
else if (T3) begin mode = DOWN; {
mode1, mode2, mode3, mode4} = 4'b0010; end
else if (T4) begin mode = ONTIME; {
mode1, mode2, mode3, mode4} = 4'b0000; end
else begin mode = MAIN; {
mode1, mode2, mode3, mode4} = 4'b0000; end
if (T15) DISP = HIGH;
else DISP = LOW;
UP = tmpU1 & tmpU2 & tmpU3;
LEFT = tmpL1 & tmpL2 & tmpL3;
RIGHT = tmpR1 & tmpR2 & tmpR3;
CENTER = tmpC1 & tmpC2 & tmpC3;
RESET = tmpD1 & tmpD2 & tmpD3;
end
// Main logic to handle clock/stopwatch increment and time settings
integer cnt_sec = 0, cnt_centi = 0, cnt_disp = 0, cnt_flip = 0;
// logic clk_sec = 1'b0, clk_centi = 1'b0, clk_disp = 1'b0;
logic flip = 1'b1;
logic jw_d = 1'b0, jw_m = 1'b0, jw_y = 1'b0;
logic prehand = 1'b0, preleft = 1'b0,preright = 1'b0, preup = 1'b0, predown_sig = 1'b0, prealarm_sig = 1'b0, preontime_sig = 1'b0, precenter, prereset;
always_ff @ (posedge clk_pre) begin
cnt_sec <= cnt_sec + 1;
cnt_centi <= cnt_centi + 1;
cnt_disp <= cnt_disp + 1;
cnt_flip <= cnt_flip +