FPGA用Verilog设计倒计时,按键控制时钟复位、启动/暂停、加1、减1
但是key3和key4不能够正常消抖,如何修改代码?
顶层文件
module counter
(
clk , //时钟
rst , //复位
hold , //启动暂停按键
seg_led_1 , //数码管 1
seg_led_2 , //数码管 2
led, //led
key
//buzz //蜂鸣器
);
input clk,rst;
input hold;
input [4:3]key; //key1复位rst,key2暂停hold,key3加一,key4减一
output [8:0] seg_led_1,seg_led_2;
output reg [7:0] led;
//output reg buzz;
wire clk1h; //1Hz 时钟
wire hold_pulse; //暂停按键消抖后信号
wire key3_pulse;//key_pulse[3]加一按键消抖后信号
wire key4_pulse;//key_pulse[4]减一按键消抖后信号
reg key3_flag;//加一按键标志位
reg key4_flag;//减一按键标志位
reg hold_flag; //按键标志位
reg back_to_zero_flag ; //计时完成信号
reg [6:0] seg [9:0];
reg [3:0] cnt_ge; //个位
reg [3:0] cnt_shi; //十位
initial
begin
seg[0] = 7'h3f; // 0
seg[1] = 7'h06; // 1
seg[2] = 7'h5b; // 2
seg[3] = 7'h4f; // 3
seg[4] = 7'h66; // 4
seg[5] = 7'h6d; // 5
seg[6] = 7'h7d; // 6
seg[7] = 7'h07; // 7
seg[8] = 7'h7f; // 8
seg[9] = 7'h6f; // 9
end
// 用于分出一个 1Hz 的频率
divide #(.WIDTH(32),.N(12000000)) U1 (
.clk(clk),
.rst_n(rst),
.clkout(clk1h)
);
// 启动/暂停按键进行消抖
debounce U2(
.clk(clk),
.rst(rst),
.key(hold),
.key_pulse(hold_pulse)
);
debounce3 U3 (
.clk(clk),
.rst(rst),
.key(key[3]),
.key_pulse(key3_pulse)
);
debounce4 U4 (
.clk(clk),
.rst(rst),
.key(key[4]),
.key_pulse(key4_pulse)
);
//按键动作标志信号产生
always @ (posedge hold_pulse)
if(!rst==1)
hold_flag <= 0;
else
hold_flag <= ~hold_flag;
always @ (posedge key3_pulse)
if(!rst==1)
key3_flag <= 0;
else
key3_flag <= ~key3_flag;
always @ (posedge key4_pulse)
if(!rst==1)
key4_flag <= 0;
else
key4_flag <= ~key4_flag;
//计时完成标志信号产生
always @ (*)
if(!rst == 1)
back_to_zero_flag <= 0;
else if(cnt_shi==0 && cnt_ge==0)
back_to_zero_flag <= 1;
else
back_to_zero_flag <= 0;
//20 秒倒计时控制
always @ (posedge clk1h or negedge rst) begin
if (!rst == 1) begin
cnt_ge <= 4'd0;
cnt_shi <= 4'd2;
end
else if(hold_flag == 1)begin
cnt_ge <= cnt_ge;
cnt_shi <= cnt_shi;
if(key3_flag == 1)begin //在暂停界面下调整数值
cnt_ge <= cnt_ge + 1;
if(cnt_ge == 4'd9)begin
cnt_ge <= 4'd0;
cnt_shi <= cnt_shi + 1;
end
end
if(key4_flag == 1)begin
cnt_ge <= cnt_ge - 1;
if(cnt_ge == 4'd0)begin
cnt_ge <= 4'd9;
cnt_shi <= cnt_shi - 1;
end
end
end
else if(cnt_shi==0 && cnt_ge==0) begin
cnt_shi <= cnt_shi;
cnt_ge <= cnt_ge;
end
else if(cnt_ge==0)begin
cnt_ge <= 4'd9;
cnt_shi <= cnt_shi-1;
end
else
cnt_ge <= cnt_ge -1;
end
//计时完成点亮 led
always @ ( back_to_zero_flag)begin
if (back_to_zero_flag==1)
led = 8'b0;
else
led = 8'b11111111;
end
/*//计时完成蜂鸣器鸣叫
always @ ( back_to_zero_flag)begin
if (back_to_zero_flag==1)
buzz <= 1'b0; //低电平触发
else
buzz <= 1'b1;
end*/
assign seg_led_1[8:0] = {2'b00,seg[cnt_ge]};
assign seg_led_2[8:0] = {2'b00,seg[cnt_shi]};
endmodule
消抖模块
module debounce (clk,rst,key,key_pulse);
parameter N = 3; //要消除的按键的数量
input clk;
input rst;
input [N-1:0] key; //输入的按键
output [N-1:0] key_pulse; //按键动作产生的脉冲
reg [N-1:0] key_rst_pre; //定义一个寄存器型变量存储上一个触发时的按键值
reg [N-1:0] key_rst; //定义一个寄存器变量储存储当前时刻触发的按键值
wire [N-1:0] key_edge; //检测到按键由高到低变化是产生一个高脉冲
//利用非阻塞赋值特点, 将两个时钟触发时按键状态存储在两个寄存器变量中
always @(posedge clk or negedge rst)
begin
if (!rst) begin
key_rst <= {N{1'b1}}; //初始化时给key_rst赋值全为1, {}中表示N个1
key_rst_pre <= {N{1'b1}};
end
else begin
key_rst <= key; //第一个时钟上升沿触发之 后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
key_rst_pre <= key_rst; //非阻塞赋值。 相当于经过两个时钟触发, key_rst存储的是当前时刻key的值, key_rst_pre存储的是前一个时钟的key的值
end
end
assign key_edge = key_rst_pre & (~key_rst);//脉冲边沿检测。 当key检测到下降沿时, key_edge产生一个时钟周期的高电平
reg [17:0] cnt; //产生延时所用的计数器, 系统时钟12MHz, 要延时20ms左右时间, 至少需要18位计数器
//产生20ms延时, 当检测到key_edge有效是计数器清零开始计数
always @(posedge clk or negedge rst)
begin
if(!rst)
cnt <= 18'h0;
else if(key_edge)
cnt <= 18'h0;
else
cnt <= cnt + 1'h1;
end
reg [N-1:0] key_sec_pre; //延时后检测电平寄存器变量
reg [N-1:0] key_sec;
//延时后检测key, 如果按键状态变低产生一个时钟的高脉冲。 如果按键状态是高的话说明按键无效
always @(posedge clk or negedge rst)
begin
if (!rst)
key_sec <= {N{1'b1}};
else if (cnt==18'h3ffff)
key_sec <= key;
end
always @(posedge clk or negedge rst)
begin
if (!rst)
key_sec_pre <= {N{1'b1}};
else
key_sec_pre <= key_sec;
end
assign key_pulse = key_sec_pre & (~key_sec);
endmodule