FPGA学习笔记 -- 按键消抖

FPGA学习笔记 -- 按键消抖_第1张图片

 硬件消抖:RS触发器

FPGA学习笔记 -- 按键消抖_第2张图片

软件消抖:

FPGA学习笔记 -- 按键消抖_第3张图片

模拟按键产生的高低电平毛刺,低电平有效,由于毛刺的存在,当确定按下时间时,若是每次都按照消抖的最大时间10ms考虑,在高频情况下,会浪费一定的时间,而按5ms考虑又无法保证按键已经消抖。所以这里添加一个计数器,当检测到低电平就开始计数,检测到高电平就将其清零。输出采用信号标志,当计数器计数到最大值时升高一个系统时钟周期的电平,其余时间保持低电平。

FPGA学习笔记 -- 按键消抖_第4张图片

module key_filter
#(parameter CNT_MAX = 20'd999_999) //端口内的参数只能在这里定义
(
	input wire sys_clk,
	input wire res_n,
	input wire key_in,
	
	output reg key_flag //输出为消抖后的按键脉冲信号
	
);

reg [19:0] cnt_20ms;

always@(posedge sys_clk or negedge res_n)
	if(res_n == 1'b0)
		cnt_20ms <= 20'd0;
	else if(key_in == 1'b1)
		cnt_20ms <= 20'd0;
	else if(cnt_20ms == CNT_MAX)
		cnt_20ms <= CNT_MAX;
	else
		cnt_20ms <= cnt_20ms + 1'b1;

always@(posedge sys_clk or negedge res_n)
	if(res_n == 1'b0)
		key_flag <= 1'b0;
	else if(cnt_20ms == CNT_MAX - 20'd1)
		key_flag <= 1'b1;
	else
		key_flag <= 1'b0;

		
endmodule
`timescale 1ns/1ns

module tb_key_filter();

reg sys_clk;
reg res_n;
reg key_in;

reg [7:0] tb_cnt; // 使用计数器来确定按键的毛刺以及按下状态的时间确定模拟

wire key_flag;

initial
	begin
		sys_clk <= 1'b1;
		res_n <= 1'b0;
		#20
		res_n <= 1'b1;
	end

always #10 sys_clk = ~sys_clk;

always@(posedge sys_clk or negedge res_n) // 初始化tb_cnt的状态
	if(res_n == 1'b0)	
		tb_cnt <= 8'd0;
	else if(tb_cnt == 8'd249)
		tb_cnt <= 8'd0;
	else
		tb_cnt <= tb_cnt + 8'd1;

always@(posedge sys_clk or negedge res_n)
	if(res_n == 1'b0)
		key_in <= 1'b1;
	else if((tb_cnt >= 8'd19)&&(tb_cnt <= 8'd49)||(tb_cnt >= 8'd149)&&(tb_cnt <= 8'd199))
		key_in <= {$random}%2; // 利用随机数取余模拟按键的毛刺状态,利用tb_cnt来确认毛刺的产生
	else if((tb_cnt < 8'd19)||(tb_cnt > 8'd199))
		key_in <= 1'b1;
	else
		key_in <= 1'b0; // 在tb_cnt其他的计数时间里保持按键按下状态,即低电平

key_filter
#(.CNT_MAX(20'd24)) // 减少计数时间
key_filter_1
(
	.sys_clk(sys_clk),
	.res_n(res_n),
	.key_in(key_in),
	
	.key_flag(key_flag)
);
		
endmodule

触摸按键控制LED灯 -- 边沿检测方法

FPGA学习笔记 -- 按键消抖_第5张图片

电阻式耐用性差现在已经很少用了,电容式弥补了电阻式耐用性的缺点,红外扫描常应用在环境较差的场合,表面声波常应用在公共场合下 。

FPGA学习笔记 -- 按键消抖_第6张图片

FPGA学习笔记 -- 按键消抖_第7张图片 

module touch_ctrl_led
(
	input wire sys_clk,
	input wire res_n,
	input wire touch_key,
	
	output reg led
);

reg touch_key_1;
reg touch_key_2;
wire touch_flag;

//利用key1,key2,flag,形成一个边沿检测
always@(posedge sys_clk or negedge res_n)
	if(res_n == 1'b0)
		begin
			touch_key_1 <= 1'b1;
			touch_key_2 <= 1'b1;
		end
	else
		begin
			touch_key_1 <= touch_key;
			touch_key_2 <= touch_key_1;
		end
assign touch_flag = ((touch_key_1 == 1'b0)&&(touch_key_2 == 1'b1)); //检测下降沿
// assign touch_flag = ((touch_key_1 == 1'b1)&&(touch_key_2 == 1'b0)); //检测上升沿

always@(posedge sys_clk or negedge res_n)
	if(res_n == 1'b0)
		led <= 1'b1;
	else if(touch_flag == 1'b1)
		led <= ~led;
	else
		led <= led;

endmodule

`timescale 1ns/1ns

module tb_touch_ctrl_led();

reg sys_clk;
reg res_n;
reg touch_key;

wire led;

initial
	begin
		sys_clk = 1'b1;
		res_n <= 1'b0;
		touch_key <= 1'b1;
		#20
		res_n <= 1'b1;
		#200
		touch_key <= 1'b0;
		#1000
		touch_key <= 1'b1;
		#3000
		touch_key <= 1'b0;
		#1000
		touch_key <= 1'b0;	
	end
	
always #10 sys_clk = ~sys_clk;

touch_ctrl_led touch_ctrl_led_1
(
	.sys_clk(sys_clk),
	.res_n(res_n),
	.touch_key(touch_key),
	 
	.led(led)
);

endmodule

你可能感兴趣的:(FPGA学习笔记及心得,fpga开发)