FPGA学习系列:26. 矩阵键盘的设计

描述

设计背景:

矩阵键盘在工程设计越来越多的被用到,已然成为了我们做开发接触到的不可缺少的小型项目,利于我们理解设计方向的原理为以后的强化学习打好了坚实的基础。

设计原理: 

 

 在使用按键的时候,如果按键不多的话,我们可以直接按键与FPGA相连接,但是如果按键比较多的时候,如何还继续使用直接按键与FPGA相连接的话,所会大量增加FPGA端口的消耗,为了减少FPGA端口的消

耗,我们可以把按键设计成矩阵的形式,就如下图所示:

FPGA

 由上图可以知道,矩阵键盘的行row(行)与col(列)的交点,都是通过一个按键来相连接。传统的一个按键一个端口的方法,若要实现16个按键,则需要16个端口,而现在这个矩阵键盘的设计,16个按键,仅仅需要8个端口,如果使用16个端口来做矩阵键盘的话,可以识别64个按键,端口的利用率远远比传统的设计好的多,所以如果需要的按键少的话,可以选择传统的按键设计,如果需要的按键比较多的话,可以采用这种矩阵键盘的设计。而我们现在就以扫描法为例来介绍矩阵键盘的工作原理。

首先col(列)是FPGA给矩阵键盘输出的扫描信号,而row(行)是矩阵键盘反馈给FPGA的输入信号,用于检测哪一个按键被按下来,如下图所示:

FPGA

详细如上图所示,FPGA给出扫描信号COL[3:0]COL = 4’b0111,等下一个时钟周期COL = 4’b1011,再等下一个时钟周期COL =4’b1101,再等下一个时钟周期COL = 4’b1110,再等下一个时钟周期COL = 4’b0111COL就是这样不断循环,给矩阵键盘一个低电平有效的扫描信号,当FPGA给矩阵键盘COL扫描信号的同时,FPGA也要在检测矩阵键盘给FPGA的的反馈信号ROW,举个例子,假若矩阵键盘中的9号案件被按下了:

COL = 4’b1101ROW =4’b1011 ;

9号按键被按下的时候,9号按键的电路就会被导通,扫描电路COL开始扫描,当扫描到COL[1]的时候,由于9号按键的电路被导通了,COL[1]的电压等于ROW[2]的电压,所以会出现当COL = 4’b1101的时候ROW = 4’b1011;然后我们就可以利用这一种现象,来设计一个识别按键的电路。

 

设计架构图:

FPGA

设计代码:

设计模块

0 module key_borad(clk,rst_n,row,col,key_num);

1  input clk;

2  input rst_n;

3  input [3:0] row;  //输入反馈信号

4 

5 

6  output reg [3:0] col; //输出扫描信号

7  output reg [3:0] key_num; //按键值得输除

8 

9  reg [15:0] count;

10

11 parameter T1ms = 50000;   //扫描的时间间隔 50000 * 20ns

12 //parameter T1ms = 5;

13

14 reg flag;

15 always @ (posedge clk or negedge rst_n)

16  if(!rst_n)

17   begin

18    count <= 16'd0;

19    flag <= 1'b0;

20   end

21  else

22   begin

23    if(count <  T1ms - 1)   //计数时间

24     begin

25      count <= count + 1'b1;

26      flag <= 0;

27     end

28    else

29     begin 

30      flag <= 1'b1;     //计数到了就给一个标志位

31      count <= 16'b0;

32     end

33   end

34 always @ (posedge clk or negedge rst_n)

35  if(!rst_n)

36   begin

37    col <= 4'b0111;

38   end

39  else

40   begin

41    if(flag)

42     col <= {col[2:0],col[3]};   //列扫描

43    else

44     col <= col;

45   end

46

47 //键值得翻译模块

48 always @ (posedge clk or negedge rst_n)

49  if(!rst_n)

50   key_num = 4'd0;

51  else

52   case ({row,col})  //位拼接行和列的信号,翻译出对应的键值

53    8'b0111_0111:key_num = 4'hf;

54    8'b0111_1011:key_num = 4'he;

55    8'b0111_1101:key_num = 4'hd;

56    8'b0111_1110:key_num = 4'hc;

57    

58    8'b1011_0111:key_num = 4'hb;

59    8'b1011_1011:key_num = 4'ha;

60    8'b1011_1101:key_num = 4'h9;

61    8'b1011_1110:key_num = 4'h8;

62    

63    8'b1101_0111:key_num = 4'h7;

64    8'b1101_1011:key_num = 4'h6;

65    8'b1101_1101:key_num = 4'h5;

66    8'b1101_1110:key_num = 4'h4;

67    

68    8'b1110_0111:key_num = 4'h3;

69    8'b1110_1011:key_num = 4'h2;

70    8'b1110_1101:key_num = 4'h1;

71    8'b1110_1110:key_num = 4'h0;

72    default: ;

73   endcase

74 endmodule 

 

测试模块

0 `timescale 1ns/1ps

1 

2 module key_borad_tb();

3  reg clk;

4  reg rst_n;

5  reg [4:0] pressnum;  //按键的值

6  wire [3:0] row;

7 

8  wire [3:0] col;

9  wire [3:0] key_num;   //输出的值

10

11 initial begin

12   clk = 1'b1;

13   rst_n = 1'b0;

14   pressnum = 5'd16;

15

16   #200.1

17    rst_n = 1'b1;

18   #1000

19    pressnum = 5'd16;

20    

21   #1000

22    pressnum = 5'd8;

23    

24   #1000

25    pressnum = 5'd16;

26    

27   #1000

28    pressnum = 5'd15;

29   #1000

30    pressnum = 5'd16;

31   #1000

32    $stop;

33

34  end

35 always #10 clk = ~clk;

36 //例化对应的模块

37 key_top borad_dut(

38   .clk(clk),

39   .rst_n(rst_n),

40   .row(row),

41   .col(col),

42   .key_num(key_num)

43  );

44 yingjian yingjian_dut(    //硬件检测电路   //此模块自己可以设计

45   .clk(clk),

46   .rst_n(rst_n),

47   .col(col),

48   .row(row),

49   .pressnum(pressnum)

50  );

51 endmodule 

 

 

仿真图:

在仿真图中可以清晰的看出当按键按下的时候为8,显示出来的键值也为8,当抬起的时候为16,那么键值就保持不变,在设置的时候我们设置的是按键抬起为16,通过验证我们得到我们的设计是正确的。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分