状态机实现电子门锁

一.功能描述

  • 设计密码为1234的电子门锁,4个按键分别对应密码的四个位,例如key[0]表示密码第一位,每按下一次该位加一。按错需要蜂鸣器响并回到初态。输入对密码led灯0.3s闪烁。

二.模块图

在这里插入图片描述

三.状态转移图

在这里插入图片描述

四.设计思路

  • 状态空间设置初始状态IDLE,对了一位的状态RIGHT_1,对了两位的状态RIGHT_2,对了三位的状态RIGHT_3,对了四位的状态RIGHT_4和错误状态。
  • 动作空间,IDLE状态灯全灭,RIGHT_1状态灯亮1个,RIGHT_2状态灯亮2个,RIGHT_3状态灯亮3个,RIGHT_4状态灯0.3s从1111-0000闪烁,WRONG状态蜂鸣器响。
  • 设置计数器,分别计算按键按下的次数。
  • 状态转移条件:IDLE_RIGHT_1按键key[0]按下1次,RIGHT_1_RIGHT_2按键key[1]按下2次,RIGHT_2_RIGHT_3按键key[2]按下3次,RIGHT_3_RIGHT_4按键key[3]按下4次。RIGHT_4_IDLE这里我设置按下key[1]返回IDLE。IDLE_WRONG,RIGHT_1_WRONG,RIGHT_2_WRONG,RIGHT_3_WRONG分别是该状态下出错的情况。WRONG_IDLE为计满0.5s。
  • 0.5s计数器从WRONG状态开始计数,当回到IDLE态停止计数。0.3s计数器从RIGHT_4状态开始计数

五.代码

  • key_debounce
/**************************************功能介绍***********************************
Date	: 2023年7月28日14:30:48
Author	: Alegg xy.
Version	: 1.0
Description: 四位按键消抖模块
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module key_debounce #(parameter   WIDTH = 4,
                      parameter   DELAY_20MS = 1000_000
)( 
    input				           clk		,
    input				           rst_n	,
    input		   [WIDTH-1:0]     key_in	,
    output         [WIDTH-1:0]     key_out   
);								 
//---------<参数定义>--------------------------------------------------------- 
    
    reg [WIDTH-1:0] key_out_r;
    //状态机参数定义
    localparam  IDLE         = 4'b0001,//空闲状态
                FILETER_DOWN = 4'b0010,//按键按下抖动状态
                HOLD_DOWN    = 4'b0100,//按下稳定按下状态
                FILTER_UP    = 4'b1000;//按键释放抖动状态
    
//---------<内部信号定义>-----------------------------------------------------
    reg 	[3:0]	        cstate     ;//现态
    reg	    [3:0]	        nstate     ;//次态

    reg     [WIDTH-1:0]     key_r0      ;//同步打拍
    reg     [WIDTH-1:0]     key_r1      ;
    reg     [WIDTH-1:0]     key_r2      ;
    wire    [WIDTH-1:0]     n_edge      ;//下降沿
    wire    [WIDTH-1:0]     p_edge      ;//上升沿  

    reg		[19:0]	        cnt_20ms	;//20ms计数器
    wire				    add_cnt_20ms;
    wire				    end_cnt_20ms;

    //状态转移条件定义
    wire            idle2filter_down        ;
    wire            fiter_down2hold_down    ;
    wire            hold_down2filter_up     ;
    wire            filter_up2idle          ;

//****************************************************************
//--cstate
//****************************************************************
    //第一段:时序逻辑描述状态转移
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cstate <= IDLE;//复位的初始状态
        end 
        else begin 
            cstate <= nstate;
        end 
    end
    
    //第二段:组合逻辑描述状态转移规律和状态转移条件
    always @(*) begin
        case(cstate)
            IDLE         : begin 
                if(idle2filter_down)begin 
                    nstate = FILETER_DOWN;
                end
                else begin
                    nstate = cstate;
                    // state_n = IDLE;
                end
            end
            FILETER_DOWN : begin 
                if(fiter_down2hold_down)begin 
                    nstate = HOLD_DOWN;
                end
                else begin
                    nstate = cstate;
                end
            end
            HOLD_DOWN    : begin 
                if(hold_down2filter_up)begin 
                    nstate = FILTER_UP;
                end
                else begin
                    nstate = cstate;
                end
            end
            FILTER_UP    : begin 
                if(filter_up2idle)begin 
                    nstate = IDLE;
                end
                else begin
                    nstate = cstate;
                end
            end
            default : nstate = IDLE;
        endcase
    end

    assign idle2filter_down     = cstate == IDLE         && n_edge;
    assign fiter_down2hold_down = cstate == FILETER_DOWN && end_cnt_20ms;
    assign hold_down2filter_up  = cstate == HOLD_DOWN    && p_edge;
    assign filter_up2idle       = cstate == FILTER_UP    && end_cnt_20ms;
                
//****************************************************************
//--n_edge、p_edge 
//****************************************************************
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            key_r0 <= {WIDTH{1'b1}};
            key_r1 <= {WIDTH{1'b1}};
            key_r2 <= {WIDTH{1'b1}};
        end 
        else begin 
            key_r0 <= key_in;
            key_r1 <= key_r0;
            key_r2 <= key_r1;
        end 
    end      
          
    assign n_edge = ~key_r1 & key_r2;
    assign p_edge = ~key_r2 & key_r1;          
    
//****************************************************************
//--cnt_20ms
//****************************************************************
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_20ms <= 'd0;
        end 
        else if(add_cnt_20ms)begin 
            if(end_cnt_20ms)begin 
                cnt_20ms <= 'd0;
            end
            else begin 
                cnt_20ms <= cnt_20ms + 1'b1;
            end 
        end
    end 
    
    assign add_cnt_20ms = cstate == FILETER_DOWN || cstate == FILTER_UP;
    assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == DELAY_20MS - 1;
    
//****************************************************************
//--key_out
//****************************************************************
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            key_out_r <= 'd0;
        end 
        else if(hold_down2filter_up)begin 
            key_out_r <= ~key_r2;
        end 
        else begin 
            key_out_r <= 'd0;
        end 
    end
    
    assign key_out = key_out_r;
endmodule
  • lock_ctrl
/**************************************功能介绍***********************************
Date	: 2023年7月28日14:30:56
Author	: Alegg xy.
Version	: 1.0
Description: 控制密码锁
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module lock_ctrl( 
    input				clk		,
    input				rst_n	,
    input		[3:0]	key		,
    output              beep    ,
    output		[3:0]	led	
);								 
//---------<参数定义>--------------------------------------------------------- 
    parameter MAX_300ms = 24'd15_000_000;//0.3s
    parameter MAX = 26'd25_000_000;//0.5s
    parameter MAX_TIME = 4'd9;
//---------<内部信号定义>-----------------------------------------------------
    reg [3:0] led_r;
    reg [3:0] beep_r;
    //状态空间
    localparam  IDLE        = 3'd1,//初始状态
                RIGHT_1     = 3'd2,//对了一位状态
                RIGHT_2     = 3'd3,//对了两位状态
                RIGHT_3     = 3'd4,//对了三位状态
                RIGHT_4     = 3'd5,//全对状态
                WRONG       = 3'd6;//出错状态
    
    reg 	[2:0]	cstate     ;//现态
    reg	    [2:0]	nstate     ;//次态
    

    //0.5s计数器
    reg			[25:0]	cnt	   	;
    wire				add_cnt	;
    wire				end_cnt	;
    
    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'b1;
            end 
        end
    end 
    
    assign add_cnt = cstate == WRONG;
    assign end_cnt = add_cnt && cnt == MAX - 1'd1;
    

    //0.3s计数器
    reg			[26:0]	cnt_300ms	   	;
    wire				add_cnt_300ms	;
    wire				end_cnt_300ms	;
    
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_300ms <= 'd0;
        end 
        else if(add_cnt_300ms)begin 
            if(end_cnt_300ms)begin 
                cnt_300ms <= 26'd0;
            end
            else begin 
                cnt_300ms <= cnt_300ms + 1'b1;
            end 
        end
    end 
    
    assign add_cnt_300ms = cstate == RIGHT_4;
    assign end_cnt_300ms = add_cnt_300ms && cnt_300ms == MAX_300ms - 1'd1;
    
    //状态转移条件
    //成功
    wire IDLE_RIGHT_1   ;
    wire RIGHT_1_RIGHT_2;
    wire RIGHT_2_RIGHT_3;
    wire RIGHT_3_RIGHT_4;
    wire RIGHT_4_IDLE   ;
    //失败回到WRONG
    wire IDLE_WRONG      ;
    wire RIGHT_1_WRONG   ;
    wire RIGHT_2_WRONG   ;
    wire RIGHT_3_WRONG   ;
    wire WRONG_IDLE      ;


    //key_in[0]计数器
    reg [3:0] cnt_key0;
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cnt_key0 <= 'd0;
        end 
        else if(key[0] && cnt_key0 <= MAX_TIME)begin 
            cnt_key0 <= cnt_key0 + 1'd1;
        end
        else if(cstate == IDLE)begin
            cnt_key0 <= 1'd0;
        end 
        else begin 
            cnt_key0 <= cnt_key0;
        end 
    end

    //key_in[1]计数器
    reg [3:0] cnt_key1;
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cnt_key1 <= 'd0;
        end 
        else if(key[1] && cnt_key1 <= MAX_TIME)begin 
            cnt_key1 <= cnt_key1 + 1'd1;
        end
        else if(cstate == IDLE)begin
            cnt_key1 <= 1'd0;
        end  
        else begin 
            cnt_key1 <= cnt_key1;
        end 
    end

    //key_in[2]计数器
    reg [3:0] cnt_key2;
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cnt_key2 <= 'd0;
        end 
        else if(key[2] && cnt_key2 <= MAX_TIME)begin 
            cnt_key2 <= cnt_key2 + 1'd1;
        end
        else if(cstate == IDLE)begin
            cnt_key2 <= 1'd0;
        end  
        else begin 
            cnt_key2 <= cnt_key2;
        end 
    end

    //key_in[3]计数器
    reg [3:0] cnt_key3;
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cnt_key3 <= 'd0;
        end 
        else if(key[3] && cnt_key3 <= MAX_TIME)begin 
            cnt_key3 <= cnt_key3 + 1'd1;
        end
        else if(cstate == IDLE)begin
            cnt_key3 <= 1'd0;
        end  
        else begin 
            cnt_key3 <= cnt_key3;
        end 
    end

    assign IDLE_RIGHT_1    =  cstate == IDLE && cnt_key0 == 1   ; 
    assign RIGHT_1_RIGHT_2 =  cstate == RIGHT_1 && cnt_key1 == 2;
    assign RIGHT_2_RIGHT_3 =  cstate == RIGHT_2 && cnt_key2 == 3;
    assign RIGHT_3_RIGHT_4 =  cstate == RIGHT_3 && cnt_key3 == 4;
    assign RIGHT_4_IDLE    =  cstate == RIGHT_4 && key[1]       ;
    
    assign IDLE_WRONG    = (cstate == IDLE   ) && (key[1] || key[2] || key[3]);
    assign RIGHT_1_WRONG = (cstate == RIGHT_1) && (cnt_key1 < 2) && (key[0] || key[2] || key[3]);
    assign RIGHT_2_WRONG = (cstate == RIGHT_2) && (cnt_key2 < 3) && (key[0] || key[1] || key[3]);
    assign RIGHT_3_WRONG = (cstate == RIGHT_3) && (cnt_key3 < 4) && (key[0] || key[1] || key[2]);
    assign WRONG_IDLE    =  end_cnt;

    //第一段:时序逻辑描述状态转移
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cstate <= IDLE;
        end 
        else begin 
            cstate <= nstate;
        end 
    end
    
    //第二段:组合逻辑描述状态转移规律和状态转移条件
    always @(*) begin
        case(cstate)
            IDLE    :begin
                if (IDLE_RIGHT_1) begin
                    nstate = RIGHT_1;
                end
                else if(IDLE_WRONG) begin
                    nstate = WRONG;
                end
                else begin
                    nstate = cstate;
                end
            end 
            RIGHT_1 :begin
                if (RIGHT_1_RIGHT_2) begin
                    nstate = RIGHT_2;
                end
                else if(RIGHT_1_WRONG) begin
                    nstate = WRONG;
                end
                else begin
                    nstate = cstate;
                end
            end 
            RIGHT_2 :begin
                if (RIGHT_2_RIGHT_3) begin
                    nstate = RIGHT_3;
                end
                else if(RIGHT_2_WRONG) begin
                    nstate = WRONG;
                end
                else begin
                    nstate = cstate;
                end
            end 
            RIGHT_3 :begin
                if (RIGHT_3_RIGHT_4) begin
                    nstate = RIGHT_4;
                end
                else if(RIGHT_3_WRONG) begin
                    nstate = WRONG;
                end
                else begin
                    nstate = cstate;
                end
            end 
            RIGHT_4 :begin
                if (RIGHT_4_IDLE) begin
                    nstate = IDLE;
                end
                else begin
                    nstate = RIGHT_4;
                end
            end
            WRONG  :begin
                if (WRONG_IDLE) begin
                    nstate = IDLE;
                end
                else begin
                    nstate = WRONG;
                end
            end 
            default : nstate = IDLE;
        endcase
    end

    reg [3:0] led_r0;
    //每0.3s从1111-0000闪烁的灯
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            led_r0 <= 4'b1111;
        end
        else if (end_cnt_300ms) begin
            led_r0 <= ~led_r0;
        end
        else begin
            led_r0 <= led_r0;
        end
    end

    //控制beep
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            beep_r <= 1'b1;
        end
        else if(cstate == WRONG) begin
            beep_r <= 1'b0;
        end
        else begin
            beep_r <= 1'b1;
        end
    end
    
    //第三段:描述输出,时序逻辑或组合逻辑皆可
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            led_r <= 4'd0000;
        end 
        else begin 
            case (cstate)
                IDLE       :led_r <= 4'b0000;
                RIGHT_1    :led_r <= 4'b0001;
                RIGHT_2    :led_r <= 4'b0011;
                RIGHT_3    :led_r <= 4'b0111;
                RIGHT_4    :led_r <= led_r0;
                default: led_r <= 4'b0000;
            endcase
        end 
    end
    assign led = led_r;  
    assign beep = beep_r;            
endmodule
  • top_fsm_lock
/**************************************功能介绍***********************************
Date	: 2023年7月28日15:14:23
Author	: Alegg xy.
Version	: 1.0
Description: 顶层模块
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module top_fsm_lock( 
    input				clk		,
    input				rst_n	,
    input		[3:0]	key_in	,
    output              beep    ,
    output		[3:0]	led	    
);								 
//---------<参数定义>--------------------------------------------------------- 
    wire [3:0] key_link;
    key_debounce u_key_debounce(
        .clk		(clk),
        .rst_n	    (rst_n),
        .key_in	    (key_in),
        .key_out    (key_link)
    );
    
    lock_ctrl u_lock_ctrl(
        .clk		(clk),
        .rst_n	    (rst_n),
        .key		(key_link),
        .beep       (beep),
        .led	    (led)
    );
    
endmodule

六.引脚配置

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值