文章目录
- 项目要求
- 项目设计
项目要求
设计一个时钟秒表,共六个数码管,前两位显示分钟,中间两位显示时间秒,后两位显示毫秒的高两位,可以通过按键来开始、暂停以及重新开始秒表的计数。
项目设计
为完成此项目共设计四个模块,按键消抖模块、时钟计时器模块、数码管显示模块以及顶层文件模块,详细代码设计如下:
按键消抖模块:
/* * @Description: 按键销抖模块(延迟方法销抖) * @Author: Fu Yu * @Date: 2023-08-01 14:31:19 * @LastEditTime: 2023-08-01 16:29:44 * @LastEditors: Fu Yu */module key_filter (input wireclk ,input wirerst_n ,input wirekey_in,//按键输入,低有效outputwirekey_down //按键输出,高有效);parameter MAX_20MS = 20'd999_999;//20msreg key_r;//同步reg key_r1;//打拍reg key_r2;wire nedge;//下降沿reg key_down_r;//保存key_down信号reg [19:0]cnt_20ms;reg flag;//计数开始标志信号wire add_cnt_20ms;wire end_cnt_20ms;//****************************************************************//--同步打拍,检测下降沿//****************************************************************always @(posedge clk or negedge rst_n) beginif(!rst_n) beginkey_r <= 1'b1;key_r1 <= 1'b1;key_r2 <= 1'b1;endelse beginkey_r <= key_in;key_r1 <= key_r;key_r2 <= key_r1;endend//下降沿检测assign nedge = ~key_r1 & key_r2;//****************************************************************//--flag信号定义//****************************************************************always @(posedge clk or negedge rst_n) beginif(!rst_n) beginflag <= 1'b0;endelse if(nedge) beginflag <= 1'b1;endelse if(end_cnt_20ms) beginflag <= 1'b0;endelse beginflag <= flag;endend//****************************************************************//--计数//****************************************************************always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_20ms <= 20'd0;end else if(add_cnt_20ms)begin if(end_cnt_20ms)begin cnt_20ms <= 20'd0;endelse begin cnt_20ms <= cnt_20ms + 1'b1;end endend assign add_cnt_20ms = flag;assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == MAX_20MS;//****************************************************************//--key_down//****************************************************************always @(posedge clk or negedge rst_n) beginif(!rst_n) beginkey_down_r <= 1'b0;endelse if(end_cnt_20ms) beginkey_down_r <= ~key_r2;endelse beginkey_down_r <= 1'b0;endendassign key_down = key_down_r;endmodule //key_filter
时钟计时器模块:
/* * @Description: 通过输入的按键控制计数开始与暂停,实现秒表设计(毫秒、秒、分计时) * @Author: Fu Yu * @Date: 2023-08-01 14:46:43 * @LastEditTime: 2023-08-01 15:53:12 * @LastEditors: Fu Yu */module counter_time (input wireclk ,input wirerst_n ,input wirekey_in,//销抖后的脉冲信号,高有效outputwire [23:0] din_out //输出当前计数的值);parameter MAX_1MS = 16'd49_999;//1msparameter MAX_1S = 10'd999;//1ms*1000 = 1sparameter MAX_1MIN = 6'd59;//1s*60 = 1minparameter MAX_1H = 6'd59;//1min*60 = 1hreg flag;//开始、暂停结束信号reg [15:0] cnt_1ms;wire add_cnt_1ms;wire end_cnt_1ms;reg [9:0] cnt_1s;wire add_cnt_1s;wire end_cnt_1s;reg [5:0] cnt_1min;wire add_cnt_1min;wire end_cnt_1min;reg [5:0] cnt_1h;wire add_cnt_1h;wire end_cnt_1h;reg [7:0] data_min;//保存此时有多少分钟reg [7:0] data_s;//保存此时有多少秒reg [7:0] data_ms;//保存此时有多少毫秒,只取高两位//****************************************************************//--flag//****************************************************************always @(posedge clk or negedge rst_n) beginif(!rst_n) beginflag <= 1'b0;endelse if (key_in) beginflag <= ~flag;endelse beginflag <= flag;endend//****************************************************************//--1ms计数器//****************************************************************always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_1ms <= 16'd0;end else if(add_cnt_1ms)begin if(end_cnt_1ms)begin cnt_1ms <= 16'd0;endelse begin cnt_1ms <= cnt_1ms + 1'b1;end endend assign add_cnt_1ms = flag;assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == MAX_1MS;//****************************************************************//--1s计数器//****************************************************************always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_1s <= 10'd0;end else if(add_cnt_1s)begin if(end_cnt_1s)begin cnt_1s <= 10'd0;endelse begin cnt_1s <= cnt_1s + 1'b1;end endend assign add_cnt_1s = end_cnt_1ms;assign end_cnt_1s = add_cnt_1s && cnt_1s == MAX_1S ;//&& end_cnt_1ms//****************************************************************//--1min计数器//****************************************************************always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_1min <= 6'd0;end else if(add_cnt_1min)begin if(end_cnt_1min)begin cnt_1min <= 6'd0;endelse begin cnt_1min <= cnt_1min + 1'b1;end endend assign add_cnt_1min = end_cnt_1s;assign end_cnt_1min = add_cnt_1min && cnt_1min == MAX_1MIN ;//&& end_cnt_1s//****************************************************************//--1h计数器//****************************************************************always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_1h <= 6'd0;end else if(add_cnt_1h)begin if(end_cnt_1h)begin cnt_1h <= 6'd0;endelse begin cnt_1h <= cnt_1h + 1'b1;end endend assign add_cnt_1h = end_cnt_1min;assign end_cnt_1h = add_cnt_1h && cnt_1h == MAX_1H;// && end_cnt_1min//****************************************************************//--din_out//****************************************************************always @(posedge clk or negedge rst_n) beginif(!rst_n) begindata_min <= 8'd0;data_s <= 8'd0;data_ms <= 8'd0;endelse begindata_min <= cnt_1h;data_s <= cnt_1min;data_ms <= cnt_1s/10;endendassign din_out = {data_min,data_s,data_ms};endmodule //counter_time
数码管显示模块:
/* * @Description: 数码管显示时钟,前两位显示分钟,中间两位显示秒,最后两位显示毫秒 * @Author: Fu Yu * @Date: 2023-08-01 15:19:52 * @LastEditTime: 2023-08-01 16:22:40 * @LastEditors: Fu Yu */module seg_sel (input wireclk ,input wirerst_n ,input wire [23:0] din ,outputwire [5:0]sel ,//位选信号outputwire [7:0]dig //段选信号);parameter MAX_1MS = 16'd49_999;//1msparameter 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] point_n;//小数点位置reg point_n_r;reg [15:0] cnt_1ms;wire add_cnt_1ms;wire end_cnt_1ms;reg [5:0] sel_r;reg [7:0] dig_r;reg [3:0] disp_data ;//每一位数码管显示的数值//****************************************************************//--1ms计数器//****************************************************************always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_1ms <= 16'd0;end else if(add_cnt_1ms)begin if(end_cnt_1ms)begin cnt_1ms <= 16'd0;endelse begin cnt_1ms <= cnt_1ms + 1'b1;end endend assign add_cnt_1ms = 1'b1;assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == MAX_1MS;//****************************************************************//--小数点//****************************************************************always @(posedge clk or negedge rst_n) beginif(!rst_n) beginpoint_n <= 6'b111111;endelse beginpoint_n <= 6'b110101;endend//****************************************************************//--sel信号//****************************************************************always @(posedge clk or negedge rst_n) beginif(!rst_n) beginsel_r <= 6'b111110;endelse if(end_cnt_1ms) beginsel_r <= {sel_r[4:0],sel_r[5]};//循环左移endendassign sel = sel_r;//****************************************************************//--disp_data//****************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)begindisp_data <= 'd0;point_n_r <= 1'b1;end else begin case (sel_r)6'b111_110 : begin disp_data <= din[23:16]/10; point_n_r <= point_n[0]; end//第一位数码管显示的数值6'b111_101 : begin disp_data <= din[23:16]%10; point_n_r <= point_n[1]; end6'b111_011 : begin disp_data <= din[15:8]/10 ; point_n_r <= point_n[2]; end6'b110_111 : begin disp_data <= din[15:8]%10 ; point_n_r <= point_n[3]; end6'b101_111 : begin disp_data <= din[7:0]/10 ; point_n_r <= point_n[4]; end6'b011_111 : begin disp_data <= din[7:0]%10 ; point_n_r <= point_n[5]; enddefault: disp_data <= 'd0;endcaseend 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;endcaseendassign dig = dig_r;endmodule //seg_sel
顶层文件模块:
module top (input wireclk ,input wirerst_n ,input wirekey_in,outputwire [5:0]sel ,outputwire [7:0]dig );wire key;wire [23:0] data;key_filter u_key_filter(. clk(clk) ,. rst_n (rst_n),. key_in(key_in),. key_down (key));counter_time u_counter_time(. clk(clk) ,. rst_n(rst_n) ,. key_in (key) ,. din_out(data));seg_sel u_seg_sel(. clk(clk) ,. rst_n (rst_n),. din (data),. sel(sel) ,. dig(dig));endmodule //top
效果展示:
秒表