题目要求:
密码锁共有12个键,0-9的数字键,*为取消键,#为确定键。
开锁时,需要输入4位正确密码后,按#号键确定,密码锁可以打开,注意这里只要最后按#键前4位正确即可,密码门打开后30秒回到初始态。
如果连续3次输错密码,密码门自动死锁3分钟。
密码门有一个六位超级密码230419,输入后可以用户重置并且设置四位开锁密码,用于设置新的开锁密码时,需要连续输入两次并按#确认,两次必须相同,否则设置失败。
无论是开锁还是设置密码可以按*号来取消。
具体功能:
使用两个状态机实现:
对于"输入密码——判定密码——开锁/死锁"部分功能,划分一个状态机S。
对于"输入超级密码——重设密码"功能,划分一个状态机T。
状态机S共有6个状态:
S0-S3:当前已输入了正确密码的前0/1/2/3位。
S4:已输入正确密码,等待确认。
Open:已开启,开启状态保持两个时钟。
Lock:已死锁,死锁状态保持两个时钟。
状态机T共有22个状态:
T0 - T11:检测12位序列230419230419已经正确输入到哪一位
T11 - T15:输入新密码第1/2/3/4位
T16 - T19:重复新密码的第1/2/3/4位
T20:等待确认。
OK:重设密码成功。
T0-T11的状态转移为常见的序列检测思路,T11-T15将输入的数字暂存在reg[3:0] newpasswd0/1/2/3中,T16-T19分别检测第二次输入的密码是否与寄存器中的密码相同,如果相同,进入T20等待按下确认键。
以上各状态中,超级密码出错/再次输出密码不一致/按下取消键都会回到T0状态。
T20时按下确认键进入OK状态,将newpasswd中的密码复制到passwd中,并重置连续输错次数wrong_count为0。
部分代码示例:
/***********************状态机S*************************//
always @(posedge clk or posedge clr)
begin
if(clr)
begin
present_state_s <= S0;
unlock_ok <= 1'b0;
locking <= 1'b0;
wrong_count <= 0;
end
else
present_state_s <= next_state_s;
end
always @(*)
begin
case(present_state_s)
S0:begin
if(cancel)
next_state_s = S0;
else if(confirm)
begin
next_state_s = S0;
wrong_count = wrong_count + 1;
end
else if(din == passwd0)
next_state_s = S1;
else
next_state_s = S0;
end
S1:begin
if(cancel)
next_state_s = S0;
else if(confirm)
begin
next_state_s = S0;
wrong_count = wrong_count + 1;
end
else if(din == passwd1)
next_state_s = S2;
else
next_state_s = S0;
end
S2:begin
if(cancel)
next_state_s = S0;
else if(confirm)
begin
next_state_s = S0;
wrong_count = wrong_count + 1;
end
else if(din == passwd2)
next_state_s = S3;
else
next_state_s = S0;
end
S3:begin
if(cancel)
next_state_s = S0;
else if(confirm)
begin
next_state_s = S0;
wrong_count = wrong_count + 1;
end
else if(din == passwd3)
next_state_s = S4;
else
next_state_s = S0;
end
S4: begin
if(confirm)
next_state_s = Open;
else
next_state_s = S0;
end
Open: begin
unlock_ok = 1'b1;
//open_time <= 3;// 设置为3个周期
if(open_time == 3)
begin
unlock_ok = 1'b0;
next_state_s = S0;
end
else
next_state_s = Open;
end
Lock: begin
locking = 1'b1;
//lock_time <= 3;// 设置为3个周期
if(lock_time == 3)
begin
locking = 1'b0;
next_state_s = S0;
end
else
next_state_s = Lock;
end
default:
begin
next_state_s = S0;
wrong_count = 0;
unlock_ok = 1'b0;
locking = 1'b0;
open_time = 0;
lock_time = 0;
end
endcase
if (wrong_count >= 3)
begin
next_state_s = Lock;
wrong_count = 0;
end//判断错误逻辑
end
// 计时逻辑
always @(posedge clk or posedge clr)
begin
if(clr)
begin
open_time <= 0;
lock_time <= 0;
end
else
begin
if(present_state_s == Open && open_time < 3)
open_time <= open_time + 1;
else if(open_time == 3)
open_time <= 0;
if(present_state_s == Lock && lock_time < 3)
lock_time <= lock_time + 1;
else if(lock_time == 3)
lock_time <= 0;
end
end
//****************************************************************//
//**********************状态机T***********************************//
reg [4:0] present_state_t, next_state_t;// 当前状态,下一状态
parameter T0 = 5'b00000,T1 = 5'b00001,T2 = 5'b00010,T3 = 5'b00011,T4 = 5'b00100,
T5 = 5'b00101,T6 = 5'b00110,T7 = 5'b00111,T8 = 5'b01000,T9 = 5'b01001,
T10 = 5'b01010,T11 = 5'b01011,T12 = 5'b01100,T13 = 5'b01101,
T14 = 5'b01110,T15 = 5'b01111,T16 = 5'b10000,T17 = 5'b10001,
T18 = 5'b10010,T19 = 5'b10011,T20 = 5'b10100,OK = 5'b10101;
always @(posedge clk or posedge clr)
begin
if(clr)
begin
reset_ok <= 1'b0;
present_state_t <= T0;
end
else
present_state_t <= next_state_t;
end
always @(*)
begin
case(present_state_t)
T0:
begin
reset_ok = 1'b0;
if(cancel)
next_state_t = T0;
else if(din == superwd0)//2
next_state_t = T1;
else
next_state_t = T0;
end
T1:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd1)//3
next_state_t = T2;
else
next_state_t = T0;
end
T2:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd2) //0
next_state_t = T3;
else
next_state_t = T0;
end
T3:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd3) //4
next_state_t = T4;
else
next_state_t = T0;
end
T4:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd4) //1
next_state_t = T5;
else
next_state_t = T0;
end
T5:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd5) //9
next_state_t = T6;
else
next_state_t = T0;
end
T6:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd0)//2
next_state_t = T7;
else
next_state_t = T0;
end
T7:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd1)//3
next_state_t = T8;
else
next_state_t = T0;
end
T8:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd2)//0
next_state_t = T9;
else
next_state_t = T0;
end
T9:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd3)//4
next_state_t = T10;
else
next_state_t = T0;
end
T10:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd4)//1
next_state_t = T11;
else
next_state_t = T0;
end
T11:
begin
if(cancel)
next_state_t = T0;
else if(din == superwd5)//9
next_state_t = T12;
else
next_state_t = T0;
end
T12: //T12~T15将数字暂存在newpasswd中
begin
if(cancel)
next_state_t = T0;
else
begin
newpasswd0 = din;
next_state_t = T13;
end
end
T13:
begin
if(cancel)
next_state_t = T0;
else
begin
newpasswd1 = din;
next_state_t = T14;
end
end
T14:
begin
if(cancel)
next_state_t = T0;
else
begin
newpasswd2 = din;
next_state_t = T15;
end
end
T15:
begin
if(cancel)
next_state_t = T0;
else
begin
newpasswd3 = din;
next_state_t = T16;
end
end
T16: //T16~T19用于检测第二次输入密码与寄存器密码是否相同
begin
if(cancel)
next_state_t = T0;
else if(din == newpasswd0)
next_state_t = T17;
else
next_state_t = T0;
end
T17:
begin
if(cancel)
next_state_t = T0;
else if(din == newpasswd1)
next_state_t = T18;
else
next_state_t = T0;
end
T18:
begin
if(cancel)
next_state_t = T0;
else if(din == newpasswd2)
next_state_t = T19;
else
next_state_t = T0;
end
T19:
begin
if(cancel)
next_state_t = T0;
else if(din == newpasswd3)
next_state_t = T20;
else
next_state_t = T0;
end
T20:
begin
if(cancel)
next_state_t = T0;
else if(confirm)
next_state_t = OK;
else
next_state_t = T20;
end
OK:
begin
passwd0 = newpasswd0;
passwd1 = newpasswd1;
passwd2 = newpasswd2;
passwd3 = newpasswd3;
reset_ok = 1'b1;
wrong_count = 0;
next_state_t = T0;
end
// default:
// begin
// reset_ok = 1'b0;
// wrong_count = 0;
// unlock_ok = 1'b0;
// locking = 1'b0;
// end
endcase
end
//****************************************************************//
Endmodule
TB文件:
module tb_lock();
reg clk;
reg clr;
reg cancel; //取消键*
reg [3:0] din; //数字键
reg confirm; //确定键#
wire unlock_ok; // 成功开锁,输出 1
wire reset_ok; //成功重设密码,输出 1
wire locking; //输错密码锁定状态 输出 1
initial
begin
clk <= 0;
confirm <= 0;
din <= 0;
cancel <= 0;
clr <= 1;
#30 clr <= 0;
//依次输入 1 2 3 4 确认 成功开锁
din <= 1;
#20 din <= 2;
#20 din <= 3;
#20 din <= 4;
#20 din <= 0;
confirm <= 1;
#20 confirm <= 0;
#20
#20
#20
#20
//依次输入 1 2 3 5 确认 无法
din <= 1;
#20 din <= 2;
#20 din <= 3;
#20 din <= 5;
#20 din <= 0;
confirm <= 1;
#20 confirm <= 0;
din <= 1;
#20 din <= 0;
#20
#20
#20
#20
//依次输入 230419 230419 6789 6789 确认
//密码从默认的 1234 修改为 6789
din <= 2; #20
din <= 3; #20
din <= 0; #20
din <= 4; #20
din <= 1; #20
din <= 9; #20
din <= 2; #20
din <= 3; #20
din <= 0; #20
din <= 4; #20
din <= 1; #20
din <= 9; #20
din <= 6; #20
din <= 7; #20
din <= 8; #20
din <= 9; #20
din <= 6; #20
din <= 7; #20
din <= 8; #20
din <= 9; #20
confirm <= 1; #20
confirm <= 0; din <= 0; #20
//连续输入 3 次错误密码:
//1234 # 1234 # 1234 #
din <= 1; confirm <= 0; #20
din <= 2; #20
din <= 3; # 20
din <= 4; #20
din <= 0; confirm <= 1; #20
din <= 1; confirm <= 0; #20
din <= 2; #20
din <= 3; #20
din <= 4; #20
din <= 0; confirm <= 1; #20
din <= 1; confirm <= 0; #20
din <= 2; #20
din <= 3; #20
din <= 4; #20
din <= 0; confirm <= 1; #20
//连续输错三次后,进入 lock 状态
#20 din <= 6; confirm <= 0;
#20 din <= 7;
#20 din <= 8;
#20 din <= 9;
#20 din <= 0; confirm <= 1;
#20 confirm <= 0;
#20
#20
#20
#20
din <= 6;
#20 din <= 7;
#20 din <= 8;
#20 cancel <= 1; din <= 0;
#20 din <= 9; cancel <= 0;
#20 din <= 0; confirm <= 1;
#20 confirm <= 0;
end
always #10 clk = ~clk; //晶振周期 20ns
lock test_lock(
.clk(clk),
.clr(clr),
.din(din),
.confirm(confirm),
.cancel(cancel),
.unlock_ok(unlock_ok),
.reset_ok(reset_ok),
.locking(locking)
);
endmodule
运行演示:
end