本次案例是按著小梅哥的思路來寫的,部分截圖和文字來自其教學視頻。 1、狀態機的設定 2、模塊代碼 `timescale 1ns / 1ps //////////////////////////////////////////////////////////////////////////////// ...
本次案例是按著小梅哥的思路來寫的,部分截圖和文字來自其教學視頻。
1、狀態機的設定
2、模塊代碼
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:Lclone
//
// Create Date: 2023/01/14 20:44:54
// Design Name:
// Module Name: key_filter
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module key_filter(
input Clk, //時鐘信號
input Rst_n, //複位信號
input Key_in, //按鍵輸入信號
output reg Key_press, //按鍵按下信號
output reg Key_release //按鍵釋放信號
);
reg [1:0] key_reg;
always @(posedge Clk or negedge Rst_n) begin
if(Rst_n == 0)
key_reg <= 0;
else
key_reg <= {key_reg[0],Key_in};//打拍子,為了捕獲上升沿和下降沿
end
reg key_nedge;
reg key_pedge;
always @(posedge Clk or negedge Rst_n) begin
if(Rst_n == 0)
begin
key_nedge <= 0;
key_pedge <= 0;
end
else if(key_reg == 2'b10 )//下降沿捕獲
key_nedge <= 1'b1;
else if(key_reg == 2'b01 )//上降沿捕獲
key_pedge <= 1'b1;
else
begin
key_nedge <= 0;
key_pedge <= 0;
end
end
parameter CNT_20MS = 1_000_000;
reg [19:0] cnt_20ms;
reg [ 1:0] state;
always @(posedge Clk or negedge Rst_n) begin
if(Rst_n == 0)
begin
state <= 0;
cnt_20ms <= 0;
Key_press <= 0;
Key_release <= 0;
end
else case(state)
0:
begin
Key_release <= 0;
if(key_nedge == 1)
state <= 1;
else
state <= 0;
end
1:
begin
if(cnt_20ms < CNT_20MS & key_pedge == 1)
begin
state <= 0;
cnt_20ms <= 0;
end
else if(cnt_20ms == CNT_20MS - 1)
begin
state <= 2;
cnt_20ms <= 0;
Key_press <= 1;
end
else
cnt_20ms <= cnt_20ms + 1'b1;
end
2:
begin
Key_press <= 0;
if(key_pedge == 1)
state <= 3;
else
state <= 2;
end
3:
begin
if(cnt_20ms < CNT_20MS & key_nedge == 1)
begin
state <= 2;
cnt_20ms <= 0;
end
else if(cnt_20ms == CNT_20MS - 1)
begin
state <= 0;
cnt_20ms <= 0;
Key_release <= 1;
end
else
cnt_20ms <= cnt_20ms + 1'b1;
end
default:;
endcase
end
endmodule
3、模擬
(1)$random函數的使用
rand = {$random(seed)} % 10_000_000;
- 表示生成0-9_999_999範圍內的隨機數並賦值給rand;
- 1個seed數對應著1個的隨機數,可以通過設定seed的值來複現該隨機數;
- 可以去掉花括弧後使生成的範圍變成(-9_999_999) - 9_999_999;
(2)模擬代碼
`timescale 1ns / 1ps
module key_filter_tb();
reg clk_50m;
initial clk_50m <= 1;
always #10 clk_50m <= ~clk_50m;
reg rst_n;
initial begin
rst_n <= 0;
#200
rst_n <= 1;
end
reg key_in;
wire key_press;
wire key_release;
key_filter key_filter_inst(
.Clk (clk_50m),
.Rst_n (rst_n),
.Key_in (key_in),
.Key_press (key_press),
.Key_release (key_release)
);
initial begin
key_in <= 1;
#400
press_key(1);
#20
press_key(2);
#20
press_key(3);
end
reg [31:0]rand;
task press_key;
input [3:0]seed;
begin
key_in = 1;
#20_000_000;
repeat(5)begin
rand = {$random(seed)} % 10_000_000;
#rand key_in = ~key_in;
end
key_in = 0;
#40_000_000;
repeat(5)begin
rand = {$random(seed)} % 10_000_000;
#rand key_in = ~key_in;
end
key_in = 1;
#40_000_000;
end
endtask
endmodule
(3)模擬結果
第一次按下
第二次按下
第三次按下
實驗結果:每次按下都能準確發出Key_press和Key_release信號,實驗初步驗證成功。
4、參考文獻
[1]【零基礎輕鬆學習FPGA】小梅哥Xilinx FPGA基礎入門到項目應用培訓教程】 https://www.bilibili.com/video/BV1va411c7Dz/?p=20&share_source=copy_web&vd_source=c6135c3b3a9878c08e2ddc91acdf6853&t=0