CrazyBingo

矩阵键盘Verilog程控简析

0
阅读(3123)

矩阵键盘Verilog程控简析

 

目    录

1. 写在前面的话 1

2. 矩阵键盘程控简析 1

2.1. PCB原理图设计 1

2.2. 键盘工作简析 2

2.2.1. 工作流程 2

2.2.2. 状态机 3

2.2.3. 仿真图 4

2.3. 时序及编码 4

1. 写在前面的话

NND当年写的代码让我恶心了半死,瞅了半天时间重新开始架构!以前没用Mdelsim瞎JB乱搞,现在会了Modelsim各种不放心,没有仿真过的代码不是一个可靠的代码!

问题是以前的代码Load进去竟然不行,可是神奇的是重新搞原理,Modelsim完美之后一下再进去就Perfect,得出一个结论:“永远不要相信任何人,包括你自己!”

2. 矩阵键盘程控简析

2.1. PCB原理图设计

wps_clip_image-22530

wps_clip_image-23979

wps_clip_image-18686

wps_clip_image-27660

2.2. 键盘工作简析

2.2.1. 工作流程

1) 默认:

Row[3:0]为输入,默认为4'b1111,因为电阻上拉

Col[3:0]为输出,默认输出4'b0000,保证按键按下时电流流向Col[3:0]

2) 当某一按键按下时,电流流向Col[x]=1,相应Row[x]=0

3) 通过循环Col键值扫描,代码如下:

    case(next_state)
    SCAN_IDLE    :    begin
                col_data <= 4'b0000;    //ensure current can flow when key is down
                row_data_r <= 4'b0000;
                col_data_r <= 4'b0000;
                end
    //SCAN_JITTER1:    
    SCAN_COL0    :    col_data <= 4'b1110;    //scan the 1th row if the key is down
    SCAN_COL1    :    col_data <= 4'b1101;    //scan the 2th row if the key is down
    SCAN_COL2    :    col_data <= 4'b1011;    //scan the 3th row if the key is down
    SCAN_COL3    :    col_data <= 4'b0111;    //scan the 4th row if the key is down
    SCAN_READ    :    begin
                row_data_r <= row_data;    //register the sudden col_data
                col_data_r <= col_data;    //register the sudden row_data
                end    
    //SCAN_JITTER2:
    default:;    //default vaule
    Endcase

当col_data为某一值的时候,若row_data!=4'b1111,则可确定是该列的键被按下!从而可以通过{row_data,col_data}来确定被按下的键。

1.1.1. 状态机

采用三段式状态机描述整个矩阵键盘的扫描状态控制,状态如下:

    parameter    SCAN_IDLE    =    3'd0;    表示初始化状态
    parameter    SCAN_JITTER1=    3'd1;    表示消抖动状态
    parameter    SCAN_COL0    =    3'd2;    表示Col0检测状态
    parameter    SCAN_COL1    =    3'd3;    表示Col1检测状态
    parameter    SCAN_COL2    =    3'd4;    表示Col2检测状态
    parameter    SCAN_COL3    =    3'd5;    表示Col3检测状态
    parameter    SCAN_READ    =    3'd6;    表示读取{Row[3:0],Col[3:0]}键值
    parameter    SCAN_JITTER2=    3'd7;    表示按键松手检测

其中消抖动为了简便,做了20ms状态检测计,如下:

    //---------------------------------------
    //generate for 20ms signal        
    localparam    KEY_DELAY = 20'hf_ffff;    //50MHz, 20ms    
    reg [19:0]    delay_cnt;    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n) 
            delay_cnt <= 0; 
        else if(delay_cnt < KEY_DELAY)    //(current_state == SCAN_JITTER1)
            delay_cnt <= delay_cnt + 1'b1;
        else
            delay_cnt <= 20'd0;
    end
    wire    delay_20ms = (delay_cnt == KEY_DELAY) ? 1'b1 : 1'b0;//key is down

状态机如下:

wps_clip_image-22801

1.1.1. 仿真图

通过testbench仿真,符合预期目标,结果如下:

wps_clip_image-31361

时序及编码

    case ({row_data_r, col_data_r})
    8'b0111_0111:    key_value <= 4'h0;
    8'b0111_1011:    key_value <= 4'h1;
    8'b0111_1101:    key_value <= 4'h2;
    8'b0111_1110:    key_value <= 4'h3;
                                 
    8'b1011_0111:    key_value <= 4'h4;
    8'b1011_1011:    key_value <= 4'h5;
    8'b1011_1101:    key_value <= 4'h6;
    8'b1011_1110:    key_value <= 4'h7;
                                 
    8'b1101_0111:    key_value <= 4'h8;
    8'b1101_1011:    key_value <= 4'h9;
    8'b1101_1101:    key_value <= 4'hA;
    8'b1101_1110:    key_value <= 4'hB;
                                             
    8'b1110_0111:    key_value <= 4'hC;
    8'b1110_1011:    key_value <= 4'hD;
    8'b1110_1101:    key_value <= 4'hE;
    8'b1110_1110:    key_value <= 4'hF;
    default        :    key_value <= key_value;        
    endcase

每次接受到key_flag一个触发的高电平,表示按键按下,可以直接读取键值,进行相应的操作!接口如下:

 

    //----------------------------------------------
    //the target component instantiation
    matrix_key_scan u_matrix_key_scan
    (
        .clk        (clk),      //global clock
        .rst_n        (rst_n),    //global reset
                                
        .row_data    (row_data),    //row data: pull-up with 3.3V    
        .col_data    (col_data),    //column data: for key scan
                                
        .key_flag    (key_flag), //the mark of key is pressed
        .key_value    (key_value)    //the returned value of matrix key
    );