设计背景:
矩阵键盘在工程设计越来越多的被用到,已然成为了我们做开发接触到的不可缺少的小型项目,利于我们理解设计方向的原理为以后的强化学习打好了坚实的基础。
设计原理:
在使用按键的时候,如果按键不多的话,我们可以直接按键与FPGA相连接,但是如果按键比较多的时候,如何还继续使用直接按键与FPGA相连接的话,所会大量增加FPGA端口的消耗,为了减少FPGA端口的消
耗,我们可以把按键设计成矩阵的形式,就如下图所示:
由上图可以知道,矩阵键盘的行row(行)与col(列)的交点,都是通过一个按键来相连接。传统的一个按键一个端口的方法,若要实现16个按键,则需要16个端口,而现在这个矩阵键盘的设计,16个按键,仅仅需要8个端口,如果使用16个端口来做矩阵键盘的话,可以识别64个按键,端口的利用率远远比传统的设计好的多,所以如果需要的按键少的话,可以选择传统的按键设计,如果需要的按键比较多的话,可以采用这种矩阵键盘的设计。而我们现在就以扫描法为例来介绍矩阵键盘的工作原理。
首先col(列)是FPGA给矩阵键盘输出的扫描信号,而row(行)是矩阵键盘反馈给FPGA的输入信号,用于检测哪一个按键被按下来,如下图所示:
详细如上图所示,FPGA给出扫描信号COL[3:0],COL = 4’b0111,等下一个时钟周期COL = 4’b1011,再等下一个时钟周期COL =4’b1101,再等下一个时钟周期COL = 4’b1110,再等下一个时钟周期COL = 4’b0111,COL就是这样不断循环,给矩阵键盘一个低电平有效的扫描信号,当FPGA给矩阵键盘COL扫描信号的同时,FPGA也要在检测矩阵键盘给FPGA的的反馈信号ROW,举个例子,假若矩阵键盘中的9号案件被按下了:
当 COL = 4’b1101,ROW =4’b1011 ;
当9号按键被按下的时候,9号按键的电路就会被导通,扫描电路COL开始扫描,当扫描到COL[1]的时候,由于9号按键的电路被导通了,COL[1]的电压等于ROW[2]的电压,所以会出现当COL = 4’b1101的时候ROW = 4’b1011;然后我们就可以利用这一种现象,来设计一个识别按键的电路。
设计架构图:
设计代码:
设计模块
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,通过验证我们得到我们的设计是正确的。
全部0条评论
快来发表一下你的评论吧 !