差不多最近三天都在忙着调试秒表这个程序,其实昨天就能实现秒表的功能的,就是键盘这里出现的问题,当按键下去时,秒表没有停止计数,我很仔细检查了键盘消抖模块,觉得应该没什么问题,这个模块在前面的johnson计数器中用过,消抖情况良好,没有一点抖动!那到底是什么问题呢?

    接下来差不多一天时间里,都在思考这个问题,我还是觉的是计数模块出了问题,为什么键盘按下去没有停止计数呢?起初,我还在想,我让分频时钟停下来,不就可以了吗?往往想法是好的,但是实践起来,却事与愿违,现在体会到了实践的重要性,这样还是不能解决,那应该用什么方法解决了?我上网查了很多资料,还是没什么实质的办法。今天突然想到是不是按键下去的值必须用一个寄存器保存起来,不然,当手动开后,按键值状态发生变化,又开始计数,所以键盘按下去没反应!我通过验证,果然是这个原因,现在键盘终于按下去有反应了,秒表终于弄好了!

//程序实现的功能:秒表(数码管+键盘),当key1按下时,停止计数,当key2按下时,开始计数!
//复位键按下时,数码管清零;
//顶层模块;
module miao_biao
         (
          sysclk,
          rst_b,
          key1,
          key2,
          smg_sel,
          smg_data
          );
          
input       sysclk;        //系统时钟 50MHZ
input       rst_b;         //复位:低电平有效;
input       key1;          //key1: 按下后秒表停止计数;
input       key2;          //Key2: 按下后秒表继续计数;
output[3:0] smg_sel;       //数码管片选;
output[7:0] smg_data;      //数码管段选; 
wire[1:0]   key_edge; 
//----------------------------------------------------------// 
parameter  div_clk_num1=32'h26_25A0;    //0.1秒分频系数;
parameter  div_clk_num2=32'h17D_7840;   //1秒分频系数;
parameter  div_clk_num3=32'hEE6_B280;   //10秒分频系数;
parameter  div_clk_num4=32'h5968_2F00;   //1分,分频系数;
//----------------------------------------------------------//
wire [3:0] sec_div;
wire [3:0] sec_l;
wire [3:0] sec_h;
wire [3:0] min;
//-----------------------------------------------------------//键盘消抖模块;
key   key (
            .sysclk(sysclk),
            .rst_b(rst_b),
            .key1(key1),
            .key2(key2),
            .key_edge(key_edge)
          );       
//-----------------------------------------------------------//计数模块;

count   counter_divs (                                      //0.1s
                     .sysclk(sysclk),
                     .rst_b(rst_b),
                     .key_edge(key_edge),
                     .cnt_max_num(4'h9),
                     .div_clk_num(div_clk_num1),
                     .data_out(sec_div) 
           
                     );  
count   counter_1s(                                        //1s
                    .sysclk(sysclk),
                    .rst_b(rst_b),
                    .key_edge(key_edge),
                    .cnt_max_num(4'h9),
                    .div_clk_num(div_clk_num2),
                    .data_out(sec_l) 
           
                  ); 

count   counter_10s(                                      //10s
                    .sysclk(sysclk),
                    .rst_b(rst_b),
                    .key_edge(key_edge),
                    .cnt_max_num(4'h5),
                    .div_clk_num(div_clk_num3),
                    .data_out(sec_h) 
           
                  );              
 
count   counter_1min(                                    //1min
                     .sysclk(sysclk),
                     .rst_b(rst_b),
                     .key_edge(key_edge),
                     .cnt_max_num(4'h9),
                     .div_clk_num(div_clk_num4),
                     .data_out(min) 
           
                    ); 
//----------------------------------------------------------//数码管模块;
smg    smg        (
                   .sysclk(sysclk),
                   .rst_b(rst_b),
                   .sec_div(sec_div),
                   .sec_l(sec_l),
                   .sec_h(sec_h),
                   .min(min),
                   .smg_sel(smg_sel),
                   .smg_data(smg_data)
               
                  );  
endmodule                                                              
// 程序实现的功能:键盘消抖
module key 
     (
      sysclk,
      rst_b,
      key1,
      key2,
      key_edge  
     );
input       sysclk;
input       rst_b;
input       key1;         //对应硬件电路图SW4;
input       key2;         //对应硬件电路图SW5;
output[1:0] key_edge;

wire         sysclk;
wire         rst_b;
wire         key1;
wire         key2;
wire[1:0]    key_edge;
//--------------------------------------------------//
reg[1:0] key;
always @ (posedge sysclk or negedge rst_b)
 begin
      if(!rst_b)
         key<=2'b11;
      else
         key<={key1,key2};     
 end

reg[1:0] key_r;
always @ (posedge sysclk or negedge rst_b)
  begin
      if(!rst_b)
        key_r<=2'b11;
      else
        key_r<=key;  
  end 

wire[1:0] key_change;
assign  key_change=key_r&(~key);
//-----------------------------------------------------//
reg[19:0]  time_cnt;
always @ (posedge sysclk or negedge rst_b)
  begin
       if(!rst_b)
          time_cnt<=20'h0;
        else if(key_change)
          time_cnt<=20'h0;
        else 
          time_cnt<=time_cnt+20'h1; 
  end
//-----------------------------------------------------//
reg[1:0] key_rst;
always @ (posedge sysclk or negedge rst_b)
 begin
       if(!rst_b)
         key_rst<=2'b11;
       else if(time_cnt==20'hfffff)
         key_rst<={key1,key2};
          
 end 
 
reg [1:0] key_rst_r;
always @ (posedge sysclk or negedge rst_b)
 begin
       if(!rst_b)
         key_rst_r<=2'b11;
       else 
         key_rst_r<=key_rst;
 end 

assign  key_edge=key_rst_r&(~key_rst);
endmodule
         
  
      
module count                                           //计数模块
        (
          sysclk,
          rst_b,
          key_edge,
          cnt_max_num,
          div_clk_num,
          data_out
         );
input        sysclk;
input        rst_b;
input[1:0]   key_edge;
input[3:0]   cnt_max_num;
input[31:0]  div_clk_num;
output[3:0]  data_out;
//--------------------------------------------------//
wire         sysclk;
wire         rst_b;
wire[1:0]    key_edge;
wire[3:0]    cnt_max_num;
wire[31:0]   div_clk_num;
wire[3:0]    data_out;
//--------------------------------------------------//
reg[31:0] num;
always @(posedge sysclk or negedge rst_b)
 begin
       if(!rst_b)
         num<=32'h0;
       else if(num==div_clk_num)
         num<=32'h0;
       else    
        num<=num+32'h1;
              
             
 end 
//---------------------------------------------------//
reg start_stop;                                    //高电平:停止;
                                                   //低电平: 开始
always @(posedge sysclk or negedge rst_b)
  begin
      if(!rst_b)
       start_stop<=1'h0;
      else if(key_edge[1])
        start_stop<=1'h1;
      else if(key_edge[0])
        start_stop<=1'h0; 
      else 
        start_stop<=start_stop;   
          
        
  end

reg clk_div;
always @(posedge sysclk or negedge rst_b)
  begin
         if(!rst_b)
           clk_div<=1'h0;                            //此处要注意:如果复位时,clk_div=1’h0;那下面用它触发时,必须用它的下降沿触发;
                                                     //否则就得不到一个周期; 
         else if((num==div_clk_num)&&(!start_stop))                 
            clk_div=~clk_div;
         else
            clk_div=clk_div;   
  end         

          
        
reg[3:0]  data_out_r;
always @(negedge clk_div or negedge rst_b)
  begin
         if(!rst_b)
            data_out_r<=4'h0;
         else if(data_out_r==cnt_max_num)
            data_out_r<=4'h0; 
                          
         else         
            data_out_r<=data_out_r+4'h1; 
           
  end  
assign data_out=data_out_r;
endmodule                    
         
module smg                                                     //数码管译码模块;
       (
        sysclk,
        rst_b,
        sec_div,
        sec_l,
        sec_h,
        min,
        smg_sel,
        smg_data     
       );
input            sysclk;
input            rst_b;
input[3:0]       sec_div;
input[3:0]       sec_l;
input[3:0]       sec_h;
input[3:0]       min;
output[3:0] smg_sel;
output[7:0] smg_data;
//--------------------------------------------------------------------------//
wire        sysclk;
wire        rst_b;
reg[3:0]    smg_sel;
reg[7:0]    smg_data;

reg[23:0] cnt;                                  //数码管扫描时间
always @ (posedge sysclk or negedge rst_b)
  begin
        if(!rst_b)
          cnt<=24'h0;
        else if(cnt==24'h3D090)
          cnt<=24'h0;
        else  
          cnt<=cnt+24'h1;
  end  
   
reg[1:0]  smg_sel_num ;
always @ (posedge sysclk or negedge rst_b)
 begin
       if(!rst_b)
          smg_sel_num<=2'h0;
       else if(cnt==24'h3D090)               //3d090=250000*20ns=5ms;
           smg_sel_num<=smg_sel_num+2'h1;
       else
          smg_sel_num<=smg_sel_num;      
 end
  
//-----------------------------------------------------------------//
always @(*)                                     //数码管片选;
  begin
       case(smg_sel_num)
         2'b00:     smg_sel=4'b0111;
         2'b01:     smg_sel=4'b1011;
         2'b10:     smg_sel=4'b1101;
         2'b11:     smg_sel=4'b1110;
         default:   smg_sel=4'b0000;
       endcase  
  end  

reg[3:0] smg_data_num;
always @(*)
  begin
        case(smg_sel_num)
          2'b00:  smg_data_num=sec_div; 
          2'b01:  smg_data_num=sec_l; 
          2'b10:  smg_data_num=sec_h;
          2'b11:  smg_data_num=min;
          default:smg_data_num=4'h0;
        endcase       
end 
always @(*)  
       smg_data[7]=(smg_sel_num==2'b01)?1'b0:1'b1;  // 第二个数码管显示小数点,共阳极数码管;      
//------------------------------------------------- // 数码管段选;
always @ (*)
 begin
         case(smg_data_num)
          4'h0 :smg_data[6:0]=7'b100_0000;
          4'h1: smg_data[6:0]=7'b111_1001;
          4'h2: smg_data[6:0]=7'b010_0100;
          4'h3: smg_data[6:0]=7'b011_0000;
          4'h4: smg_data[6:0]=7'b001_1001;
          4'h5: smg_data[6:0]=7'b001_0010;
          4'h6: smg_data[6:0]=7'b000_0010;
          4'h7: smg_data[6:0]=7'b111_1000;
          4'h8: smg_data[6:0]=7'b000_0000;
          4'h9: smg_data[6:0]=7'b001_0000;
          default:smg_data[6:0]=7'b111_1111; 
       endcase   
          
 end  
endmodule 


     


         

大家放心,程序都是经过我在板子上调试过的,应该没问题,如果大家有更好的方法或意见,也可以留言和我讨论一下,我也是一个初学者还有很多东西不懂,希望可以和大家共同进步!