1.设计要求: 用 verilog 语言设计一个数字密码锁,需要满足以下基本功能:
(1). 密码为 4 位,每位密码为数字 0-5,4 位密码各不相同。 (2). 具有使能输入端 en,用于控制密码锁的开启和关闭。密码锁开启, 允许输入密码;密码锁关闭,禁止输入密码。 (3). 具有清零输入端 clr,用于清除已输入的密码,重新进行密码输入。 (4). 可输出显示密码正确与否。 进阶功能: (1). 具有密码修改功能,允许修改预设的四位密码。 (2). 密码连续输错 3 次以上,密码锁输出显示锁定,不允许再进行密码 输入。 (3). 可自定义添加其他功能。 编写 testbench 验证功能并下板验证。
2.基本功能:
Stay状态:
stay:begin //等待状态(测试各输出是否能够正常输出)
unlock_led <= 1;
error_led <= 1;
inpw3 <= 8;
inpw2 <= 8;
inpw1 <= 8;
inpw0 <= 8;
s <= 3;
if(en) begin //若en为1,则进入输入(inpt)状态
state <= inpt;
unlock_led <= 0;
error_led <= 0;
inpw3 <= 10; //显示横线
end
end
当en=1时,进入输入状态,当clr=0时清0,
inpt:begin //输入密码状态
unlock_led <= 0;
error_led <= 0;
if(en) begin //使能端en为1,进行密码输入
case(s)
3:begin
inpw3 <= pw;
s <= s-1;
inpw2 <= 10; //显示横线
end
2:begin
inpw2 <= pw;
s <= s-1;
inpw1 <= 10; //显示横线
end
1:begin
inpw1 <= pw;
s <= s-1;
inpw0 <= 10; //显示横线
end
0:begin
inpw0 <= pw;
s <= 3;
state <= check;
end
default;
endcase
end
else begin //若en为0,返回stay状态
state <= stay;
end
end
当最后一个数字输入后,进入check状态进行检测,
check:begin //密码检测状态
if(en) begin
inpw3 <= 10;
inpw2 <= 10;
inpw1 <= 10;
inpw0 <= 10;
if((inpw3==password3)&&
(inpw2==password2)&&
(inpw1==password1)&&
(inpw0==password0)) begin
state <= ulock;
t <= 3; //错误计数重置
end
else begin
state <= er;
t <= t-1; //错误次数计数
end
end
else begin
state <= stay;
end
end
如果与设置的密码相符,则进入ulock状态,解锁,会有unlock_led <= 1;error_led <= 0;显示;
ulock:begin //密码正确,解锁成功状态
unlock_led <= 1;
error_led <= 0;
state <= stay;
end
如果不符则进入er状态,会有unlock_led <= 0;error_led <= 1;显示,并且此时数码管上显示EEEE。
er:begin //密码错误
inpw3 <= 11; //显示E
inpw2 <= 11;
inpw1 <= 11;
inpw0 <= 11;
unlock_led <= 0;
error_led <= 1;
state <= stay;
end
3.进阶功能
如果set=1,则进入密码输入状态
setpw:begin //更改密码状态
unlock_led <= 0;
error_led <= 0;
inpw3 <= 10; //显示横线
inpw2 <= 12;
inpw1 <= 12;
inpw0 <= 12;
case(s)
3:begin
password3 <= pw;
s <= s-1;
inpw3 <= pw;
inpw2 <= 10; //显示横线
end
2:begin
password2 <= pw;
s <= s-1;
inpw3 <= password3;
inpw2 <= pw;
inpw1 <= 10; //显示横线
end
1:begin
password1 <= pw;
s <= s-1;
inpw3 <= password3;
inpw2 <= password2;
inpw1 <= pw;
inpw0 <= 10; //显示横线
end
0:begin
password0 <= pw;
s <= 3;
inpw3 <= password3;
inpw2 <= password2;
inpw1 <= password1;
inpw0 <= pw;
state <= stay;
end
default;
endcase
end
如果错误超过三次,计数的t由3减为0,进入lock状态,数码管上显示lock
lock:begin //错误3次,上锁
inpw3 <= 13; //显示L
inpw2 <= 0; //显示O
inpw1 <= 14; //显示C
inpw0 <= 15; //显示K
error_led <= 1;
unlock_led <= 0;
end
二、仿真
#50 en=1; //测试初始密码:2023
#10 pw=2;
#10 pw=0;
#10 pw=2;
#10 pw=3;
#10 pw=0;
#40 en=0;
数码管3: 0100100对应2
数码管2:1000000对应0
数码管1:0100100对应0
数码管0:0110000对应3
之后数码管全部变为0111111,及为横杠,unlock_led 变为 1,解锁成功
#50 en=1; //输入错误密码:1111
pw=1;
#100 en=0;
数码管上显示的数字均变为1111001,对应1,此时error_led 变为 1;数码管均显示0000110,及E,未能解锁
#50 set=1;//设置新密码为:1211
#10 set=0;
pw=1;
#10 pw=2;
#10 pw=1;
#10 pw=1;
#10 pw=0;
数码管
3:1111001对应1
数码管2:0100100对应2
数码管1:1111001对应1
数码管0:1111001对应1
及密码变为了1211
#50 en=1;//输入原始密码:2023
#10 pw=2;
#10 pw=0;
#10 pw=2;
#10 pw=3;
#40 en=0;
输入密码2023后
数码管3: 0100100对应2
数码管2:1000000对应0
数码管1:0100100对应0
数码管0:0110000对应3
之后数码管上显示的数字均变为1111001,对应1,此时error_led 变为 1;数码管均显示0000110,及E,未能解锁
#50 en=1;//输入新密码:1211
#10 pw=1;
#10 pw=2;
#10 pw=1;
#10 pw=1;
#40 en=0;
数码管3:1111001对应1
数码管2:0100100对应2
数码管1:1111001对应1
数码管0:1111001对应1
之后数码管全部变为0111111,及为横杠,unlock_led 变为 1,解锁成功
#50 en=1;//输入错误密码:2222
#10 pw=2;
#400 //错误输入超过3次
en=0;
数码管数字均变为0100100,对应2,之后数码管变为0001110,及对应E
重复输入达到三次之后
数码管3:1000111,对应L
数码管2:1000000,对应O
数码管1:1000110,对应C
数码管0:0000111,对应K
再输入依旧时lock,及超过三次后锁定
#50 en=1;//输入新密码:1211,测试是否能够继续输入密码
#10 pw=1;
#10 pw=2;
#10 pw=1;
#10 pw=1;
#40 en=0;
再次输入正确密码,但此时
数码管3:1000111,对应L
数码管2:1000000,对应O
数码管1:1000110,对应C
数码管0:0000111,对应K
依旧保持不变,及超过三次后锁定,不允许再输入密码
#100 $finish;
end
endmodule
三、
顶层电路图
附录:
完整的代码
module digital_lock(
input wire clr, //清零输入
input wire en, //使能输入
input wire [3:0] pw, //4位密码输入
input wire set, //设置密码按键
input wire clk,
output reg unlock_led, //密码正确输出标志
output reg error_led, //密码错误标志
output reg [6:0] shumaguan3, //数码管
output reg [6:0] shumaguan2,
output reg [6:0] shumaguan1,
output reg [6:0] shumaguan0
);
reg [3:0] password3; //密码储存
reg [3:0] password2;
reg [3:0] password1;
reg [3:0] password0;
reg [3:0] inpw3; //输入密码储存
reg [3:0] inpw2;
reg [3:0] inpw1;
reg [3:0] inpw0;
reg [2:0] state; //状态机
reg [1:0] s; //置位计数
reg [1:0] t; //错误次数记录
//状态定义
parameter [3:0] stay=0,inpt=1,setpw=2,check=3,ulock=4,er=5,lock=6;
initial begin //初始状态
state = stay;
s = 3;
t = 3;
password3 = 2; //初始密码2023
password2 = 0;
password1 = 2;
password0 = 3;
end
always @(posedge clk) begin
if(clr) begin //清零输入
state <= stay;
s <= 3;
end
else if(set) begin //进入修改密码状态
state <= setpw;
s <= 3;
unlock_led <= 0;
error_led <= 0;
inpw3 <= 10; //显示横线
inpw2 <= 12; //显示右边框
inpw1 <= 12;
inpw0 <= 12;
end
else if(t==0) begin //失败3次后上锁
state <= lock;
inpw3 <= 13; //显示L
inpw2 <= 0; //显示O
inpw1 <= 14; //显示C
inpw0 <= 15; //显示K
error_led <= 1;
unlock_led <= 0;
end
else begin
case (state) //各个状态
stay:begin //等待状态(测试各输出是否能够正常输出)
unlock_led <= 1;
error_led <= 1;
inpw3 <= 8;
inpw2 <= 8;
inpw1 <= 8;
inpw0 <= 8;
s <= 3;
if(en) begin //若en为1,则进入输入(inpt)状态
state <= inpt;
unlock_led <= 0;
error_led <= 0;
inpw3 <= 10; //显示横线
end
end
inpt:begin //输入密码状态
unlock_led <= 0;
error_led <= 0;
if(en) begin //使能端en为1,进行密码输入
case(s)
3:begin
inpw3 <= pw;
s <= s-1;
inpw2 <= 10; //显示横线
end
2:begin
inpw2 <= pw;
s <= s-1;
inpw1 <= 10; //显示横线
end
1:begin
inpw1 <= pw;
s <= s-1;
inpw0 <= 10; //显示横线
end
0:begin
inpw0 <= pw;
s <= 3;
state <= check;
end
default;
endcase
end
else begin //若en为0,返回stay状态
state <= stay;
end
end
setpw:begin //更改密码状态
unlock_led <= 0;
error_led <= 0;
inpw3 <= 10; //显示横线
inpw2 <= 12;
inpw1 <= 12;
inpw0 <= 12;
case(s)
3:begin
password3 <= pw;
s <= s-1;
inpw3 <= pw;
inpw2 <= 10; //显示横线
end
2:begin
password2 <= pw;
s <= s-1;
inpw3 <= password3;
inpw2 <= pw;
inpw1 <= 10; //显示横线
end
1:begin
password1 <= pw;
s <= s-1;
inpw3 <= password3;
inpw2 <= password2;
inpw1 <= pw;
inpw0 <= 10; //显示横线
end
0:begin
password0 <= pw;
s <= 3;
inpw3 <= password3;
inpw2 <= password2;
inpw1 <= password1;
inpw0 <= pw;
state <= stay;
end
default;
endcase
end
check:begin //密码检测状态
if(en) begin
inpw3 <= 10;
inpw2 <= 10;
inpw1 <= 10;
inpw0 <= 10;
if((inpw3==password3)&&
(inpw2==password2)&&
(inpw1==password1)&&
(inpw0==password0)) begin
state <= ulock;
t <= 3; //错误计数重置
end
else begin
state <= er;
t <= t-1; //错误次数计数
end
end
else begin
state <= stay;
end
end
ulock:begin //密码正确,解锁成功状态
unlock_led <= 1;
error_led <= 0;
state <= stay;
end
er:begin //密码错误
inpw3 <= 11; //显示E
inpw2 <= 11;
inpw1 <= 11;
inpw0 <= 11;
unlock_led <= 0;
error_led <= 1;
state <= stay;
end
lock:begin //错误3次,上锁
inpw3 <= 13; //显示L
inpw2 <= 0; //显示O
inpw1 <= 14; //显示C
inpw0 <= 15; //显示K
error_led <= 1;
unlock_led <= 0;
end
default;
endcase
end
end
//数码管显示
always @ (*) begin
// 将二进制数转换为七段数码管的控制信号
// 0为亮,1为灭
case (inpw3)
4'b0000: shumaguan3 = 7'b1000000; // 0
4'b0001: shumaguan3 = 7'b1111001; // 1
4'b0010: shumaguan3 = 7'b0100100; // 2
4'b0011: shumaguan3 = 7'b0110000; // 3
4'b0100: shumaguan3 = 7'b0011001; // 4
4'b0101: shumaguan3 = 7'b0010010; // 5
4'b0110: shumaguan3 = 7'b0000010; // 6
4'b0111: shumaguan3 = 7'b1111000; // 7
4'b1000: shumaguan3 = 7'b0000000; // 8
4'b1001: shumaguan3 = 7'b0010000; // 9
4'b1010: shumaguan3 = 7'b0111111; //10显示横线
4'b1011: shumaguan3 = 7'b0000110; //11显示E
4'b1100: shumaguan3 = 7'b1110000; //12显示右半框
4'b1101: shumaguan3 = 7'b1000111; //13显示L
4'b1110: shumaguan3 = 7'b1000110; //14显示C
4'b1111: shumaguan3 = 7'b0000111; //15显示K
default: shumaguan3 = 7'b1111111; // 灭
endcase
case (inpw2)
4'b0000: shumaguan2 = 7'b1000000; // 0
4'b0001: shumaguan2 = 7'b1111001; // 1
4'b0010: shumaguan2 = 7'b0100100; // 2
4'b0011: shumaguan2 = 7'b0110000; // 3
4'b0100: shumaguan2 = 7'b0011001; // 4
4'b0101: shumaguan2 = 7'b0010010; // 5
4'b0110: shumaguan2 = 7'b0000010; // 6
4'b0111: shumaguan2 = 7'b1111000; // 7
4'b1000: shumaguan2 = 7'b0000000; // 8
4'b1001: shumaguan2 = 7'b0010000; // 9
4'b1010: shumaguan2 = 7'b0111111; //10显示横线
4'b1011: shumaguan2 = 7'b0000110; //11显示E
4'b1100: shumaguan2 = 7'b1110000; //12显示右半框
4'b1101: shumaguan2 = 7'b1000111; //13显示L
4'b1110: shumaguan2 = 7'b1000110; //14显示C
4'b1111: shumaguan2 = 7'b0000111; //15显示K
default: shumaguan2 = 7'b1111111; // 灭
endcase
case (inpw1)
4'b0000: shumaguan1 = 7'b1000000; // 0
4'b0001: shumaguan1 = 7'b1111001; // 1
4'b0010: shumaguan1 = 7'b0100100; // 2
4'b0011: shumaguan1 = 7'b0110000; // 3
4'b0100: shumaguan1 = 7'b0011001; // 4
4'b0101: shumaguan1 = 7'b0010010; // 5
4'b0110: shumaguan1 = 7'b0000010; // 6
4'b0111: shumaguan1 = 7'b1111000; // 7
4'b1000: shumaguan1 = 7'b0000000; // 8
4'b1001: shumaguan1 = 7'b0010000; // 9
4'b1010: shumaguan1 = 7'b0111111; //10显示横线
4'b1011: shumaguan1 = 7'b0000110; //11显示E
4'b1100: shumaguan1 = 7'b1110000; //12显示右半框
4'b1101: shumaguan1 = 7'b1000111; //13显示L
4'b1110: shumaguan1 = 7'b1000110; //14显示C
4'b1111: shumaguan1 = 7'b0000111; //15显示K
default: shumaguan1 = 7'b1111111; // 灭
endcase
case (inpw0)
4'b0000: shumaguan0 = 7'b1000000; // 0
4'b0001: shumaguan0 = 7'b1111001; // 1
4'b0010: shumaguan0 = 7'b0100100; // 2
4'b0011: shumaguan0 = 7'b0110000; // 3
4'b0100: shumaguan0 = 7'b0011001; // 4
4'b0101: shumaguan0 = 7'b0010010; // 5
4'b0110: shumaguan0 = 7'b0000010; // 6
4'b0111: shumaguan0 = 7'b1111000; // 7
4'b1000: shumaguan0 = 7'b0000000; // 8
4'b1001: shumaguan0 = 7'b0010000; // 9
4'b1010: shumaguan0 = 7'b0111111; //10显示横线
4'b1011: shumaguan0 = 7'b0000110; //11显示E
4'b1100: shumaguan0 = 7'b1110000; //12显示右半框
4'b1101: shumaguan0 = 7'b1000111; //13显示L
4'b1110: shumaguan0 = 7'b1000110; //14显示C
4'b1111: shumaguan0 = 7'b0000111; //15显示K
default: shumaguan0 = 7'b1111111; // 灭
endcase
end
endmodule
仿真:
`timescale 1ns/1ps
module digital_lock_tb;
reg clr;
reg en;
reg [3:0] pw;
reg set;
reg clk;
wire unlock_led;
wire error_led;
wire [6:0] shumaguan3;
wire [6:0] shumaguan2;
wire [6:0] shumaguan1;
wire [6:0] shumaguan0;
digital_lock u1(
.clr(clr),
.en(en),
.set(set),
.pw(pw),
.clk(clk),
.unlock_led(unlock_led),
.error_led(error_led),
.shumaguan3(shumaguan3),
.shumaguan2(shumaguan2),
.shumaguan1(shumaguan1),
.shumaguan0(shumaguan0)
);
always begin
#5 clk = ~clk;
end
initial begin
en=0;
clr=0;
set=0;
pw=0;
clk=0;
#50 en=1; //测试初始密码:2023
#10 pw=2;
#10 pw=0;
#10 pw=2;
#10 pw=3;
#10 pw=0;
#40 en=0;
#50 en=1; //输入错误密码:1111
pw=1;
#100 en=0;
#50 set=1;//设置新密码为:1211
#10 set=0;
pw=1;
#10 pw=2;
#10 pw=1;
#10 pw=1;
#10 pw=0;
#50 en=1;//输入原始密码:2023
#10 pw=2;
#10 pw=0;
#10 pw=2;
#10 pw=3;
#40 en=0;
#50 en=1;//输入新密码:1211
#10 pw=1;
#10 pw=2;
#10 pw=1;
#10 pw=1;
#40 en=0;
#50 en=1;//输入错误密码:2222
#10 pw=2;
#400 //错误输入超过3次
en=0;
#50 en=1;//输入新密码:1211,测试是否能够继续输入密码
#10 pw=1;
#10 pw=2;
#10 pw=1;
#10 pw=1;
#40 en=0;
#100 $finish;
end
endmodule