10_触摸按键控制 LED
1. 实验目标
实验目标:使用触摸按键去控制 led 灯的亮灭,led 灯初始状态为熄灭状态,当按下触摸按键时 led 灯点亮,当再次按下触摸按键时 led 灯熄灭。触摸按键未按下时为高电平、按下后为低电平。
2. 边沿检测
2.1 原理波形
2.2 上升沿检测核心代码
在①处检测到 data 为高电平且 data_reg 为低电平时,表示有上升沿产生。
2.2.1 与逻辑实现
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
podge <= 1'b0;
else if((data) && (~data_reg)) //核心逻辑
podge <= 1'b1;
else
podge <= 1'b0;
2.2.2 或逻辑实现
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
podge <= 1'b0;
else if((~data) || (data_reg)) //核心逻辑
podge <= 1'b0;
else
podge <= 1'b1;
2.3 下降沿检测核心代码
在②处检测到 data 为低电平且 data_reg 为高电平时,表示有下降沿产生,和上升沿的情况刚好相反。
2.3.1 与逻辑实现
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
nedge <= 1'b0;
else if((~data) && (data_reg)) //核心逻辑
nedge <= 1'b1;
else
nedge <= 1'b0;
2.3.2 或逻辑实现
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
nedge <= 1'b0;
else if((data) || (~data_reg)) //核心逻辑
nedge <= 1'b0;
else
nedge <= 1'b1;
3. 波形图绘制
4. RTL
module touch_ctrl_led
(
input wire sys_clk, //系统时钟 50Mh
//根据频率的转换 一个时钟周期20ns 20ms 就是 1_000_000
input wire sys_rst_n,
input wire touch_key, //触摸按键信号
output reg led //led 输出信号
);
reg touch_key_dly1; //touch_key 延迟一个时钟信号
reg touch_key_dly2; //touch_key 延迟两个时钟信号
wire touch_en; //触摸使能信号
// 下降沿检测代码
// 手触摸的时候才变成低电平,从 高电平到低电平就是下降沿
// 用的是组合逻辑电路,没有延迟一拍
assign touch_en = touch_key_dly2 & (~touch_key_dly1);
//对 touch_key 信号延迟两个时钟周期用来产生触摸按键信号
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
begin
touch_key_dly1 <= 1'b1;
touch_key_dly2 <= 1'b1;
end
else
begin
touch_key_dly1 <= touch_key;
touch_key_dly2 <= touch_key_dly1;
end
end
//根据触摸使能信号控制 led 状态
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
begin
led <= 1'b1;
end
else if(touch_en == 1'b1)
begin
led = ~led;
end
else
begin
led <= led;
end
end
endmodule
5. testbench
`timescale 1ns/1ns
module tb_touch_ctrl_led();
//因为 testbench 不对外进行信号的输入输出,只是自己产生
//激励信号提供给内部实例化待测 RTL 模块使用,所以端口列表
//中没有内容,只是列出“()”,当然可以将“()”省略,括号
//后有个“;”不要忘记
//要在 initial 块和 always 块中被赋值的变量一定要是 reg 型
//在 testbench 中待测试 RTL 模块的输入永远是 reg 型变量
//输出信号,我们直接观察,也不用在任何地方进行赋值
//所以是 wire 型变量(在 testbench 中待测试 RTL 模块的输出永远是 wire 型变量)
reg sys_clk;
reg sys_rst_n;
reg touch_key;
//输出信号,我们直接观察,也不用在任何地方进行赋值
//所以是 wire 型变量(在 testbench 中待测试 RTL 模块的输出永远是 wire 型变量)
wire led;
//初始化值在没有特殊要求的情况下给 0 或 1 都可以。如果不赋初值,仿真时信号
//会显示为不定态(ModelSim 中的波形显示红色)
initial
//initial 只在通电执行一次
//在仿真中 begin...end 块中的内容都是顺序执行的,
//在没有延时的情况下几乎没有差别,看上去是同时执行的,
//如果有延时才能表达的比较明了;
//而在 rtl 代码中 begin...end 相当于括号的作用, begin...end 在 Testbench 中的用法及意义(区别 -----------------------------------------------------)
//在同一个 always 块中给多个变量赋值的时候要加上
begin
sys_clk = 1'b1; //时钟信号的初始化为 1,且使用“=”赋值,
//其他信号的赋值都是用“<=”
sys_rst_n <= 1'b0; //因为低电平复位,所以复位信号的初始化为 0
touch_key <= 1'b1 ;
#20 //延时20ns
sys_rst_n <= 1'b1; //初始化 20ns 后,复位释放,因为是低电平复位
#200
touch_key <= 1'b0 ;
#2000
touch_key <= 1'b1 ;
#1000
touch_key <= 1'b0 ;
#3000
touch_key <= 1'b1 ;
//都是顺序执行的
end
// always语句 一直在执行
sys_clk:模拟系统时钟,每 10ns 电平翻转一次,周期为 20ns,频率为 50Mhz
always #10 sys_clk = ~sys_clk;//取模求余数,产生随机数 1'b0、1'b1//每隔 10ns 产生一次随机数
touch_ctrl_led touch_ctrl_led_inst
(
//前面的“in1”表示被实例化模块中的信号,后面的“in1”表示实例化该模块并要和这个
//模块的该信号相连接的信号(可以取名不同,一般取名相同,方便连接和观察)
//“.”可以理解为将这两个信号连接在一起
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.touch_key (touch_key),
.led (led)
);
endmodule