一)功能描述
a.可以产生秒,分,时。
b.校时功能:可以对时,和分进行修改
c.整点报时功能,1-23每整点发出短音,0点发出长音
d.数码管显示
二)效果展示
时:分:秒
8:44:18
key3按下保持校时状态,之后key1、key2分别控制时、分,再次按下key3返回计时状态。
用蜂鸣器实现整点报时。
3)RTL图
4)顶层模块分为按键消抖,计时模块,显示模块和整点报时模块
顶层代码
// This is a simple example.
// You can make a your own header file and set its path to settings.
// (Preferences > Package Settings > Verilog Gadget > Settings - User)
//
// "header": "Packages/Verilog Gadget/template/verilog_header.v"
//
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2021 All rights reserved
// -----------------------------------------------------------------------------
// Author : dengzhen (Kris) 472643309@qq.com
// wechat : 13315379910
// File : top.v
// Create : 2021-08-01 16:37:43
// Revise : 2021-08-01 20:51:13
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
module top(
input wire clk ,
input wire rst_n ,
input wire [2:0] key ,
output wire [6:0] po_seg ,
output wire [2:0] po_sel ,
output wire po_bell
);
reg en ;
wire key1,key2,key3;
wire [7:0] hour ;
wire [7:0] minuter ;
wire [7:0] second ;
wire [1:0] bell ;
wire key_flag1,key_value1;
wire key_flag2,key_value2;
wire key_flag3,key_value3;
key_debounce inst_key_debounce1
(
.sys_clk (clk),
.sys_rst_n (rst_n),
.key (key[0]),
.key_flag (key_flag1),
.key_value (key_value1)
);
key_debounce inst_key_debounce2
(
.sys_clk (clk),
.sys_rst_n (rst_n),
.key (key[1]),
.key_flag (key_flag2),
.key_value (key_value2)
);
key_debounce inst_key_debounce3
(
.sys_clk (clk),
.sys_rst_n (rst_n),
.key (key[2]),
.key_flag (key_flag3),
.key_value (key_value3)
);
assign key1 = key_flag1&(!key_value1) ;
assign key2 = key_flag2&(!key_value2) ;
assign key3 = key_flag3&(!key_value3) ;
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
en <= 1'b0 ;
end
else if (key3==1'b1) begin
en <= ~en ;
end
end
count inst_count (
.clk (clk),
.rst_n (rst_n),
.en (en),
.pi_hc (key1),
.pi_mc (key2),
.po_hour (hour),
.po_min (minuter),
.po_sec (second),
.bell (bell)
);
mulx inst_mulx (
.clk (clk),
.rst_n (rst_n),
.pi_hour (hour),
.pi_min (minuter),
.pi_sec (second),
.po_seg (po_seg),
.po_sel (po_sel)
);
ring inst_ring (
.clk (clk),
.rst_n (rst_n),
.pi_data (bell),
.po_bell (po_bell)
);
endmodule
5)按键消抖
module key_debounce(
input sys_clk, //外部50M时钟
input sys_rst_n, //外部复位信号,低有效
input key, //外部按键输入
output reg key_flag, //按键数据有效信号
output reg key_value //按键消抖后的数据
);
//reg define
reg [31:0] delay_cnt;
reg key_reg;
//*****************************************************
//** main code
//*****************************************************
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
key_reg <= 1'b1;
delay_cnt <= 32'd0;
end
else begin
key_reg <= key;
if(key_reg != key) //一旦检测到按键状态发生变化(有按键被按下或释放)
delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为20ms)
else if(key_reg == key) begin //在按键状态稳定时,计数器递减,开始20ms倒计时
if(delay_cnt > 32'd0)
delay_cnt <= delay_cnt - 1'b1;
else
delay_cnt <= delay_cnt;
end
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
key_flag <= 1'b0;
key_value <= 1'b1;
end
else begin
if(delay_cnt == 32'd1) begin //当计数器递减到1时,说明按键稳定状态维持了20ms
key_flag <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
key_value <= key; //并寄存此时按键的值
end
else begin
key_flag <= 1'b0;
key_value <= key_value;
end
end
end
endmodule
计时模块
// This is a simple example.
// You can make a your own header file and set its path to settings.
// (Preferences > Package Settings > Verilog Gadget > Settings - User)
//
// "header": "Packages/Verilog Gadget/template/verilog_header.v"
//
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2021 All rights reserved
// -----------------------------------------------------------------------------
// Author : dengzhen (Kris) 472643309@qq.com
// wechat : 13315379910
// File : count.v
// Create : 2021-08-01 11:55:38
// Revise : 2021-08-01 21:43:06
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
module count(
input wire clk ,
input wire rst_n ,
input wire en ,
input wire pi_hc,
input wire pi_mc ,
output wire [7:0] po_hour ,
output wire [7:0] po_min ,
output wire [7:0] po_sec ,
output wire [1:0] bell
);
parameter CNTMAX_10 = 10 -1 ;//10s进位
parameter CNTMAX_6 = 6 -1 ;//6进位
parameter CNTMAX_4 = 4 -1 ;//4进位
parameter CNTMAX_3 = 3 -1 ;
parameter CNTMAX_1S = 50_000_000 -1 ;
reg [27:0] cnt_1s ;
reg [7:0] cnt_min;
reg [7:0] cnt_sec ;
reg [7:0] cnt_hour ;
reg [1:0] T ;
assign bell = T ;
assign po_hour = cnt_hour ;
assign po_min = cnt_min ;
assign po_sec = cnt_sec ;
//1s计数
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
cnt_1s <= 'd0 ;
end
else if (cnt_1s==CNTMAX_1S) begin
cnt_1s <= 'd0 ;
end
else begin
cnt_1s <= 1'b1 +cnt_1s;
end
end
//60s计数
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
cnt_sec <= 'd0 ;
end
else if (cnt_1s==CNTMAX_1S&&cnt_sec[3:0]==CNTMAX_10&&cnt_sec[7:4]==CNTMAX_6) begin
cnt_sec <= 0 ;
end
else if (cnt_1s==CNTMAX_1S&&cnt_sec[3:0]==CNTMAX_10) begin
cnt_sec[3:0] <= 'd0 ;
cnt_sec[7:4] <= cnt_sec[7:4] + 1'b1 ;
end
else if (cnt_1s==CNTMAX_1S) begin
cnt_sec <= cnt_sec + 1'b1 ;
end
end
//60m计数
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
cnt_min <= 'd0 ;
end
else if (en==0) begin
if (cnt_1s==CNTMAX_1S&&cnt_sec[3:0]==CNTMAX_10&&cnt_sec[7:4]==CNTMAX_6&&cnt_min[3:0]==CNTMAX_10&&cnt_min[7:4]==CNTMAX_6) begin
cnt_min <= 'd0 ;
end
else if (cnt_1s==CNTMAX_1S&&cnt_sec[3:0]==CNTMAX_10&&cnt_sec[7:4]==CNTMAX_6&&cnt_min[3:0]==CNTMAX_10) begin
cnt_min[3:0] <= 'd0 ;
cnt_min[7:4] <= cnt_min[7:4] + 1'b1 ;
end
else if(cnt_1s==CNTMAX_1S&&cnt_sec[3:0]==CNTMAX_10&&cnt_sec[7:4]==CNTMAX_6)begin
cnt_min <= cnt_min + 1'b1 ;
end
end
else if (en==1'b1) begin
if(pi_mc==1'b1&&cnt_min[3:0]==CNTMAX_10&&cnt_min[7:4]==CNTMAX_6)begin
cnt_min <= 'd0 ;
end
else if (pi_mc==1'b1&&cnt_min[3:0]==CNTMAX_10) begin
cnt_min[3:0] <= 'd0 ;
cnt_min[7:4] <= cnt_min[7:4] + 1'b1 ;
end
else if (pi_mc==1'b1) begin
cnt_min[3:0] <= cnt_min[3:0] + 1'b1 ;
end
end
end
//24时计数
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
cnt_hour <= 'd0 ;
end
else if (en==0) begin
if (cnt_1s==CNTMAX_1S&&cnt_sec[3:0]==CNTMAX_10&&cnt_sec[7:4]==CNTMAX_6&&cnt_min[3:0]==CNTMAX_10&&cnt_min[7:4]==CNTMAX_6&&cnt_hour[3:0]==CNTMAX_4&&cnt_hour[7:4]==CNTMAX_3) begin
cnt_hour <= 'd0 ;
end
else if (cnt_1s==CNTMAX_1S&&cnt_sec[3:0]==CNTMAX_10&&cnt_sec[7:4]==CNTMAX_6&&cnt_min[3:0]==CNTMAX_10&&cnt_min[7:4]==CNTMAX_6&&cnt_hour[3:0]==CNTMAX_10) begin
cnt_hour[3:0] <= 'd0 ;
cnt_hour[7:4] <= cnt_hour[7:4] + 1'b1 ;
end
else if (cnt_1s==CNTMAX_1S&&cnt_sec[3:0]==CNTMAX_10&&cnt_sec[7:4]==CNTMAX_6&&cnt_min[3:0]==CNTMAX_10&&cnt_min[7:4]==CNTMAX_6) begin
cnt_hour[3:0] <= cnt_hour + 1'b1 ;
end
end
else if (en==1'b1) begin
if (pi_hc==1'b1&&cnt_hour[3:0]==CNTMAX_4&&cnt_hour[7:4]==CNTMAX_3) begin
cnt_hour <= 'd0 ;
end
else if (pi_hc==1'b1&&cnt_hour[3:0]==CNTMAX_10) begin
cnt_hour[3:0] <= 'd0 ;
cnt_hour[7:4] <= cnt_hour[7:4] + 1'b1 ;
end
else if(pi_hc==1'b1)begin
cnt_hour <= cnt_hour + 1'b1 ;
end
end
end
//整点模式:普通整点01和24点10
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
T <= 2'b0 ;
end
else if (en==0) begin
if (cnt_1s==CNTMAX_1S&&cnt_sec[3:0]==CNTMAX_10&&cnt_sec[7:4]==CNTMAX_6&&cnt_min[3:0]==CNTMAX_10&&cnt_min[7:4]==CNTMAX_6&&cnt_hour[3:0]==CNTMAX_4&&cnt_hour[7:4]==CNTMAX_3) begin
T <= 2'b01 ;
end
else if (cnt_1s==CNTMAX_1S&&cnt_sec[3:0]==CNTMAX_10&&cnt_sec[7:4]==CNTMAX_6&&cnt_min[3:0]==CNTMAX_10&&cnt_min[7:4]==CNTMAX_6&&cnt_hour[3:0]!=CNTMAX_4&&cnt_hour[7:4]!=CNTMAX_3) begin
T <= 2'b10 ;
end
else begin
T <= 2'b00 ;
end
end
else begin
T <= 2'b00 ;
end
end
endmodule
数码管显示模块
// This is a simple example.
// You can make a your own header file and set its path to settings.
// (Preferences > Package Settings > Verilog Gadget > Settings - User)
//
// "header": "Packages/Verilog Gadget/template/verilog_header.v"
//
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2021 All rights reserved
// -----------------------------------------------------------------------------
// Author : dengzhen (Kris) 472643309@qq.com
// wechat : 13315379910
// File : mulx.v
// Create : 2021-08-01 14:10:48
// Revise : 2021-08-01 21:44:22
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
module mulx(
input wire clk ,
input wire rst_n ,
input wire [7:0] pi_hour ,
input wire [7:0] pi_min ,
input wire [7:0] pi_sec ,
output wire [6:0] po_seg ,
output wire [2:0] po_sel
);
parameter CNTMAX_1K = 50000 - 1 ;
parameter CNT_SEL = 6 - 1 ;
reg [15:0] cnt_1k ;
reg sel_flag ;
reg [2:0] sel_r ;//
wire [23:0] disp_data ;
reg [6:0] seg ;
reg [3:0] data_tmp ;
assign po_sel = sel_r;
assign po_seg = seg ;
assign disp_data = {pi_hour,pi_min,pi_sec} ;
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
cnt_1k <= 'd0 ;
end
else if (cnt_1k==CNTMAX_1K) begin
cnt_1k <= 'd0 ;
end
else begin
cnt_1k <= cnt_1k + 1'b1 ;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
sel_flag <= 1'b1 ;
end
else if (cnt_1k==CNTMAX_1K) begin
sel_flag <= 1'b1 ;
end
else begin
sel_flag <= 1'b0 ;
end
end
//通过3-8译码器减少输出位
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
sel_r <= 3'd0 ;
end
else if (sel_flag==1'b1&&sel_r == CNT_SEL) begin
sel_r <= 'd0 ;
end
else if (sel_flag==1'b1) begin
sel_r <= sel_r + 1'b1 ;
end
end
always@(*)
case(sel_r)
3'd0:data_tmp = disp_data[23:20];
3'd1:data_tmp = disp_data[19:16];
3'd2:data_tmp = disp_data[15:12];
3'd3:data_tmp = disp_data[11:8];
3'd4:data_tmp = disp_data[7:4];
3'd5:data_tmp = disp_data[3:0];
default:data_tmp = 4'b0000;
endcase
always@(*)
case(data_tmp)
4'h0:seg = 7'b1000000;
4'h1:seg = 7'b1111001;
4'h2:seg = 7'b0100100;
4'h3:seg = 7'b0110000;
4'h4:seg = 7'b0011001;
4'h5:seg = 7'b0010010;
4'h6:seg = 7'b0000010;
4'h7:seg = 7'b1111000;
4'h8:seg = 7'b0000000;
4'h9:seg = 7'b0010000;
4'ha:seg = 7'b0001000;
4'hb:seg = 7'b0000011;
4'hc:seg = 7'b1000110;
4'hd:seg = 7'b0100001;
4'he:seg = 7'b0000110;
4'hf:seg = 7'b0001110;
endcase
endmodule
报时模块
// This is a simple example.
// You can make a your own header file and set its path to settings.
// (Preferences > Package Settings > Verilog Gadget > Settings - User)
//
// "header": "Packages/Verilog Gadget/template/verilog_header.v"
//
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2021 All rights reserved
// -----------------------------------------------------------------------------
// Author : dengzhen (Kris) 472643309@qq.com
// wechat : 13315379910
// File : ring.v
// Create : 2021-08-01 15:50:20
// Revise : 2021-08-01 21:40:11
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
module ring(
input wire clk ,
input wire rst_n ,
input wire [1:0] pi_data ,
output wire po_bell
);
parameter CNTMAX = 1000_000 ;
parameter CNT_1S = 50_000_000 ;
reg [19:0] cnt ;
reg [26:0] cnt_1s ;
reg bell1,bell2 ;
reg [1:0] data ;
reg bell_r ;
assign po_bell = bell_r;
//整点提示
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
data <= 2'b0 ;
end
else if (pi_data!=0) begin
data <= pi_data ;
end
else if (cnt_1s==CNT_1S) begin
data <= 1'b0 ;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
cnt_1s <= 'd0 ;
end
else if (data!=0) begin
cnt_1s <= cnt_1s + 1'b1 ;
end
else begin
cnt_1s <= 'd0 ;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
cnt <= 'd0 ;
end
else if (cnt==CNTMAX) begin
cnt <= 'd0 ;
end
else begin
cnt <= cnt + 1'b1 ;
end
end
//整点提示1
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
bell1 <= 1'b0 ;
end
else if (cnt<=(CNTMAX>>1)) begin
bell1 <= 1'b0 ;
end
else begin
bell1 <= 1'b1 ;
end
end
//24时提示2
always @(posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
bell2 <= 1'b0 ;
end
else if (cnt<=(CNTMAX>>2)) begin
bell2 <= 1'b0 ;
end
else begin
bell2 <= 1'b1 ;
end
end
always @(posedge clk) begin
if(data==2'b01)begin
bell_r <= bell1 ;
end
else if (data==2'b10) begin
bell_r <= bell2 ;
end
else begin
bell_r <= 1'b0 ;
end
end
endmodule