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