设计要求:按键控制蜂鸣器通断。
//----------------------------------------------------------------------------------------
// Created by: Active_Zmw
// File name: top_key_beep
// Descriptions: 按键控制蜂鸣器通断
//content: 源代码+仿真
//----------------------------------------------------------------------------------------
//源码顶层
module top_key_beep(
input sys_clk, //时钟信号50Mhz@[TOC]顶层
input sys_rst_n, //复位信号
input key, //按键信号
output beep //蜂鸣器控制信号
);
//wire define
wire key_value;
wire key_flag;
//*****************************************************
//** main code
//*****************************************************
//例化按键消抖模块
key_debounce u_key_debounce(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key (key),
.key_flag (key_flag),
.key_value (key_value)
);
//例化蜂鸣器控制模块
beep_control u_beep_control(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key_flag (key_flag),
.key_value (key_value),
.beep (beep)
);
endmodule
// Descriptions: 按键消抖
module key_debounce(
input sys_clk, //外部50M时钟
input sys_rst_n, //外部复位信号,低有效
input key, //外部按键输入
output reg key_flag, //按键数据有效信号
output reg key_value //按键消抖后的数据
);
//reg define
reg [31:0] delay_cnt;
reg key_reg;
//*****************************************************
//** main code
//*****************************************************
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
key_reg <= 1'b1;
delay_cnt <= 32'd0;
end
else begin
key_reg <= key;
if(key_reg != key) //一旦检测到按键状态发生变化(有按键被按下或释放)
delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为20ms)
else if(key_reg == key) begin //在按键状态稳定时,计数器递减,开始20ms倒计时
if(delay_cnt > 32'd0)
delay_cnt <= delay_cnt - 1'b1;
else
delay_cnt <= delay_cnt;
end
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
key_flag <= 1'b0;
key_value <= 1'b1;
end
else begin
if(delay_cnt == 32'd1) begin //当计数器递减到1时,说明按键稳定状态维持了20ms
key_flag <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
key_value <= key; //并寄存此时按键的值
end
else begin
key_flag <= 1'b0;
key_value <= key_value;
end
end
end
endmodule
// Descriptions: 蜂鸣器控制
module beep_control(
//input
input sys_clk, //系统时钟
input sys_rst_n, //复位信号,低电平有效
input key_flag, //按键有效信号
input key_value, //消抖后的按键信号
output reg beep //蜂鸣器控制信号
);
//*****************************************************
//** main code
//*****************************************************
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
beep <= 1'b1;
else if(key_flag && (~key_value)) //判断按键是否有效按下
beep <= ~beep;
end
endmodule
//仿真
`timescale 1 ns/ 1 ns
module tb_top_key_beep();
//parameter define
parameter T = 20;
//reg define
reg key;
reg sys_clk;
reg sys_rst_n;
reg key_value;
// wire define
wire beep;
//*****************************************************
//** main code
//*****************************************************
//给信号初始值
initial begin
key <= 1'b1;
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
#20 sys_rst_n <= 1'b1; //在第20ns的时候复位信号信号拉高
#30 key <= 1'b0; //在第50ns的时候按下按键
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#170 key <= 1'b1; //在第300ns的时候松开按键
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#170 key <= 1'b0; //在第550ns的时候再次按下按键
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#170 key <= 1'b1; //在第800ns的时候松开按键
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
#20 key <= 1'b0; //模拟抖动
#20 key <= 1'b1; //模拟抖动
end
//50Mhz的时钟,周期则为1/50Mhz=20ns,所以每10ns,电平取反一次
always # (T/2) sys_clk <= ~sys_clk;
//例化key_beep模块
top_key_beep u1 (
.beep(beep),
.key(key),
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n)
);
endmodule