请编写程序,可以给出仿真图,题目如下图,请按题目要求编写,并给出程序。
请注意题目必须用按键!

3 个按键,选择,取消,确认
采用数码滚动的方式,通过选择键选择数字
//初始密码是 1234
//需要录入修改密码,将sw[0]拨到 0 ,操作键盘输入密码,按确认就能将当前密码保存。
//将sw[0]拨到 1 是正常密码锁
//3 个按键
//k0 选择//k1 取消//k2 确认
//按下 K0 时,当前位数码管开始 0 - 9 的半秒循环跳变一次,抬起 K0 数码管停止跳动记录当前这位密码,密码计数加 1
//输入四位密码后,按下 K2 比较密码,成功 LED 0 亮,或失败错误计数器加1
//在没按确认前,按 K1 会将所有的密码取消,回到没有输入密码的状态,密码计数归 0,需要重新输入 4 位密码。
//没输够 4 位密码时,按 K2 无效果
//sw[0] 修改密码开关 = 0 录入修改密码,= 1 正常密码锁
//sw[1] 解锁键盘开关,在加电状态将开关拨到 0 后再拨回到 1
//sw[0]/sw[1]这俩开关拨到 1 时才能正常工作
module passwd_lock //密码锁
(
input clk, //50MHz 时钟
input [2:0] k, //轻触按键 k[0][选择]/k[1][取消]/k[2][确认]/
input [1:0] sw, //开关,sw[0]:修改密码开关/sw[1]:解锁键盘开关
//修改密码开关 = 0 录入修改密码,= 1 正常密码锁
//解锁键盘开关 = 0 解锁,=1正常
output [1:0] led, //输出1 LED 亮。led[0]密码正确、led[1]密码三次错误锁键盘
output [6:0] led_7a, //七段数码管 A 最左边
output [6:0] led_7b, //七段数码管 B 左边第二
output [6:0] led_7c, //七段数码管 C 左边第三
output [6:0] led_7d //七段数码管 D 最右边
);
parameter CLK_IN_FREQ = 50*1000*1000;
parameter CLK_KEY_FREQ = 100;
reg[15:0] passwd_dat_save = 16'h4321; //初始密码 1234
reg [3:0] err_cnt=0; //密码错误计数器
reg lock_key=0; //键盘锁,1锁,0解锁
reg passwd_ok=0;
wire[15:0] key_dat; //键盘输出的4位数
wire key_valid; //键盘输出有效
wire k_clk;
wire[2:0] k_up;
wire[2:0] k_down;
wire[6:0] led_7a_i;
wire[6:0] led_7b_i;
wire[6:0] led_7c_i;
wire[6:0] led_7d_i;
wire en;
key_num u2 //滚动数字键盘
(
.clk (k_clk),
.en (en),
.k (k), //k0 sel 选择按键,k1 cancel 取消按键,k[2] ok 确认按键
.k_up (k_up), //对应 K[2:0] 的抬起键脉冲
.k_down (k_down), //对应 K[2:0] 的按下键脉冲
.key_valid (key_valid),
.key_dat (key_dat)
);
led_7s led_a
(
.dat (key_dat[3:0]),
.led7s (led_7a_i) //七段数码管 A 最左边
);
led_7s led_b
(
.dat (key_dat[7:4]),
.led7s (led_7b_i) //七段数码管 B 左边第二
);
led_7s led_c
(
.dat (key_dat[11:8]),
.led7s (led_7c_i) //七段数码管 C 左边第三
);
led_7s led_d
(
.dat (key_dat[15:12]),
.led7s (led_7d_i) //七段数码管 D 最右边
);
assign led_7a = ~led_7a_i; //共阳输出需要翻转
assign led_7b = ~led_7b_i; //共阳输出需要翻转
assign led_7c = ~led_7c_i; //共阳输出需要翻转
assign led_7d = ~led_7d_i; //共阳输出需要翻转
assign led[0] = passwd_ok;
assign led[1] = lock_key;
assign en = ~lock_key & sw[1];
reg clk1 = 0;
reg[31:0]cnt = 0;
assign k_clk = clk1;
//时钟分频模块 //输入时钟频率 50MHz 输出时钟 100Hz,键盘用 100Hz 低频有去抖动的效果
always @(posedge clk)
begin
if(cnt < CLK_IN_FREQ/CLK_KEY_FREQ/2 -1)
cnt <= cnt + 1;
else
begin
cnt <= 0;
clk1 <= !clk1;
end
end
always @(posedge k_clk)
begin
if(sw[0]==0) //修改密码
begin
lock_key <= 0; //修改密码时不锁键盘
err_cnt <= 0;
passwd_ok <= 0;
if(key_valid == 1)
passwd_dat_save <= key_dat; //保存密码
end
else if(sw[1]==0) //解锁键盘
begin
lock_key <= 0;
err_cnt <= 0;
passwd_ok <= 0;
end
else //正常的密码锁
begin
if(key_valid == 1)
begin
if(key_dat == passwd_dat_save)
begin
lock_key <= 0;
err_cnt <= 0;
passwd_ok <= 1; //开锁
end
else if(err_cnt < 3-1)
begin
lock_key <= 0;
err_cnt <= err_cnt + 1; //密码错误,计数器+1
passwd_ok <= 0;
end
else
begin
lock_key <= 1; //3次密码错误,锁键盘
err_cnt <= 3;
passwd_ok <= 0;
end
end
else if(k_up[2]==1) //判断[确认]抬起,开锁结束
passwd_ok <= 0;
end
end
endmodule
module led_7s //led 7 段数码管译码 0-F,共阴数码管
(
input [3:0] dat,
output reg [6:0] led7s //{a,b,c,d,e,f,g} //7段LED 排列 a->led7s[6] g->led7s[0]
);
always@(*)
begin
case(dat)
4'b0000:led7s=7'b0111111; //0
4'b0001:led7s=7'b0000110; //1
4'b0010:led7s=7'b1011011; //2
4'b0011:led7s=7'b1001111; //3
4'b0100:led7s=7'b1100110; //4
4'b0101:led7s=7'b1101101; //5
4'b0110:led7s=7'b1111101; //6
4'b0111:led7s=7'b0000111; //7
4'b1000:led7s=7'b1111111; //8
4'b1001:led7s=7'b1101111; //9
4'b1010:led7s=7'b1110111; //A
4'b1011:led7s=7'b1111100; //B
4'b1100:led7s=7'b0111001; //C
4'b1101:led7s=7'b1011110; //D
4'b1110:led7s=7'b1111001; //E
4'b1111:led7s=7'b1110001; //F
endcase
end
endmodule
module key_num //滚动数字键盘
(
input clk,
input en,
input[2:0] k, //k0 sel 选择按键,k1 cancel 取消按键,k[2] ok 确认按键
output key_valid,
output[2:0] k_up,
output[2:0] k_down,
output [15:0] key_dat
);
parameter CLK_IN_FREQ =100; //100Hz
reg [2:0] k_r0=0;
reg [2:0] k_r1=0;
reg [3:0] kb_dat[3:0];
reg [3:0] kb_cnt=0;
wire k_sel;
wire k_sel_up;
wire k_sel_down;
wire k_cancel_up;
wire k_cancel_down;
wire k_ok_up;
wire k_ok_down;
reg key_valid_r=0;
reg clk_s=0;
reg [7:0] cnts=0;
initial
begin
kb_dat[0]=0;
kb_dat[1]=0;
kb_dat[2]=0;
kb_dat[3]=0;
end
assign k_sel = k_r1[0]; //k[0]sel [选择]按键,按下开始数字滚动,抬起滚动停止,0为按下,1为抬起
assign k_sel_up = k_r0[0] & ~k_r1[0]; //k[0]sel [选择]按键抬起脉冲,1 有效
assign k_sel_down =~k_r0[0] & k_r1[0]; //k[0]sel [选择]按键按下脉冲,1 有效
assign k_cancel_up = k_r0[1] & ~k_r1[1]; //k[1]cancel[取消]按键抬起脉冲,1 有效
assign k_cancel_down =~k_r0[1] & k_r1[1]; //k[1]cancel[取消]按键按下脉冲,1 有效
assign k_ok_up = k_r0[2] & ~k_r1[2]; //k[2]ok [确认]按键抬起脉冲,1 有效
assign k_ok_down =~k_r0[2] & k_r1[2]; //k[2]ok [确认]按键按下脉冲,1 有效
assign k_up[0] = k_sel_up;
assign k_down[0] = k_sel_down;
assign k_up[1] = k_cancel_up;
assign k_down[1] = k_cancel_down;
assign k_up[2] = k_ok_up;
assign k_down[2] = k_ok_down;
assign key_dat = {kb_dat[3],kb_dat[2],kb_dat[1],kb_dat[0]};
assign key_valid = key_valid_r;
always @(posedge clk)
begin
if(cnts < CLK_IN_FREQ/2-1)
begin
cnts <= cnts + 1;
clk_s <= 0;
end
else
begin
cnts <= 0;
clk_s <= 1; //2Hz脉冲,用于数字滚动
end
end
always @(posedge clk)
begin
k_r0 <= k;
k_r1 <= k_r0;
end
always @(posedge clk)
begin
if(en == 1) //en = 1 允许键盘
begin
if(k_cancel_up == 1 || (k_ok_up == 1 && kb_cnt >= 4)) //[取消]抬起键||[确认]抬起并且输入了4位数
kb_cnt <= 0;
else if(k_sel_up == 1 && kb_cnt < 4) //用抬起[选择]的脉冲来计数
kb_cnt <= kb_cnt + 1;
end
else //en = 0 锁键盘
kb_cnt <= 0;
end
always @(posedge clk)
begin
if(en == 1) //en = 1 允许键盘
begin
if(k_cancel_up == 1)
key_valid_r <= 0;
else if(k_ok_down == 1 && kb_cnt >= 4)
key_valid_r <= 1;
else
key_valid_r <= 0;
end
else //en = 0 锁键盘
key_valid_r <= 0;
end
always @(posedge clk)
begin
if(en == 1) //en = 1 允许键盘
begin
if(k_cancel_up == 1 || k_ok_up == 1)
begin
kb_dat[0] <= 0;
kb_dat[1] <= 0;
kb_dat[2] <= 0;
kb_dat[3] <= 0;
end
else if(kb_cnt < 4)
begin
if(k_sel == 0 && clk_s == 1) //选择键按下,2Hz脉冲
begin
if(kb_dat[kb_cnt] <10-1)
kb_dat[kb_cnt] <= kb_dat[kb_cnt] + 1;
else
kb_dat[kb_cnt] <= 0;
end
end
end
else //en = 0 锁键盘
begin
kb_dat[0] <= 0;
kb_dat[1] <= 0;
kb_dat[2] <= 0;
kb_dat[3] <= 0;
end
end
endmodule