FPGA Verilog HDL 设计实例系列连载--------矩阵键盘接口
时间:10-02
整理:3721RD
点击:
矩阵键盘的原理
矩阵键盘又叫行列式键盘。用带IO口的线组成行列结构,按键设置在行列的交点上。例如用4×4的行列式结构可以构成16个键的键盘。这样,当按键数量平方增长时,I/O口只是线性增长,这样就可以节省I/O口。矩阵键盘的原理图如图1.1所示:
图1.1 矩阵键盘的原理图
按键设置在行列线交叉点,行列线分别连接到按键开关的两端。列线通过上拉电阻接3.3V电压,即列线的输出被钳位到高电平状态。 判断键盘中有无按键按下式通过行线送入扫描线好然后从列线读取状态得到的。其方法是依次给行线送低电平,检查列线的输入。如果列线全是高电平,则代表低电平信号所在的行中无按键按下;如果列线有输入为低电平,则代表低电平信号所在的行和出现低电平的列的交点处有按键按下。2、一个完整的键盘控制程序应解决以下任务:
(1)检测有无按键按下
(2)有键按下,在无硬件去抖得情况下,应有软件延时除去抖动影响
(3)键扫描程序
(4)将键编码转换成相应建值
整个设计程序包括三个模块:时钟分频、键盘扫描和键译码转换。为了显示,还必须在顶层添加显示部分。
3、时钟分频
- //-------------------------------------------------------------------------------------------------
- // File : scan_clk.v
- // Generated : 2011-07-20
- // Author : wangliang
- //-------------------------------------------------------------------------------------------------
- `timescale 1 ns / 1 ps
-
- module scan_clk ( clkout ,clk ,rst );
-
- input rst ;
- input clk ;
- wire clk ;
-
- output clkout ;
-
- reg clkout_r ;
-
- parameter period= 200000;
- //parameter period= 10;
- reg [31:0] cnt;
-
- always @( posedge clk or negedge rst) //分频50Hz
- begin
- if ( !rst )
- begin
- cnt > 1) - 1) //设定周期时间的一半
- clkout_r <= #1 1'b1;
- else if (cnt == period - 1) //设定的周期时间
- begin
- clkout_r <= #1 1'b0;
- cnt <= #1 'b0;
- end
-
- end
- end
- assign clkout = clkout_r ;
-
- endmodule
图1.2 分频模块
4、键盘扫描
键盘扫描电路是用于产生keydrv3~ keydrv0 信号,其变化顺序是1110→1101→1011→0111→1110…周而复始地扫描。其停留时间大慨在20ms。更短的时间没有必要,因为人为按键的时间大慨为20ms,不可能产生有更快的动作;另外,更短的停留时间还容易采集到抖动信号,会干扰判断。而太长的时间容易丢失某些较快的按键动作。图1.3是键盘扫描模块。- //-------------------------------------------------------------------------------------------------
- // File : key_scan.v
- // Generated : 2011-07-20
- // Author : wangliang
- //-------------------------------------------------------------------------------------------------
- `timescale 1 ns / 1 ps
-
- module key_scan ( clk ,keydrv ,rst );
-
- input clk ;
- input rst ;
- wire clk ;
-
- output [3:0] keydrv ;
- wire [3:0] keydrv ;
-
- parameter s1 = 4'b1110;
- parameter s2 = 4'b1101;
- parameter s3 = 4'b1011;
- parameter s4 = 4'b0111;
-
- reg [3:0]current_state;
- reg [3:0]next_state;
-
- always @ ( posedge clk or negedge rst )
-
- begin
- if ( !rst )
- current_state <= s1 ;
- else current_state <= next_state ;
- end
-
- always @ ( current_state )
- begin
- case ( current_state )
- s1: next_state <=s2;
- s2: next_state <=s3;
- s3: next_state <=s4;
- s4: next_state <=s1;
- default: next_state <=s1;
- endcase
- end
-
- assign keydrv = current_state ;
-
- endmodule
图1.3 键盘扫描模块
5、键译码转换
- //-------------------------------------------------------------------------------------------------
- // File : top.v
- // Generated : 2011-07-20
- // Author : wangliang
- //-------------------------------------------------------------------------------------------------
- `timescale 1 ns / 1 ps
-
- module top ( KEYO ,KEYI ,clk ,Y , rst);
-
- input [3:0] KEYO ; //与原理图一致,是键盘输出端口给FPGA
- input clk ;
- input rst ;
-
- output [3:0] KEYI ; //与原理图一致,是FPGA输出给 键盘
- output [7:0] Y ;
-
- wire keypress;
- wire scanclk;
- wire [7:0] temp ;
- wire [3:0] keydrv ;
-
- reg [7:0] temp_r ;
- reg [7:0] Y_r;
- reg [4:0] keyvalue ;
-
- reg [3:0] scankey_o;
- reg [3:0] scankey_i;
- wire dis;
- reg dis_pre;
-
- assign dis = &KEYO ;
-
- scan_clk key_clk(
- .clk ( clk),
- .clkout ( scanclk) ,
- .rst ( rst )
- );
-
- key_scan key_scan(
- .clk ( scanclk ) ,
- .keydrv (keydrv) ,
- .rst ( rst )
- );
-
- always @ ( posedge clk or negedge rst ) begin
- if ( rst==1'b0 ) begin
- scankey_o <= 4'b0 ;
- scankey_i <= 4'b0 ;
- dis_pre <= dis;
- end else if ( clk ==1'b1 ) begin
- dis_pre <= dis;
- if ( (dis == 1'b0)&&(dis_pre==1'b1) ) begin
- scankey_o <= keydrv ;
- scankey_i <= KEYO ;
- end
- end
- end
-
- assign KEYI = keydrv;
-
- assign temp = {scankey_o,scankey_i};
-
- always @ ( posedge clk or negedge rst ) begin
- if ( rst==1'b0 ) begin
- temp_r <= 8'b0;
- end else if ( clk == 1'b1 )
- temp_r <= temp ;
- end
-
- always @( temp_r or rst ) begin
- if ( rst==1'b0 ) begin //译码输出
- keyvalue <= 5'b0;
- end else
- case ( temp_r )
- 8'b0111_0111 : keyvalue <= 5'hb; //无用,仅作为复位
- 8'b1110_1110 : keyvalue <= 5'h7;
- 8'b1110_1101 : keyvalue <= 5'h8;
- 8'b1110_1011 : keyvalue <= 5'h9;
- 8'b1101_1110 : keyvalue <= 5'h4;
- 8'b1101_1101 : keyvalue <= 5'h5;
- 8'b1101_1011 : keyvalue <= 5'h6;
- 8'b1011_1110 : keyvalue <= 5'h1;
- 8'b1011_1101 : keyvalue <= 5'h2;
- 8'b1011_1011 : keyvalue <= 5'h3;
- 8'b0111_1101 : keyvalue <= 5'h0;
- 8'b0111_1011 : keyvalue <= 5'b1_0001; //小数点
- default: keyvalue <= 5'h0;
- endcase
- end
-
- always @(keyvalue or rst ) begin
- if ( rst==1'b0 ) //译码输出
- Y_r <= 8'b0000_0000;
- else begin
- Y_r =8'b0000_0000;
- case (keyvalue )
- 5'h0: Y_r = 8'b0011_1111; // 0
- 5'h1: Y_r = 8'b0000_0110; // 1
- 5'h2: Y_r = 8'b0101_1011; // 2
- 5'h3: Y_r = 8'b0100_1111; // 3
- 5'h4: Y_r = 8'b0110_0110; // 4
- 5'h5: Y_r = 8'b0110_1101; // 5
- 5'h6: Y_r = 8'b0111_1101; // 6
- 5'h7: Y_r = 8'b0000_0111; // 7
- 5'h8: Y_r = 8'b0111_1111; // 8
- 5'h9: Y_r = 8'b0110_1111; // 9
- 5'b1_0001: Y_r = 8'b1000_0000; //.
- default: Y_r = 8'b0000_0000;
- endcase
- end
- end
-
- assign Y =~Y_r;
-
- endmodule
图1.4 键译码转换模块
分配引脚:
按照图1.4的结构,将其对应的接口配以引脚,其中,Y[7..0]是七段数码管的引脚;clk是系统时钟;rst接复位信号;KEYO[3..0]接行扫描码;KEYI[3..0]接列的状态(可对应原理图)。
实验结果:
这样子
很好
太给力了
好强大啊,谢谢了!
haohao..
很强大,学习了!
给力
谢谢小编很好的东西啊
为啥看不到代码的
好强大 学习了
小编给力,怎么做LCD1602的动态显示,可以边采样边显示的那种,用Verilog写的
你好,请问一下如何通过矩阵键盘依次输入数据,并显示在数码管上?刚接触FPGA,请大神指教
很好,谢谢小编分享了
非常实用!nice!
好东东了!我要好好学习。
好东西,好给力啊