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

你可能感兴趣的:(fpga开发,notepad++)