资源描述
二、矩阵键盘显示电路设计(显示键盘值的平方)
矩阵键盘显示电路的设计
一、 实验目的
1、 了解普通 4×4 键盘扫描的原理。
2、 进一步加深七段码管显示过程的理解。
3、 了解对输入/输出端口的定义方法。
二、实验原理
实现键盘有两种方案:一是采用现有的一些芯片实现键盘扫描;再就是用软 件实现键盘扫描。作为一个嵌入系统设计人员,总是会关心产品成本。目前有很 多芯片可以用来实现键盘扫描,但是键盘扫描的软件实现方法有助于缩减一个系 统的重复开发成本,且只需要很少的 CPU 开销。嵌入式控制器的功能能强,可 能充分利用这一资源,这里就介绍一下软键盘的实现方案。
图 10-1 简单键盘电路
通常在一个键盘中使用了一个瞬时接触开关,并且用如图 10-1 所示的简单电路,微处理器可以容易地检测到闭合。当开关打开时,通过处理器的 I/O 口的一个上拉电阻提供逻辑 1;当开关闭合时,处理器的/IO口的输入将被拉低得到逻辑 0。可遗憾的是,开关并不完善,因为当它们被按下或者被释放时,并不能够产生一个明确的 1或者 0。尽管触点可能看起来稳定而且很快地闭合,但与微处理器快速的运行速度相比,这种动作是比较慢的。当触点闭合时,其弹起就像一个球。弹起效果将产生如图 10-2所示的好几个脉冲。弹起的持续时间通常将维持在 5ms∼30ms 之间。如果需要多个键,则可以将每个开关连接到微处理器上它自己的输入端口。然而,当开关的数目增加时,这种方法将很快使用完所有的输入端口。
图 10-2 按键抖动
键盘上阵列这些开关最有效的方法(当需要5个以上的键时)就形成了一个如图 10-3 所示的二维矩阵。当行和列的数目一样多时,也就是方型的矩阵,将产生一个最优化的布列方式(I/O 端被连接的时候),一个瞬时接触开关(按钮)放置在每一行与线一列的交叉点。矩阵所需的键的数目显然根据应用程序而不同。 每一行由一个输出端口的一位驱动,而每一列由一个电阻器上拉且供给输入端口一位。
图 10-3 矩阵键盘
键盘扫描的实现过程如下:对于4×4键盘,通常连接为4行、4列,因此要识别按键,只需要知道是哪一行和哪一列即可,为了完成这一识别过程,我们的思想是,首先固定输出 4 行为高电平,然后输出 4 列为低电平,在读入输出的4行的值,通常高电平会被低电平拉低,如果读入的 4 行均为高电平,那么肯定没有按键按下,否则,如果读入的4 行有一位为低电平,那么对应的该行肯定有一个按键按下,这样便可以获取到按键的行值。同理,获取列值也是如此,先输出 4 列为高电平,然后在输出4 行为低电平,再读入列值,如果其中有哪一位为低电平,那么肯定对应的那一列有按键按下。
获取到行值和列值以后,组合成一个 8 位的数据,根据实现不同的编码在对每个按键进行匹配,找到键值后在 7 段码管显示。
三、实验内容
本实验要求完成的任务是通过编程实现对4X4矩阵键盘按下键的键值的读 取,并在数码管上完成一定功能(如移动等)的显示。按键盘的定义,按下“*” 键则在数码管是显示“E”键值。按下“#”键在数码管上显示“F”键值。其它的键则按键盘上的标识进行显示。
在此实验中数码管与 FPGA的连接电路和管脚连接在以前的实验中都做了详细说明,这里不在赘述。本实验箱上的 4X4 矩阵键盘的电路原理如图 10-4 所示。与 FPGA 的管脚连接如表 10-1 所示。
图 10-4 4X4 矩阵键盘电路原理图
表 10-1 4X4 矩阵键与 FPGA 的管脚连接表
信号名称
对应 FPGA 管脚名
说明
KEY-C0
B8
矩阵键盘的第 1 列选择
KEY-C1
A9
矩阵键盘的第 2 列选择
KEY-C2
B9
矩阵键盘的第 3 列选择
KEY-C3
E5
矩阵键盘的第 4 列选择
KEY-R0
B6
矩阵键盘的第 1 行选择
KEY-R1
A7
矩阵键盘的第 2 行选择
KEY-R2
B7
矩阵键盘的第 3 行选择
KEY-R3
A8
矩阵键盘的第 4 行选择
四、实验步骤
1、 打开 QUARTUSII 软件,新建一个工程。
2、 建完工程之后,再新建一个 VHDL File,打开 VHDL编辑器对话框。
3、 按照实验原理和自己的想法,在 VHDL 编辑窗口编写 VHDL 程序,用户可参照光盘中提供的示例程序。
4、 编写完 VHDL 程序后,保存起来。方法同实验一。
5、 对自己编写的 VHDL 程序进行编译并仿真,对程序的错误进行修改。
6、 编译仿真无误后,依照 4X4 矩阵键、数码管与 FPGA 的管脚连接表(表或参照附录)进行管脚分配。表 10-2 是示例程序的管脚分配表。分配完成后,再进行全编译一次,以使管脚分配生效。
端口名
使用模块信号
对应 FPGA 管脚
说 明
CLK
数字信号源
C13
时钟为 1KHZ
KR0
4*4 矩阵键盘 R0
B6
矩阵键盘行信号
KR1
4*4 矩阵键盘 R1
A7
KR2
4*4 矩阵键盘 R2
B7
KR3
4*4 矩阵键盘 R3
A8
KC0
4*4 矩阵键盘 C0
B8
矩阵键盘列信号
KC1
4*4 矩阵键盘 C1
A9
表 10-2 端口管脚分配表
KC2
4*4 矩阵键盘 C2
B9
矩阵键盘列信号
KC3
4*4 矩阵键盘 C3
E5
A
数码管模块 A 段
F13
键值显示
B
数码管模块 B 段
F14
C
数码管模块 C 段
F15
D
数码管模块 D 段
E15
E
数码管模块 E 段
F16
F
数码管模块 F 段
F17
G
数码管模块 G 段
E18
SA
数码管模块 SEL0
G18
SB
数码管模块 SEL1
G17
SC
数码管模块 SEL2
G16
7、 用下载电缆通过 JTAG 口将对应的 sof 文件加载到 FPGA 中。观察实验 结果是否与自己的编程思想一致。
五、实验结果与现象
以设计的参考示例为例,当设计文件加载到目标器件后,将数字信号源模块 的时钟选择为1KHz,按动“模式”按键使单8字数码管显示“0”(参考实验四),按下矩阵键盘的某一个键,则在数码管上显示对应的这个键标识的键值,当再按下第二个键的时候前一个键的键值在数码管上左移一位。按下“*”键则在数码管是显示“E”键值。按下“#”键在数码管上显示“F”键 值。
/************************************************
工 程:4x4矩阵键盘
日 期:2011-08-3
最后修改:
功 能:键盘
说 明:ROW【3:0】设为输入,COL【3:0】设为输出。
如果没有按键按下,则ROW【3:0】一直被上
拉为高电平,且 COL【3:0】有低电平输出,
ROW【3:0】中才有可能低电平输入。
*************************************************/
module keys(clk_50M,rst_n,row,col,dataout,smg_wei);
/*************************************************/
output [3:0]col; //矩阵键盘列
input rst_n; //复位键
input clk_50M; //系统时钟
input [3:0]row; //矩阵键盘行
output [7:0]dataout; //键盘值数码管显示数据
output [7:0]smg_wei; //数码管显示使能
reg [7:0]dataout;
reg [3:0]col;
reg [3:0]key_board_val;
/*************************************************/
assign smg_wei=0; //八个数码管显示
/*************************************************/
//分频部分开始
/*************************************************/
reg[19:0]cnt; //计数子
always @(posedge clk_50M or negedge rst_n)
if(!rst_n)
cnt<=0;
else
cnt<=cnt+1'b1;
wire key_clk=cnt[19];
// 2^20/50M=21ms
/*************************************************
状态机部分 独热码编码
*************************************************/
parameter NO_KEY_PRESSED=6'b000_001;//没有键按下
parameter SCAN_COL0 =6'b000_010;//扫描第 0 列
parameter SCAN_COL1 =6'b000_100;//扫描第 1 列
parameter SCAN_COL2 =6'b001_000;//扫描第 2 列
parameter SCAN_COL3 =6'b010_000;//扫描第 3 列
parameter KEY_PRESSED =6'b100_000;//有键按下
/*************************************************/
reg [5:0]current_state,next_state; //现态和次态
/*************************************************/
//复位
/*************************************************/
always @(posedge key_clk or negedge rst_n)
if(!rst_n)
current_state<=NO_KEY_PRESSED;
else
current_state<=next_state;
/*************************************************/
always @ * //(current_state) //根据条件转移状态
case (current_state)
NO_KEY_PRESSED: //没有键按下
if(row!=4'hf)
next_state=SCAN_COL0;
else
next_state=NO_KEY_PRESSED;
SCAN_COL0: //扫描第 0 列
if(row!=4'hf)
next_state=KEY_PRESSED;
else
next_state=SCAN_COL1;
SCAN_COL1: //扫描第 1 列
if(row!=4'hf)
next_state=KEY_PRESSED;
else
next_state=SCAN_COL2;
SCAN_COL2: //扫描第 2 列
if(row!=4'hf)
next_state=KEY_PRESSED;
else
next_state=SCAN_COL3;
SCAN_COL3: //扫描第 3 列
if(row!=4'hf)
next_state=KEY_PRESSED;
else
next_state=NO_KEY_PRESSED;
KEY_PRESSED: //有按键按下
if(row!=4'hf)
next_state=KEY_PRESSED;
else
next_state=NO_KEY_PRESSED;
endcase
/*************************************************/
reg key_pressed_flag; //按键按下标志
reg [3:0]col_val; //列值
reg [3:0]row_val; //行值
/*************************************************/
//根据次态,给相应的寄存器赋值
/*************************************************/
always @(posedge key_clk or negedge rst_n)
if(!rst_n) //复位
begin
col<=4'h0;
key_pressed_flag<=0;
end
else
case (next_state)
NO_KEY_PRESSED:
begin
col<=4'h0;
key_pressed_flag<=0;
end
SCAN_COL0: //扫描第 0 列
col<=4'b1110;
SCAN_COL1: //扫描第 1 列
col<=4'b1101;
SCAN_COL2: //扫描第 2 列
col<=4'b1011;
SCAN_COL3: //扫描第 3 列
col<=4'b0111;
KEY_PRESSED: //有按键按下
begin
col_val<=col; // 锁存列值
row_val<=row; // 锁存行值
key_pressed_flag<=1;
// 置键盘按下标
end
endcase
/********************************************************************************/
// 扫描行列值部分 开始
/********************************************************************************/
always @(posedge key_clk or negedge rst_n)
if(!rst_n)
key_board_val<=4'h0;
else
if(key_pressed_flag)
case({col_val,row_val})
8'b11101110 : key_board_val <= 4'h0;
8'b11101101 : key_board_val <= 4'h4;
8'b11101011 : key_board_val <= 4'h8;
8'b11100111 : key_board_val <= 4'hC;
8'b11011110 : key_board_val <= 4'h1;
8'b11011101 : key_board_val <= 4'h5;
8'b11011011 : key_board_val <= 4'h9;
8'b11010111 : key_board_val <= 4'hD;
8'b10111110 : key_board_val <= 4'h2;
8'b10111101 : key_board_val <= 4'h6;
8'b10111011 : key_board_val <= 4'hA;
8'b10110111 : key_board_val <= 4'hE;
8'b01111110 : key_board_val <= 4'h3;
8'b01111101 : key_board_val <= 4'h7;
8'b01111011 : key_board_val <= 4'hB;
8'b01110111 : key_board_val <= 4'hF;
endcase
/*********************************************************************************/
// 键盘值转换为数码管显示
/*********************************************************************************/
always @ * //(key_board_val)
begin
case(key_board_val)
4'h0:
dataout<=8'b11000000; //0
4'h1:
dataout<=8'b11111001; //1
4'h2:
dataout<=8'b10100100; //2
4'h3:
dataout<=8'b10110000; //3
4'h4:
dataout<=8'b10011001; //4
4'h5:
dataout<=8'b10010010; //5
4'h6:
dataout<=8'b10000010; //6
4'h7:
dataout<=8'b11111000; //7
4'h8:
dataout<=8'b10000000; //8
4'h9:
dataout<=8'b10010000; //9
4'hA:
dataout<=8'b10001000; //a
4'hB:
dataout<=8'b10000011; //b
4'hC:
dataout<=8'b11000110; //c
4'hD:
dataout<=8'b10100001; //d
4'hE:
dataout<=8'b10000110; //e
4'hF:
dataout<=8'b10001110; //f
endcase
end
/*********************************************************************************/
// 键盘值转换为数码管显示结束
/*********************************************************************************/
endmodule
展开阅读全文