基于FPGA的4x4矩阵键盘驱动设计---第一版

fpga,4x4 · 浏览次数 : 0

小编点评

**代码解析:** ```assembly .text # Keyboard simulation keyboard4x4_drive keyboard4x4_inst( .clk (clk ), // 100MHz .rst_n (rst_n ), .keyboard4x4_row (keyboard4x4_row), .keyboard4x4_col (keyboard4x4_col), .key_num (key_num ), .flag_key (flag_key ) ); keyboard4x4 keyboard4x4_inst( .press_num (press_num ), .keyboard4x4_col (keyboard4x4_col), .keyboard4x4_row (keyboard4x4_row) ); # Simulation tasks initial begin rst_n = 1'b0; press_num = 5'd16; # 1001 rst_n = 1'b1; # 2000; press_data(5'd15); press_data(5'd14); press_data(5'd13); press_data(5'd12); press_data(5'd11); press_data(5'd10); press_data(5'd9); press_data(5'd8); press_data(5'd7); press_data(5'd6); press_data(5'd5); press_data(5'd4); press_data(5'd3); press_data(5'd2); press_data(5'd1); press_data(5'd0); $stop; end task press_data; end # Input capture input [4:0] data; begin repeat (5) begin press_num = data; # 10000; press_num = 5'd16; # 10000; end press_num = data; # 15_000_000; end endtask   ``` **功能:** 该代码模拟矩阵键盘的按键按下和释放事件。 * `keyboard4x4_drive` 和 `keyboard4x4_inst` 是一个驱动电路,它与 FPGA 通过 `clk` 和 `rst` 连接。 * `key_num` 用于存储当前按键的识别值,`flag_key` 用于存储按键按下标志。 * `press_num` 用于记录按键按下的时间。 * `data` 是输入的按键值。 * `press_data` 用于模拟按键按下和释放。 **仿真结果:** 当按下按键 K6 时,四个 LED 灭亮亮灭,显示数字 6。

正文

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的4x4矩阵键盘驱动设计---第一版

功能说明:

1. 驱动4x4矩阵键盘:按下任意一个按键,解析出对应按键信息,并给出标志

 

使用平台:纯代码形式

使用语言:Verilog HDL

 

作者QQ:746833924

说明:本篇设计中不涉及到IP和原语,代码在其他平台依然可以适用;当其他板卡电路不同时,会导致不同的现象出现,如有需要修改代码请联系作者;如需作者使用的板卡,请联系作者;

 

4x4矩阵键盘实物图如下:

 

 

 

电路原理图如下:

 

注:此电路设计按照四角按键设计,按键按下时,对角导通;按键释放时,对角不导通。

 

矩阵键盘驱动检测原理:

 

根据矩阵键盘排布的方式可以看到:对外引出了四根行线,四根列线;当有按键闭合时,所在的行线和列线就会导通。

 

主控芯片控制输出列线,然后检测行线(也可以反过来控制和检测)。

 

每次按键按下只有一个按键按下。

 

控制最后一列为低电平,其他列为高电平;如果此时最后一列有按键按下,那么对应的行线将会检测到低电平;此时根据最后一列和检测到行线的情况即可推断出对应的按键。如果最后一列没有按键按下,那么此时行线全部为高电平。

最后一列检测完毕后,可以控制倒数第二列为电平,方式同上。

四列全部检测完毕即可检测出来按键闭合的位置,根据位置译码出对应的标志即可。

 

假设K1闭合;第四列为低电平,此时行线全部为高电平;第三列为低电平,此时行线全部为高电平;第二列为低电平,此时第一行线为电平,其他行线为高电平;此时即可得出第二列,第一行有按键闭合。

 

设计思想如下:

 

 

 

根据上述原理,我们增加一些设计考虑。

 

  1.  矩阵键盘并不是一直在使用,或者说使用的时间较少,因此不建议一直处于扫描状态(不断切换列为低电平)。带来的问题:功耗增加、增加CPU的运行负担(FPGA不增加负担)等等。解决方案:先给所有列为低电平,检测行线情况,如果有按键闭合,行线将会不全为高电平,此时进行扫描,并且扫描到就退出,等待下一次有按键闭合;如果没有按键闭合,行线一直都为高电平,则此时一直等待即可。

  2. 矩阵键盘的按键在闭合时会有一定的抖动,所以要增加按键消抖机制。

 

 

本设计利用状态机设计进行实现。共有八个状态。

  
localparam          STATE_OFF             =   9'b00000_0001;  
localparam STATE_ON_SHAKE = 9
'b00000_0010;
localparam STATE_OUT_SCAN = 9'b00000_0100;
localparam STATE_SCAN_WAIT0 = 9
'b00000_1000;
localparam STATE_SCAN_WAIT1 = 9'b00001_0000;
localparam STATE_SCAN_WAIT2 = 9
'b00010_0000;
localparam STATE_SCAN_WAIT3 = 9'b00100_0000;
localparam STATE_CHECK_PRESS = 9
'b01000_0000;
localparam STATE_OFF_SHAKE = 9'b10000_0000;

 

复位结束后,在OFF状态。此时列全部为低电平,如果没有按键闭合,则行线一直全部为高电平,保持OFF状态;如果有按键闭合,则行线就不全为高电平,此时进入ON_SHAKE状态,在此状态中,列全部为低电平,检测行线是不是一直不全为高电平,如果按键有抖动,则行线会变为全部高电平,此时回到OFF状态;当行线一直不全为高电平保持10ms或者20ms,则认为按键无抖动,之后进入OUT_SCAN状态;

在OUT_SCAN状态输出单列为低电平,等待四个状态即等待四个时钟周期:用于输出行线的同步(STATE_SCAN_WAIT0、STATE_SCAN_WAIT1、STATE_SCAN_WAIT2、STATE_SCAN_WAIT3),在CHECK_PRESS状态监测行线,判断是否为全高,即监测此列是否有按键闭合。如果有按键闭合,则记录行列情况;如果没有按键按下,则返回OUT_SCAN状态,进行下一列监测。如果监测完四列没有发现有按键按下,则也跳出。

在OFF_SHAKE状态,是检测按键放开的抖动,原理和检测按下的抖动类似。

 

 

 

    always @ * begin
    case (c_state)
      STATE_OFF           :     n_state = (row_rr == 4'hf) ? STATE_OFF : STATE_ON_SHAKE;
      STATE_ON_SHAKE      :     n_state = (row_rr == 4'hf) ? STATE_OFF : (cnt_10ms < T_10ms - 1'b1) ? STATE_ON_SHAKE : STATE_OUT_SCAN;
      STATE_OUT_SCAN      :     n_state = STATE_SCAN_WAIT0;
      STATE_SCAN_WAIT0    :     n_state = STATE_SCAN_WAIT1;
      STATE_SCAN_WAIT1    :     n_state = STATE_SCAN_WAIT2;
      STATE_SCAN_WAIT2    :     n_state = STATE_SCAN_WAIT3;
      STATE_SCAN_WAIT3    :     n_state = STATE_CHECK_PRESS;
      STATE_CHECK_PRESS   :     n_state = (row_rr == 4'hf) ? (keyboard4x4_col == 4'b0111) ? STATE_OFF : STATE_OUT_SCAN : STATE_OFF_SHAKE;
      STATE_OFF_SHAKE     :     n_state = (row_rr == 4'hf && cnt_10ms == T_10ms - 1'b1) ? STATE_OFF : STATE_OFF_SHAKE;
      default             :     n_state = STATE_OFF;
    endcase
  end

 

根据上述的状态机,我们就可以找出来对应的行列位置。

 

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      row_col <= 8'd0;
    else
      if (c_state == STATE_CHECK_PRESS && row_rr != 4'hf)
        row_col <= {row_rr, keyboard4x4_col};
      else
        row_col <= row_col;
  end

 

 

然后根据行列位置进行译码出对应的按键值。

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      key_num <= 4'd0;
    else
      case (row_col)
        8'b1110_1110    : key_num <= 4'd0;
        8'b1110_1101    : key_num <= 4'd1;
        8'b1110_1011    : key_num <= 4'd2;
        8'b1110_0111    : key_num <= 4'd3;
        
        8'b1101_1110    : key_num <= 4'd4;
        8'b1101_1101    : key_num <= 4'd5;
        8'b1101_1011    : key_num <= 4'd6;
        8'b1101_0111    : key_num <= 4'd7;
        
        8'b1011_1110    : key_num <= 4'd8;
        8'b1011_1101    : key_num <= 4'd9;
        8'b1011_1011    : key_num <= 4'd10;
        8'b1011_0111    : key_num <= 4'd11;
        
        8'b0111_1110    : key_num <= 4'd12;
        8'b0111_1101    : key_num <= 4'd13;
        8'b0111_1011    : key_num <= 4'd14;
        8'b0111_0111    : key_num <= 4'd15;
        
        default         : key_num <= 4'd0;
      endcase
  end

 

 

使用时,根据标志是否为高以及对应的数值即可知道是是否有按键按下,并且知道是那个按键按下。

 

此项仿真较难,由于输入和输出有一定的相关关系,所以在仿真时,需要设计矩阵键盘的仿真模型keyboard4x4(下面链接会提供源码)。

 

  keyboard4x4_drive keyboard4x4_drive_inst(

      .clk                          (clk            ),        //  100MHz
      .rst_n                        (rst_n          ),
                                     
      .keyboard4x4_row              (keyboard4x4_row),
      .keyboard4x4_col              (keyboard4x4_col),
                                     
      .key_num                      (key_num        ),
      .flag_key                     (flag_key       )
    );
      

  keyboard4x4 keyboard4x4_inst(

      .press_num                    (press_num      ),
                                     
      .keyboard4x4_col              (keyboard4x4_col),
      .keyboard4x4_row              (keyboard4x4_row)
    );

利用task语句模拟按键的抖动和按下。
initial begin
    rst_n = 1'b0;
    press_num = 5'd16;
    # 1001
    rst_n = 1'b1;
    
    # 2000;
    press_data(5'd15);
    press_data(5'd14);
    press_data(5'd13);
    press_data(5'd12);
    press_data(5'd11);
    press_data(5'd10);
    press_data(5'd9);
    press_data(5'd8);
    press_data(5'd7);
    press_data(5'd6);
    press_data(5'd5);
    press_data(5'd4);
    press_data(5'd3);
    press_data(5'd2);
    press_data(5'd1);
    press_data(5'd0);
    
    $stop;
  end
  
  
  task press_data;
    input   [4:0]   data;
    
    begin
      repeat (5) begin
        press_num = data;
        # 10000;
        press_num = 5'd16;
        # 10000;
      end
      
      press_num = data;
      # 15_000_000;
      
      repeat (5) begin
        press_num = data;
        # 10000;
        press_num = 5'd16;
        # 10000;
      end
      
      press_num = 5'd16;
      # 30_000_000;
      
    end
  endtask

 

 

在press_num给16,即表示按键的释放。通过快速释放和按下,模拟的抖动。

 

 

通过仿真图可以看出来,我们检测出来了正确的结果。

 

下板测试的话,我们可以将矩阵键盘与FPGA连接好,然后将检测出来的值放到数码管或者led上,用于显示数值,在此我选择led(因为懒的写数码管了)。

 

 

 

按下按键K6后,四个led呈现灭亮亮灭;led的驱动原理为高电平点亮,低电平熄灭;故而此时为0110,即为数字6。

 

按下其他的按键也可以正确显示,故而验证设计正确。

 

文章同款矩阵键盘购买链接:

 

https://item.taobao.com/item.htm?abbucket=10&id=796054801643&ns=1&priceTId=215044ff17157343140338659e0404&spm=a21n57.1.item.14.1d4a523cRO1waY

 

讲解和演示视频链接如下:
https://www.bilibili.com/video/BV1YH4y1u7ye/?vd_source=b5405faeab8632f02533bcbfc5e52e55
     

本设计所有内容(设计代码、设计工程)链接为:

     

链接:https://pan.baidu.com/s/1x9pP6Z0gGkR77XG8kFXvRA

提取码:mroh

 

  本篇内容中有部分资源来源于网络,如有侵权,请联系作者。

 

  如果您觉得本公众号还不错的话,可以推给身边的朋友们,感谢并祝好!

与基于FPGA的4x4矩阵键盘驱动设计---第一版相似的内容:

基于FPGA的4x4矩阵键盘驱动设计---第一版

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的4x4矩阵键盘驱动设计 第一版 功能说明: 1. 驱动4x4矩阵键盘:按下任意一个按键,解析出对应按键信息,并给出标志 使用平台:纯代码形式 使用语言:Verilog HDL 作者QQ:746833924 说明:本篇设计中不涉及

基于FPGA的计算器设计---第一版

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的计算器设计 第一版。 功能说明: 1. 计算器的显示屏幕为数码管。 2. 4x4矩阵键盘作为计算器的输入设备。 3. 计算任意两位正整数的加减乘除。 4. 当减法结果出现负数时(一个小的数字减去一个大的数字),数码管需要显示负数

基于FPGA的电子琴设计(按键和蜂鸣器)----第一版

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的电子琴设计(按键和蜂鸣器) 第一版。 功能说明: 外部输入七个按键,分别对应音符的“1、2、3、4、5、6、7”,唱作do、re、mi、fa、sol、la、si。当某个按键按下时,蜂鸣器发出对应的声音 1. 默认发出0.2秒(可

基于FPGA的数字钟设计---第三版

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的数字钟设计 第三版。 功能说明: 1. 在数码管上面显示时分秒(共计六个数码管,前两个显示小时;中间两个显示分钟;最后两个显示秒)。 2. 利用按键可以切换24/12小时制(默认24小时制)。 3. led1的亮灭表示24小时制

基于FPGA的贪吃蛇游戏 之代码解析

基于FPGA的贪吃蛇游戏 之代码解析 1. 代码结构 代码结构包含7格.v文件。 下面依次解析。 2. 代码解析 (1) seg_display.v 数码管的译码模块是最熟悉,最简单的模块了。这里是共阳极的数码管,用case语句编码即可。从上图可以看到,这个模块被例化了3次,分别驱动3个数码管显示,

ZynqMP PL固件通过U-BOOT从指定位置加载FPGA BIT

原因 PL固件可能经常修改,而BOOT.BIN和文件系统、内核实际上基本不会变,在一个平台上可以用同一份。如果每次修改都要重新打包PL 固件到BOOT.BIN,操作起来非常麻烦。所以希望PL 的固件可以直接从指定位置加载。典型的可以从SD卡的FAT32分区加载。 https://xilinx-wik

基于 Three.js 的 3D 模型加载优化

作为一个3D的项目,从用户打开页面到最终模型的渲染加载的时间也会比普通的H5项目要更长一些,从而造成大量的用户流失。为了提升首屏加载的转化率,需要尽可能的降低loading的时间。这里就分享一些我们在模型加载优化方面的心得。

基于MindSpore实现BERT对话情绪识别

本文分享自华为云社区《【昇思25天学习打卡营打卡指南-第二十四天】基于 MindSpore 实现 BERT 对话情绪识别》,作者:JeffDing。 模型简介 BERT全称是来自变换器的双向编码器表征量(Bidirectional Encoder Representations from Trans

基于 Vagrant 手动部署多个 Redis Server

环境准备 宿主机环境:Windows 10 虚拟机环境:Vagrant + VirtualBox Vagrantfile 配置 首先,我们需要编写一个 Vagrantfile 来定义我们的虚拟机配置。假设已经在 D:\Vagrant\redis 目录下创建了一个 Vagrantfile,其内容如下:

基于EF Core存储的Serilog持久化服务

前言 Serilog是 .NET 上的一个原生结构化高性能日志库,这个库能实现一些比内置库更高度的定制。日志持久化是其中一个非常重要的功能,生产环境通常很难挂接调试器或者某些bug的触发条件很奇怪。为了在脱离调试环境的情况下尽可能保留更多线索来辅助解决生产问题,持久化的日志就显得很重要了。目前Ser