电子门锁模拟


前言

  密码解锁的过程也是一个有限状态机,只有按正确密码的顺序输入密码,才能打开电子锁。本次课程就用开发板模拟这一过程。

电子门锁

一、设计规范(需求)

  Cyclone IV开发板上有四个按键,每个按键通过消抖后作为密码按键KEY1,KEY2,KEY3,KEY4分别代表密码1,2,3,4。按下每个按键4个led灯做相应的动作,只有按照正确的密码1423输入,4个led灯才同时以20ms的间隔闪烁1s时间(同时闪2次),表示开锁成功。

二、原理图

在这里插入图片描述

三、设计输入

  1. 创建password.v文件,编写密码状态切换代码
 /***密码1423***/
module password#(parameter TIME_1S = 26'd49_999_999,
                 parameter TIME_200MS = 24'd9_999_999)(
	input wire clk,//时钟信号
	input wire rst_n,//复位信号
	input wire [3:0] key,//4个按键
	
	output wire [3:0] led//4个led信号,用于指示密码输入
);
//状态空间
parameter IDLE = 3'd0;
parameter S1 = 3'd1;
parameter S2 = 3'd2;
parameter S3 = 3'd3;
parameter S4 = 3'd4;

reg [2:0] cstate;//状态寄存器
reg [25:0] cnt;//1s计数寄存器
reg [23:0] cnt_200ms;//200ms计数寄存器
wire add_cnt;
wire end_cnt;
wire add_cnt_200ms;
wire end_cnt_200ms;
reg [3:0] led_r;

//1s计数功能
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt <= 26'd0;
    end 
    else if(add_cnt)begin 
            if(end_cnt)begin 
                cnt <= 26'd0;
            end
            else begin 
                cnt <= cnt + 1'd1;
            end 
    end
   else  begin
       cnt <= 26'd0;
    end
end 

assign add_cnt = (cstate==S4);
assign end_cnt = add_cnt && cnt == TIME_1S;

//200ms计数功能
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_200ms <= 24'd0;
    end 
    else if(add_cnt_200ms)begin 
            if(end_cnt_200ms)begin 
                cnt_200ms <= 24'd0;
            end
            else begin 
                cnt_200ms <= cnt_200ms + 1'd1;
            end 
    end
   else  begin
       cnt_200ms <= 24'd0;
    end
end 

assign add_cnt_200ms =(cstate==S4);
assign end_cnt_200ms = add_cnt_200ms && cnt_200ms == TIME_200MS;

//密码状态切换功能
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cstate <= IDLE;
       
    end 
    else begin
        case (cstate)
            IDLE: begin
                if(key[0])begin//按下第1个按键,输入密码1
                    cstate <= S1;
                end 
                else if(key[1]||key[2]||key[3]) begin//按下其他按键,状态回归
                    cstate <= IDLE;
                end
                else begin
                    cstate <= IDLE;
                end 
            end  
            S1:begin
                if(key[3])begin//按下第4个按键,输入密码4
                    cstate <= S2;
                end 
                else if(key[0]||key[1]||key[2])begin//按下其他按键,状态回归
                    cstate <= IDLE;
                end 
                else begin
                    cstate <= S1;
                end 
            end 
            S2:begin
                if(key[1])begin//按下第2个按键,输入密码2
                    cstate <= S3;
                end 
                else if(key[0]||key[2]||key[3])begin//按下其他按键,状态回归
                    cstate <= IDLE;
                end 
                else begin
                    cstate <= S2;
                end 
            end 
            S3:begin
                if(key[2])begin//按下第3个按键,输入密码3
                    cstate <= S4;
                end 
                else if(key[0]||key[1]||key[3])begin//按下其他按键,状态回归
                    cstate <= IDLE;
                end 
                else begin
                    cstate <= S3;
                end
            end 
            S4: begin//解锁状态
                if(end_cnt)begin//维持1s
                    cstate <= IDLE;//状态回归
                end 
                else begin
                    cstate <= S4;
                end 
            end 
            default:;
        endcase
    end 
end

//led灯功能,根据状态切换
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        led_r <= 4'b0000;
    end 
    else begin
        case(cstate)
            IDLE: led_r <= 4'b0001;
            S1:   led_r <= 4'b0011;
            S2:   led_r <= 4'b0111;
            S3:   led_r <= 4'b1111;
            S4:   begin
                if(end_cnt_200ms)begin
                    led_r <= ~led_r;
                end 
                else begin
                    led_r <= led_r;
                end 
            end 
            default:led_r <= 4'b0000;
        endcase 
    end 
end 
assign led = led_r;
endmodule 
  1. 创建key_debounce.v文件,编写按键消抖代码
module key_debounce
#(
    parameter TIMER_20MS = 20'd1_000_000
)
(
    input clk,
    input rst_n,
    input key_in,

    output key_value,
    output key_flag
);

//将按键值存入一拍
reg key_in_r;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        key_in_r <= 1'b0;
    end
    else begin
        key_in_r <= key_in;
    end
end
//按键消抖
reg [19:0]timer_20ms_r;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        timer_20ms_r <=20'd0;
    end
    else if (key_in == key_in_r && key_in !=1'b1) begin
        if (timer_20ms_r <= TIMER_20MS-1'b1) begin
            timer_20ms_r <= timer_20ms_r +1'b1;
        end
        else begin
            timer_20ms_r <= TIMER_20MS;
        end
    end
    else begin
        timer_20ms_r <= 20'd0;
    end
end
//按键按下标志
wire key_flag_w = (timer_20ms_r == TIMER_20MS - 1'd1) ? 1'b1:1'b0;
//保存当前按键值
reg key_value_r;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        key_value_r <= 1'b0;
    end
    else if (key_flag_w) begin
        key_value_r <= ~key_value_r;
    end
    else key_value_r <= 1'b0;
end
//使能信号输出,延迟一个clk周期
reg key_flag_r;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        key_flag_r <= 1'b0;
    end
    else key_flag_r <= key_flag_w;
end
assign key_flag = key_flag_r;
assign key_value = key_value_r;
endmodule 
  1. 编写digital_lock.v文件,编写电子锁顶层代码
module digital_lock#( parameter TIMER_20MS = 20'd1_000_000,
					  parameter TIME_1S = 26'd49_999_999,
                 	  parameter TIME_200MS = 24'd9_999_999
					)
(
	input wire clk,
	input wire rst_n,
	input wire [3:0] key,
	
	output wire [3:0] led
);
wire [3:0] key_flag;
wire [3:0] key_value;

key_debounce#(TIMER_20MS) key_debounce_u1//实例化按键消抖
(
.clk		(clk),
.rst_n		(rst_n),
.key_in		(key[0]),

.key_value	(key_value[0]),
.key_flag	(key_flag[0])
);
key_debounce#(TIMER_20MS) key_debounce_u2//实例化按键消抖
(
.clk		(clk),
.rst_n		(rst_n),
.key_in		(key[1]),

.key_value	(key_value[1]),
.key_flag	(key_flag[1])
);
key_debounce#(TIMER_20MS) key_debounce_u3//实例化按键消抖
(
.clk		(clk),
.rst_n		(rst_n),
.key_in		(key[2]),

.key_value	(key_value[2]),
.key_flag	(key_flag[2])
);
key_debounce#(TIMER_20MS) key_debounce_u4//实例化按键消抖
(
.clk		(clk),
.rst_n		(rst_n),
.key_in		(key[3]),

.key_value	(key_value[3]),
.key_flag	(key_flag[3])
);
password#(TIME_1S,TIME_200MS)	password_inst(//实例化密码模块
.clk		(clk),
.rst_n		(rst_n),
.key		({(key_flag[3]&&key_value[3]),(key_flag[2]&&key_value[2]),(key_flag[1]&&key_value[1]),(key_flag[0]&&key_value[0])}),
	
.led		(led)
);
endmodule 

四、电子门锁仿真

  1. 创建digital_lock_tb.v文件,编写仿真代码
`timescale  1ns/1ns
module digital_lock_tb();
    parameter CYCLE = 20;
    parameter TIMER_20MS = 4'd9;
    parameter TIME_1S = 4'd9;
    parameter TIME_200MS = 4'd9;

    reg clk;
    reg rst_n;
    reg [3:0] key;
    wire [3:0] led;

    always #(CYCLE/2) clk = ~clk;
    initial begin
        clk = 1'b0             ;
        rst_n = 1'b0           ;
        #(CYCLE)               ;
        rst_n = 1'b1           ;
        key = 4'b1101          ;
        #(CYCLE*(TIME_1S+1))   ;
        key = 4'b1110          ;
        #(CYCLE*(TIME_1S+1))   ;
        key = 4'b0111          ;
        #(CYCLE*(TIME_1S+1))   ;
        key = 4'b1101          ;
        #(CYCLE*(TIME_1S+1))   ;
        key = 4'b1011          ;
        #(CYCLE*(TIME_1S+1)*10);
        $stop                  ;
    end
    digital_lock#(TIMER_20MS,TIME_1S,TIME_200MS)    digital_lock_inst(
    .clk    (clk),
    .rst_n  (rst_n),
    .key    (key),
        
    .led    (led)
    );
endmodule 
  1. 仿真结果

在这里插入图片描述

五、运行效果

电子门锁模拟

总结

  电子门锁其实在状态机中提到过,可能同学们也只是听听原理,但是极少同学会去使用FPGA实现。实践是检验真理的唯一标准,懂的人很多,做的人很少。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值