项目要求:
设计一个数字时钟,数码管前两位显示小时,数码管中间两位显示分钟,数码管后面两位显示秒。
项目设计:
系统框架图:
计数模块时序图:
代码实现:
计数模块:
/*
* @Description: 用于记数产生时钟
* @Author: Fu Yu
* @Date: 2023-08-02 11:16:46
* @LastEditTime: 2023-08-02 15:23:14
* @LastEditors: Fu Yu
*/
module counter (
input wire clk ,
input wire rst_n ,
output wire [23:0] clock_data //输出时钟数值
);
parameter MAX_1S = 26'd49_999_999;//1s
parameter MAX_S = 6'd59;//1S*60 = 1min
parameter MAX_MIN = 6'd59;//1min*60 = 1h
parameter MAX_H = 5'd23;//1h*24 = 1d
localparam INIT_S = 40,//赋初值
INIT_M = 58,
INIT_H = 23;
reg [25:0] cnt_1s;
reg [5:0] cnt_s;
reg [5:0] cnt_min;
reg [4:0] cnt_h;
reg [3:0] time_s_low;
reg [3:0] time_s_high;
reg [3:0] time_min_low;
reg [3:0] time_min_high;
reg [3:0] time_h_low;
reg [3:0] time_h_high;
wire add_cnt_1s;
wire end_cnt_1s;
wire add_cnt_s;
wire end_cnt_s;
wire add_cnt_min;
wire end_cnt_min;
wire add_cnt_h;
wire end_cnt_h;
//****************************************************************
//--1s计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_1s <= 26'd0;
end
else if(add_cnt_1s) begin
if(end_cnt_1s) begin
cnt_1s <= 26'd0;
end
else begin
cnt_1s <= cnt_1s + 1'd1;
end
end
else begin
cnt_1s <= cnt_1s;
end
end
assign add_cnt_1s = 1'b1;
assign end_cnt_1s = add_cnt_1s && cnt_1s == MAX_1S;
//****************************************************************
//--秒计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_s <= INIT_S;
end
else if(add_cnt_s) begin
if(end_cnt_s) begin
cnt_s <= 6'd0;
end
else begin
cnt_s <= cnt_s + 1'd1;
end
end
else begin
cnt_s <= cnt_s;
end
end
assign add_cnt_s = end_cnt_1s;
assign end_cnt_s = add_cnt_s && cnt_s == MAX_S;
//****************************************************************
//--分钟计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_min <= INIT_M;
end
else if(add_cnt_min) begin
if(end_cnt_min) begin
cnt_min <= 6'd0;
end
else begin
cnt_min <= cnt_min + 1'd1;
end
end
else begin
cnt_min <= cnt_min;
end
end
assign add_cnt_min = end_cnt_s;
assign end_cnt_min = add_cnt_min && cnt_min == MAX_MIN;
//****************************************************************
//--小时计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_h <= INIT_H;
end
else if(add_cnt_h) begin
if(end_cnt_h) begin
cnt_h <= 5'd0;
end
else begin
cnt_h <= cnt_h + 1'd1;
end
end
else begin
cnt_h <= cnt_h;
end
end
assign add_cnt_h = end_cnt_min;
assign end_cnt_h = add_cnt_h && cnt_h == MAX_H;
//****************************************************************
//--clock_data
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
time_s_high <= 4'd0;
time_s_low <= 4'd0;
time_min_high <= 4'd0;
time_min_low <= 4'b0;
time_h_high <= 4'd0;
time_h_low <= 4'd0;
end
else begin
time_h_high <= cnt_h/10;
time_h_low <= cnt_h%10;
time_min_high <= cnt_min/10;
time_min_low <= cnt_min%10;
time_s_high <= cnt_s/10;
time_s_low <= cnt_s%10;
end
end
assign clock_data = {time_h_high,time_h_low,time_min_high,time_min_low,time_s_high,time_s_low};
endmodule //counter
数码管显示模块:
/*
* @Description: 数码管显示模块,前两位显示时钟数据的小时,中间两位显示时间数据的分钟,最后两位显示时间数据的秒
* @Author: Fu Yu
* @Date: 2023-08-02 13:43:47
* @LastEditTime: 2023-08-02 14:00:00
* @LastEditors: Fu Yu
*/
module seg_driver (
input wire clk ,
input wire rst_n ,
input wire [23:0] clock_data_in ,
output wire [5:0] sel ,//位选信号
output wire [7:0] dig //段选信号
);
parameter MAX_1MS = 16'd49_999;//1ms
parameter ZERO = 7'b100_0000,
ONE = 7'b111_1001,
TWO = 7'b010_0100,
THREE = 7'b011_0000,
FOUR = 7'b001_1001,
FIVE = 7'b001_0010,
SIX = 7'b000_0010,
SEVEN = 7'b111_1000,
EIGHT = 7'b000_0000,
NINE = 7'b001_0000;
reg [5:0] sel_r;
reg [7:0] dig_r;
reg [5:0] point_n;//小数点
reg point_n_r;
reg [3:0] disp_data ;//每一位数码管显示的数值
reg [15:0] cnt_1ms;
wire add_cnt_1ms;
wire end_cnt_1ms;
//****************************************************************
//--1ms计数器
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_1ms <= 16'd0;
end
else if(add_cnt_1ms)begin
if(end_cnt_1ms)begin
cnt_1ms <= 16'd0;
end
else begin
cnt_1ms <= cnt_1ms + 1'b1;
end
end
end
assign add_cnt_1ms = 1'b1;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == MAX_1MS;
//****************************************************************
//--point_n
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
point_n <= 6'b111_111;
end
else begin
point_n <= 6'b110101;
end
end
//****************************************************************
//--sel
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
sel_r <= 6'b111110;
end
else if(end_cnt_1ms) begin
sel_r <= {sel_r[4:0],sel_r[5]};
end
else begin
sel_r <= sel_r;
end
end
assign sel = sel_r;
//****************************************************************
//-- disp_data
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
disp_data <= 4'd0;
point_n_r <= 1'b1;
end
else begin
case (sel_r)
6'b111110 : begin
disp_data <= clock_data_in[23:20];
point_n_r <= point_n[0];
end
6'b111101 : begin
disp_data <= clock_data_in[19:16];
point_n_r <= point_n[1];
end
6'b111011 : begin
disp_data <= clock_data_in[15:12];
point_n_r <= point_n[2];
end
6'b110111 : begin
disp_data <= clock_data_in[11:8];
point_n_r <= point_n[3];
end
6'b101111 : begin
disp_data <= clock_data_in[7:4];
point_n_r <= point_n[4];
end
6'b011111 : begin
disp_data <= clock_data_in[3:0];
point_n_r <= point_n[5];
end
endcase
end
end
//****************************************************************
//--dig
//****************************************************************
always @(*)begin
case (disp_data)
0 : dig_r <= {point_n_r,ZERO };
1 : dig_r <= {point_n_r,ONE };
2 : dig_r <= {point_n_r,TWO };
3 : dig_r <= {point_n_r,THREE };
4 : dig_r <= {point_n_r,FOUR };
5 : dig_r <= {point_n_r,FIVE };
6 : dig_r <= {point_n_r,SIX };
7 : dig_r <= {point_n_r,SEVEN };
8 : dig_r <= {point_n_r,EIGHT };
9 : dig_r <= {point_n_r,NINE };
default: dig_r <= 8'hff;
endcase
end
assign dig = dig_r;
endmodule //seg_driver
顶层文件:
module top (
input wire clk ,
input wire rst_n ,
output wire [5:0] sel ,
output wire [7:0] dig
);
wire [23:0] data;
counter u_counter(
. clk (clk) ,
. rst_n (rst_n) ,
. clock_data (data)
);
seg_driver u_seg_driver (
. clk (clk) ,
. rst_n (rst_n) ,
. clock_data_in (data),
. sel (sel) ,
. dig (dig)
);
endmodule //top