Article Directory
foreword
Write the digital clock Verilog program again to make it conform to the specification, and use template and modular programming to make the program idea clearer. Different from the previous ones, this time the project is set up in Quartus II 13.0, downloaded and debugged on the AX530 development board, the pin definition and configuration need to be changed according to the situation, and the project file will be uploaded to the resource.
1. Design content
The design function remains the same as before:
1. It has the function of timing "second", "minute" and "hour", and the hour counter is in 24-hour format;
2. It has the function of correcting time and can adjust "minute" and "hour" ;
3. It has the function of manually inputting and setting the timed alarm clock, and it lights up for 1 minute; 4.
The clock reset function can be realized: 00:00:00; The AX530 development board has six digital tubes without a DIP switch. In order to be consistent with the previous ones, only four of the digital tubes are used, and the displayed content is switched by buttons.
2. Module structure
The modules are divided according to the input and output. The top-level module only realizes the connection between the modules. The state control module controls the current display content. The timing module realizes the functions of timing, timing, second hand output, and hourly time reporting. The alarm clock module realizes the setting and output of the timing alarm clock. The display module determines displayed content according to the current working mode.
3. Code writing
1. Top-level module Digclk
The top-level module minimizes logic and is only used for module connection, and divides module functions according to output content
/***************数字钟顶层模块***************/
module Digclk(
clk,
rst_n,
btn,
led,
smg_sig,
smg_loc
);
//输入输出
input clk;
input rst_n;
input [2:0] btn;
output [3:0] led;
output [7:0] smg_sig;
output [5:0] smg_loc;
wire [2:0] led;
wire [7:0] smg_sig;
wire [5:0] smg_loc;
/***************状态控制模块***************/
wire [1:0] mode;
wire [3:0] set_loc;
wire set_inc;
Ctrl U_ctrl(
.clk(clk),
.rst_n(rst_n),
.swc_btn(btn[2]),//切换按键
.mov_btn(btn[1]),//移位按键
.inc_btn(btn[0]),//加一按键
.mode(mode),//工作状态
.set_loc(set_loc),//位置信号
.set_inc(set_inc)//加一信号
);
/***************计时模块***************/
wire [23:0] time_data;
Time U_time(
.clk(clk),
.rst_n(rst_n),
.mode(mode),
.set_loc(set_loc),
.set_inc(set_inc),
.time_data(time_data),
.sec(led[0]),//秒针LED
.hour(led[2])//整点报时
);
/***************闹钟模块***************/
wire [15:0] alm_data;
Alarm U_alarm(
.clk(clk),
.rst_n(rst_n),
.mode(mode),
.set_loc(set_loc),
.set_inc(set_inc),
.time_data(time_data),
.alm_data(alm_data),
.alm(led[1])//定时闹钟
);
/***************显示模块***************/
Display U_display(
.clk(clk),
.rst_n(rst_n),
.mode(mode),
.time_data(time_data),
.alm_data(alm_data),
.set_loc(set_loc),
.smg_sig(smg_sig),//数码管信号
.smg_loc(smg_loc)//数码管位置
);
endmodule
2. State control module Ctrl
Process the button information through the debounce module, output the current working status and timing operation signal and position
/***************状态控制模块***************/
module Ctrl(
clk,
rst_n,
swc_btn,//切换按键
mov_btn,//移位按键
inc_btn,//加一按键
mode,//工作状态
set_loc,//位置信号
set_inc//加一信号
);
//输入输出
input clk;
input rst_n;
input swc_btn;
input mov_btn;
input inc_btn;
output [1:0] mode;
output [3:0] set_loc;
output set_inc;
reg [1:0] mode;
reg [3:0] set_loc;
wire set_inc;
/***************按键消抖***************/
wire swc_btn_f;
wire mov_btn_f;
wire inc_btn_f;
Filter U_filter1(
.clk(clk),
.rst_n(rst_n),
.btn(swc_btn),
.btn_f(swc_btn_f)
);
Filter U_filter2(
.clk(clk),
.rst_n(rst_n),
.btn(mov_btn),
.btn_f(mov_btn_f)
);
Filter U_filter3(
.clk(clk),
.rst_n(rst_n),
.btn(inc_btn),
.btn_f(inc_btn_f)
);
/***************工作状态***************/
wire en_mode;
wire co_mode;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
mode <= 0;
end
else if(en_mode)begin
if(co_mode)
mode <= 0;
else
mode <= mode + 1;
end
end
assign en_mode = swc_btn_f;
assign co_mode = (en_mode) && (mode == 2);
/***************位置信号***************/
reg [3:0] cnt_loc;
wire en_loc;
wire co_loc;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_loc <= 0;
end
else if(en_loc)begin
if(co_loc)
cnt_loc <= 0;
else
cnt_loc <= cnt_loc + 1;
end
end
assign en_loc = mov_btn_f || swc_btn_f;
assign co_loc = (en_loc) && ((cnt_loc == 4) || swc_btn_f);
always@(*)begin
case(cnt_loc)
0: set_loc = 4'b0000;
1: set_loc = 4'b1000;
2: set_loc = 4'b0100;
3: set_loc = 4'b0010;
4: set_loc = 4'b0001;
default: set_loc = 4'b0000;
endcase
end
/***************加一信号***************/
assign set_inc = inc_btn_f;
endmodule
3. Key debounce module Filter
Sampling at intervals, converting the falling edge of the button into a clk pulse output, which can be used as a basic module
/***************按键消抖模块***************/
module Filter(
clk,
rst_n,
btn,
btn_f
);
//参数定义
parameter CNT_200MS = 24'd9_999_999;
parameter CNT_200NS = 24'd9;
//输入输出
input clk;
input rst_n;
input btn;
output btn_f;
wire btn_f;
/***************间隔200ms***************/
reg [23:0] cnt;
wire en;
wire co;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(en)begin
if(co)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign en = 1;
assign co = (en) && (cnt == CNT_200MS);
/***************buf1***************/
reg btn_buf1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
btn_buf1 <= 0;
end
else begin
if(co)
btn_buf1 <= btn;
end
end
/***************buf2***************/
reg btn_buf2;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
btn_buf2 <= 0;
end
else begin
btn_buf2 <= btn_buf1;
end
end
/***************输出正脉冲***************/
assign btn_f = (!btn_buf1) && (btn_buf2);
endmodule
4. Timing module Time
Use six counters to time the hours, minutes and seconds, and connect the plus-one signal to the enable signal to realize the time-calibration function. The
hourly timekeeping and second hand functions can also be divided into a separate module
/***************计时模块***************/
module Time(
clk,
rst_n,
mode,
set_loc,
set_inc,
time_data,
sec,
hour
);
//参数定义
parameter CNT_1S = 26'd49_999_999;
parameter CNT_1US = 26'd49;
//输入输出
input clk;
input rst_n;
input [1:0] mode;
input [3:0] set_loc;
input set_inc;
output [23:0] time_data;
output sec;
output hour;
wire [23:0] time_data;
reg sec;
reg hour;
/***************校时***************/
wire set_state;
assign set_state = ((mode == 0) || (mode == 1)) && (set_loc != 0);
reg [5:0] inc;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
inc <= 0;
end
else begin
if((mode == 0) && set_inc)
inc <= {
set_loc, 2'b00};
else if((mode == 1) && set_inc)
inc <= {
2'b00, set_loc};
else
inc <= 0;
end
end
/***************分频***************/
reg [25:0] cnt_div;
wire en_div;
wire co_div;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_div <= 0;
end
else if(en_div)begin
if(co_div)
cnt_div <= 0;
else
cnt_div <= cnt_div + 1;
end
end
assign en_div = !set_state;
assign co_div = (en_div) && (cnt_div == CNT_1S);
/***************秒个位***************/
reg [3:0] cnt_s0;
wire en_s0;
wire co_s0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_s0 <= 0;
end
else if(en_s0)begin
if(co_s0)
cnt_s0 <= 0;
else
cnt_s0 <= cnt_s0 + 1;
end
end
assign en_s0 = co_div || inc[0];
assign co_s0 = (en_s0) && (cnt_s0 == 9);
/***************秒十位***************/
reg [3:0] cnt_s1;
wire en_s1;
wire co_s1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_s1 <= 0;
end
else if(en_s1)begin
if(co_s1)
cnt_s1 <= 0;
else
cnt_s1 <= cnt_s1 + 1;
end
end
assign en_s1 = co_s0 || inc[1];
assign co_s1 = (en_s1) && (cnt_s1 == 5);
/***************分个位***************/
reg [3:0] cnt_m0;
wire en_m0;
wire co_m0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_m0 <= 0;
end
else if(en_m0)begin
if(co_m0)
cnt_m0 <= 0;
else
cnt_m0 <= cnt_m0 + 1;
end
end
assign en_m0 = co_s1 || inc[2];
assign co_m0 = (en_m0) && (cnt_m0 == 9);
/***************分十位***************/
reg [3:0] cnt_m1;
wire en_m1;
wire co_m1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_m1 <= 0;
end
else if(en_m1)begin
if(co_m1)
cnt_m1 <= 0;
else
cnt_m1 <= cnt_m1 + 1;
end
end
assign en_m1 = co_m0 || inc[3];
assign co_m1 = (en_m1) && (cnt_m1 == 5);
/***************时个位***************/
reg [3:0] cnt_h0;
reg [3:0] cnt_h1;
wire en_h0;
wire co_h0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_h0 <= 0;
end
else if(en_h0)begin
if(co_h0)
cnt_h0 <= 0;
else
cnt_h0 <= cnt_h0 + 1;
end
end
assign en_h0 = co_m1 || inc[4];
assign co_h0 = (en_h0) && ((cnt_h0 == 9) || (((cnt_h1 == 2) && ((cnt_h0 == 3)))));
/***************时十位***************/
wire en_h1;
wire co_h1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_h1 <= 0;
end
else if(en_h1)begin
if(co_h1)
cnt_h1 <= 0;
else
cnt_h1 <= cnt_h1 + 1;
end
end
assign en_h1 = co_h0 || inc[5];
assign co_h1 = (en_h1) && ((((cnt_h1 == 2) && ((cnt_h0 >= 3)))) || ((cnt_h1 >= 2) && inc[5]));
assign time_data = {
cnt_h1, cnt_h0, cnt_m1, cnt_m0, cnt_s1, cnt_s0};
/***************整点报时***************/
reg flag_hour;
reg [5:0] cnt_hour;
wire en_hour;
wire co_hour;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_hour <= 0;
end
else begin
if(en_hour)begin
if(co_hour)
cnt_hour <= 0;
else
cnt_hour <= cnt_hour + 1;
end
end
end
assign en_hour = ({
cnt_h1, cnt_h0} != 0) && ({
cnt_m1, cnt_m0} == 0) && flag_hour && co_div;
assign co_hour = (en_hour) && (cnt_hour >= (2 * (10 * cnt_h1 + cnt_h0) - 1));
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
flag_hour <= 1;
end
else begin
if(co_hour)
flag_hour <= 0;
else if({
cnt_m1, cnt_m0} != 0)
flag_hour <= 1;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
hour <= 1;
end
else begin
if(set_state == 1)
hour <= 1;
else if(({
cnt_h1, cnt_h0} != 0) && ({
cnt_m1, cnt_m0} == 0) && flag_hour)
hour <= cnt_hour[0];
end
end
/***************秒针***************/
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sec <= 1;
end
else begin
if(set_state == 1)
sec <= 1;
else
sec <= cnt_s0[0];
end
end
endmodule
5. Alarm clock module Alarm
The alarm clock setting is similar to the school time function,
compare the timing time with the alarm clock time and output the alarm clock signal
/***************闹钟模块***************/
module Alarm(
clk,
rst_n,
mode,
set_loc,
set_inc,
time_data,
alm_data,
alm
);
//输入输出
input clk;
input rst_n;
input [1:0] mode;
input [3:0] set_loc;
input set_inc;
input [23:0] time_data;
output [23:0] alm_data;
output alm;
wire [23:0] alm_data;
reg alm;
/***************校时***************/
reg [3:0] inc;
always@(*)begin
if((mode == 2) && set_inc)
inc = set_loc;
else
inc = 4'b0000;
end
/***************分个位***************/
reg [3:0] cnt_m0;
wire en_m0;
wire co_m0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_m0 <= 0;
end
else if(en_m0)begin
if(co_m0)
cnt_m0 <= 0;
else
cnt_m0 <= cnt_m0 + 1;
end
end
assign en_m0 = inc[0];
assign co_m0 = (en_m0) && (cnt_m0 == 9);
/***************分十位***************/
reg [3:0] cnt_m1;
wire en_m1;
wire co_m1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_m1 <= 0;
end
else if(en_m1)begin
if(co_m1)
cnt_m1 <= 0;
else
cnt_m1 <= cnt_m1 + 1;
end
end
assign en_m1 = co_m0 || inc[1];
assign co_m1 = (en_m1) && (cnt_m1 == 5);
/***************时个位***************/
reg [3:0] cnt_h0;
reg [3:0] cnt_h1;
wire en_h0;
wire co_h0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_h0 <= 0;
end
else if(en_h0)begin
if(co_h0)
cnt_h0 <= 0;
else
cnt_h0 <= cnt_h0 + 1;
end
end
assign en_h0 = co_m1 || inc[2];
assign co_h0 = (en_h0) && ((cnt_h0 == 9) || (((cnt_h1 == 2) && ((cnt_h0 == 3)))));
/***************时十位***************/
wire en_h1;
wire co_h1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_h1 <= 0;
end
else if(en_h1)begin
if(co_h1)
cnt_h1 <= 0;
else
cnt_h1 <= cnt_h1 + 1;
end
end
assign en_h1 = co_h0 || inc[3];
assign co_h1 = (en_h1) && ((((cnt_h1 == 2) && ((cnt_h0 >= 3)))) || ((cnt_h1 >= 2) && inc[3]));
assign alm_data = {
cnt_h1, cnt_h0, cnt_m1, cnt_m0};
/***************输出***************/
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
alm <= 1;
end
else begin
if(set_loc != 0)
alm <= 1;
else if(time_data[23:8] == alm_data)
alm <= 0;
else
alm <= 1;
end
end
endmodule
6. Display module Display
Determine the displayed content according to the current working mode
/***************显示模块***************/
module Display(
clk,
rst_n,
mode,
time_data,
alm_data,
set_loc,
smg_sig,
smg_loc
);
//输入输出
input clk;
input rst_n;
input [1:0] mode;
input [23:0] time_data;
input [15:0] alm_data;
input [3:0] set_loc;
output [7:0] smg_sig;
output [5:0] smg_loc;
wire [7:0] smg_sig;
wire [5:0] smg_loc;
/***************取数***************/
reg [15:0] show_data;
wire [23:0] num_data;
wire [5:0] dot_data;
always@(*)begin
case(mode)
0: show_data = time_data[23:8];
1: show_data = time_data[15:0];
2: show_data = alm_data;
default: show_data = 0;
endcase
end
assign num_data = {
8'b00000000, show_data};
assign dot_data = {
2'b00, set_loc};
/***************数码管驱动***************/
Smg U_smg(
.clk(clk),
.rst_n(rst_n),
.num_data(num_data),
.dot_data(dot_data),
.smg_sig(smg_sig),
.smg_loc(smg_loc)
);
endmodule
7. Nixie tube drive module Smg
Digital tube drive module with decimal point, can be used as a basic module
/***************显示模块***************/
module Smg(
clk,
rst_n,
num_data,
dot_data,
smg_sig,
smg_loc
);
//参数定义
parameter CNT_2MS = 17'd99_999;
parameter CNT_200NS = 17'd9;
//输入输出
input clk;
input rst_n;
input [23:0] num_data;
input [5:0] dot_data;
output [7:0] smg_sig;
output [5:0] smg_loc;
reg [7:0] smg_sig;
reg [5:0] smg_loc;
/***************分频***************/
reg [16:0] cnt_div;
wire en_div;
wire co_div;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_div <= 0;
end
else if(en_div)begin
if(co_div)
cnt_div <= 0;
else
cnt_div <= cnt_div + 1;
end
end
assign en_div = 1;
assign co_div = (en_div) && (cnt_div == CNT_2MS);
/***************扫描***************/
reg [3:0] cnt_scan;
wire en_scan;
wire co_scan;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_scan <= 0;
end
else if(en_scan)begin
if(co_scan)
cnt_scan <= 0;
else
cnt_scan <= cnt_scan + 1;
end
end
assign en_scan = co_div;
assign co_scan = (en_scan) && (cnt_scan == 5);
/***************取数***************/
reg [3:0] smg_data;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
smg_data <= 0;
end
else begin
case(cnt_scan)
0: smg_data <= num_data[3:0];
1: smg_data <= num_data[7:4];
2: smg_data <= num_data[11:8];
3: smg_data <= num_data[15:12];
4: smg_data <= num_data[19:16];
5: smg_data <= num_data[23:20];
endcase
end
end
/***************显示***************/
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
smg_loc <= 6'b000000;
end
else begin
case(cnt_scan)
0: smg_loc <= 6'b111110;
1: smg_loc <= 6'b111101;
2: smg_loc <= 6'b111011;
3: smg_loc <= 6'b110111;
4: smg_loc <= 6'b101111;
5: smg_loc <= 6'b011111;
endcase
end
end
/***************译码***************/
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
smg_sig <= 8'b00000011;
end
else begin
case(smg_data)
0: smg_sig[7:1] = 7'b0000001;
1: smg_sig[7:1] = 7'b1001111;
2: smg_sig[7:1] = 7'b0010010;
3: smg_sig[7:1] = 7'b0000110;
4: smg_sig[7:1] = 7'b1001100;
5: smg_sig[7:1] = 7'b0100100;
6: smg_sig[7:1] = 7'b0100000;
7: smg_sig[7:1] = 7'b0001111;
8: smg_sig[7:1] = 7'b0000000;
9: smg_sig[7:1] = 7'b0000100;
default: smg_sig[7:1] = 7'b0110000;//E
endcase
smg_sig[0] <= ~dot_data[cnt_scan];
end
end
endmodule
4. Test file
The test file is modified on the basis of the previous
`timescale 1 ns/ 1 ns
module Digclk_tb();
reg [2:0] btn;
reg clk;
reg rst_n;
wire [2:0] led;
wire [5:0] smg_loc;
wire [7:0] smg_sig;
//模拟按键按下
task SWC;
begin
#1000 btn[2] = 0;
#1000 btn[2] = 1;
end
endtask
task MOV;
begin
#1000 btn[1] = 0;
#1000 btn[1] = 1;
end
endtask
task INC;
begin
#1000 btn[0] = 0;
#1000 btn[0] = 1;
end
endtask
Digclk u1 (
.btn(btn),
.clk(clk),
.led(led),
.rst_n(rst_n),
.smg_loc(smg_loc),
.smg_sig(smg_sig)
);
initial begin
clk = 0;
rst_n = 1;
end
always begin
#10 clk = ~clk;
end
initial begin
// Initialize Inputs
rst_n = 1;
btn = 3'b111;
// Wait 200 ns for global rst_n to finish
#100 rst_n = 0;
#100 rst_n = 1;
// Add stimulus here
//////////////////////////////////////////////闹钟测试
//闹钟置数1200,闹钟指针1000
INC;//空加
repeat(2) SWC;//2
MOV;
repeat(4) INC;//1
MOV;
repeat(2) INC;//2
//////////////////////////////////////////////校时测试
//时分置数1159
//置数模式
#10000;
SWC;
MOV;
INC;//1
MOV;
INC;//1
MOV;
repeat(5) INC;//5
MOV;
repeat(9) INC;//9
//秒置数58
SWC;
#10000;
repeat(3) MOV;
repeat(1) INC;//5
MOV;
repeat(1) INC;//8
MOV;
//////////////////////////////////////////////状态切换测试
//显示分秒
#10000;
SWC;
//显示闹钟
#10000;
SWC;
//////////////////////////////////////////////清零测试
//清零
#10000 rst_n = 0;
#10000 rst_n = 1;
//////////////////////////////////////////////进位测试
//分置数59
SWC;
MOV;
repeat(5) INC;//5
MOV;
repeat(8) INC;//8
//时置数23
repeat(2) SWC;
#10000
MOV;
repeat(5) INC;//2
MOV;
repeat(3) INC;//3
SWC;
//////////////////////////////////////////////防抖测试
#10000 btn[2] = 0;//忽略
#10 btn[2] = 1;
#30 btn[2] = 0;//触发
#1000 btn[2] = 1;
#50 btn[2] = 0;//忽略
#70 btn[2] = 1;
#1000 btn[2] = 0;//触发
#1000 btn[2] = 1;
end
endmodule
5. Waveform simulation
1. Variable name description
rst_n: reset button;
btn[2:0]: switch, shift, plus one button;
xxx_btn_f: button signal after debounce module;
mode: working mode (0: hour, 1: minute seconds, 2: alarm clock)
time_data: timing time;
alm_data: alarm clock time;
num_data: display content;
smg_loc: digital tube position;
smg_data: digital tube data;
smg_sig: digital tube signal;
set_loc: operating position;
dot_data: decimal point information;
led [2:0]: Hourly chime LED, alarm clock LED, second LED.
2. Alarm clock setting test
Set the alarm clock to 12:00
3. Clock calibration test
Set the clock to 11:59:58
4. Alarm clock and hourly timekeeping test
The alarm clock rings for one minute at 12:00, and the hourly timekeeping flashes 12 times
5. Display content test
Switch working status, respectively display hours, minutes, seconds
, alarm clock 6, reset test
7, carry test
Set the timing value to 23:59:23, test digital clock carry
8, debounce test
pair button btn[2] Perform a debounce test and convert it to swc_btn_f
Summarize
The program passed the actual test on the AX530 development board.
Some changes were made in the logic part, mainly for the convenience of operation.
The control module was originally intended to be written with a state machine, but later it was found that it was not necessary to
write a control module alone. It always feels a little strange
. Chaos, including the hourly timekeeping can also be changed