用FPGA实现简易秒表功能

本文详细介绍了一种基于FPGA的计时器设计方法,包括独立按键去抖动处理、秒分时计数器实现及暂停与启动控制逻辑。通过精确的时序控制和状态机设计,确保了计时器稳定可靠的工作。

功能如下:

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

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

设计思路如下:

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的数字秒表设计 学生姓名: *********** 学 号: ********** 专业班级: 自动化******班 指导老师: ************ 2010年 3 月 20 日 论文(设计)题目 ISP技术及其应用研究 课题目的、意义及相关研究动态: 课题设计的主要目的:运用所学的数字电子技术的基本知识和数字电子电路的设计方法,将数字电子技术的基础知识与EDA技术有机地联系起来,EDA电子仿真软件的仿真功能强大,具有完备的文件库,具有选用元器件创建电路、仿真模拟运行电路的功能,并且在输入信号的加入、输出信号的显示上能完全模拟实际和调制过程中的各种波型和操作过程。此类设计需要在EDA仿真软件上仿真进行,并利用下载工具,下载到特定的硬件设备上,进行实时的运行与验证,来证明所设计的电路的正确性。这样把所学到的理论知识综合的运用到一些较复杂的数字逻辑电路系统中去,使我们在实践基本技能方面得到一次全面系统的锻炼;这样可以使我们了解和掌握现代复杂数字系统芯片的设计方法和所用到的EDA工具,为走上社会进入专业的电子技术公司后,能胜任各种电子产品集成化的实际设计工作打下了坚实的基础。 课题的意义:秒表是一种常见的计时工具,种类比较多。这里用EDA技术设计一种基于FPGA 的数字秒表。它可以为用户提供了传统的PLD技术无法达到的灵活性,带来了巨大的时间效益和经济效益,是可编程技术的实质性飞跃。FPGA还是有其具大的优势比如它的高速性。 相关研究动态:现在对EDA的概念或范畴用得很宽。包括在机械、电子、通信、航空航天、化工、矿产、生物、医学、军事等各个领域,都有EDA的应用。目前EDA 技术已在各大公司、企事业单位和科研教学部门广泛使用。例如在飞机制造过程中,从设计、性能测试及特性分析直到飞行模拟,都可能涉及到EDA技术。本文所指的EDA技术,主要针对电子电路设计、PCB设计和IC设计。EDA 设计可分为系统级、电路级和物理实现级。 课题的主要内容(观点)、创新之处: 课题设计的主要内容: 1. 设计任务: 设计一个采用六位LED数码管显示分、秒,0.1s,0.01s计时方式的数字秒表。使用按键开关可实现开始/结束计时操作,及复位清零操作。 2.设计要求: 要求:1、设计方案具有合理性、科学性; 2、系统工作稳定可靠; 3、系统抗干扰性能强; 4、系统硬件电路简单、程序结构明晰。 3.系统功能 1. 有启/停开关,用于开始/结束计时操作 2. 秒表计时长度为59.分59.99秒,超过计时长度,有溢出则报警,计时长度可手动设置。 3. 设置复位开关,在任何情况下只要按下复位开关,秒表都要无条件进行复位清0操作。 4. 用FPGA器件实现,用VHDL语言编程,并进行下载,仿真。 创新之处: 利用EDA技术中最为瞩目的在系统可编程技术进行电子系统的设计的创新之处:1、用软件的方式设计硬件;2、用软件方式设计的系统到硬件系统的转换是由有关的开发软件自动完成;3、设计过程中可用有关软件进行各种仿真;4、系统可现场编程,在线升级;5、整个系统可集成在一个芯片上,体积小、功耗低、可靠性高。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值