差不多最近三天都在忙着调试秒表这个程序,其实昨天就能实现秒表的功能的,就是键盘这里出现的问题,当按键下去时,秒表没有停止计数,我很仔细检查了键盘消抖模块,觉得应该没什么问题,这个模块在前面的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
大家放心,程序都是经过我在板子上调试过的,应该没问题,如果大家有更好的方法或意见,也可以留言和我讨论一下,我也是一个初学者还有很多东西不懂,希望可以和大家共同进步!