基于FPGA的数字密码锁
顶层文件
module lock (
input clk,//时钟
input rst_n,//复位
input [3:0] number_in,//输入
input key_open1,
input key_lock1,
// input key_reset1,
output beep,//蜂鸣器
output lock_flag,//锁标志位
output [3:0] dtube_cs_n, //7段数码管位选信号
output [7:0] dtube_data //7段数码管段选信号
);
wire [1:0] keyin;
wire [1:0] keyout;
assign keyin={key_lock1,key_open1};
assign {key_lock,key_open}=keyout;
debounce_button u_debounce_button(
.clk (clk ),
.rst (rst_n ),
.key (keyin ),
.key_pulse (keyout )
);
wire [15:0] display_num;
wire beep1;
fsm u_fsm(
.clk (clk ),
.rst_n (rst_n ),
.number_in (number_in ),
.key_open_reset (key_open ),
.key_lock (key_lock ),
// .key_reset (key_reset ),
.beep (beep1 ),
.display_num (display_num ),
.lock_flag (lock_flag )
);
seg7 u_seg7(
.clk (clk ),
.rst_n (rst_n ),
.display_num (display_num ),
.dtube_cs_n (dtube_cs_n ),
.dtube_data (dtube_data )
);
beep_ctr u_beep_ctr(
.clk (clk ),
.rst_n (rst_n ),
.beep1 (beep1 ),
.beep (beep )
);
endmodule
状态机模块
module fsm (
input clk,
input rst_n,
input [3:0] number_in,
input key_open_reset,
input key_lock,
// input key_open_reset,
output beep,
output [15:0] display_num,
output reg lock_flag
);
localparam //一共五个状态,使用Gray码提高翻转效率
LOCK = 3'b000,
OPEN_PRE = 3'b001,
OPEN = 3'b011,
RESET_PRE = 3'b010,
RESET = 3'b110;
//数码管显示 0~F 对应段选输出
parameter NUM0 = 4'h0,//c0,
NUM1 = 4'h1,//f9,
NUM2 = 4'h2,//a4,
NUM3 = 4'h3,//b0,
NUM4 = 4'h4,//99,
NUM5 = 4'h5,//92,
NUM6 = 4'h6,//82,
NUM7 = 4'h7,//F8,
NUM8 = 4'h8,//80,
NUM9 = 4'h9,//90,
NUMA = 4'hA,//88,
NUMB = 4'hB,//83,
NUMC = 4'hC,//c6,
NUMD = 4'hD,//a1,
NUME = 4'hE,//86,
NUMF = 4'hF;//8e;
reg [2:0] state; //下一拍执行状态
//密码储存
reg [3:0] mima;
reg reset_mima_flag;
reg merroy;
reg beep1;
reg beep2;
assign beep=beep2;
always @(posedge clk or negedge rst_n) begin//状态转移
if(!rst_n)state <= LOCK;
else if (cnt == 32'h1dcd6500) begin
state <= LOCK;
end
else if(beep2)
state<=LOCK;
else
case (state)
LOCK:
if (number_in == mima && key_open_reset)
state <= OPEN_PRE;
else if (key_open_reset)
state <= LOCK;
else
state <= LOCK;
OPEN_PRE:
if (number_in == mima && key_open_reset)
state <= OPEN;
else if (key_lock)
state <= LOCK;
else
state <= OPEN;
OPEN:
if (key_open_reset)
state <= RESET_PRE;
else if (key_lock)
state <= LOCK;
else
state <= state;
RESET_PRE:
if (key_open_reset)
state <= RESET;
else if (key_lock)
state <= LOCK;
else
state <= state;
RESET:
if (key_open_reset)
state <= OPEN;
else if (key_lock)
state <= LOCK;
else
state <= state;
default: state <= state;
endcase
end
reg jilu_key;
reg jilu_key1;
always @(posedge clk or negedge rst_n) begin//输出
if (rst_n == 0) begin
lock_flag = 0;
reset_mima_flag = 0;
merroy = 0;
jilu_key=0;
end
else if (state == OPEN) begin
lock_flag = 1;
end
else if (state == RESET) begin
reset_mima_flag = 1;
merroy = 1;
end
else if (state == LOCK) begin
lock_flag = 0;
reset_mima_flag = 0;
end
else if (key_lock|key_open_reset)
jilu_key=1;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)jilu_key1<=0;
else if(jilu_key&(!jilu_key1))beep1<=1;
else beep1<=0;
end
//定时10s
reg [31:0] cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)cnt<=0;
else if(cnt==32'd500000000)cnt<=0;
else if(beep1)cnt<=cnt+1;
else cnt<=cnt;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)beep2<=0;
else if(cnt==32'd499999999)beep2<=1;
else beep2<=beep2;
end
always @(*) begin//密码控制
if (!merroy) begin
mima <= 4'b1010;
end
else if (reset_mima_flag) begin
mima <= number_in;
end
else begin
mima <= mima;
end
end
//数码管显示译码
wire [3:0] qian;
wire [3:0] bai;
wire [3:0] shi;
wire [3:0] ge;
assign qian = number_in[3]?NUM1:NUM0;
assign bai = number_in[2]?NUM1:NUM0;
assign shi = number_in[1]?NUM1:NUM0;
assign ge = number_in[0]?NUM1:NUM0;
assign display_num ={qian,bai,shi,ge};
endmodule
数码管动态显示模块
//reg [15:0] display_num;
module seg7(
input clk, //时钟信号,50MHz
input rst_n, //复位信号,低电平有效
input[15:0] display_num, //数码管显示数据,[15:12]--数码管千位,[11:8]--数码管百位,[7:4]--数码管十位,[3:0]--数码管个位
output reg[3:0] dtube_cs_n, //7段数码管位选信号
output reg[7:0] dtube_data //7段数码管段选信号(包括小数点为8段)
);
//-------------------------------------------------
//参数定义
//数码管显示 0~F 对应段选输出
parameter NUM0 = 8'h3f,//c0,
NUM1 = 8'h06,//f9,
NUM2 = 8'h5b,//a4,
NUM3 = 8'h4f,//b0,
NUM4 = 8'h66,//99,
NUM5 = 8'h6d,//92,
NUM6 = 8'h7d,//82,
NUM7 = 8'h07,//F8,
NUM8 = 8'h12,//80,
NUM9 = 8'h6f,//90,
NUMA = 8'h77,//88,
NUMB = 8'h7c,//83,
NUMC = 8'h39,//c6,
NUMD = 8'h5e,//a1,
NUME = 8'h38,//86,
NUMF = 8'h71,//8e;
NDOT = 8'h80; //小数点显示
//数码管位选 0~3 对应输出
parameter CSN = 4'b1111,
CS0 = 4'b1110,
CS1 = 4'b1101,
CS2 = 4'b1011,
CS3 = 4'b0111;
//-------------------------------------------------
//分时显示数据控制单元
reg[3:0] current_display_num; //当前显示数据
reg[7:0] div_cnt; //分时计数器
//分时计数器
always @(posedge clk or negedge rst_n)
if(!rst_n) div_cnt <= 8'd0;
else div_cnt <= div_cnt+1'b1;
//显示数据
always @(posedge clk or negedge rst_n)
if(!rst_n) current_display_num <= 4'h0;
else begin
case(div_cnt)
8'hff: current_display_num <= display_num[3:0];
8'h3f: current_display_num <= display_num[7:4];
8'h7f: current_display_num <= display_num[11:8];
8'hbf: current_display_num <= display_num[15:12];
default: ;
endcase
end
//段选数据译码
always @(posedge clk or negedge rst_n)
if(!rst_n) dtube_data <= NUM0;
else begin
case(current_display_num)
4'h0: dtube_data <= NUM0;
4'h1: dtube_data <= NUM1;
4'h2: dtube_data <= NUM2;
4'h3: dtube_data <= NUM3;
4'h4: dtube_data <= NUM4;
4'h5: dtube_data <= NUM5;
4'h6: dtube_data <= NUM6;
4'h7: dtube_data <= NUM7;
4'h8: dtube_data <= NUM8;
4'h9: dtube_data <= NUM9;
4'ha: dtube_data <= NUMA;
4'hb: dtube_data <= NUMB;
4'hc: dtube_data <= NUMC;
4'hd: dtube_data <= NUMD;
4'he: dtube_data <= NUME;
4'hf: dtube_data <= NUMF;
default: ;
endcase
end
//位选译码
always @(posedge clk or negedge rst_n)
if(!rst_n) dtube_cs_n <= CSN;
else begin
case(div_cnt[7:6])
2'b00: dtube_cs_n <= CS0;
2'b01: dtube_cs_n <= CS1;
2'b10: dtube_cs_n <= CS2;
2'b11: dtube_cs_n <= CS3;
default: dtube_cs_n <= CSN;
endcase
end
endmodule
蜂鸣器模块
module beep_ctr(
input clk,
input rst_n,
input beep1,
output reg beep
);
reg[19:0] cnt; //20位计数器
//cnt计数器进行0-999999的循环计数,即ext_clk_25m时钟的1000000分频,对应cnt一个周期为25Hz
always @(posedge clk or negedge rst_n)
if(!rst_n) cnt <= 20'd0;
else if(cnt < 20'd999_99) cnt <= cnt+1'b1;
else cnt <= 20'd0;
always @(posedge clk or negedge rst_n)
if(!rst_n)begin
beep <= 0;
end
else if(cnt < 20'd500_00 && beep1)
beep <= ~beep;
else
beep <= 1'b0;
endmodule
按键消抖模块
// ********************************************************************
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// ********************************************************************
// File name : debounce.v
// Module name : debounce
// Author : STEP
// Description :
// Web : www.stepfpga.com
//
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Version: |Mod. Date: |Changes Made:
// V1.0 |2017/03/02 |Initial ver
// --------------------------------------------------------------------
// Module Function:按键消抖
module debounce_button (clk,rst,key,key_pulse);
parameter N = 2; //要消除的按键的数量
input clk;
input rst;
input [N-1:0] key; //输入的按键
output [N-1:0] key_pulse; //按键动作产生的脉冲
reg [N-1:0] key_rst_pre; //定义一个寄存器型变量存储上一个触发时的按键值
reg [N-1:0] key_rst; //定义一个寄存器变量储存储当前时刻触发的按键值
wire [N-1:0] key_edge; //检测到按键由高到低变化是产生一个高脉冲
//利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
always @(posedge clk or negedge rst)
begin
if (!rst) begin
key_rst <= {N{1'b1}}; //初始化时给key_rst赋值全为1,{}中表示N个1
key_rst_pre <= {N{1'b1}};
end
else begin
key_rst <= key; //第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
key_rst_pre <= key_rst; //非阻塞赋值。相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值
end
end
assign key_edge = key_rst_pre & (~key_rst);//脉冲边沿检测。当key检测到下降沿时,key_edge产生一个时钟周期的高电平
reg [3:0] cnt; //产生延时所用的计数器,系统时钟50MHz,要延时20ms左右时间,至少需要20位计数器
//产生20ms延时,当检测到key_edge有效是计数器清零开始计数
always @(posedge clk or negedge rst)
begin
if(!rst)
cnt <= 4'h0;
else if(key_edge)
cnt <= 4'h0;
else
cnt <= cnt + 1'h1;
end
reg [N-1:0] key_sec_pre; //延时后检测电平寄存器变量
reg [N-1:0] key_sec;
//延时后检测key,如果按键状态变低产生一个时钟的高脉冲。如果按键状态是高的话说明按键无效
always @(posedge clk or negedge rst)
begin
if (!rst)
key_sec <= {N{1'b1}};
else if (cnt==4'hf)
key_sec <= key;
end
always @(posedge clk or negedge rst)
begin
if (!rst)
key_sec_pre <= {N{1'b1}};
else
key_sec_pre <= key_sec;
end
assign key_pulse = key_sec_pre & (~key_sec);
endmodule
testbench
到此结束,如有问题请留言评论文章来源地址https://www.toymoban.com/news/detail-765815.html
文章来源:https://www.toymoban.com/news/detail-765815.html
到了这里,关于基于FPGA的数字密码锁的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!