用FPGA实现简易秒表功能

功能如下:

1. 6个数码管显示 时、分、秒。

        2. 按键控制计时的暂停与启动。

设计思路如下:

1.独立按键的分析与编程思路。

                                                                                       用FPGA实现简易秒表功能_第1张图片

如图所示,由于机械的固有震动属性,在按键按下来的过程中以及松开按键的过程中都会产生震动,因此代码设计务必进行相关的处理。

        已知FPGA连接按键的引脚,在按键未按下的时候被拉高。

key_en==1 表示按一下按键,下面给出这个信号的设计思路。

        当按键被按下,检测到按键低电平的时间不低于20ms,为有效,低于20ms的低电平信号被认为是毛刺。

         key_en 这个信号,在稳定期产生。且应该是只产生一拍,也就是当按键按下,FPGA检测到按下的有效性后key_en由低电平变高电平,松开就变成低电平。代码里处理成检测到按下的有效性后,只维持一个时钟周期高电平,这样是最合理的。


如何确定稳定期?          低电平持续20ms             如何知道持续20ms? 用计数器count_20ms  低电平计数,高电平清零,计到20ms时保持。

哪个时刻产生?开始、中间、结尾?

开始,前一时刻不够20ms,后一时刻够20ms           中间,中间不能确定                   结尾,前一时钟20ms,后一时钟key高电平

flag_20ms=1 表示计数到20ms   flag_20ms_ff0 表示前一时钟指示

如果 key_an==1  产生时刻在开始

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_20ms<=15'd0;
        end
        else if(key)begin 
count_20ms<=15'd0;
 end 
 else if(count_20ms>=19999&&count_1us==TIMES_1us)begin   //这个应该为
count_20ms<=count_20ms;
 end 
 else  if(count_1us==TIMES_1us&&count_20ms<19999)begin
count_20ms<=count_20ms+1'b1;
 end 
    end


  always @(*) begin
if(count_20ms>=19999)
flag_20ms<=1'b1;
else 
flag_20ms<=1'b0;
  end 

  always  @(posedge clk or negedge rst_n)begin
 if(rst_n==1'b0)begin
            flag_20ms_ff0<=1'b0;
         end
 else 
flag_20ms_ff0 <= flag_20ms;
 end

 always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
            key_en<=1'b0;
        end
else if(flag_20ms&&flag_20ms_ff0==1'b0)
key_en <= 1'b1;
else 
key_en <= 1'b0;
end                                                                                                                  

       如果key_an==1产生在结尾

          always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
             key_en<=1'b0;
         end
else if(flag_20ms==1'b0&&flag_20ms_ff0)
key_en <= 1'b1;
else 
key_en <= 1'b0;
end     

                   

2.计时部分设计思路:

时   24进制计数器      分   60进制计数器      秒   60进制计数器

1. 设计1s计数器   parameter  TIMES_1s=4999_9999   26位寄存器 count_1s  ,这个计时器时最基础的

       always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_1s<=26'd0 ;
        end
        else  if(count_1s==TIMES_1S)
            count_1s<=26'd0 ;
        else  if(pause==1'b1)
            count_1s<=count_1s+1'b1;
 else 
count_1s<=count_1s     ;
    end                               

2. 设计秒计数器,即60进制计数器

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_60s<=6'd0;
        end
        else if(count_60s==59&&count_1s==TIMES_1S)
           count_60s<=6'd0;
        else if(count_1s==TIMES_1S)
           count_60s<=count_60s+1'b1; 

end

3. 设计分计数器,即60进制计数器

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_60m<=6'd0;
        end
        else if(count_60m==59&&count_60s==59&&count_1s==TIMES_1S)
              count_60m<=6'd0;
        else if(count_60s==59&&count_1s==TIMES_1S)
              count_60m<=count_60m+1'b1;
        
    end

4. 设计时计数器,即24进制计数器

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_24h<=5'd0;
        end
        else if(count_60m==59&&count_60s==59&&count_1s==TIMES_1S)begin
            if(count_24h==23)
                count_24h<=5'd0;
            else
                count_24h<=count_24h+1'b1;
        end
    end

3. 如何暂停计时器与启动计时器

设计一个1位 暂停与启动信号  pause  当pause==1时启动计时   当pause==0时暂停计时功能。 

用这个信号控制1s计时器就行了,因为秒,时,分计时都与这个1s计时器有关。

       always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_1s<=26'd0 ;
        end
        else  if(count_1s==TIMES_1S)
            count_1s<=26'd0 ;
        else  if(pause==1'b1)
            count_1s<=count_1s+1'b1;
  else 
count_1s<=count_1s     ;
       end             

pause信号的产生:

always  @(posedge clk or negedge rst_n)begin
 if(rst_n==1'b0)begin
            pause<=1'b1;
        end
 else if(pause==1'b1&&key_en)
pause <= 1'b0;
 else if(pause==1'b0&&key_en)
pause <= 1'b1;
end  

完毕  完整代码如下所示:

module miaobiao(
    clk     ,
    rst_n   ,
    segment ,
    seg_sel ,
    key     
    );

    //can shu
    parameter      DATA_W =         8;
    parameter      TIMES_1S =   4999_999;
    parameter      TIMES_1us= 49    ;
    parameter _0 = 8'b1100_0000, _1 = 8'b1111_1001, _2 = 8'b1010_0100,
              _3 = 8'b1011_0000, _4 = 8'b1001_1001, _5 = 8'b1001_0010,
              _6 = 8'b1000_0010, _7 = 8'b1111_1000, _8 = 8'b1000_0000,
              _9 = 8'b1001_0000;



    //输入信号定义
    input               key       ;
    input               clk       ;
    input               rst_n     ;
    output[DATA_W-1:0]  segment   ;
    output[DATA_W-3:0]  seg_sel   ;

    reg   [DATA_W-1:0]  segment   ;
    reg   [DATA_W-3:0]  seg_sel   ;
    //一些中间变量
    reg   [22:0]        count_1s  ;
    reg   [5:0]         count_1us ;
    reg   [6:0]         count_120us ;
    //miao
    reg   [5:0]         count_60s ;
    //fen
    reg   [5:0]         count_60m ;
    //shi
    reg   [4:0]         count_24h ;
    //20ms 定时器
    reg   [14:0]        count_20ms ;
    //按键  打两拍
    reg     key_reg1    ;
    reg     key_reg2    ;
	 reg     key_flag    ;
	 reg[DATA_W-1:0]  s_ge    ;
	 reg[DATA_W-1:0]  s_shi   ;
	 reg[DATA_W-1:0]  m_ge    ;
	 reg[DATA_W-1:0]  m_shi   ;
	 reg[DATA_W-1:0]  h_ge    ;
	 reg[DATA_W-1:0]  h_shi   ;
	 //停止与启动信号  按键
	 reg pause                ;
	 reg flag_20ms            ;
	 reg key_en               ;
	 reg flag_20ms_ff0        ;
/********************************************************************************************/
//1s timer
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_1s<=23'd0 ;
        end
        else  if(count_1s==TIMES_1S)
            count_1s<=23'd0 ;
        else  if(pause==1'b1)
            count_1s<=count_1s+1'b1;
		  else 
				count_1s<=count_1s     ;
    end 
/********************************************************************************************/
    //逐一设计每个输出信号
    //列扫描  刷新时间为20us  总共用了6个数码管,设计一个计时器  6*20us=120us
    
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_1us<=6'd0;
        end
        else if(count_1us==TIMES_1us) 
            count_1us<=6'd0;
        else
            count_1us<=count_1us+1'b1;
    end
    
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_120us<=7'd0;
        end
        else if(count_120us==119&&count_1us==TIMES_1us)
            count_120us<=7'd0;
        else if(count_1us==TIMES_1us)
            count_120us<=count_120us+1'b1;      
    end

    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            seg_sel<=6'b111_110 ;
        end
        else if(count_120us==0)
            seg_sel<=6'b111_110 ;
        else if(count_120us==19&&count_1us==TIMES_1us)
            seg_sel<=6'b111_101 ; 
        else if(count_120us==39&&count_1us==TIMES_1us)
            seg_sel<=6'b111_011 ;
        else if(count_120us==59&&count_1us==TIMES_1us)
            seg_sel<=6'b110_111 ;
        else if(count_120us==79&&count_1us==TIMES_1us)
            seg_sel<=6'b101_111 ;
        else if(count_120us==99&&count_1us==TIMES_1us)
            seg_sel<=6'b011_111 ;        
    end
	
/********************************************************************************************/
    //shi 设计一个24进制计数器
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_24h<=5'd0;
        end
        else if(count_60m==59&&count_60s==59&&count_1s==TIMES_1S)begin
            if(count_24h==23)
                count_24h<=5'd0;
            else
                count_24h<=count_24h+1'b1;
        end
    end
      //shi_ge   
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            h_ge<=4'd0;
        end
        else if(seg_sel==6'b101_111)begin
            case (count_24h%10)
                0:
                    h_ge<=_0;
                1:
                    h_ge<=_1;
                2:
                    h_ge<=_2;
                3:
                    h_ge<=_3;
                4:
                    h_ge<=_4;
                5:
                    h_ge<=_5;
                6:
                    h_ge<=_6;
                7:
                    h_ge<=_7;
                8:
                    h_ge<=_8;
                9:
                    h_ge<=_9;
            endcase

        end
    end
//shi_shi
   always  @(posedge clk or negedge rst_n)begin
       if(rst_n==1'b0)begin
           h_shi<=4'd0;
       end
       else if(seg_sel==6'b011_111)begin
           case (count_24h/10)
                0:
                    h_shi<=_0;
                1:
                    h_shi<=_1;
                2:
                    h_shi<=_2;
                3:
                    h_shi<=_3;
                4:
                    h_shi<=_4;
                5:
                    h_shi<=_5;
                6:
                    h_shi<=_6;
                7:
                    h_shi<=_7;
                8:
                    h_shi<=_8;
                9:
                    h_shi<=_9;
           endcase
       end
   end

    
/********************************************************************************************/
    //fen 设计一个60进制计数器 count_60m
 
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_60m<=6'd0;
        end
        else if(count_60m==59&&count_60s==59&&count_1s==TIMES_1S)
              count_60m<=6'd0;
        else if(count_60s==59&&count_1s==TIMES_1S)
              count_60m<=count_60m+1'b1;
        
    end

    //fen_ge   
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            m_ge<=4'd0;
        end
        else if(seg_sel==6'b111_011)begin
            case (count_60m%10)
                0:
                    m_ge<=_0;
                1:
                    m_ge<=_1;
                2:
                    m_ge<=_2;
                3:
                    m_ge<=_3;
                4:
                    m_ge<=_4;
                5:
                    m_ge<=_5;
                6:
                    m_ge<=_6;
                7:
                    m_ge<=_7;
                8:
                    m_ge<=_8;
                9:
                    m_ge<=_9;
            endcase
        end
    end
//fen_shi
   always  @(posedge clk or negedge rst_n)begin
       if(rst_n==1'b0)begin
           m_shi<=4'd0;
       end
       else if(seg_sel==6'b110_111)begin
           case (count_60m/10)
                0:
                    m_shi<=_0;
                1:
                    m_shi<=_1;
                2:
                    m_shi<=_2;
                3:
                    m_shi<=_3;
                4:
                    m_shi<=_4;
                5:
                    m_shi<=_5;
                6:
                    m_shi<=_6;
                7:
                    m_shi<=_7;
                8:
                    m_shi<=_8;
                9:
                    m_shi<=_9;
           endcase
       end
   end
/********************************************************************************************/
    //miao 设计一个60计数器  count_60s 
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_60s<=6'd0;
        end
        else if(count_60s==59&&count_1s==TIMES_1S)
           count_60s<=6'd0;
        else if(count_1s==TIMES_1S)
           count_60s<=count_60s+1'b1; 
        
    end
//miao_ge   
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            s_ge<=4'd0;
        end
        else if(seg_sel==6'b111_110)begin
            case (count_60s%10)
                0:
                    s_ge<=_0;
                1:
                    s_ge<=_1;
                2:
                    s_ge<=_2;
                3:
                    s_ge<=_3;
                4:
                    s_ge<=_4;
                5:
                    s_ge<=_5;
                6:
                    s_ge<=_6;
                7:
                    s_ge<=_7;
                8:
                    s_ge<=_8;
                9:
                    s_ge<=_9;
            endcase
        end
    end
//miaoshi
   always  @(posedge clk or negedge rst_n)begin
       if(rst_n==1'b0)begin
           s_shi<=4'd0;
       end
       else if(seg_sel==6'b111_101)begin
           case (count_60s/10)
                0:
                    s_shi<=_0;
                1:
                    s_shi<=_1;
                2:
                    s_shi<=_2;
                3:
                    s_shi<=_3;
                4:
                    s_shi<=_4;
                5:
                    s_shi<=_5;
                6:
                    s_shi<=_6;
                7:
                    s_shi<=_7;
                8:
                    s_shi<=_8;
                9:
                    s_shi<=_9;
           endcase
       end
   end
/********************************************************************************************/
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            key_reg1<=1'b1;
            key_reg2<=1'b1;
        end
        else begin
            key_reg1<=key       ;
            key_reg2<=key_reg1  ;
        end
    end
	 
//按键输入
//20ms 定时器
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            count_20ms<=15'd0;
        end
        else if(key_reg2)begin 
				count_20ms<=15'd0;
		  end 
		  else if(count_20ms==19999&&count_1us==TIMES_1us)begin
				count_20ms<=count_20ms;
		  end 
		  else  if(count_1us==TIMES_1us)begin
				count_20ms<=count_20ms+1'b1;
		  end 
    end
  always @(*) begin
	if(count_20ms>=19999)
		flag_20ms<=1'b1;
	else 
		flag_20ms<=1'b0;
  end 

	always  @(posedge clk or negedge rst_n)begin
		  if(rst_n==1'b0)begin
            flag_20ms_ff0<=1'b0;
        end
		  else 
				flag_20ms_ff0 <= flag_20ms;
	end
//	always  @(posedge clk or negedge rst_n)begin
//		  if(rst_n==1'b0)begin
//            key_en<=1'b0;
//        end
//		  else if(flag_20ms&&flag_20ms_ff0==1'b0)
//				key_en <= 1'b1;
//		  else 
//				key_en <= 1'b0;
//	end
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
             key_en<=1'b0;
         end
	 else if(flag_20ms==1'b0&&flag_20ms_ff0==1)
				 key_en <= 1'b1;
	 else 
				 key_en <= 1'b0;
	 end         
	always  @(posedge clk or negedge rst_n)begin
		  if(rst_n==1'b0)begin
            pause<=1'b1;
        end
		  else if(pause==1'b1&&key_en)
				pause <= 1'b0;
		  else if(pause==1'b0&&key_en)
				pause <= 1'b1;
	end   



/********************************************************************************************/
 always  @(posedge clk or negedge rst_n)begin
	if(rst_n==1'b0)begin
            segment<=8'd0;
   end
	else begin
		case(seg_sel)
		6'b111_110:
			segment<=s_ge;
		6'b111_101:
			segment<=s_shi;
		6'b111_011:
			segment<=m_ge;
		6'b110_111:
			segment<=m_shi;
		6'b101_111:
			segment<=h_ge;
		6'b011_111:
			segment<=h_shi;
		default:
			segment<=segment;
		endcase
	end
 end
   
    endmodule


你可能感兴趣的:(FPGA设计简易计时器)