99在线精品免费视频九九视-99在线精品视频-99在线精品视频免费观里-99在线精品视频在线观看-99在线免费播放



官方論壇
官方淘寶
官方博客
微信公眾號(hào)
點(diǎn)擊聯(lián)系吳工 點(diǎn)擊聯(lián)系周老師

【案例】電子密碼鎖設(shè)計(jì)

發(fā)布時(shí)間:2023-04-13   作者:admin 瀏覽量:


至簡(jiǎn)設(shè)計(jì)系列_電子密碼鎖


--作者:肖肖肖

--案例作者:WB_Yih


本文為明德?lián)P原創(chuàng)及錄用文章,轉(zhuǎn)載請(qǐng)注明出處!

1.1 總體設(shè)計(jì)

1.1.1 概述

隨著生活質(zhì)量的不斷提高,加強(qiáng)家庭防盜安全變得非常重要,但傳統(tǒng)機(jī)械鎖的構(gòu)造過于簡(jiǎn)單,很容易被打開,從而降低了安全性。數(shù)字密碼鎖因?yàn)樗谋C苄院芨撸踩禂?shù)也非常高,再加上其不需要攜帶避免了丟失的可能,省去了因鑰匙丟失而需要換鎖的麻煩,受到了越來越多的人的歡迎。隨看人們對(duì)高科技產(chǎn)品也越來越推崇,在當(dāng)今社會(huì)科技的高度集中和創(chuàng)新,人們對(duì)日常生活中保護(hù)自身及財(cái)產(chǎn)安全的物品非常追捧,對(duì)其安全性的要求也非常的高。為了達(dá)到人們對(duì)鎖具安全性的高要求,加強(qiáng)鎖具的安全保密性,用密碼鎖來取代傳統(tǒng)機(jī)械鎖的鎖具是必然趨勢(shì)。數(shù)字密碼鎖比傳統(tǒng)機(jī)械鎖具更加的安全。在本案例的設(shè)計(jì)過程中,應(yīng)用了至簡(jiǎn)設(shè)計(jì)法、狀態(tài)機(jī)模板應(yīng)用等,在經(jīng)過逐步改進(jìn)、調(diào)試等一系列工作之后,最終達(dá)到了設(shè)計(jì)目標(biāo)。


基于明德?lián)P至簡(jiǎn)設(shè)計(jì)法和明德?lián)P設(shè)計(jì)規(guī)范,設(shè)計(jì)一個(gè)基于FPGA的密碼鎖、并將數(shù)值顯示在數(shù)碼管上,然后根據(jù)輸入的鍵值判斷密碼是否正確。


1.1.2 設(shè)計(jì)目標(biāo)

實(shí)現(xiàn)電子密碼鎖的功能,具體功能要求如下:

1. 密碼4位,初始密碼2345。

2. 密碼鎖狀態(tài):LOCKED和OPEN,初始狀態(tài)為L(zhǎng)OCKED。

1) 當(dāng)在LOCKED狀態(tài)時(shí),連續(xù)兩次輸入正確密碼,狀態(tài)變?yōu)镺PEN狀態(tài)。當(dāng)輸入錯(cuò)誤密碼時(shí)(包括第一次就輸入錯(cuò)誤;或者第一次輸入正確,第二次輸入錯(cuò)誤的情況),數(shù)碼管顯示ERROR 2秒后重新顯示原來的狀態(tài)(LOCKED)。

2) 當(dāng)在OPEN狀態(tài)時(shí),一次輸入錯(cuò)誤密碼,狀態(tài)變?yōu)長(zhǎng)OCKED狀態(tài)。當(dāng)輸入正確密碼時(shí),數(shù)碼管無顯示,10秒后重新顯示原來的狀態(tài)(OPEN)。

3) 不管在何狀態(tài),當(dāng)輸入4位密碼或者某幾位密碼,但未按下確認(rèn)鍵,并超過10S時(shí),返回原來的狀態(tài)。(即輸入密碼超時(shí),返回原狀態(tài))


對(duì)于點(diǎn)撥開發(fā)板,使用矩陣按鍵輸入(本文以點(diǎn)撥603開發(fā)板為例)。

對(duì)于Mp801開發(fā)板,密碼顯示及確認(rèn):無論在OPEN,還是LOCKED狀態(tài)下,均可以通過撥碼開關(guān)輸入密碼。當(dāng)有撥碼開關(guān)撥動(dòng)時(shí),數(shù)碼管當(dāng)前顯示的OPEN或LOCKED消失,并顯示當(dāng)前輸入的密碼,暫未輸入的密碼位不顯示。4位密碼輸入完畢后,再撥動(dòng)撥碼開關(guān)時(shí)視為無效輸入,當(dāng)前顯示的密碼不改變。4位密碼輸入完畢后,按下確認(rèn)鍵后,系統(tǒng)判斷密碼是否正確。


撥碼開關(guān)及按鍵:初始狀態(tài)下,撥碼開關(guān)全部往下?lián)堋.?dāng)撥碼開關(guān)向上撥后,再向下?lián)埽ɑ氐匠跏紶顟B(tài)),表示一個(gè)數(shù)字的有效輸入。按鍵每按下一次(會(huì)自動(dòng)彈起),為一次有效輸入(復(fù)位/確認(rèn))。



1.1.3 系統(tǒng)結(jié)構(gòu)框圖

系統(tǒng)結(jié)構(gòu)框圖如下圖所示:

「每周FPGA案例」電子密碼鎖設(shè)計(jì)


1.1.4模塊功能按鍵檢測(cè)模塊實(shí)現(xiàn)功能

1、 檢測(cè)按鍵的數(shù)值


控制模塊實(shí)現(xiàn)功能

1、 對(duì)接收到的按鍵數(shù)值進(jìn)行判斷和控制對(duì)應(yīng)的密碼鎖狀態(tài),實(shí)現(xiàn)對(duì)輸入密碼的正誤判斷和對(duì)密碼鎖的開啟和閉合控制。


數(shù)碼管顯示模塊實(shí)現(xiàn)功能

1、 顯示輸入的密碼數(shù)值;

2、 顯示當(dāng)前密碼鎖的狀態(tài)(開啟狀態(tài)或者閉鎖狀態(tài));

3、 提示密碼輸入錯(cuò)誤的狀態(tài)。


1.1.5頂層信號(hào)


1.1.6參考代碼

下面是使用工程的頂層代碼:


module top_mdyPwdlock_keyscan(
    clk             ,   
    rst_n           ,   

    key_col         ,
    key_row         ,

    seg_sel         ,  
    segment            
    
    );

    input               clk                 ;
    input               rst_n               ;
    input [3:0]         key_col             ;

    output[5:0]         seg_sel             ;
    output[7:0]         segment             ;
    output[3:0]         key_row             ;

    wire  [5:0]         seg_sel             ;
    wire  [7:0]         segment             ;
    wire  [3:0]         key_row             ;

    wire  [3:0]         key_out             ;
    wire                key_vld             ;
    wire  [6*5-1:0]     seg_dout            ;
    wire  [5:0]         seg_dout_vld        ;

    
   
    key_scan u_key_scan(
        .clk                (clk           ),        
        .rst_n              (rst_n         ),     
        .key_col            (key_col       ),
        .key_row            (key_row       ),
        .key_out            (key_out       ),
        .key_vld            (key_vld       )
    );


    control u_ctrl(
        .clk                (clk            ),       
        .rst_n              (rst_n          ),       
                                      
        .key_num            (key_out        ),       
        .key_vld            (key_vld        ),       
                                      
        .seg_dout           (seg_dout       ),       
        .seg_dout_vld       (seg_dout_vld   )        
    );

    seg_display u_segment(
        .clk                (clk            ),       
        .rst_n              (rst_n          ),       

        .din                (seg_dout       ),       
        .din_vld            (seg_dout_vld   ),      

        .segment            (segment        ),       
        .seg_sel            (seg_sel        )        
    );

    endmodule


1.2.1接口信號(hào)


1.2.2 設(shè)計(jì)思路

在前面的案例中已經(jīng)有矩陣按鍵檢測(cè)模塊的介紹,所以這里不在過多介紹,詳細(xì)介紹請(qǐng)看下方鏈接:

http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=310&highlight=%BE%D8%D5%F3

其中,按鍵的功能面板如下圖所示:



1.2.3參考代碼

module  key_scan(
                 clk    ,
                 rst_n  ,
                 key_col,
                 key_row,
                 key_out,
                 key_vld   
               );

    parameter      KEY_W  =         4 ;
    parameter      CHK_COL  =   0 ;
    parameter      CHK_ROW  =   1 ;
    parameter      DELAY    =   2 ;
    parameter      WAIT_END =   3 ;
    parameter      COL_CNT  =   16;
    parameter      TIME_20MS=   1000000;

    input               clk    ;
    input               rst_n  ;
    input  [3:0]        key_col;

    output              key_vld;
    output[3:0]         key_out;
    output[KEY_W-1:0]   key_row;

    reg   [3:0]         key_out;
    reg   [KEY_W-1:0]   key_row;
    reg                 key_vld;


    reg [3:0]           key_col_ff0;
    reg [3:0]           key_col_ff1;
    reg [1:0]           key_col_get;
    wire                shake_flag ;
    reg                 shake_flag_ff0;
    reg[3:0]            state_c;
    reg [19:0]          shake_cnt;
    reg[3:0]            state_n;
    reg [1:0]           row_index;
    reg[15:0]           row_cnt;
    wire                chk_col2chk_row ; 
    wire                chk_row2delay   ;
    wire                delay2wait_end  ;
    wire                wait_end2chk_col;


always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        key_col_ff0 <= 4'b1111;
        key_col_ff1 <= 4'b1111;
    end
    else begin
        key_col_ff0 <= key_col    ;
        key_col_ff1 <= key_col_ff0;
    end
end


wire        add_shake_cnt ;
always @(posedge clk or negedge rst_n) begin 
    if (rst_n==0) begin
        shake_cnt <= 0; 
    end
    else if(add_shake_cnt) begin
        if(shake_flag)
            shake_cnt <= 0; 
        else
            shake_cnt <= shake_cnt+1 ;
   end
end
assign add_shake_cnt = key_col_ff1!=4'hf;
assign shake_flag = add_shake_cnt  && shake_cnt == TIME_20MS-1 ;

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        state_c <= CHK_COL;
    end
    else begin
        state_c <= state_n;
    end
end

always  @(*)begin
    case(state_c)
        CHK_COL: begin
                     if(shake_flag && shake_flag_ff0==1'b0)begin
                         state_n = CHK_ROW;
                     end
                     else begin
                         state_n = CHK_COL;
                     end
                 end
        CHK_ROW: begin
                     if(row_index==3 && row_cnt==0)begin
                         state_n = DELAY;
                     end
                     else begin
                         state_n = CHK_ROW;
                     end
                 end
        DELAY :  begin
                     if(row_cnt==0)begin
                         state_n = WAIT_END;
                     end
                     else begin
                         state_n = DELAY;
                     end
                 end
        WAIT_END: begin
                     if(key_col_ff1==4'hf)begin
                         state_n = CHK_COL;
                     end
                     else begin
                         state_n = WAIT_END;
                     end
                  end
       default: state_n = CHK_COL;
    endcase
end

assign chk_col2chk_row = shake_flag && shake_flag_ff0 ==1'b0;
assign chk_row2delay   = row_index==3 && row_cnt==0;
assign delay2wait_end  = row_cnt==0;
assign wait_end2chk_col= key_col_ff1==4'hf;

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        key_row <= 4'b0;
    end
    else if(state_c==CHK_ROW)begin
        key_row <= ~(1'b1 << row_index);
    end
    else begin
        key_row <= 4'b0;
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        row_index <= 0;
    end
    else if(state_c==CHK_ROW)begin
       if(row_cnt==0)begin
           if(row_index==3)
               row_index <= 0;
           else
               row_index <= row_index + 1;
       end
    end
    else begin
        row_index <= 0;
    end
end


wire        add_row_cnt ;
wire        end_row_cnt ;
always @(posedge clk or negedge rst_n) begin 
    if (rst_n==0) begin
        row_cnt <= COL_CNT; 
    end
    else if(add_row_cnt) begin
        if(end_row_cnt)
            row_cnt <= COL_CNT; 
        else
            row_cnt <= row_cnt-1 ;
   end
   else begin
       row_cnt <= COL_CNT;
   end
end
assign add_row_cnt = state_c==CHK_ROW || state_c==DELAY;
assign end_row_cnt = add_row_cnt  && row_cnt == 0 ;



always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        shake_flag_ff0 <= 1'b0;
    end
    else begin
        shake_flag_ff0 <= shake_flag;
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        key_col_get <= 0;
    end
    else if(state_c==CHK_COL && shake_flag==1'b1 && shake_flag_ff0==1'b0) begin
        if(key_col_ff1==4'b1110)
            key_col_get <= 0;
        else if(key_col_ff1==4'b1101)
            key_col_get <= 1;
        else if(key_col_ff1==4'b1011)
            key_col_get <= 2;
        else 
            key_col_get <= 3;
    end
end


always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        key_out <= 0;
    end
    else if(state_c==CHK_ROW && row_cnt==0)begin
        key_out <= {row_index,key_col_get};
    end
    else begin
        key_out <= 0;
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        key_vld <= 1'b0;
    end
    else if(state_c==CHK_ROW && row_cnt==0 && key_col_ff1[key_col_get]==1'b0)begin
        key_vld <= 1'b1;
    end
    else begin
        key_vld <= 1'b0;
    end
end

endmodue


1.3 控制模塊設(shè)計(jì)

1.3.1接口信號(hào)


1.3.2設(shè)計(jì)思路

  • 狀態(tài)機(jī)架構(gòu)

本模塊的主要功能是根據(jù)輸入的按鍵信息進(jìn)行不同狀態(tài)的判斷和切換當(dāng)前工作狀態(tài)。根據(jù)項(xiàng)目功能要求,一共有四種工作狀態(tài):密碼鎖開啟狀態(tài)(open)、密碼鎖閉合狀態(tài)(clocked)、輸入密碼狀態(tài)(password)和提示輸入錯(cuò)誤狀態(tài)(error)。

以下為本模塊的狀態(tài)跳轉(zhuǎn)圖:


復(fù)位后,狀態(tài)機(jī)進(jìn)入LOCKED的狀態(tài),即初始狀態(tài)為L(zhǎng)OCKED;

在LOCKED狀態(tài)下:

A. 有按鍵按下,跳到PASSWORD狀態(tài);

B. 否則,保持LOCKED狀態(tài)不變;

在OPEN狀態(tài)下:

A. 有按鍵按下,跳到PASSWORD狀態(tài);

B. 否則,保持OPEN狀態(tài)不變;

在PASSWORD狀態(tài)下:

A. 有密碼輸入但超過10秒沒有確認(rèn),跳到原來的LOCKED狀態(tài)或者OPEN狀態(tài);

B. 密碼正確輸入并確認(rèn)兩次,跳到OPEN狀態(tài);

C. 密碼錯(cuò)誤輸入并確認(rèn),跳到ERROR狀態(tài);

D. 否則,保持PASSWORD狀態(tài)不變;

在ERROR狀態(tài)下:

A. 提示輸入錯(cuò)誤2秒,跳到LOCKED狀態(tài);

B. 否則,保持ERROR狀態(tài)不變;

無論當(dāng)前處于什么狀態(tài),只要不滿足狀態(tài)間的跳轉(zhuǎn)條件就跳到LOCKED狀態(tài)。

  • 計(jì)數(shù)器架構(gòu)

本模塊的某些狀態(tài)跳轉(zhuǎn)之間存在一定的時(shí)間間隔,根據(jù)項(xiàng)目功能要求,一共有兩種時(shí)間的間隔:10秒的等待輸入時(shí)間間隔和2秒的顯示提示時(shí)間間隔。

以下為計(jì)數(shù)器的架構(gòu)示意圖:


10秒計(jì)數(shù)器cnt_10s_nvld:用于計(jì)算10秒的時(shí)間。加一條件為state_c==PASSWORD,表示進(jìn)入密碼輸入狀態(tài)就開始計(jì)數(shù)。結(jié)束條件為數(shù)500_000_000個(gè),系統(tǒng)時(shí)鐘為50M,一個(gè)時(shí)鐘周期為20ns,500_000_000個(gè)時(shí)鐘周期就是10秒。

2秒計(jì)數(shù)器cnt_2s:用于計(jì)算2秒的時(shí)間。加一條件為state_c==ERROR,表示進(jìn)入提示輸入錯(cuò)誤狀態(tài)就開始計(jì)數(shù)。結(jié)束條件為數(shù)100_000_000個(gè),系統(tǒng)時(shí)鐘為50M,一個(gè)時(shí)鐘周期為20ns,100_000_000個(gè)時(shí)鐘周期就是2秒。



1.3.3參考代碼

module control(
    clk             ,
    rst_n           ,

    key_num         ,
    key_vld         ,

    seg_dout        , 
    seg_dout_vld     
    
    );

    parameter PASSWORD_INI     = 16'h2345    ; 
    parameter CHAR_O           = 5'h10       ; 
    parameter CHAR_P           = 5'h11       ; 
    parameter CHAR_E           = 5'h12       ; 
    parameter CHAR_N           = 5'h13       ; 
    parameter CHAR_L           = 5'h14       ; 
    parameter CHAR_C           = 5'h15       ; 
    parameter CHAR_K           = 5'h16       ; 
    parameter CHAR_D           = 5'h17       ; 
    parameter CHAR_R           = 5'h18       ; 
    parameter NONE_DIS         = 5'h1F       ; 

    parameter C_10S_WID        = 29          ;
    parameter C_10S_NUM        = 500_000_000 ;
    parameter C_2S_WID         = 27          ;
    parameter C_2S_NUM         = 100_000_000 ;
    parameter C_PWD_WID        = 3           ;

    input               clk                 ;
    input               rst_n               ;
    input [3:0]         key_num             ;
    input               key_vld             ;

    output[6*5-1:0]     seg_dout            ;
    output[5:0]         seg_dout_vld        ;

    reg   [6*5-1:0]     seg_dout            ;
    wire  [5:0]         seg_dout_vld        ;

    reg   [1:0]         state_c             ;
    reg   [1:0]         state_n             ;
    reg                 lock_stata_flag     ;
    reg                 password_correct_twice  ;
    
    reg   [C_2S_WID-1:0]    cnt_2s          ; 
    reg   [C_10S_WID-1:0]   cnt_10s_nvld    ;
    reg   [C_PWD_WID-1:0]   cnt_password    ;

    reg   [15:0]            password        ;

    
    parameter LOCKED    = 2'b00             ;
    parameter OPEN      = 2'b01             ;
    parameter PASSWORD  = 2'b10             ;
    parameter ERROR     = 2'b11             ;

    //current state
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            state_c <= LOCKED;
        end
        else begin
            state_c <= state_n;
        end
    end

    //next state and the condition of state LOCKEDtransition
    always@(*)begin
        case(state_c)
            LOCKED:begin
                if(locked2password_switch)begin
                    state_n = PASSWORD;
                end
                else begin
                    state_n = state_c;
                end
            end
            OPEN:begin
                if(open2password_switch)begin
                    state_n = PASSWORD;
                end
                else begin
                    state_n = state_c;
                end
            end            
            PASSWORD:begin
                if(password2locked_switch0)begin
                    state_n = LOCKED;
                end
                else if(password2open_switch0 || password2open_switch1)begin
                    state_n = OPEN;
                end
                else if(password2error_switch || password2locked_switch1)begin
                    state_n = ERROR;
                end
                else begin
                    state_n = state_c;
                end
            end
            ERROR:begin
                if(error2locked_switch0 )begin
                    state_n = LOCKED;
                end
                else begin
                    state_n = state_c;
                end
            end
            default:begin
                state_n = LOCKED;
            end
        endcase
    end
    assign locked2password_switch    = state_c==LOCKED   &&  lock_stata_flag && key_num<10 && key_vld;
    assign open2password_switch      = state_c==OPEN     && !lock_stata_flag && key_num<10 && key_vld;
    assign password2locked_switch0   = state_c==PASSWORD &&  lock_stata_flag && end_cnt_10s_nvld;
    assign password2locked_switch1   = state_c==PASSWORD &&  lock_stata_flag && confirm && password!=PASSWORD_INI ;//TO ERROR
    assign password2open_switch0     = state_c==PASSWORD &&  lock_stata_flag && confirm && password==PASSWORD_INI &&  password_correct_twice;
    assign password2open_switch1     = state_c==PASSWORD && !lock_stata_flag && end_cnt_10s_nvld;
    assign password2error_switch     = state_c==PASSWORD && !lock_stata_flag && confirm && password!=PASSWORD_INI;
    assign error2locked_switch0      = state_c==ERROR    &&  end_cnt_2s;


    //lock_stata_flag
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            lock_stata_flag <= 1;
        end
        else if(password2locked_switch0 || password2locked_switch1 || error2locked_switch0)begin
            lock_stata_flag <= 1;
        end
        else if(password2open_switch0 || password2open_switch1 )begin
            lock_stata_flag <= 0;
        end
    end

    //cnt_10s_nvld
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            cnt_10s_nvld <= 0;
        end
        else if(end_cnt_10s_nvld)begin
            cnt_10s_nvld <= 0;
        end
        else if(add_cnt_10s_nvld)begin
            cnt_10s_nvld <= cnt_10s_nvld + 1;
        end
    end
    assign add_cnt_10s_nvld = state_c==PASSWORD;
    assign end_cnt_10s_nvld = add_cnt_10s_nvld && cnt_10s_nvld==C_10S_NUM-1;

    //confirm
    assign confirm = key_num==10 && key_vld;

    //password_correct_twice    
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            password_correct_twice <= 0;
        end
        else if(state_c==PASSWORD && lock_stata_flag && confirm && password==PASSWORD_INI && !password_correct_twice)begin
            password_correct_twice <= 1;
        end
        else if(password2locked_switch0 || password2locked_switch1 || password2open_switch0 || password2open_switch1 || password2error_switch)begin
            password_correct_twice <= 0;
        end
    end

    //cnt_2s
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            cnt_2s <= 0;
        end
        else if(end_cnt_2s )begin
            cnt_2s <= 0;
        end
        else if(add_cnt_2s )begin
            cnt_2s <= cnt_2s + 1;
        end
    end
    assign add_cnt_2s = state_c==ERROR;
    assign end_cnt_2s = add_cnt_2s && cnt_2s==C_2S_NUM-1;



    //seg_dout
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            seg_dout <= 0;
        end
        else if(state_c==OPEN)begin
            seg_dout <= {NONE_DIS,NONE_DIS,CHAR_O,CHAR_P,CHAR_E,CHAR_N};
        end
        else if(state_c==LOCKED)begin
            seg_dout <= {CHAR_L,CHAR_O,CHAR_C,CHAR_K,CHAR_E,CHAR_D};
        end
        else if(state_c==ERROR)begin
            seg_dout <= {NONE_DIS,CHAR_E,CHAR_R,CHAR_R,CHAR_O,CHAR_R};
        end
        else if(state_c==PASSWORD)begin
            if(cnt_password==0)
                seg_dout <= {NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS};
            else if(cnt_password==1)
                seg_dout <= {NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS,{1'b0,password[3:0]}};
            else if(cnt_password==2)
                seg_dout <= {NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS,{1'b0,password[7:4]},{1'b0,password[3:0]}};
            else if(cnt_password==3)
                seg_dout <= {NONE_DIS,NONE_DIS,NONE_DIS,{1'b0,password[11:8]},{1'b0,password[7:4]},{1'b0,password[3:0]}};
            else if(cnt_password==4)
                seg_dout <= {NONE_DIS,NONE_DIS,{1'b0,password[15:12]},{1'b0,password[11:8]},{1'b0,password[7:4]},{1'b0,password[3:0]}};
        end
    end
    
    //seg_dout_vld
    assign seg_dout_vld = 6'b11_1111;

    //cnt_password
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            cnt_password <= 0;
        end
        else if(end_cnt_password)begin
            cnt_password <= 0;
        end
        else if(add_cnt_password)begin
            cnt_password <= cnt_password + 1;
        end
    end
    assign add_cnt_password = state_c!=ERROR && key_num<10 && key_vld && cnt_password<4;
    assign end_cnt_password = confirm || end_cnt_10s_nvld;

    //password
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            password <= 16'h0000;
        end
        else if(add_cnt_password)begin
            password <= {password[11:0],key_num};
        end
    end



    endmodule


1.4 數(shù)碼管顯示模塊設(shè)計(jì)

1.4.1接口信號(hào)


1.4.2設(shè)計(jì)思路

在前面的案例中已經(jīng)有數(shù)碼管顯示的介紹,所以這里不在過多介紹,詳細(xì)介紹請(qǐng)看下方鏈接:

http://fpgabbs.com/forum.php?mod=viewthread&tid=1085&fromuid=100105

其中,數(shù)碼管顯示的數(shù)值和英文字母對(duì)應(yīng)圖像如下圖所示:


1.4.3參考代碼

module seg_display(
    clk     ,       
    rst_n   ,       
    din     ,       
    din_vld ,       
    segment ,       
    seg_sel         
    );

    parameter SEGMENT_NUM   = 6             ;   
    parameter W_DATA        = 5             ;   

    parameter SEGMENT_WID   = 8             ;   
    parameter TIME_300US    = 15_000         ;  

    parameter SEG_DATA_0    = 7'b100_0000   ;  
    parameter SEG_DATA_1    = 7'b111_1001   ;
    parameter SEG_DATA_2    = 7'b010_0100   ;
    parameter SEG_DATA_3    = 7'b011_0000   ;
    parameter SEG_DATA_4    = 7'b001_1001   ;
    parameter SEG_DATA_5    = 7'b001_0010   ;
    parameter SEG_DATA_6    = 7'b000_0010   ;
    parameter SEG_DATA_7    = 7'b111_1000   ;
    parameter SEG_DATA_8    = 7'b000_0000   ;
    parameter SEG_DATA_9    = 7'b001_0000   ;  

    parameter SEG_CHAR_O    = 7'b010_0011   ;  
    parameter SEG_CHAR_P    = 7'b000_1100   ;  
    parameter SEG_CHAR_E    = 7'b000_0110   ;  
    parameter SEG_CHAR_N    = 7'b010_1011   ;  
    parameter SEG_CHAR_L    = 7'b100_0111   ;  
    parameter SEG_CHAR_C    = 7'b100_0110   ;  
    parameter SEG_CHAR_K    = 7'b000_0101   ;  
    parameter SEG_CHAR_D    = 7'b010_0001   ;  
    parameter SEG_CHAR_R    = 7'b010_1111   ;  
    parameter SEG_NONE_DIS  = 7'b111_1111   ;  

    input                           clk         ;
    input                           rst_n       ;
    input [SEGMENT_NUM*W_DATA-1:0]  din         ;
    input [SEGMENT_NUM-1:0]         din_vld     ;

    output[SEGMENT_WID-1:0]         segment     ;
    output[SEGMENT_NUM-1:0]         seg_sel     ;

    reg   [SEGMENT_WID-1:0]         segment     ;
    reg   [SEGMENT_NUM-1:0]         seg_sel     ;

    reg   [W_DATA-1:0]              segment_pre ;
    reg   [SEGMENT_NUM*W_DATA-1:0]  din_get     ;
    reg   [14:0]                    cnt_300us   ;
    reg   [2:0]                     cnt_sel     ;
    wire                            dot         ;


   
wire        add_cnt_300us ;
wire        end_cnt_300us ;
always @(posedge clk or negedge rst_n) begin 
    if (rst_n==0) begin
        cnt_300us <= 0; 
    end
    else if(add_cnt_300us) begin
        if(end_cnt_300us)
            cnt_300us <= 0; 
        else
            cnt_300us <= cnt_300us+1 ;
   end
end
assign add_cnt_300us =1;
assign end_cnt_300us = add_cnt_300us  && cnt_300us == TIME_300US-1 ;

   


wire        add_cnt_sel ;
wire        end_cnt_sel ;
always @(posedge clk or negedge rst_n) begin 
    if (rst_n==0) begin
        cnt_sel <= 0; 
    end
    else if(add_cnt_sel) begin
        if(end_cnt_sel)
            cnt_sel <= 0; 
        else
            cnt_sel <= cnt_sel+1 ;
   end
end
assign add_cnt_sel = end_cnt_300us;
assign end_cnt_sel = add_cnt_sel  && cnt_sel == SEGMENT_NUM-1 ;


reg     [SEGMENT_NUM-1:0]   din_vvld;
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        din_vvld <= 0 ;
    end
    else begin
        din_vvld <= din_vld ;
    end
end


reg [ 2:0]  cnt     ;
wire        add_cnt ;
wire        end_cnt ;
always @(posedge clk or negedge rst_n) begin 
    if (rst_n==0) begin
        cnt <= 0; 
    end
    else if(add_cnt) begin
        if(end_cnt)
            cnt <= 0; 
        else
            cnt <= cnt+1 ;
   end
end
assign add_cnt = 1;
assign end_cnt = add_cnt  && cnt == SEGMENT_NUM-1 ;

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        din_get <= 0;
    end
    else if(din_vvld[cnt])begin
        din_get[W_DATA*(cnt+1)-1 -:W_DATA] <= din[W_DATA*(cnt+1)-1 -:W_DATA];
    end
end


    always  @(*)begin
        segment_pre = din_get[W_DATA*(cnt_sel+1)-1 -:W_DATA];
    end


    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            segment <= {dot,SEG_NONE_DIS};
        end
        else if(add_cnt_300us  && cnt_300us ==10-1)begin
            case(segment_pre)
                5'h00: segment <= {dot,SEG_DATA_0};
                5'h01: segment <= {dot,SEG_DATA_1};
                5'h02: segment <= {dot,SEG_DATA_2};
                5'h03: segment <= {dot,SEG_DATA_3};
                5'h04: segment <= {dot,SEG_DATA_4};
                5'h05: segment <= {dot,SEG_DATA_5};
                5'h06: segment <= {dot,SEG_DATA_6};
                5'h07: segment <= {dot,SEG_DATA_7};
                5'h08: segment <= {dot,SEG_DATA_8};
                5'h09: segment <= {dot,SEG_DATA_9};
                5'h10: segment <= {dot,SEG_CHAR_O};
                5'h11: segment <= {dot,SEG_CHAR_P};
                5'h12: segment <= {dot,SEG_CHAR_E};
                5'h13: segment <= {dot,SEG_CHAR_N};
                5'h14: segment <= {dot,SEG_CHAR_L};
                5'h15: segment <= {dot,SEG_CHAR_C};
                5'h16: segment <= {dot,SEG_CHAR_K};
                5'h17: segment <= {dot,SEG_CHAR_D};
                5'h18: segment <= {dot,SEG_CHAR_R};
                5'h1F: segment <= {dot,SEG_NONE_DIS};
                default:segment <= {dot,SEG_NONE_DIS};
            endcase
        end
    end
    assign dot = 1'b1; 

    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            seg_sel <= {SEGMENT_NUM{1'b0}};
        end
        else begin
            seg_sel <= ~(1'b1<<cnt_sel);
        end
    end


    endmodule


1.5 效果和總結(jié)

下圖是該工程在db603開發(fā)板上的現(xiàn)象——密碼鎖初始狀態(tài)和閉合狀態(tài)



下圖是該工程在db603開發(fā)板上的現(xiàn)象——提示輸入錯(cuò)誤狀態(tài)




下圖是該工程在db603開發(fā)板上的現(xiàn)象——密碼鎖開啟狀態(tài)




下圖是該工程在db603開發(fā)板上的現(xiàn)象——輸入密碼狀態(tài)




下圖是該工程在mp801開發(fā)板上的現(xiàn)象——密碼鎖初始狀態(tài)和閉合狀態(tài)




下圖是該工程在mp801開發(fā)板上的現(xiàn)象——提示輸入錯(cuò)誤狀態(tài)


下圖是該工程在ms980開發(fā)板上的現(xiàn)象——密碼鎖初始狀態(tài)和閉合狀態(tài)




下圖是該工程在ms980開發(fā)板上的現(xiàn)象——提示輸入錯(cuò)誤狀態(tài)




下圖是該工程在ms980開發(fā)板上的現(xiàn)象——密碼鎖開啟狀態(tài)




下圖是該工程在ms980開發(fā)板上的現(xiàn)象——輸入密碼狀態(tài)



由于該項(xiàng)目的上板現(xiàn)象是在數(shù)碼管上顯示輸入的密碼,并且判斷密碼是否正確:正確則在數(shù)碼管上顯示OPEN,錯(cuò)誤則在數(shù)碼管上顯示ERROR并提示輸入錯(cuò)誤2秒,然后數(shù)碼管顯示LOCKED。想觀看完整現(xiàn)象的朋友可以看一下上板演示的視頻。

感興趣的朋友也可以訪問明德?lián)P論壇(http://www.fpgabbs.cn/)進(jìn)行FPGA相關(guān)工程設(shè)計(jì)學(xué)習(xí)。

源工程和設(shè)計(jì)教學(xué)視頻請(qǐng)到論壇下載。

明德?lián)P至簡(jiǎn)設(shè)計(jì)案例200例:

http://fpgabbs.net/thread-1134-1-1.html

(出處: 明德?lián)P論壇)



1.6 公司簡(jiǎn)介

明德?lián)P是一家專注于FPGA領(lǐng)域的專業(yè)性公司,公司主要業(yè)務(wù)包括開發(fā)板、教育培訓(xùn)、項(xiàng)目承接、人才服務(wù)等多個(gè)方向。點(diǎn)撥開發(fā)板——學(xué)習(xí)FPGA的入門之選。
MP801開發(fā)板——千兆網(wǎng)、ADDA、大容量SDRAM等,學(xué)習(xí)和項(xiàng)目需求一步到位。網(wǎng)絡(luò)培訓(xùn)班——不管時(shí)間和空間,明德?lián)P隨時(shí)在你身邊,助你快速學(xué)習(xí)FPGA。周末培訓(xùn)班——明天的你會(huì)感激現(xiàn)在的努力進(jìn)取,升職加薪明德?lián)P來助你。就業(yè)培訓(xùn)班——七大企業(yè)級(jí)項(xiàng)目實(shí)訓(xùn),獲得豐富的項(xiàng)目經(jīng)驗(yàn),高薪就業(yè)。專題課程——高手修煉課:提升設(shè)計(jì)能力;實(shí)用調(diào)試技巧課:提升定位和解決問題能力;FIFO架構(gòu)設(shè)計(jì)課:助你快速成為架構(gòu)設(shè)計(jì)師;時(shí)序約束、數(shù)字信號(hào)處理、PCIE、綜合項(xiàng)目實(shí)踐課等你來選。項(xiàng)目承接——承接企業(yè)FPGA研發(fā)項(xiàng)目。人才服務(wù)——提供人才推薦、人才代培、人才派遣等服務(wù)。

   拓展閱讀
主站蜘蛛池模板: 一级毛片特黄久久免费看 | 国产一区二区不卡 | 8mav福利视频在线播放 | 亚洲淫视频 | 久久精品免费全国观看国产 | 精品国产成人系列 | 91视频毛片| 国产伦一区二区三区四区久久 | 久久亚洲国产精品 | 亚洲大成色www永久网址 | 麻豆资源 | 国产亚洲欧美视频 | 欧美一区二区三 | 欧美大片一区 | 精品国产成人 | 亚洲欧美日韩精品永久在线 | 成人免费看黄网址 | 日本在线观看免费看片 | 亚洲操片| 国产日韩精品一区二区 | 精品哟哟哟国产在线观看不卡 | 国产精品久久精品牛牛影视 | 亚洲精品国产三级在线观看 | 伊人影院视频 | 国产精品揄拍100视频最近 | 免费观看欧美一级高清 | 免费一级黄 | 久青草国产手机在线观 | 一级黄色片免费播放 | 国产99久久精品一区二区 | 九九夜夜 | 三级黄色在线视频中文 | 在线观看视频一区二区 | 毛片免费看牛牛影视 | 久久久久国产精品免费免费 | 91粉色视频在线观看 | 激情亚洲 | 精品国产电影网久久久久婷婷 | 亚洲综合伊人制服丝袜美腿 | 中文字幕亚洲综合久久202 | 亚洲综合一区二区精品久久 |