mdykj33

明德扬至简设计法---分享一份实现矩阵键盘的verilog代码 可直接使用

0
阅读(1154)

本案例:明德扬首创全新FPGA设计技巧--至简设计法,教你如何一步一步去完成一个复杂电路的设计,里面很多有实用技巧,熟练运用这些技巧,有助于你写出非常优秀的FPGA设计代码。非常简洁易读,欢迎比较。

`define  SCAN


module  key_scan(

                 clk    , 

                 rst_n  ,

                 key_col, //键盘列输入

                 key_row, //键盘行输出

                 key_num, //指示哪一个按键按下,用0~15指示

                 key_vld  //按下有效指示信号,其为1表示按下一次。

               );



    parameter      KEY_W    =   4 ;

    parameter      COL      =   0 ;

    parameter      ROW      =   1 ;

    parameter      DLY      =   2 ;

    parameter      FIN      =   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_num;

    output[KEY_W-1:0]   key_row;


    //输出信号reg定义

    reg   [3:0]         key_num;

    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   ;

    reg                 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       ;

reg   [ 2:0]        x             ;



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



always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        shake_cnt <= 0;

    end

    else if(add_shake_cnt)begin

        if(end_shake_cnt)

            shake_cnt <= 0;

        else

            shake_cnt <= shake_cnt + 1;

    end

    else begin

        shake_cnt <= 0;

    end

end


assign  add_shake_cnt = key_col_ff1!=4'hf && shake_flag==0;

assign  end_shake_cnt = add_shake_cnt && shake_cnt==TIME_20MS-1;


always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        shake_flag <= 0;

    end

    else if(end_shake_cnt) begin

        shake_flag <= 1'b1;

    end

    else if(key_col_ff1==4'hf) begin

        shake_flag <= 1'b0;

    end

end



`ifdef SCAN

always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        state_c <= COL;

    end

    else begin

        state_c <= state_n;

    end

end




always  @(*)begin

    case(state_c)

        COL: begin

                     if(col2row_start)begin

                         state_n = ROW;

                     end

                     else begin

                         state_n = state_c;

                     end

                 end

        ROW: begin

                     if(row2dly_start)begin

                         state_n = DLY;

                     end

                     else begin

                         state_n = state_c;

                     end

                 end

        DLY :  begin

                     if(dly2fin_start)begin

                         state_n = FIN;

                     end

                     else begin

                         state_n = state_c;

                     end

                 end

        FIN: begin

                     if(fin2col_start)begin

                         state_n = COL;

                     end

                     else begin

                         state_n = state_c;

                     end

                  end

       default: state_n = COL;

    endcase

end


assign  col2row_start = state_c==COL && end_shake_cnt;

assign  row2dly_start = state_c==ROW && end_row_index; 

assign  dly2fin_start = state_c==DLY && end_row_index; 

assign  fin2col_start = state_c==FIN && 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==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_cnt <= 0;

    end

    else if(add_row_cnt) begin

        if(end_row_cnt)

            row_cnt <= 0;

        else

            row_cnt <= row_cnt + 1;

    end

end

assign add_row_cnt = state_c==ROW || state_c==DLY;

assign end_row_cnt = add_row_cnt && row_cnt==COL_CNT-1;



always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        row_index <= 0;

    end

    else if(add_row_index) begin

        if(end_row_index)

            row_index <= 0;

        else

            row_index <= row_index + 1;

    end

end

assign add_row_index = end_row_cnt;

assign end_row_index = add_row_index && row_index==x-1;

always  @(*)begin

    if(state_c==ROW)

        x = 4;

    else

        x = 1;

end



always  @(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

        key_col_get <= 0;

    end

    else if(col2row_start) 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_num <= 0;

    end

    else if(state_c==ROW && end_row_cnt)begin

        key_num <= {row_index,key_col_get};

    end

    else begin

        key_num <= 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==ROW && end_row_cnt && key_col_ff1[key_col_get]==1'b0)begin

        key_vld <= 1'b1;

    end

    else begin

        key_vld <= 1'b0;

    end

end


`else

    always  @(posedge clk or negedge rst_n)begin

        if(rst_n==1'b0)begin

            key_vld <= 0;

        end

        else begin

            key_vld <= end_shake_cnt;

        end

    end


    always  @(*)begin

        key_num = 0;

    end




`endif


endmodule