对行列按键的学习与实现,包含行列按键的原理、FPGA的完整实现过程,使用FPGA开发板artix-7A35ftg256-1。
一、行列按键基本原理
1.原理图分析
4行4列,共8个引脚,控制16个按键。其中每一列需要额外添加下拉电阻。行输入,列输出,根据输入输出的结果判断按键的位置
下拉电阻可以在约束文件中体现。
设计思路:1.逐行扫描,检测被按下的键,输出至一个8维数组中
2.将数组与key0~key15对应起来
2.按键消抖
按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,一般来说,抖动会持续5ms~20ms(取决于机械特性)。为了不产生这种现象而作的措施就是按键消抖。
去抖设计:声明3个寄存器btn0、btn1、btn2,并将它们组合成移位寄存器,将移位方向定义为btn0->btn1->btn2。将按键输入送btn0。每隔20ms执行一次移位。在每20ms后,btn0中存储的是当前的按键电平,btn1中存储的是20ms之前的按键电平,btn2中存储的是40ms之前的按键电平。
若判断按下,则结果为1
[btn0,btn1,btn2]若检测到011,111,110,则认为当前按键被按下;
反之[btn0,btn1,btn2]若检测到001,100,000,则认为当前按键松开
至于010和101则认为状态不存在
assign btn_out = (btn2&btn1&btn0)|(~btn2&btn1&btn0)|(btn2&btn1&~btn0); //当40ms内按键的值不发生变化,认为输出为高电平
二、FPGA实现
1.时钟分频
对于FPGA开发板artix-7A35ftg256-1,一般设置为50Mhz,通过下列代码实现(因为系统 #1=1ns)
assign #10 clk=~clk;
之后在50MHz时钟的基础上,又进行了25000分频和500000分频,得到1KHz和50HZ时钟
代码如下:
module v_divclk(
input clk,
output clk_ms,
output clk_btn
);
parameter divclk_ms=25000,divclk_btn=500000;
reg clk_ms=1;
reg clk_btn=1;
reg [31:0]cnt_ms=0;
reg [31:0]cnt_btn=0;
always @(posedge clk) begin
if(cnt_ms==divclk_ms)begin
cnt_ms=0;
clk_ms=~clk_ms;
end
else begin
cnt_ms=cnt_ms+1;
end
end
always @(posedge clk) begin
if(cnt_btn==divclk_btn)begin
cnt_btn=0;
clk_btn=~clk_btn;
end
else begin
cnt_btn=cnt_btn+1;
end
end
endmodule
2.按键模块
2.1 设计代码
module v_xd_test(
input clk,
input clk_btn,
input [3:0]col,
output [3:0]row,
output [15:0]btn_out
);
reg [3:0]row=4'b0001;
reg[15:0]btn0,btn1,btn2,btn3;
wire[3:0]col;
wire[15:0]btn_out;
//*********scan the row**********//
always @(posedge clk)begin
if (row[3:0]==4'b1000) begin
row[3:0]=4'b0001;
end
else begin
row[3:0]=row[3:0]<<1;
end
end
//************assign the value***************//
always @(posedge clk)begin
case(row[3:0])
4'b0001:btn0[3:0]=col[3:0];
4'b0010:btn0[7:4]=col[3:0];
4'b0100:btn0[11:8]=col[3:0];
4'b1000:btn0[15:12]=col[3:0];
default:btn0=16'b0;
endcase
end
//************** disappears shakes**************//
always@ (posedge clk_btn) begin
btn1<=btn0;
btn2<=btn1;
btn3<=btn2;
end
assign btn_out= (btn2&btn1&btn3)|(~btn3&btn1&btn2);
endmodule
3.数码管显示
module v_smg(
input clk,
input [15:0]sw,
output [7:0]seg,
output [3:0]DIG
);
reg clkDiv=0;
reg [31:0]clkCnt=0;
reg [2:0]bit=0;
reg [3:0]disp_bat;
reg [5:0]DIG;
reg [7:0]seg;
parameter clkNum=25000;
always@(posedge clk) begin
if (clkCnt==clkNum) begin
clkDiv=~clkDiv;
clkCnt=0;
end
else begin
clkCnt=clkCnt+1;
end
end
always@(posedge clkDiv) begin
if(bit>5) begin
bit=0;
end
else begin
bit=bit+1;
end
case (bit)
3'h0:
begin
disp_bat=sw[3:0];
DIG=6'b111110;
end
3'h1:
begin
disp_bat=sw[7:4];
DIG=6'b111101;
end
3'h2:
begin
disp_bat=sw[11:8];
DIG=6'b111011;
end
3'h3:
begin
disp_bat=sw[15:12];
DIG=6'b110111;
end
default:
begin
disp_bat=sw[3:0];
DIG=6'b111111;
end
endcase
end
always@(disp_bat) begin
case(disp_bat)
4'h0: seg=8'h3f;
4'h1: seg=8'h06;
4'h2: seg=8'h5b;
4'h3: seg=8'h4f;
4'h4: seg=8'h66;
4'h5: seg=8'h6d;
4'h6: seg=8'h7d;
4'h7: seg=8'h07;
4'h8: seg=8'h7f;
4'h9: seg=8'h6f;
4'ha: seg=8'h88;
4'hb: seg=8'h83;
4'hc: seg=8'hc6;
4'hd: seg=8'ha1;
4'he: seg=8'h86;
4'hf : seg=8'h8e;
endcase
end
endmodule
4.顶层文件
module v_keyboard(
input clk,
input [7:0]sw,
output [3:0]row,
input [3:0]col,
output [5:0]DIG,
output [7:0]seg,
output [11:0]led
);
reg [31:0]divclk_cnt=0;
reg [31:0]btn_clk=0;
reg [11:0]led;
reg [9:0]ms=0;
wire [15:0]dispdata;
wire [15:0]btnout;
reg [15:0]btn_out0,btn_out1,btn_down;
reg [3:0]sec_l=0,sec_h=0,min_l=0,min_h=0; //minute,second
assign dispdata={min_h,min_l,sec_h,sec_l}; // display time
v_smg ttra(
.clk(clk),
.sw(dispdata),
.seg(seg),
.DIG(DIG)
);
v_divclk uuc(
.clk(clk),
.clk_ms(divclk), //1khz
.clk_btn(btnclk) //50hz
);
v_xd_test ctta(
.clk(clk),
.clk_btn(btnclk),
.col(col),
.row(row),
.btn_out(btnout)
);
/***************use led to test the button**********************/
always @ (posedge divclk)begin
led<=btnout[11:0];
end
always @(posedge divclk) begin
btn_out0<=btnout; //after finshing the block,the value of btn_out0 changes
btn_out1<=btn_out0;
btn_down<=btn_out0&~btn_out1;
end
// if sw[0]==0, it's timer;else you can set the value of second,minute...
always@ (posedge divclk) begin
if(sw[0]==0) begin//fisplay the time
ms=ms+1;
if(ms==1000) begin
ms=0;
sec_l=sec_l+1;
end
if(sec_l==10) begin
sec_h=sec_h+1;
sec_l=0;
end
if (sec_h==6) begin
sec_h=0;
min_l=min_l+1;
end
if(min_l==10) begin
min_l=0;
min_h=min_h+1;
end
if (min_h==6) begin
min_h=0;
end
end
else begin
// set the four buttons,they have the different fuctions
if(btn_down[0]==1) begin
sec_l=0;
sec_h=0;
min_l=0;
min_h=0;
end
else begin
if(btn_down[1]==1) begin
sec_l=sec_l+1;
if(sec_l==10) begin
sec_l=0;
end
end
if(btn_down[2]==1) begin
sec_h=sec_h+1;
if(sec_h==6) begin
sec_h=0;
end
end
if(btn_down[3]==1) begin
min_l=min_l+1;
if(min_l==10) begin
min_l=0;
end
end
if(btn_down[4]==1) begin
min_h=min_h+1;
if(min_h==6) begin
min_h=0;
end
end
end
end
end
endmodule
5.约束文件
## CLK
set_property PACKAGE_PIN D4 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
## switches
set_property PACKAGE_PIN F3 [get_ports {sw[11]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[11]}]
set_property PACKAGE_PIN H4 [get_ports {sw[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[10]}]
set_property PACKAGE_PIN N4 [get_ports {sw[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[9]}]
set_property PACKAGE_PIN R2 [get_ports {sw[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[8]}]
set_property PACKAGE_PIN R3 [get_ports {sw[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[7]}]
set_property PACKAGE_PIN P4 [get_ports {sw[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[6]}]
set_property PACKAGE_PIN R5 [get_ports {sw[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[5]}]
set_property PACKAGE_PIN P6 [get_ports {sw[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[4]}]
set_property PACKAGE_PIN R6 [get_ports {sw[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[3]}]
set_property PACKAGE_PIN T7 [get_ports {sw[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[2]}]
set_property PACKAGE_PIN T8 [get_ports {sw[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[1]}]
set_property PACKAGE_PIN T9 [get_ports {sw[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[0]}]
## SEG A~G DP=seg[0]~seg[7]
set_property PACKAGE_PIN P11 [get_ports {seg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[0]}]
set_property PACKAGE_PIN N12 [get_ports {seg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[1]}]
set_property PACKAGE_PIN L14 [get_ports {seg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[2]}]
set_property PACKAGE_PIN K13 [get_ports {seg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[3]}]
set_property PACKAGE_PIN K12 [get_ports {seg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[4]}]
set_property PACKAGE_PIN P13 [get_ports {seg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[5]}]
set_property PACKAGE_PIN M14 [get_ports {seg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[6]}]
set_property PACKAGE_PIN L13 [get_ports {seg[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[7]}]
## DIG
set_property PACKAGE_PIN G12 [get_ports {DIG[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {DIG[0]}]
set_property PACKAGE_PIN H13 [get_ports {DIG[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {DIG[1]}]
set_property PACKAGE_PIN M12 [get_ports {DIG[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {DIG[2]}]
set_property PACKAGE_PIN N13 [get_ports {DIG[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {DIG[3]}]
set_property PACKAGE_PIN N14 [get_ports {DIG[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {DIG[4]}]
set_property PACKAGE_PIN N11 [get_ports {DIG[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {DIG[5]}]
## col
set_property PACKAGE_PIN R12 [get_ports {col[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {col[0]}]
set_property PACKAGE_PIN T12 [get_ports {col[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {col[1]}]
set_property PACKAGE_PIN R11 [get_ports {col[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {col[2]}]
set_property PACKAGE_PIN T10 [get_ports {col[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {col[3]}]
set_property PULLDOWN true [get_ports {col[3]}]
set_property PULLDOWN true [get_ports {col[2]}]
set_property PULLDOWN true [get_ports {col[1]}]
set_property PULLDOWN true [get_ports {col[0]}]
## row
set_property PACKAGE_PIN K3 [get_ports {row[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {row[0]}]
set_property PACKAGE_PIN M6 [get_ports {row[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {row[1]}]
set_property PACKAGE_PIN P10 [get_ports {row[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {row[2]}]
set_property PACKAGE_PIN R10 [get_ports {row[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {row[3]}]
## LED
set_property PACKAGE_PIN E3 [get_ports {led[11]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[11]}]
set_property PACKAGE_PIN H3 [get_ports {led[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[10]}]
set_property PACKAGE_PIN G5 [get_ports {led[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[9]}]
set_property PACKAGE_PIN R1 [get_ports {led[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[8]}]
set_property PACKAGE_PIN T2 [get_ports {led[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[7]}]
set_property PACKAGE_PIN T3 [get_ports {led[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[6]}]
set_property PACKAGE_PIN T4 [get_ports {led[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[5]}]
set_property PACKAGE_PIN N6 [get_ports {led[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[4]}]
set_property PACKAGE_PIN T5 [get_ports {led[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}]
set_property PACKAGE_PIN R7 [get_ports {led[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}]
set_property PACKAGE_PIN R8 [get_ports {led[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}]
set_property PACKAGE_PIN P9 [get_ports {led[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}]
endmodule