VIVADO下的按键消抖实验
实验内容
在黑金AX7050开发板上实现按键消抖,通过按键实现对led 的控制。实验本身比较基础,最近在重新整理FPGA相关知识,买了块黑金的开发板,也希望能学到更多东西,第一篇就从按键的消抖开始,后期会不定期更新一些自己对其他实验原理的一些感悟,为一年多以后找工作打好基础。
实验环境
windows 10 64 位
vivado (vicado 2019.1)
黑金AX7050 开发板
实验原理
通过FPGA计时的方法,当检测到按键输入有变化的时候,计数器清零,否则计数器加一,这样的话我可以认为在一段时间内计数器累加,说明按键稳定了一段时间,这样的话我们可以认为这样的按键是消除了抖动后的按键值。
消抖部分代码
`timescale 1 ns / 100 ps
module ax_debounce
(
input clk,
input rst,
input button_in,
output reg button_posedge,
output reg button_negedge,
output reg button_out
);
---------------- internal constants --------------
parameter N = 32 ; // debounce timer bitwidth
parameter FREQ = 50; //model clock :Mhz
parameter MAX_TIME = 20; //ms
localparam TIMER_MAX_VAL = MAX_TIME * 1000 * FREQ;
---------------- internal variables ---------------
reg [N-1 : 0] q_reg; // timing regs
reg [N-1 : 0] q_next;
reg DFF1, DFF2; // input flip-flops
wire q_add; // control flags
wire q_reset;
reg button_out_d0;
------------------------------------------------------
contenious assignment for counter control
assign q_reset = (DFF1 ^ DFF2); // xor input flip flops to look for level chage to reset counter
assign q_add = ~(q_reg == TIMER_MAX_VAL); // add to counter when q_reg msb is equal to 0
combo counter to manage q_next
always @ ( q_reset, q_add, q_reg)
begin
case( {q_reset , q_add})
2'b00 :
q_next <= q_reg;
2'b01 :
q_next <= q_reg + 1;
default :
q_next <= { N {1'b0} };
endcase
end
Flip flop inputs and q_reg update
always @ ( posedge clk or posedge rst)
begin
if(rst == 1'b1)
begin
DFF1 <= 1'b0;
DFF2 <= 1'b0;
q_reg <= { N {1'b0} };
end
else
begin
DFF1 <= button_in;
DFF2 <= DFF1;
q_reg <= q_next;
end
end
counter control
always @ ( posedge clk or posedge rst)
begin
if(rst == 1'b1)
button_out <= 1'b1;
else if(q_reg == TIMER_MAX_VAL)
button_out <= DFF2;
else
button_out <= button_out;
end
always @ ( posedge clk or posedge rst)
begin
if(rst == 1'b1)
begin
button_out_d0 <= 1'b1;
button_posedge <= 1'b0;
button_negedge <= 1'b0;
end
else
begin
button_out_d0 <= button_out;
button_posedge <= ~button_out_d0 & button_out;
button_negedge <= button_out_d0 & ~button_out;
end
end
endmodule
代码中q_reset的表示使用了异或运算,用来表示前后两个锁存的寄存器是否正确,如果前后两级寄存器的值一致,表示当前锁存的键值没有变化,此时当计数器累加到我们设定的可以输出的值,表示锁存的按键值可以稳定输出。
计数部分代码(稳定时间设定10ms)
module count_m10
(
input clk,
input rst_n,
input en, //Counter enable
input clr, //Counter synchronous reset
output reg[3:0]data, //counter value
output reg t // carry enable signal
);
always@(posedge clk or negedge rst_n)
begin
if(rst_n==0)
begin
data <= 4'd0;
t <= 1'd0;
end
else if(clr)
begin
data <= 4'd0;
t <= 1'd0;
end
else if(en)
begin
if(data==4'd9)
begin
t<= 1'b1; //Counter to 9 to generate carry
data <= 4'd0;//Counter to 9 reset
end
else
begin
t <= 1'b0;
data <= data + 4'd1;
end
end
else
t <= 1'b0;
end
endmodule
TOP顶层文件
module key_debounce
(
input sys_clk, //system clock 50Mhz on board
input rst_n, //reset ,low active
input key, //user key on board
output [3:0] led //user leds on board
);
wire button_negedge; //Key falling edge
/*************************************************************************
Only one pulse is generated when a key is pressed to meet requirements
****************************************************************************/
ax_debounce ax_debounce_m0
(
.clk (sys_clk ),
.rst (~rst_n ),
.button_in (key ),
.button_posedge ( ),
.button_negedge (button_negedge),
.button_out ( )
);
wire[3:0] count;
wire t0;
/*************************************************************************
Decimal counts when button_negedge changes
****************************************************************************/
count_m10 count10_m0
(
.clk (sys_clk ),
.rst_n (rst_n ),
.en (button_negedge),
.clr (1'b0 ),
.data (count ),
.t (t0 )
);
assign led = ~count;
endmodule