一.前言
- 前文已经发过电子门锁初步设计,但是后来发现有缺陷:多错误几次就很容易猜到正确的密码,有损安全性,于是本文做改进设计,并补充加入数码管显示键入密码功能
二.功能描述
- 1.按下key[0]密码+1
2.按下key[1]密码-1
3.按下key[2]确认该位密码并跳转到下一位密码输入
4.输入第一位密码时,数码管显示(AA–(密码值))
5.输入第二位密码时,数码管显示(BB–(密码值))
6.输入第三位密码时,数码管显示(CC–(密码值))
7.输入第四位密码时,数码管显示(DD–(密码值))
8.密码正确时,数码管显示(111111)
9.密码错误时,数码管显示(FFFFFF)
三.状态转移图
四.模块设计图
五.设计思路
-
状态转移条件:重点关注按下key[2](确认按键);比较键入值和设定密码;延时10s条件。
-
设置1ms计数器,并使sel每隔1ms进行位拼接{sel[4:0],sel[5]}的操作,由于余晖效应,肉眼是无法辨别sel的变换,视觉上显示的是数码管全亮的状态。
-
每一个状态观测sel值(case(sel)),不同的sel值让对应的数码管点亮需求的显示。
六.代码
- key_debounce.v
/**************************************功能介绍***********************************
Date : 2023年8月1日16:55:52
Author : Alegg xy.
Version : 1.0
Description: 四位按键消抖模块
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module key_debounce #(parameter WIDTH = 4,
parameter DELAY_20MS = 1000_000
)(
input clk ,
input rst_n ,
input [WIDTH-1:0] key_in ,
output [WIDTH-1:0] key_out
);
//---------<参数定义>---------------------------------------------------------
reg [WIDTH-1:0] key_out_r;
//状态机参数定义
localparam IDLE = 4'b0001,//空闲状态
FILETER_DOWN = 4'b0010,//按键按下抖动状态
HOLD_DOWN = 4'b0100,//按下稳定按下状态
FILTER_UP = 4'b1000;//按键释放抖动状态
//---------<内部信号定义>-----------------------------------------------------
reg [3:0] cstate ;//现态
reg [3:0] nstate ;//次态
reg [WIDTH-1:0] key_r0 ;//同步打拍
reg [WIDTH-1:0] key_r1 ;
reg [WIDTH-1:0] key_r2 ;
wire [WIDTH-1:0] n_edge ;//下降沿
wire [WIDTH-1:0] p_edge ;//上升沿
reg [19:0] cnt_20ms ;//20ms计数器
wire add_cnt_20ms;
wire end_cnt_20ms;
//状态转移条件定义
wire idle2filter_down ;
wire fiter_down2hold_down ;
wire hold_down2filter_up ;
wire filter_up2idle ;
//****************************************************************
//--cstate
//****************************************************************
//第一段:时序逻辑描述状态转移
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate <= IDLE;//复位的初始状态
end
else begin
cstate <= nstate;
end
end
//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
case(cstate)
IDLE : begin
if(idle2filter_down)begin
nstate = FILETER_DOWN;
end
else begin
nstate = cstate;
// state_n = IDLE;
end
end
FILETER_DOWN : begin
if(fiter_down2hold_down)begin
nstate = HOLD_DOWN;
end
else begin
nstate = cstate;
end
end
HOLD_DOWN : begin
if(hold_down2filter_up)begin
nstate = FILTER_UP;
end
else begin
nstate = cstate;
end
end
FILTER_UP : begin
if(filter_up2idle)begin
nstate = IDLE;
end
else begin
nstate = cstate;
end
end
default : nstate = IDLE;
endcase
end
assign idle2filter_down = cstate == IDLE && n_edge;
assign fiter_down2hold_down = cstate == FILETER_DOWN && end_cnt_20ms;
assign hold_down2filter_up = cstate == HOLD_DOWN && p_edge;
assign filter_up2idle = cstate == FILTER_UP && end_cnt_20ms;
//****************************************************************
//--n_edge、p_edge
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_r0 <= {WIDTH{1'b1}};
key_r1 <= {WIDTH{1'b1}};
key_r2 <= {WIDTH{1'b1}};
end
else begin
key_r0 <= key_in;
key_r1 <= key_r0;
key_r2 <= key_r1;
end
end
assign n_edge = ~key_r1 & key_r2;
assign p_edge = ~key_r2 & key_r1;
//****************************************************************
//--cnt_20ms
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_20ms <= 'd0;
end
else if(add_cnt_20ms)begin
if(end_cnt_20ms)begin
cnt_20ms <= 'd0;
end
else begin
cnt_20ms <= cnt_20ms + 1'b1;
end
end
end
assign add_cnt_20ms = cstate == FILETER_DOWN || cstate == FILTER_UP;
assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == DELAY_20MS - 1;
//****************************************************************
//--key_out
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_out_r <= 'd0;
end
else if(hold_down2filter_up)begin
key_out_r <= ~key_r2;
end
else begin
key_out_r <= 'd0;
end
end
assign key_out = key_out_r;
endmodule
- fsm_lock.v
/**************************************功能介绍***********************************
Date :2023年8月1日17:01:23
Author : Alegg xy.
Version : 1.0
Description:
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module fsm_lock(
input clk ,
input rst_n ,
input [3:0] key ,
output reg [5:0] sel ,
output reg [7:0] seg ,
output reg [3:0] led
);
//---------<参数定义>---------------------------------------------------------
//状态机参数定义
localparam IDLE = 7'b000_0001,//空闲状态
RIGHT_1= 7'b000_0010,//键入第1位密码值状态
RIGHT_2= 7'b000_0100,//键入第2位密码值状态
RIGHT_3= 7'b000_1000,//键入第3位密码值状态
RIGHT_4= 7'b001_0000,//键入第4位密码值状态
SUCESS = 7'b010_0000,//键入密码正确状态
FAILED = 7'b100_0000;//键入密码错误状态
//密码参数定义
localparam PASSWORD = 16'h1234;
//时间参数定义
parameter TIME_10S = 500_000_000;//10s
parameter TIME_300MS = 15_000_000;//30Oms
parameter MAX_1ms = 16'd50000;//1ms
//---------<内部信号定义>-----------------------------------------------------
reg [6:0] cstate ;//现态
reg [6:0] nstate ;//次态
reg [3:0] value_1 ;//键入第1位的数值
reg [3:0] value_2 ;//键入第2位的数值
reg [3:0] value_3 ;//键入第3位的数值
reg [3:0] value_4 ;//键入第4位的数值
wire [15:0] key_value ;//键入的4位密码值
reg [31:0] cnt_10s ;
wire add_cnt_10s ;
wire end_cnt_10s ;
reg [25:0] cnt_300ms ;
wire add_cnt_300ms ;
wire end_cnt_300ms ;
reg [3:0] led_flow ;//流水灯
reg [3:0] led_light ;//闪烁
reg [3:0] data;//存取该位数值
//1ms计数器
reg [15:0] cnt_1ms ;
wire add_cnt_1ms ;
wire end_cnt_1ms ;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_1ms <= 16'd0;
end
else if(add_cnt_1ms)begin
if(end_cnt_1ms)begin
cnt_1ms <= 16'd0;
end
else begin
cnt_1ms <= cnt_1ms + 1'd1;
end
end
end
assign add_cnt_1ms = 1'b1;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == MAX_1ms - 1'd1;
//数码管位选
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sel <= 6'b111_110;//循环移位实现时,需要给位选赋初值
end
else if(end_cnt_1ms)begin
sel <= {sel[4:0],sel[5]};//循环左移
end
end
//状态转移条件参数定义
wire IDLE_RIGHT_1 ;
wire RIGHT_1_RIGHT_2 ;
wire RIGHT_2_RIGHT_3 ;
wire RIGHT_3_RIGHT_4 ;
wire RIGHT_4_SUCCESS ;
wire RIGHT_4_FAILED ;
wire SUCCESS_IDLE ;
wire FAILED_IDLE ;
//****************************************************************
//--cstate
//****************************************************************
//第一段:时序逻辑描述状态转移
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate <= IDLE;
end
else begin
cstate <= nstate;
end
end
//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
case(cstate)
IDLE : begin
if(IDLE_RIGHT_1)begin
nstate = RIGHT_1;
end
else begin
nstate = cstate;
end
end
RIGHT_1: begin
if(RIGHT_1_RIGHT_2)begin
nstate = RIGHT_2;
end
else begin
nstate = cstate;
end
end
RIGHT_2: begin
if(RIGHT_2_RIGHT_3)begin
nstate = RIGHT_3;
end
else begin
nstate = cstate;
end
end
RIGHT_3: begin
if(RIGHT_3_RIGHT_4)begin
nstate = RIGHT_4;
end
else begin
nstate = cstate;
end
end
RIGHT_4: begin
if(RIGHT_4_SUCCESS)begin
nstate = SUCESS;
end
else if(RIGHT_4_FAILED)begin
nstate = FAILED;
end
else begin
nstate = cstate;
end
end
SUCESS : begin
if(SUCCESS_IDLE)begin
nstate = IDLE;
end
else begin
nstate = cstate;
end
end
FAILED : begin
if(FAILED_IDLE)begin
nstate = IDLE;
end
else begin
nstate = cstate;
end
end
default : nstate = IDLE;
endcase
end
assign IDLE_RIGHT_1 = (cstate == IDLE ) && 1'b1;
assign RIGHT_1_RIGHT_2 = (cstate == RIGHT_1) && key[2];
assign RIGHT_2_RIGHT_3 = (cstate == RIGHT_2) && key[2];
assign RIGHT_3_RIGHT_4 = (cstate == RIGHT_3) && key[2];
assign RIGHT_4_SUCCESS = (cstate == RIGHT_4) && key[2] && key_value == PASSWORD;
assign RIGHT_4_FAILED = (cstate == RIGHT_4) && key[2] && key_value != PASSWORD;
assign SUCCESS_IDLE = (cstate == SUCESS ) && end_cnt_10s;
assign FAILED_IDLE = (cstate == FAILED ) && end_cnt_10s;
//****************************************************************
//--value1~value4
//****************************************************************
//value1
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
value_1 <= 'd0;
end
else if(value_1 > 9)begin
value_1 <= 'd0;
end
else if(cstate == RIGHT_1 && key[0])begin
value_1 <= value_1 + 1'b1;
end
else if(cstate == RIGHT_1 && key[1])begin
value_1 <= value_1 - 1'b1;
end
end
//value2
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
value_2 <= 'd0;
end
else if(value_2 > 9)begin
value_2 <= 'd0;
end
else if(cstate == RIGHT_2 && key[0])begin
value_2 <= value_2 + 1'b1;
end
else if(cstate == RIGHT_2 && key[1])begin
value_2 <= value_2 - 1'b1;
end
end
//value3
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
value_3 <= 'd0;
end
else if(value_3 > 9)begin
value_3 <= 'd0;
end
else if(cstate == RIGHT_3 && key[0])begin
value_3 <= value_3 + 1'b1;
end
else if(cstate == RIGHT_3 && key[1])begin
value_3 <= value_3 - 1'b1;
end
end
//value_4
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
value_4 <= 'd0;
end
else if(value_4 > 9)begin
value_4 <= 'd0;
end
else if(cstate == RIGHT_4 && key[0])begin
value_4 <= value_4 + 1'b1;
end
else if(cstate == RIGHT_4 && key[1])begin
value_4 <= value_4 - 1'b1;
end
end
assign key_value = {value_1,value_2,value_3,value_4};
//****************************************************************
//--cnt_10s
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_10s <= 'd0;
end
else if(add_cnt_10s)begin
if(end_cnt_10s)begin
cnt_10s <= 'd0;
end
else begin
cnt_10s <= cnt_10s + 1'b1;
end
end
end
assign add_cnt_10s = cstate == SUCESS | cstate == FAILED;
assign end_cnt_10s = add_cnt_10s && cnt_10s == TIME_10S - 1;
//****************************************************************
//--cnt_300ms
//****************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_300ms <= 'd0;
end
else if(add_cnt_300ms)begin
if(end_cnt_300ms)begin
cnt_300ms <= 'd0;
end
else begin
cnt_300ms <= cnt_300ms + 1'b1;
end
end
end
assign add_cnt_300ms = cstate == SUCESS | cstate == FAILED;
assign end_cnt_300ms = add_cnt_300ms && cnt_300ms == TIME_300MS - 1;
//****************************************************************
//--led成功全亮,失败流水
//****************************************************************
//led_light
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
led_light <= 4'd0;
end
else if(cstate == SUCESS && end_cnt_300ms)begin
led_light <= ~led_light;
end
end
//led_flow
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
led_flow <= 4'b0001;
end
else if(cstate == FAILED && end_cnt_300ms)begin
led_flow <= {led_flow[2:0],led_flow[3]};
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
led <= 4'b1111;
end
else begin
case (cstate)
IDLE : led <= 4'b0000;
RIGHT_1: begin
led <= 4'b0001;
case (sel)
6'b111_110 :data = 4'hA;
6'b111_101 :data = 4'hA;
6'b111_011 :data = 4'hE;
6'b110_111 :data = 4'hE;
6'b101_111 :data = 4'h0;
6'b011_111 :data = value_1;
default: data = 0;
endcase
end
RIGHT_2: begin
led <= 4'b0001;
case (sel)
6'b111_110 :data = 4'hB;
6'b111_101 :data = 4'hB;
6'b111_011 :data = 4'hE;
6'b110_111 :data = 4'hE;
6'b101_111 :data = 4'h0;
6'b011_111 :data = value_2;
default: data = 0;
endcase
end
RIGHT_3: begin
led <= 4'b0111;
case (sel)
6'b111_110 :data = 4'hC;
6'b111_101 :data = 4'hC;
6'b111_011 :data = 4'hE;
6'b110_111 :data = 4'hE;
6'b101_111 :data = 4'h0;
6'b011_111 :data = value_3;
default: data = 0;
endcase
end
RIGHT_4: begin
led <= 4'b1111;
case (sel)
6'b111_110 :data = 4'hD;
6'b111_101 :data = 4'hD;
6'b111_011 :data = 4'hE;
6'b110_111 :data = 4'hE;
6'b101_111 :data = 4'h0;
6'b011_111 :data = value_4;
default: data = 0;
endcase
end
SUCESS : begin
led <= led_light;
case (sel)
6'b111_110 :data = 4'd1;
6'b111_101 :data = 4'd1;
6'b111_011 :data = 4'd1;
6'b110_111 :data = 4'd1;
6'b101_111 :data = 4'd1;
6'b011_111 :data = 4'd1;
default: data = 0;
endcase
end
FAILED : begin
led <= led_flow;
case (sel)
6'b111_110 :data = 4'hF;
6'b111_101 :data = 4'hF;
6'b111_011 :data = 4'hF;
6'b110_111 :data = 4'hF;
6'b101_111 :data = 4'hF;
6'b011_111 :data = 4'hF;
default: data = 0;
endcase
end
default: led <= 4'b0000;
endcase
end
end
always @(*)begin
case (data)
4'h0:seg <= 8'b1100_0000;
4'h1:seg <= 8'b1111_1001;
4'h2:seg <= 8'b1010_0100;
4'h3:seg <= 8'b1011_0000;
4'h4:seg <= 8'b1001_1001;
4'h5:seg <= 8'b1001_0010;
4'h6:seg <= 8'b1000_0010;
4'h7:seg <= 8'b1111_1000;
4'h8:seg <= 8'b1000_0000;
4'h9:seg <= 8'b1001_0000;
4'hA:seg <= 8'b1000_1000;
4'hB:seg <= 8'b1000_0011;
4'hC:seg <= 8'b1100_0110;
4'hD:seg <= 8'b1010_0001;
4'hE:seg <= 8'b1011_1111;
4'hF:seg <= 8'b1000_1110;
default: seg <= 8'b1100_0000;
endcase
end
endmodule
- top_fsm_lock.v
/**************************************功能介绍***********************************
Date : 2023年8月1日18:47:49
Author : Alegg xy.
Version : 1.0
Description:
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module top_fsm_lock(
input clk ,
input rst_n ,
input [3:0] key ,
output [5:0] sel ,
output [7:0] seg ,
output [3:0] led
);
//---------<参数定义>---------------------------------------------------------
wire [3:0] key_link;
//---------<内部信号定义>-----------------------------------------------------
key_debounce u_key_debounce(
.clk (clk),
.rst_n (rst_n),
.key_in (key),
.key_out (key_link)
);
fsm_lock u_fsm_lock(
.clk (clk),
.rst_n (rst_n),
.key (key_link),
.sel (sel),
.seg (seg),
.led (led)
);
endmodule
七.仿真
- tb_fsm_lock.v
`timescale 1ns/1ns
module tb_fsm_lock();
//激励信号定义
reg tb_clk ;
reg tb_rst_n ;
reg [3:0] tb_key ;
//输出信号定义
wire [5:0] tb_sel ;
wire [7:0] tb_seg ;
wire [3:0] tb_led ;
//时钟周期参数定义
parameter CLOCK_CYCLE = 20;
defparam u_top_fsm_lock.u_key_debounce.DELAY_20MS = 100;
defparam u_top_fsm_lock.u_fsm_lock.TIME_10S = 500;
defparam u_top_fsm_lock.u_fsm_lock.TIME_300MS = 15;
//模块例化
top_fsm_lock u_top_fsm_lock(
.clk (tb_clk ),
.rst_n (tb_rst_n ),
.key (tb_key ),
.sel (tb_sel ),
.seg (tb_seg ),
.led (tb_led )
);
//产生时钟
initial tb_clk = 1'b0;
always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;
integer i;
//产生激励
initial begin
tb_rst_n = 1'b1;
tb_key = 4'b1111;
#(CLOCK_CYCLE*2);
tb_rst_n = 1'b0;
#(CLOCK_CYCLE*20);
tb_rst_n = 1'b1;
#2;
//S1状态
//按下1次按键key[0]
tb_key[0] = 0;//按键按下,第一次检测到下降沿d
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILETER_DOWN);//按键按下抖动状态,延时20ms结束
#(CLOCK_CYCLE*30);//按键稳定按下持续时间
tb_key[0] = 1;//按键释放
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILTER_UP);//按键释放延时20ms结束
//在s1状态下,按下确认按键key[2]
tb_key[2] = 0;//按键按下,第一次检测到下降沿d
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILETER_DOWN);//按键按下抖动状态,延时20ms结束
#(CLOCK_CYCLE*30);//按键稳定按下持续时间
tb_key[2] = 1;//按键释放
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILTER_UP);//按键释放延时20ms结束
//S2 状态
//在S2状态下连续按5次key[0],每次按一次key[0],加1;此时value_2值为5
for (i=0;i<5;i=i+1) begin
tb_key[0] = 0;//按键按下,第一次检测到下降沿d
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILETER_DOWN);//按键按下抖动状态,延时20ms结束
#(CLOCK_CYCLE*30);//按键稳定按下持续时间
tb_key[0] = 1;//按键释放
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILTER_UP);//按键释放延时20ms结束
end
//在S2状态下连续按3次key[1],每次按一次key[1],减1;此时value_2值为2
for (i=0;i<3;i=i+1) begin
tb_key[1] = 0;//按键按下,第一次检测到下降沿d
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILETER_DOWN);//按键按下抖动状态,延时20ms结束
#(CLOCK_CYCLE*30);//按键稳定按下持续时间
tb_key[1] = 1;//按键释放
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILTER_UP);//按键释放延时20ms结束
end
//在S2状态下,按下确认按键key[2]
tb_key[2] = 0;//按键按下,第一次检测到下降沿d
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILETER_DOWN);//按键按下抖动状态,延时20ms结束
#(CLOCK_CYCLE*30);//按键稳定按下持续时间
tb_key[2] = 1;//按键释放
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILTER_UP);//按键释放延时20ms结束
//S3状态下
//在S3状态下连续按3次key[0],每次按一次key[0],加1;此时value_3值为3
for (i=0;i<3;i=i+1) begin
tb_key[0] = 0;//按键按下,第一次检测到下降沿d
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILETER_DOWN);//按键按下抖动状态,延时20ms结束
#(CLOCK_CYCLE*30);//按键稳定按下持续时间
tb_key[0] = 1;//按键释放
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILTER_UP);//按键释放延时20ms结束
end
//在S3状态下,按下确认按键key[2]
tb_key[2] = 0;//按键按下,第一次检测到下降沿d
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILETER_DOWN);//按键按下抖动状态,延时20ms结束
#(CLOCK_CYCLE*30);//按键稳定按下持续时间
tb_key[2] = 1;//按键释放
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILTER_UP);//按键释放延时20ms结束
//S4状态下
//在S4状态下连续按4次key[0],每次按一次key[0],加1;此时value_4值为4
for (i=0;i<4;i=i+1) begin
tb_key[0] = 0;//按键按下,第一次检测到下降沿d
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILETER_DOWN);//按键按下抖动状态,延时20ms结束
#(CLOCK_CYCLE*30);//按键稳定按下持续时间
tb_key[0] = 1;//按键释放
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILTER_UP);//按键释放延时20ms结束
end
//在S4状态下,按下确认按键key[2]
tb_key[2] = 0;//按键按下,第一次检测到下降沿d
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILETER_DOWN);//按键按下抖动状态,延时20ms结束
#(CLOCK_CYCLE*30);//按键稳定按下持续时间
tb_key[2] = 1;//按键释放
wait(u_top_fsm_lock.u_key_debounce.end_cnt_20ms && u_top_fsm_lock.u_key_debounce.cstate == u_top_fsm_lock.u_key_debounce.FILTER_UP);//按键释放延时20ms结束
//等待SUCESS与FAILED结束
wait(u_top_fsm_lock.u_fsm_lock.end_cnt_10s);
#10000;
$stop;
end
endmodule