基于FPGA的数字密码锁

基于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
到此结束,如有问题请留言评论

  • 4
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
FPGA(现场可编程门阵列)数字密码锁是一种安全控制设备,可将输入的数字密码与锁定的密码进行比较,以确定是否允许用户获得访问权限。要编写FPGA数字密码锁的代码,需要以下步骤: 首先,您需要了解数字密码锁的逻辑设计。它通常包括输入密码、检查密码、验证密码和控制电路。输入密码可以由数字键盘或其他输入设备提供。检查密码可以由比较器电路完成,用于比较输入密码和锁定密码。验证密码可以通过LED或LCD显示器在线上显示密码错误或正确以及其他用户指示。最后,控制电路可以控制继电器以开启或关闭门等。 接下来,您需要选择FPGA芯片并在其上编写代码。这可以使用Verilog或VHDL等硬件描述语言完成。在这种情况下,您需要定义输入和输出管脚,以便FPGA与其他电路进行交互。此外,你需要实现密码存储器的读取和写入功能。也可以将其他功能添加到系统中,例如计时器、警报器或防抄袭功能等。 最后,您可以使用仿真器或开发板测试您的代码。在仿真器中,您可以模拟输入数字密码,并检查和验证输出信号和电路状态。在开发板上,您可以将代码烧录到FPGA芯片中,并实际测试数字密码锁与其他电路的交互。 总体而言,基于FPGA数字密码锁的代码的实现需要设计电路、硬件描述语言编写,还需要对开发板进行测试检验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿智605

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值