一、问题描述
假设现在想解决的问题是通过按触摸按键来控制LED灯的亮灭。触摸按键的信号波形如下图中的touch_key所示,当未按下时,touch_key处于高电平的状态,当按下时,处于低电平的状态。而对于我们输出小灯的功能而言,并不是想让led灯的信号与touch_key的信号相同,而是想检测到按了,就亮,再检测到又按了的时候小灯灭。
根据描述的功能我们知道,我们可以通过检测touch_key下降沿的方式来控制led灯的反转即可。这样也就引入了输入信号上升下降沿如何检测这个问题。
二、解决方案
我们可以通过打节拍的方式捕捉上升或下降沿,首先定义一个寄存器变量touch_key_1将touch_key信号与系统时钟同步,再将touch_key1延迟一个节拍保存在新的寄存器变量touch_key_2中。然后可以采用组合逻辑判断如果touch_key_1为0且touch_key_2为1时赋值给标志位,这样,便产生了正好一个时钟周期的下降沿标志信号,最后,若标志位为高电平,使得小灯的状态反转即可。同理,捕捉上升沿也可以采用以上的方式(具体可以通过以下代码进一步理解)。
三、功能模块代码
module chumokey(
input clk,
input reset,
input touch_key,
output reg led
);
reg touch_key1;
reg touch_key2;
wire touch_flag;//使用组合逻辑,没有延迟一拍
//边沿检测的方式
always@(posedge clk or negedge reset)
begin
if(!reset)
touch_key1 <= 1'b1;
else
touch_key1 <= touch_key;//将触摸信号同步到系统时钟下
end
always@(posedge clk or negedge reset)
begin
if(!reset)
touch_key2 <= 1'b1;
else
touch_key2 <= touch_key1;//将同步后的触摸信号延迟一个时钟周期
end
assign touch_flag = ((touch_key1 == 1'b0)&&(touch_key2 == 1'b1));
//输出信号
always@(posedge clk or negedge reset)
begin
if(!reset)
led <= 1'b1;
else if(touch_flag == 1'b1)
led <= ~led;
else
led <= led;
end
endmodule
四、测试代码
`timescale 1ns/1ns
module chumokey_tb();
reg clk;
reg reset;
reg touch_key;
wire led;
initial
begin
clk = 1'b1;
reset <= 1'b0;
touch_key <= 1'b1;
#20
reset <= 1'b1;
#200
touch_key <= 1'b0;
#1000
touch_key <= 1'b1;
#2000
touch_key <= 1'b0;
#3000
touch_key <= 1'b1;
end
always #10 clk = ~clk;
chumokey u1(//实例化模块
.clk(clk),
.reset(reset),
.touch_key(touch_key),
.led(led)
);
endmodule