【连载】 FPGA Verilog HDL 系列实例--------矩阵键盘接口

【连载】 FPGA Verilog HDL 系列实例  

Verilog HDL 之 矩阵键盘接口

 

1、矩阵键盘的原理

  矩阵键盘又叫行列式键盘。用带IO口的线组成行列结构,按键设置在行列的交点上。例如用4×4的行列式结构可以构成16个键的键盘。这样,当按键数量平方增长时,I/O口只是线性增长,这样就可以节省I/O口。矩阵键盘的原理图如图1.1所示:

         

                           图1.1  矩阵键盘的原理图

  按键设置在行列线交叉点,行列线分别连接到按键开关的两端。列线通过上拉电阻接3.3V电压,即列线的输出被钳位到高电平状态。
  判断键盘中有无按键按下式通过行线送入扫描线好然后从列线读取状态得到的。其方法是依次给行线送低电平,检查列线的输入。如果列线全是高电平,则代表低电平信号所在的行中无按键按下;如果列线有输入为低电平,则代表低电平信号所在的行和出现低电平的列的交点处有按键按下。

2、一个完整的键盘控制程序应解决以下任务:

  (1)检测有无按键按下
  (2)有键按下,在无硬件去抖得情况下,应有软件延时除去抖动影响
  (3)键扫描程序
  (4)将键编码转换成相应建值
  整个设计程序包括三个模块:时钟分频、键盘扫描和键译码转换。为了显示,还必须在顶层添加显示部分。


3、时钟分频

  由于使用的外部时钟频率为50MHz,这个频率对扫描来说太高,所以这里需要一个分频器来分得适合键盘扫描使用的频率。

scan_clk.v
 1 //-------------------------------------------------------------------------------------------------
2 // File : scan_clk.v
3 // Generated : 2011-07-20
4 // Author : wangliang
5 //-------------------------------------------------------------------------------------------------
6 `timescale 1 ns / 1 ps
7
8 module scan_clk ( clkout ,clk ,rst );
9
10 input rst ;
11 input clk ;
12 wire clk ;
13
14 output clkout ;
15
16 reg clkout_r ;
17
18 parameter period= 200000;
19 //parameter period= 10;
20 reg [31:0] cnt;
21
22 always @( posedge clk or negedge rst) //分频50Hz
23 begin
24 if ( !rst )
25 begin
26 cnt <= {31{1'b0}} ;
27 clkout_r <= 0 ;
28 end
29 else begin
30 cnt<= cnt+1;
31 if (cnt == (period >> 1) - 1) //设定周期时间的一半
32 clkout_r <= #1 1'b1;
33 else if (cnt == period - 1) //设定的周期时间
34 begin
35 clkout_r <= #1 1'b0;
36 cnt <= #1 'b0;
37 end
38
39 end
40 end
41 assign clkout = clkout_r ;
42
43 endmodule
  注:从上面可以看出,我们经过分频得到50HZ的时钟,是为下一模块键盘扫描提供的时钟,之所以是50HZ,而不是其他的数值,是因为,人在按键的时候,其停留时间大概是20ms左右,键盘扫描时,会发送固定的数值码,本例中是循环的发送4种数值,下面会提及到,50HZ转化为时间是0.02S=20ms。图1.2是分频模块。

        

         图1.2  分频模块

4、键盘扫描

  键盘扫描电路是用于产生keydrv3~ keydrv0 信号,其变化顺序是1110→1101→1011→0111→1110…周而复始地扫描。其停留时间大慨在20ms。更短的时间没有必要,因为人为按键的时间大慨为20ms,不可能产生有更快的动作;另外,更短的停留时间还容易采集到抖动信号,会干扰判断。而太长的时间容易丢失某些较快的按键动作。图1.3是键盘扫描模块。

key_scan.v
 1 //-------------------------------------------------------------------------------------------------
2 // File : key_scan.v
3 // Generated : 2011-07-20
4 // Author : wangliang
5 //-------------------------------------------------------------------------------------------------
6 `timescale 1 ns / 1 ps
7
8 module key_scan ( clk ,keydrv ,rst );
9
10 input clk ;
11 input rst ;
12 wire clk ;
13
14 output [3:0] keydrv ;
15 wire [3:0] keydrv ;
16
17 parameter s1 = 4'b1110;
18 parameter s2 = 4'b1101;
19 parameter s3 = 4'b1011;
20 parameter s4 = 4'b0111;
21
22 reg [3:0]current_state;
23 reg [3:0]next_state;
24
25 always @ ( posedge clk or negedge rst )
26
27 begin
28 if ( !rst )
29 current_state <= s1 ;
30 else current_state <= next_state ;
31 end
32
33 always @ ( current_state )
34 begin
35 case ( current_state )
36 s1: next_state <=s2;
37 s2: next_state <=s3;
38 s3: next_state <=s4;
39 s4: next_state <=s1;
40 default: next_state <=s1;
41 endcase
42 end
43
44 assign keydrv = current_state ;
45
46 endmodule

        

         图1.3 键盘扫描模块

5、键译码转换
  

  键盘译码电路是从keydrv3~keydrv0和keyin3~keyin0信号中译码出按键值的电路。clk是全局时钟,由外部晶振提供。clk在系统的频率是最高的,其他的时钟由分频产生。Keydrv表示键盘扫描信号,keyin为键盘输入信号,keyvalue为键值。其外部接口如图1.4所示。

 

View Code
  1 //-------------------------------------------------------------------------------------------------
2 // File : top.v
3 // Generated : 2011-07-20
4 // Author : wangliang
5 //-------------------------------------------------------------------------------------------------
6 `timescale 1 ns / 1 ps
7
8 module top ( KEYO ,KEYI ,clk ,Y , rst);
9
10 input [3:0] KEYO ; //与原理图一致,是键盘输出端口给FPGA
11 input clk ;
12 input rst ;
13
14 output [3:0] KEYI ; //与原理图一致,是FPGA输出给 键盘
15 output [7:0] Y ;
16
17 wire keypress;
18 wire scanclk;
19 wire [7:0] temp ;
20 wire [3:0] keydrv ;
21
22 reg [7:0] temp_r ;
23 reg [7:0] Y_r;
24 reg [4:0] keyvalue ;
25
26 reg [3:0] scankey_o;
27 reg [3:0] scankey_i;
28 wire dis;
29 reg dis_pre;
30
31 assign dis = &KEYO ;
32
33 scan_clk key_clk(
34 .clk ( clk),
35 .clkout ( scanclk) ,
36 .rst ( rst )
37 );
38
39 key_scan key_scan(
40 .clk ( scanclk ) ,
41 .keydrv (keydrv) ,
42 .rst ( rst )
43 );
44
45 always @ ( posedge clk or negedge rst ) begin
46 if ( rst==1'b0 ) begin
47 scankey_o <= 4'b0 ;
48 scankey_i <= 4'b0 ;
49 dis_pre <= dis;
50 end else if ( clk ==1'b1 ) begin
51 dis_pre <= dis;
52 if ( (dis == 1'b0)&&(dis_pre==1'b1) ) begin
53 scankey_o <= keydrv ;
54 scankey_i <= KEYO ;
55 end
56 end
57 end
58
59 assign KEYI = keydrv;
60
61 assign temp = {scankey_o,scankey_i};
62
63 always @ ( posedge clk or negedge rst ) begin
64 if ( rst==1'b0 ) begin
65 temp_r <= 8'b0;
66 end else if ( clk == 1'b1 )
67 temp_r <= temp ;
68 end
69
70 always @( temp_r or rst ) begin
71 if ( rst==1'b0 ) begin //译码输出
72 keyvalue <= 5'b0;
73 end else
74 case ( temp_r )
75 8'b0111_0111 : keyvalue <= 5'hb; //无用,仅作为复位
76 8'b1110_1110 : keyvalue <= 5'h7;
77 8'b1110_1101 : keyvalue <= 5'h8;
78 8'b1110_1011 : keyvalue <= 5'h9;
79 8'b1101_1110 : keyvalue <= 5'h4;
80 8'b1101_1101 : keyvalue <= 5'h5;
81 8'b1101_1011 : keyvalue <= 5'h6;
82 8'b1011_1110 : keyvalue <= 5'h1;
83 8'b1011_1101 : keyvalue <= 5'h2;
84 8'b1011_1011 : keyvalue <= 5'h3;
85 8'b0111_1101 : keyvalue <= 5'h0;
86 8'b0111_1011 : keyvalue <= 5'b1_0001; //小数点
87 default: keyvalue <= 5'h0;
88 endcase
89 end
90
91 always @(keyvalue or rst ) begin
92 if ( rst==1'b0 ) //译码输出
93 Y_r <= 8'b0000_0000;
94 else begin
95 Y_r =8'b0000_0000;
96 case (keyvalue )
97 5'h0: Y_r = 8'b0011_1111; // 0
98 5'h1: Y_r = 8'b0000_0110; // 1
99 5'h2: Y_r = 8'b0101_1011; // 2
100 5'h3: Y_r = 8'b0100_1111; // 3
101 5'h4: Y_r = 8'b0110_0110; // 4
102 5'h5: Y_r = 8'b0110_1101; // 5
103 5'h6: Y_r = 8'b0111_1101; // 6
104 5'h7: Y_r = 8'b0000_0111; // 7
105 5'h8: Y_r = 8'b0111_1111; // 8
106 5'h9: Y_r = 8'b0110_1111; // 9
107 5'b1_0001: Y_r = 8'b1000_0000; //.
108 default: Y_r = 8'b0000_0000;
109 endcase
110 end
111 end
112
113 assign Y =~Y_r;
114
115 endmodule
  注:其中第33行~第43行,是实例化上面2个时钟分频模块和键盘扫描模块。第61行的temp是根据键盘的行和键盘的列确立的一个序列。第70行~第89行是根据temp确定键值。第91行~第111行是根据键值确定数码管的显示,数码管由8位组成,最高位是小数点位。

       

       图1.4 键译码转换模块

 分配引脚:

  按照图1.4的结构,将其对应的接口配以引脚,其中,Y[7..0]是七段数码管的引脚;clk是系统时钟;rst接复位信号;KEYO[3..0]接行扫描码;KEYI[3..0]接列的状态(可对应原理图)。

 实验结果:

  

  我们用到的就是这种标准的数字键盘,已经上面2个七段数码管中的一个。当按下数字键的时候,可以在数码管中显示出来。好了,这样就完成了键盘的实验了。就这样吧。如果还想了解其他的Verilog HDL的实验的话,可以点击【连载】 FPGA Verilog HDL 系列实例

 

 

 

 


 

posted @ 2011-07-21 19:25  让linux飞一会儿  阅读(6471)  评论(6编辑  收藏  举报