FPGA项目实现:秒表设计

项目要求

设计一个时钟秒表,共六个数码管,前两位显示分钟,中间两位显示时间秒,后两位显示毫秒的高两位,可以通过按键来开始、暂停以及重新开始秒表的计数。

项目设计

为完成此项目共设计四个模块,按键消抖模块、时钟计时器模块、数码管显示模块以及顶层文件模块,详细代码设计如下:

按键消抖模块:

/*
 * @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       wire        clk         ,
    input       wire        rst_n       ,
    input       wire        key_in      ,//按键输入,低有效

    output      wire        key_down       //按键输出,高有效
);

parameter MAX_20MS = 20'd999_999;//20ms

reg 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) begin
    if(!rst_n) begin
        key_r <= 1'b1;
        key_r1 <= 1'b1;
        key_r2 <= 1'b1;
    end
    else begin
        key_r <= key_in;
        key_r1 <= key_r;
        key_r2 <= key_r1;
    end
end

//下降沿检测
assign nedge = ~key_r1 & key_r2;

//****************************************************************
//--flag信号定义
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        flag <= 1'b0;
    end
    else if(nedge) begin
        flag <= 1'b1;
    end
    else if(end_cnt_20ms) begin
        flag <= 1'b0;
    end
    else begin
        flag <= flag;
    end
end

//****************************************************************
//--计数
//****************************************************************
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_20ms <= 20'd0;
    end 
    else if(add_cnt_20ms)begin 
        if(end_cnt_20ms)begin 
            cnt_20ms <= 20'd0;
        end
        else begin 
            cnt_20ms <= cnt_20ms + 1'b1;
        end 
    end
end 

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) begin
    if(!rst_n) begin
        key_down_r <= 1'b0;
    end
    else if(end_cnt_20ms) begin
        key_down_r <= ~key_r2;
    end
    else begin
        key_down_r <= 1'b0;
    end
end

assign 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       wire        clk         ,
    input       wire        rst_n       ,
    input       wire        key_in      ,//销抖后的脉冲信号,高有效

    output      wire [23:0] din_out         //输出当前计数的值
);

parameter MAX_1MS = 16'd49_999;//1ms
parameter MAX_1S = 10'd999;//1ms*1000 = 1s
parameter MAX_1MIN = 6'd59;//1s*60 = 1min
parameter MAX_1H = 6'd59;//1min*60 = 1h

reg 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) begin
    if(!rst_n) begin
        flag <= 1'b0;
    end
    else if (key_in) begin
        flag <= ~flag;
    end
    else begin
        flag <= flag;
    end
end

//****************************************************************
//--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 = flag;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == MAX_1MS;

//****************************************************************
//--1s计数器
//****************************************************************

always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_1s <= 10'd0;
    end 
    else if(add_cnt_1s)begin 
        if(end_cnt_1s)begin 
            cnt_1s <= 10'd0;
        end
        else begin 
            cnt_1s <= cnt_1s + 1'b1;
        end 
    end
end 

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)begin 
   if(!rst_n)begin
        cnt_1min <= 6'd0;
    end 
    else if(add_cnt_1min)begin 
        if(end_cnt_1min)begin 
            cnt_1min <= 6'd0;
        end
        else begin 
            cnt_1min <= cnt_1min + 1'b1;
        end 
    end
end 

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)begin 
   if(!rst_n)begin
        cnt_1h <= 6'd0;
    end 
    else if(add_cnt_1h)begin 
        if(end_cnt_1h)begin 
            cnt_1h <= 6'd0;
        end
        else begin 
            cnt_1h <= cnt_1h + 1'b1;
        end 
    end
end 

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) begin
    if(!rst_n) begin
        data_min <= 8'd0;
        data_s <= 8'd0;
        data_ms <= 8'd0;
    end
    else begin
        data_min <= cnt_1h;
        data_s <= cnt_1min;
        data_ms <= cnt_1s/10;
    end
end

assign 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       wire        clk         ,
    input       wire        rst_n       ,
    input       wire [23:0] din         ,

    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]   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)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;

//****************************************************************
//--小数点
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        point_n <= 6'b111111;
    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
end

assign sel = sel_r;

//****************************************************************
//--disp_data
//****************************************************************
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            disp_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]; end
                6'b111_011 : begin disp_data <= din[15:8]/10 ; point_n_r <= point_n[2]; end
                6'b110_111 : begin disp_data <= din[15:8]%10 ; point_n_r <= point_n[3]; end
                6'b101_111 : begin disp_data <= din[7:0]/10 ; point_n_r <= point_n[4]; end
                6'b011_111 : begin disp_data <= din[7:0]%10 ; point_n_r <= point_n[5]; end
                default: disp_data <= 'd0;
            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_sel

顶层文件模块:

module top (
    input       wire        clk         ,
    input       wire        rst_n       ,
    input       wire        key_in      ,

    output      wire [5:0]  sel         ,
    output      wire [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

效果展示:

秒表

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值