矩阵按键的试验---verilog

矩阵键盘的试验,采用三段式状态机处理方法。

难点在于检测状态机中:按键消抖以后逐列检测。

电路图:

代码

/********************************Copyright**************************************                           
**----------------------------File information--------------------------
** File name  :keyboard.v  
** CreateDate :2015.04
** Funtions   :4x4矩阵键盘
** Operate on :M5C06N3L114C7
** Copyright  :All rights reserved. 
** Version    :V1.0
**---------------------------Modify the file information----------------
** Modified by   :
** Modified data :        
** Modify Content: 2015.6
*******************************************************************************/
 
module keyboard(
                  clk,
                                    rst_n,
                                    
                                    l_in,
                                    h_out,
                                    
                                    test_1,
                                    test_2,
                                    
                                    key_val,
                                    key_val_flag
                                    );
 input             clk;          /* clk = 24M */
 input             rst_n;
 input   [3:0]     l_in;             //列输入,一般接上拉,为高电平
 
 output            test_1;
 output            test_2;
 
 output  [3:0]     h_out;            //行输出信号,低有效 
 output  [3:0]     key_val;          //按键值,输出   
 output            key_val_flag;
            
 wire    [3:0]     key_val; 
 reg               test_1;
 reg               test_2;
 //*************************************
 /* 分频Ƶ*20ms,用于消抖 .状态机直接用clk_20ms,则可以跳过消抖*/
 
//  `define   CLK_24M 
   `define   CLK_20M 
    
    `ifdef  CLK_24M
        parameter  t_20ms = 20'd479999;         
     `endif
     
     `ifdef  CLK_20M
        parameter  t_20ms = 20'd399999;         
     `endif
     
  reg    [19:0]   cnt;
 always @(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      begin
           cnt <= 'd0;
        end
      else 
       begin
         if(cnt == t_20ms)  cnt <= 'd0;
         else cnt <= cnt + 'd1;                 
         end
  end
  wire    shake_over = (cnt == t_20ms);
 //******************状态机******************
 localparam NO_KEY_pressed  =  3'd0;        /* 初始化 */
 localparam key_shake_1     =  3'd1;        /* 消抖1 */
 localparam KEY_h_1         =  3'd2;        /* 检测第一列 */
 localparam KEY_h_2         =  3'd3;        /* 检测第二列 */
 localparam KEY_h_3         =  3'd4;        /* 检测第三列 */ 
 localparam KEY_h_4         =  3'd5;        /* 检测第四列 */
 localparam KEY_pressed     =  3'd6;        /* 按键值输出*/
 localparam key_shake_2     =  3'd7;        /* 消抖2 */ 
 
 /* 3-1 */
 reg     [2:0]      current_state;
 reg     [2:0]      next_state;
 reg                key_pressed_flag; 
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      current_state <= 0;
    end
  else if(shake_over)
    begin
      current_state <= next_state;
    end
    else 
         current_state <=  current_state ;    
  end
    
 /* 3-2 */
always @(*) 
 begin
     next_state     = NO_KEY_pressed;
   case(current_state)
    NO_KEY_pressed:
              begin
                        if(l_in != 4'hf)   next_state = key_shake_1;
                 else  next_state = NO_KEY_pressed;
           end
        key_shake_1:     
         begin
                        if(l_in != 4'hf)   next_state = KEY_h_1;
                 else  next_state = NO_KEY_pressed;
           end
    KEY_h_1:
            begin
                        if(l_in != 4'hf)   next_state = KEY_pressed;
                 else  next_state = KEY_h_2;
          end
        KEY_h_2:
            begin
                        if(l_in != 4'hf)   next_state = KEY_pressed;
                 else  next_state = KEY_h_3;
          end
    KEY_h_3:
            begin
                        if(l_in != 4'hf)   next_state = KEY_pressed;
                 else  next_state = KEY_h_4;
          end
    KEY_h_4:
            begin
                        if(l_in != 4'hf)   next_state = KEY_pressed;
                 else  next_state = NO_KEY_pressed;
          end
   KEY_pressed:
          begin
                        if(l_in != 4'hf)   next_state = key_shake_2;
                 else  next_state = NO_KEY_pressed;
          end
     key_shake_2:
          begin
                        if(l_in != 4'hf)   next_state = key_shake_2;
                 else  next_state = NO_KEY_pressed;
          end
     default:;
    endcase
end

/* 3-3  */

 reg    [3:0]      l_in_reg;
 reg    [3:0]   h_out_reg;
 reg    [3:0]   h_out; 
always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      l_in_reg <= 4'd0;
            h_out_reg<= 4'd0;
            h_out <= 4'd0;
            key_pressed_flag <= 0;
    end
  else if(shake_over)
    begin
     case(next_state)
         NO_KEY_pressed:
            begin
              l_in_reg <= l_in_reg;
                    h_out_reg<= h_out_reg;
                    h_out <= 4'd0;   
                    key_pressed_flag <= 0;
             end
         KEY_h_1:
              begin
                     h_out <= 4'b1110;                             
                    end
         KEY_h_2:
              begin
                     h_out <= 4'b1101;                             
                    end
         KEY_h_3:
              begin
                     h_out <= 4'b1011;                             
                    end
         KEY_h_4:
              begin
                     h_out <= 4'b0111;                             
                    end

         KEY_pressed:
           begin
                     l_in_reg <= l_in;
                   h_out_reg<= h_out;
                end
         key_shake_2:  begin key_pressed_flag <= 1;   end
         default:;
        endcase
   end
 end
    
      
 
 reg      [3:0]      temp_key_val; 
 always @(posedge clk or negedge rst_n)
  begin
   if(!rst_n)
       temp_key_val <= 4'd0;
    else 
         begin
            if(key_pressed_flag) 
              begin
                  case ({h_out_reg,l_in_reg})
                        8'b1110_1110 :  temp_key_val <= 4'd0;
                        8'b1110_1101 :    temp_key_val <= 4'd1;
                        8'b1110_1011 :    temp_key_val <= 4'd2;
                        8'b1110_0111 :    temp_key_val <= 4'd3;
                            
                        8'b1101_1110 :    temp_key_val <= 4'd4;
                        8'b1101_1101 :    temp_key_val <= 4'd5;
                        8'b1101_1011 :    temp_key_val <= 4'd6;
                        8'b1101_0111 :    temp_key_val <= 4'd7;
                            
                        8'b1011_1110 :    temp_key_val <= 4'd8;
                        8'b1011_1101 :    temp_key_val <= 4'd9;
                        8'b1011_1011 :    temp_key_val <= 4'd10;
                        8'b1011_0111 :    temp_key_val <= 4'd11;

                        8'b0111_1110 :    temp_key_val <= 4'd12;
                        8'b0111_1101 :    temp_key_val <= 4'd13;
                        8'b0111_1011 :    temp_key_val <= 4'd14;
                        8'b0111_0111 :    temp_key_val <= 4'd15;
                     
                    default: temp_key_val <= 4'd0;
                endcase    
    end
   end
 end
 assign   key_val = ~temp_key_val;
 assign   key_val_flag =  ~key_pressed_flag;
 endmodule  
 
View Code

 

测试代码:

module  testbench;

 reg             clk;          /* clk = 24M */
 reg             rst_n;
 reg   [3:0]     l_in;             //列输入,一般接上拉,为高电平
 
 wire            test_1;
 wire            test_2;
 
 wire  [3:0]     h_out;            //行输出信号,低有效 
 wire  [3:0]     key_val;          //按键值,输出   
 wire            key_val_flag;

keyboard  u1(
                  .clk,
                                    .rst_n,
                                    
                                    .l_in,
                                    .h_out,
                                    
                                    .test_1,
                                    .test_2,
                                    
                                    .key_val,
                                    .key_val_flag
                                    );
        defparam  u1.    t_20ms = 399;                        
                                    
 parameter  tck = 100;
 parameter  t = 1000/tck;
 
 always 
     #(t/2)   clk = ~clk;


 task     key_test;
 input [3:0]   data_key;
  begin
        #(3*t)     l_in = data_key;
        #(5000*t) l_in = 4'b1111;
        #(2500*t);
        end
    endtask
    
    
initial 
  begin
    clk = 0;
    rst_n = 0;
    l_in  = 4'd0;
    
    #(6*t)  rst_n = 1; 
    
    #(60*t);
    key_test(4'B1101); 
    key_test(4'B1011); 
 
  end
 
endmodule 
View Code

 

仿真波形:

posted @ 2015-04-03 17:15  远航路上ing  阅读(1181)  评论(0编辑  收藏  举报