矩阵键盘原理
在做矩阵键盘的驱动时,写了好多次都没有成功,出现了各种奇奇怪怪的错误。最后在网上看了无数篇的博客和讲解,终于搞懂了原理。
矩阵键盘的电路原理图如图所示(在网上看到别人的就随手down了下来):
矩阵键盘一共十六个按键,共接出八个引脚(四个行四个列),其中四个输入,四个输出。一般都把四个行作为输入的四条线,把四个列作为输出。
先将四条列线全部拉低,若有按键被按下,电路接通,则对应的行线也被拉低,输出低电平,其余行线为高电平。然后在依次拉低每一条列线,其余列线置高电平,来判断是哪一根列线使输出行线拉低,则跟据输入输出八根线的电位情况,就可以判断出哪个按键被按下。
程序编写
首先要明确程序要实现一个什么样的功能,这里我写的是一个矩阵键盘驱动然后输出键值并通过一位数码管进行显示。
在明确了程序功能后,就要确定功能引脚及接口。我一共使用了两个输入(一个是系统脉冲,一个是四位行输入接口),三个输出接口(一个是四位列输出接口,一个是数码管位接口,一个是数码管的八位段接口)
module key_board(
input clk,
input [3:0] row, // 矩阵键盘 行
output reg [3:0] col, // 矩阵键盘 列
output reg [7:0] seg,
output reg sel
);
接下来就是定义了各种中间信号还有定义的数码管常量(分别根据八段数码管值定义了从0~f的十六进制的数字显示):
reg [19:0] cnt; //计数器
reg [3:0] key_out; // 键盘值
reg [5:0] current_state, next_state; // 现态、次态
reg key_pressed_flag; // 键盘按下标志
reg [3:0] col_val, row_val; // 列行值寄存器
reg key_clk; //分频脉冲
//*************数码管数值定义******************//
parameter disp0=8'b1100_0000;
parameter disp1=8'b1111_1001;
parameter disp2=8'b1010_0100;
parameter disp3=8'b1011_0000;
parameter disp4=8'b1001_1001;
parameter disp5=8'b1001_0010;
parameter disp6=8'b1000_0010;
parameter disp7=8'b1111_1000;
parameter disp8=8'b1000_0000;
parameter disp9=8'b1001_0000;
parameter dispa=8'b1000_1000;
parameter dispb=8'b1000_0011;
parameter dispc=8'b1010_0111;
parameter dispd=8'b1010_0001;
parameter dispe=8'b1000_0110;
parameter dispf=8'b1000_0011;
程序定义了六个状态的状态机,整个程序的重点就在于状态机的列状态切换。六个状态分别为 “没有按键按下”、“扫描第1列”、“扫描第2列”、“扫描第3列”、“扫描第4列”、“有按键按下”:
//*******************状态机定义*********************//
parameter IDLE = 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; // 有按键按下
状态切换考虑到按键的消抖,所以通过分频产生21ms的脉冲来作为状态切换的时间间隔。分频模块如下:
//***************分频*******************//
always @ (posedge clk)
begin
if(cnt<=20'd1048_500) //分频21ms
cnt <= cnt + 1'b1;
else begin
cnt<=0;
key_clk<=~key_clk;
end
end
//****************状态切换***************//
always @