FPGA矩阵键盘驱动设计及Testbench验证
FPGA矩阵键盘驱动设计
设计思路
采用20ms的延时电路产生使能时钟去扫描,可以直接省略掉按键的消抖延时;虽然每个状态都要进行一次延时消抖,但RTL设计上却更加简单了。
工作过程
- ROW[3:0]作为处理器的输入,COL[3:0]作为处理器的输出;
- 闲置状态下,COL[3:0]输出低电平;ROW[3:0]由于上拉电阻的原因输出高电平;
- 当某一按键被按下时,相应的行被拉低,ROW[3:0]中的某一个引脚检测到低电平,此时确定了按键所在的行;
- 为了检测哪一列被按下,人为将COL[3:0]逐个设置为低电平,其他3个I/O为高电平,扫描顺序为由高位到低位,即从左到右,进行扫描。如果检测到此时的ROW[3:0]的值与先前的一样,则确定了闭合按键的所在列。最多扫描4次,便能确定按键位置。
矩阵键盘的Verilog HDL实现
* All rights Reserved, Designed By https://blog.csdn.net/zhaogoudan
* @description :Matrix key scan design
* @author :ZhaoGoudan
* @date :21.01.14
* @version :V1.0.0
* @copyright ${YEAR} https://blog.csdn.net/zhaogoudan
*/
//
module matrix_key_scan(
input clk,
input rst_n,
input [3:0] row_data,
output reg [3:0] col_data,
output reg [3:0] key_value,
output reg key_flag
);
//----------------------------
localparam SCAN_IDLE = 3'd0;
localparam SCAN_JITTER1 = 3'd1;
localparam SCAN_COL1 = 3'd2;
localparam SCAN_COL2 = 3'd3;
localparam SCAN_COL3 = 3'd4;
localparam SCAN_COL4 = 3'd5;
localparam SCAN_READ = 3'd6;
localparam SCAN_JITTER2 = 3'd7;
//----------------------------
//Delay for 20ms
reg [19:0] delay_cnt;
//localparam DELAY_TOP = 20'd1000_000;
localparam DELAY_TOP = 20'd1000; //just for test
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
delay_cnt <= 20'd0;
else if(delay_cnt < DELAY_TOP - 1'b1) //产生一个时钟周期的信号
delay_cnt <= delay_cnt + 1'b1;
else
delay_cnt <= 20'd0;
end
wire delay_done = (delay_cnt == DELAY_TOP - 1'b1) ? 1'b1 : 1'b0;
//-------------------------------
//FSM : always1
reg [2:0] current_state,next_state;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
current_state <= SCAN_IDLE;
else if(delay_done) //每个状态都进行了消抖延时
current_state <= next_state;
else
current_state <= current_state;
end
//---------------------------------
//FSM : always2
always @(*) begin
case(current_state)
SCAN_IDLE : begin
if(row_data != 4'b1111) next_state = SCAN_JITTER1;
else next_state = SCAN_IDLE;
end
SCAN_JITTER1 : begin
if(row_data != 4'b1111) next_state = SCAN_COL1;
else next_state = SCAN_IDLE;
end
SCAN_COL1 : begin
if(row_data != 4'b1111) next_state = SCAN_READ;
else next_state = SCAN_COL2;
end
SCAN_COL2 : begin
if(row_data != 4'b1111) next_state = SCAN_READ;
else next_state = SCAN_COL3;
end
SCAN_COL3 : begin
if(row_data != 4'b1111) next_state = SCAN_READ;
else next_state = SCAN_COL4;
end
SCAN_COL4 : begin
if(row_data != 4'b1111) next_state = SCAN_READ;
else next_state = SCAN_IDLE;
end
SCAN_READ : begin
if(row_data != 4'b1111) next_state = SCAN_JITTER2;
else next_state = SCAN_IDLE;
end
SCAN_JITTER2 : begin
if(row_data != 4'b1111) next_state = SCAN_JITTER2;
else next_state = SCAN_IDLE;
end
endcase
end
//------------------------------
//FSM : always3
reg [3:0] row_data_r;
reg [3:0] col_data_r;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
col_data <= 4'b0000;
row_data_r <= 4'b0000;
col_data_r <= 4'b0000;
end
else if(delay_done) begin
case(next_state)
SCAN_IDLE : begin
col_data <= 4'b0000; //ensure current can flow when key is down
row_data_r <= row_data_r;
col_data_r <= col_data_r;
end
//SCAN JITTER1:
SCAN_COL1 : col_data <= 4'b0111;
SCAN_COL2 : col_data <= 4'b1011;
SCAN_COL3 : col_data <= 4'b1101;
SCAN_COL4 : col_data <= 4'b1110;
SCAN_READ : begin
row_data_r <= row_data;
col_data_r <= col_data;
end
//SCAN JITTER2:
default : ;
endcase
end
else begin
col_data <= col_data;
col_data_r <= col_data_r;
row_data_r <= row_data_r;
end
end
//------------------------------
//键值的解码触发信号
wire key_trigger = (current_state == SCAN_JITTER2 && next_state == SCAN_IDLE && delay_done == 1'b1) ? 1'b1 : 1'b0;
//------------------------------
//detect of matrix key value
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
key_value <= 1'b0;
else if(key_trigger) begin
case({row_data_r,col_data_r})
8'b0111_0111 : key_value <= 4'h0;
8'b0111_1011 : key_value <= 4'h1;
8'b0111_1101 : key_value <= 4'h2;
8'b0111_1110 : key_value <= 4'h3;
8'b1011_0111 : key_value <= 4'h4;
8'b1011_1011 : key_value <= 4'h5;
8'b1011_1101 : key_value <= 4'h6;
8'b1011_1110 : key_value <= 4'h7;
8'b1101_0111 : key_value <= 4'h8;
8'b1101_1011 : key_value <= 4'h9;
8'b1101_1101 : key_value <= 4'ha;
8'b1101_1110 : key_value <= 4'hb;
8'b1110_0111 : key_value <= 4'hc;
8'b1110_1011 : key_value <= 4'hd;
8'b1110_1101 : key_value <= 4'he;
8'b1110_1110 : key_value <= 4'hf;
default : key_value <= key_value;
endcase
end
else
key_value <= key_value;
end
//----------------------------
//Lag 1 clock for vaild read enable
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
key_flag <= 1'b0;
else
key_flag <= key_trigger;
end
endmodule

版权声明:本文为zhaogoudan原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。