15-触摸按键控制LED灯
1.触摸按键
触摸按键可分为四大类:电阻式,电容式,红外感应式和表面声波式
- 电阻式触摸按键使用人体破压电阻,改变电阻,实现开关效果,耐用性差,很少使用
- 红外感应式是通过红外扫描的方式,一般使用在比较恶劣的环境当中
- 表面声波式主要通过声波扫描的方式进行识别按键是否被按下,主要用于公共场合中
电容式触摸按键主要由按键IC部分和电容部分构成;按键IC用于将电容的变化转变为电信号;电容部分指的是由电容极板,地,隔离区等组成触摸按键的电容环境
- 电容式触摸按键是利用人体感应电容来检测按键是否按下,当按键没有被按下的时候是左边的情况,按键与地之间存在一定的静态电容,当按键被按下之后是右边的情况,此时,人体的电容会耦合到静态电容上,按键的电容变大,按键IC会将按键电容的变化转变为电信号,电信号的变化超过阈值就会判定为按键按下
2.FPGA设计
- 使用触摸按键控制LED灯,按下点亮,再按一次熄灭
2.1 模块框图及波形图绘制
没有触摸按键的时候是高电平,触摸按键的时候是低电平,低电平的维持时间是和触摸时间是一致的,松开之后又会回到高电平
采用touch_key信号控制按键,按键点亮需要一直按在按键上,如何实现按一次点亮,再按一次熄灭?采用touch_key的下降沿控制输出信号进行取反,触摸按键没有按下的时候,输出信号保持原来的值,检测到下降沿的时候进行取反,等到下一个下降沿的时候再次进行取反,就可以实现
如何采集下降沿,使用寄存器?
- 在时钟的上升沿,将key_touch赋值给寄存器1(touch_key_1),将触摸按键和时钟进行同步
- 再声明一个寄存器变量(touch_key_2),在时钟上升沿将寄存器1的值给寄存器2,这样就实现了一个信号打拍的效果
- 使用touch_key_1和touch_key_2提取输入触摸按键的下降沿,再声明一个变量touch_flag,初始值为低电平,touch_key_1为高电平,touch_key_2为低电平,产生一个周期的高脉冲
- 用key_flag信号产生led的输出信号
边沿检测电路:一个信号经过打拍,用上一时刻的信号与这一时刻的信号进行异或操作,相同为0,不同为1,可以检测到边沿发生变化,将产生的异或信号再与打拍之后的信号进行与操作可以得到脉冲信号
2.2 RTL
module touch_ctrl_led(
input wire sys_clk,
input wire sys_rst_n,
input wire touch_key,
output reg led
);
// 声明三个变量
reg touch_key_1;
reg touch_key_2;
wire touch_flag;
always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
begin
touch_key_1 <= 1'b1;
touch_key_2 <= 1'b0;
end
else
begin
touch_key_1 <= touch_key;
touch_key_2 <= touch_key_1;
end
assign touch_flag = (touch_key_1 && touch_key_2) ? 1'b1 : 1'b0;
// 输出信号
always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
led <= 1'b1;
else if(touch_flag)
led <= ~led;
else
led <= led;
endmodule
2.3 边沿检测
- 边沿检测主要的作用是能够准确的识别出单bit信号的上升沿或者是下降沿,我们希望当上升沿或者下降沿来的时候能够产生一个脉冲标志信号,告诉我们上升沿或者下降沿到来了,可以将脉冲标志信号作为后续功能电路的启动条件
- 边沿检测就需要对输入的单bit信号进行打拍,使用两个变量,进行打拍(一个进行同步,一个进行打拍)
- 使用组合逻辑对于边沿检测没有延迟一拍的效果,使用时序逻辑会有延迟一拍的效果
// 时序逻辑采样,上升沿
always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
podge <= 1'b0;
else if((touch_key_1 == 1'b1) && (touch_key_2 == 1'b0))
podge <= 1'b1;
else
podge <= 1'b0;
always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
podge <= 1'b0;
else if((touch_key_1 == 1'b0) || (touch_key_2 == 1'b1))
podge <= 1'b0;
else
podge <= 1'b1;
// 时序逻辑采样,下升沿
always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
nedge <= 1'b0;
else if((touch_key_1 == 1'b0) && (touch_key_2 == 1'b1))
nedge <= 1'b1;
else
nedge <= 1'b0;
always @ (posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
nedge <= 1'b0;
else if((touch_key_1 == 1'b1) || (touch_key_2 == 1'b0))
nedge <= 1'b0;
else
nedge <= 1'b1;
2.4 Testbench
`timescale 1ns/1ns
module tb_touch_ctrl_led();
reg sys_clk,
reg sys_rst_n,
reg touch_key;
wire led;
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
touch_key <= 1'b1;
#20;
sys_rst_n <= 1'b1;
#200;
touch_key <= 1'b0;
#2000;
touch_key <= 1'b1;
#1000;
touch_key <= 1'b0;
#3000;
touch_key <= 1'b1;
end
// 产生时钟信号
always #10 sys_clk = ~sys_clk;
touch_ctrl_led touch_ctrl_led_inst(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.touch_key (touch_key),
.led (led)
);
endmodule