下面是转的一个源码,俺没有细看,有兴趣的看看,讲讲如何
// author: Dandy Nee
// mail:dandynee@yeah.net
// module: HW KeyScan Module
// version:0.1
// **************************
// all functions are provided as if okay
// run at your own risk
// **************************
//
// problem:there is one keyvalue valid
//indicator signal needed
//
//------------------------------------------------
//
//^ ^ ^ ^ Pull Up
//| | | |
// x0 >--|--|--|--|-
// x1 >--|--|--|--|-
// x2 >--|--|--|--|-
// x3 >--|--|--|--|-
// y0 <--+ | | |
// y1 <-----+ | |
// y2 <--------+ |
// y3 <-----------+
//
module m_keyscan(
clk,//system clk
rstb,//system a-rst, low active
//
clkdiv,//clock divide coef
//
keyvalue,//returned key
//
x,//x-row scan out
y//y-col scan in
);
inputclk, rstb;
input[19:0] clkdiv;
output [15:0] keyvalue;
output [3:0]x;
input[3:0]y;
reg [19:0] cnt;
always @(posedge clk or negedge rstb)
if(~rstb)
cnt<=0;
else
cnt <= cnt==clkdiv ? 0 : cnt+1;
reg clken;
always @(posedge clk or negedge rstb)
if(~rstb)
clken <= 0;
else
clken <= cnt==clkdiv;
reg [2:0]fsm;
always @(posedge clk or negedge rstb)
if(~rstb)
fsm <= 0;
else if(clken)
fsm <= fsm+1;//8 states
reg [15:0] keyvalue;
reg [3:0]x;
always @(posedge clk or negedge rstb)
if(~rstb)
keyvalue <= 0;
else if(clken)
case(fsm)
0: begin
x <= 4'b1110;
end
1: begin
keyvalue[3:0] <= ~y;
end
2: begin
x <= 4'b1101;
end
3: begin
keyvalue[7:4] <= ~y;
end
4: begin
x <= 4'b1011;
end
5: begin
keyvalue[11:8] <= ~y;
end
6: begin
x <= 4'b0111;
end
7: begin
keyvalue[15:12] <= ~y;
end
endcase
endmodule
本程序做的只是按键单纯挂在IO上,并不是行列扫描的。
其消抖原理:就是采用100hz作为键盘采样的时钟,作一个8bit的reg,采用移位,当按键有效时,即8bit的reg全部为1时,进行动作。两次连续按键之间的时间间隔可以设定(这个是我根据按键感觉加进去的), 下面是我用来测试的源码,调试过的。用FPGA做的。
module key_delay
(
// {{ALTERA_ARGS_BEGIN}} DO NOT REMOVE THIS LINE!
clk, key_in, rst, led
// {{ALTERA_ARGS_END}} DO NOT REMOVE THIS LINE!
);
// Port Declaration
// {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
input clk;
input [1:0] key_in;
input rst;
output [3:0] led;
// {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
reg [17:0] counter ;
reg [3:0] led ;
reg key_clk ;
always @(negedge rst or posedge clk)
if(!rst)
begin
counter <= 0 ;
key_clk <= 0 ;
end
else begin
if(counter >= 250000) //分出用于键盘的时钟为100hz , 需要时钟速度较高时采用流水线
begin
counter <= 0;
key_clk <= ~key_clk ;
end
else counter <= counter + 1 ;
end
reg [1:0] key_reg ; //提取分频后的键盘的时钟上升沿
always @(negedge rst or posedge clk)
if(!rst)
key_reg <= 0 ;
else key_reg <= {key_reg[0] ,key_clk } ;
wire key_all = &key_in ;
reg [7:0] shift_reg ;
reg [3:0] key_interval ;
always @(negedge rst or posedge clk)
if(!rst)
begin
shift_reg <= 0 ;
key_interval <='b_1111 ;
end
else begin
if(key_reg == 2'b01)
begin
if(shift_reg == 8'b1111_1111) //一次有效的按键
begin
shift_reg <= 0 ;
key_interval <= 0;
end
else
begin
if(key_interval =='b_1111 ) //连续按键的时间间隔(可根据需要修改)
shift_reg <= {shift_reg[6:0] , (~key_all)} ;
else key_interval <= key_interval + 1 ; //每次有效的按键后都要用计数器,计数等待。
end
end
end
always @(negedge rst or posedge clk) //用于测试按键的程序 ,通过LED移位来显示
if(!rst)
led <= 2'b01;
else
begin
if(key_reg == 2'b01)
begin
if(shift_reg == 8'b1111_1111)
begin
case(key_in)
2'b01: led <= {led[2:0] ,led[3]};
2'b10: led <= {led[0] ,led[3:1]} ;
default : led <= 4'bxxxx;
endcase
end
end
end
endmodule