数码管实现电子秒表

一.功能描述

  • 6位数码管左边两位显示分钟,中间两位显示秒,右边两位显示毫秒的百位和十位;按键key[0]实现暂停计时和启动计时;按键key[1]实现清零。

二.模块设计图

在这里插入图片描述

三.设计思路

3.1按键消抖模块传输消抖成功后的按键信号

3.2设计计数器

  • 10ms计时:计10ms
  • ms计数器:每计10ms,ms计数器+1,最大值计到99
  • sec计数器:ms计数器每计满一次,sec计数器+1,最大值到59
  • min计数器:sec计数器每计满一次,min计数器+1,最大值到59

3.3设计暂停

  • 设计flag信号,当flag为0时暂停计数,当flag为1时启动计数。每识别到key[0]时,flag反转。
    在这里插入图片描述

3.4设计清零

  • 在结束计数的条件做修改,当它计满或者按下key[1]的时候则计数器清零。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 后来我才想到,好像复位就可以实现清零的操作。。。

3.5其余设计同上文电子时钟设计大同小异,可以参考前文

四.代码

  • key_debounce.v
/**************************************功能介绍***********************************
Date	: 2023年8月1日14:45:24
Author	: Alegg xy.
Version	: 1.0
Description: 四位按键消抖模块
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module key_debounce #(parameter   WIDTH = 4,
                      parameter   DELAY_20MS = 1000_000
)( 
    input				           clk		,
    input				           rst_n	,
    input		   [WIDTH-1:0]     key_in	,
    output         [WIDTH-1:0]     key_out   
);								 
//---------<参数定义>--------------------------------------------------------- 
    
    reg [WIDTH-1:0] key_out_r;
    //状态机参数定义
    localparam  IDLE         = 4'b0001,//空闲状态
                FILETER_DOWN = 4'b0010,//按键按下抖动状态
                HOLD_DOWN    = 4'b0100,//按下稳定按下状态
                FILTER_UP    = 4'b1000;//按键释放抖动状态
    
//---------<内部信号定义>-----------------------------------------------------
    reg 	[3:0]	        cstate     ;//现态
    reg	    [3:0]	        nstate     ;//次态

    reg     [WIDTH-1:0]     key_r0      ;//同步打拍
    reg     [WIDTH-1:0]     key_r1      ;
    reg     [WIDTH-1:0]     key_r2      ;
    wire    [WIDTH-1:0]     n_edge      ;//下降沿
    wire    [WIDTH-1:0]     p_edge      ;//上升沿  

    reg		[19:0]	        cnt_20ms	;//20ms计数器
    wire				    add_cnt_20ms;
    wire				    end_cnt_20ms;

    //状态转移条件定义
    wire            idle2filter_down        ;
    wire            fiter_down2hold_down    ;
    wire            hold_down2filter_up     ;
    wire            filter_up2idle          ;

//****************************************************************
//--cstate
//****************************************************************
    //第一段:时序逻辑描述状态转移
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cstate <= IDLE;//复位的初始状态
        end 
        else begin 
            cstate <= nstate;
        end 
    end
    
    //第二段:组合逻辑描述状态转移规律和状态转移条件
    always @(*) begin
        case(cstate)
            IDLE         : begin 
                if(idle2filter_down)begin 
                    nstate = FILETER_DOWN;
                end
                else begin
                    nstate = cstate;
                    // state_n = IDLE;
                end
            end
            FILETER_DOWN : begin 
                if(fiter_down2hold_down)begin 
                    nstate = HOLD_DOWN;
                end
                else begin
                    nstate = cstate;
                end
            end
            HOLD_DOWN    : begin 
                if(hold_down2filter_up)begin 
                    nstate = FILTER_UP;
                end
                else begin
                    nstate = cstate;
                end
            end
            FILTER_UP    : begin 
                if(filter_up2idle)begin 
                    nstate = IDLE;
                end
                else begin
                    nstate = cstate;
                end
            end
            default : nstate = IDLE;
        endcase
    end

    assign idle2filter_down     = cstate == IDLE         && n_edge;
    assign fiter_down2hold_down = cstate == FILETER_DOWN && end_cnt_20ms;
    assign hold_down2filter_up  = cstate == HOLD_DOWN    && p_edge;
    assign filter_up2idle       = cstate == FILTER_UP    && end_cnt_20ms;
                
//****************************************************************
//--n_edge、p_edge 
//****************************************************************
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            key_r0 <= {WIDTH{1'b1}};
            key_r1 <= {WIDTH{1'b1}};
            key_r2 <= {WIDTH{1'b1}};
        end 
        else begin 
            key_r0 <= key_in;
            key_r1 <= key_r0;
            key_r2 <= key_r1;
        end 
    end      
          
    assign n_edge = ~key_r1 & key_r2;
    assign p_edge = ~key_r2 & key_r1;          
    
//****************************************************************
//--cnt_20ms
//****************************************************************
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_20ms <= 'd0;
        end 
        else if(add_cnt_20ms)begin 
            if(end_cnt_20ms)begin 
                cnt_20ms <= 'd0;
            end
            else begin 
                cnt_20ms <= cnt_20ms + 1'b1;
            end 
        end
    end 
    
    assign add_cnt_20ms = cstate == FILETER_DOWN || cstate == FILTER_UP;
    assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == DELAY_20MS - 1;
    
//****************************************************************
//--key_out
//****************************************************************
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            key_out_r <= 'd0;
        end 
        else if(hold_down2filter_up)begin 
            key_out_r <= ~key_r2;
        end 
        else begin 
            key_out_r <= 'd0;
        end 
    end
    
    assign key_out = key_out_r;
endmodule
  • time_count.v
/**************************************功能介绍***********************************
Date	:2023年8月1日14:46:12 
Author	: Alegg xy.
Version	: 1.0
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module time_count( 
    input				clk		,
    input				rst_n	,
    input       [3:0]   key     ,

    output      [6:0]   ms      ,
    output      [5:0]   sec     ,
    output      [5:0]   min     
);								 
//---------<参数定义>--------------------------------------------------------- 
    parameter   MAX_10ms = 19'd500_000,
                MAX_ms = 7'd99,
                MAX_sec = 6'd59,
                MAX_min = 6'd59;

    reg         flag;//flag为0暂停,flag为1启动计数   
//---------<内部信号定义>-----------------------------------------------------
    
    //定义flag
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            flag <= 1'b0;
        end 
        else if(key[0])begin 
            flag <= ~flag;
        end 
        else begin 
            flag <= flag;
        end 
    end

    //10ms计数器
    reg			[18:0]	cnt_10ms	   	;
    wire				add_cnt_10ms	;
    wire				end_cnt_10ms	;
    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_10ms <= 19'd0;
        end 
        else if(add_cnt_10ms)begin 
            if(end_cnt_10ms)begin 
                cnt_10ms <= 19'd0;
            end
            else begin 
                cnt_10ms <= cnt_10ms + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_10ms = flag;
    assign end_cnt_10ms = (add_cnt_10ms && cnt_10ms == MAX_10ms - 1'd1) || key[1];
    
    //ms计数器,每计满10ms,ms位就加一,最大值为99
    reg			[6:0]	cnt_ms	   	;
    wire				add_cnt_ms	;
    wire				end_cnt_ms	;
    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_ms <= 7'd0;
        end 
        else if(add_cnt_ms)begin 
            if(end_cnt_ms)begin 
                cnt_ms <= 7'd0;
            end
            else begin 
                cnt_ms <= cnt_ms + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_ms = end_cnt_10ms;
    assign end_cnt_ms = (add_cnt_ms && cnt_ms == MAX_ms) || key[1];
    
    
    //sec计数器,每计满100个10ms,sec位就加一,最大值为59
    reg			[5:0]	cnt_sec	   	;
    wire				add_cnt_sec	;
    wire				end_cnt_sec	;
    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_sec <= 6'd0;
        end 
        else if(add_cnt_sec)begin 
            if(end_cnt_sec)begin 
                cnt_sec <= 6'd0;
            end
            else begin 
                cnt_sec <= cnt_sec + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_sec = end_cnt_ms;
    assign end_cnt_sec = (add_cnt_sec && cnt_sec == MAX_sec) || key[1];

    //min计数器,每计满60s,min位就加一,最大值为59
    reg			[5:0]	cnt_min	   	;
    wire				add_cnt_min	;
    wire				end_cnt_min	;
    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_min <= 6'd0;
        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
    end 
    
    assign add_cnt_min = end_cnt_sec;
    assign end_cnt_min = (add_cnt_min && cnt_min == MAX_min) || key[1];
    
    assign ms = cnt_ms;   
    assign sec = cnt_sec;
    assign min = cnt_min;

endmodule
  • seg_dirver.v
/**************************************功能介绍***********************************
Date	:2023年8月1日15:21:33 
Author	: Alegg xy.
Version	: 1.0
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module seg_dirver( 
    input				clk		,
    input				rst_n	,
    input		[6:0]	ms		,
    input		[5:0]	sec		,
    input		[4:0]	min	    ,
    output	reg	[5:0]	sel     ,
    output  reg [7:0]   seg	     
);								 
//---------<参数定义>--------------------------------------------------------- 
    parameter MAX_1ms = 16'd50000;
    reg [3:0]   data;//存取该位数值    
//---------<内部信号定义>-----------------------------------------------------
    //1ms计数器
    reg			[15:0]	cnt_1ms	   	;
    wire				add_cnt_1ms	;
    wire				end_cnt_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'd1;
            end 
        end
    end 
    
    assign add_cnt_1ms = 1'b1;
    assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == MAX_1ms - 1'd1;
    
    //数码管位选
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            sel <= 6'b111_110;//循环移位实现时,需要给位选赋初值
        end 
        else if(end_cnt_1ms)begin 
            sel <= {sel[4:0],sel[5]};//循环左移
        end 
    end
    
    always @(*)begin 
        case (sel)
            6'b111_110 :data = min / 10;
            6'b111_101 :data = min % 10;
            6'b111_011 :data = sec / 10;
            6'b110_111 :data = sec % 10;
            6'b101_111 :data = ms / 10;
            6'b011_111 :data = ms % 10; 
            default: data = 0;
        endcase
    end

    always @(*)begin 
        case (data)
            4'd0:seg = 8'b1100_0000;
            4'd1:seg = 8'b1111_1001;
            4'd2:seg = 8'b1010_0100;
            4'd3:seg = 8'b1011_0000;
            4'd4:seg = 8'b1001_1001;
            4'd5:seg = 8'b1001_0010;
            4'd6:seg = 8'b1000_0010;
            4'd7:seg = 8'b1111_1000;
            4'd8:seg = 8'b1000_0000;
            4'd9:seg = 8'b1001_0000;
            default: seg = 8'b1100_0000;
        endcase
    end
endmodule
  • top_seg_dirver.v
/**************************************功能介绍***********************************
Date	: 
Author	: Alegg xy.
Version	: 
Description: 
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module top_seg_dirver( 
    input				clk		,
    input				rst_n	,
    input		[3:0]	key_in	,
    output		[5:0]	sel	    ,
    output		[7:0]	seg     	
);								 
//---------<参数定义>--------------------------------------------------------- 
    wire [3:0]  key_link;
    wire [6:0]  ms_link;
    wire [5:0]  sec_link;
    wire [5:0]  min_link;
//---------<内部信号定义>-----------------------------------------------------
    key_debounce u_key_debounce(
        .clk		(clk),
        .rst_n	    (rst_n),
        .key_in	    (key_in),
        .key_out    (key_link)  
    );
    time_count u_time_count(
        .clk		(clk),
        .rst_n      (rst_n),	
        .key        (key_link),   
        .ms         (ms_link),   
        .sec        (sec_link),   
        .min        (min_link) 
    );
    seg_dirver u_seg_dirver(
        .clk		(clk),
        .rst_n      (rst_n),
        .ms		    (ms_link),
        .sec		(sec_link),
        .min	    (min_link),
        .sel        (sel),
        .seg	    (seg)    
    );
    
endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值