阅读了小梅哥的FPGA的系统设计与验证实战指南矩阵键盘这一节,了解了矩阵键盘的原理,会写Verilog代码去驱动矩阵键盘,Verilog代码中采用的是三段式状态机的方式。
图片节选自小梅哥的文档
代码如下
//矩阵键盘模块
module key_4(clk,rst_n,col,row,key_flag,key_value);
input clk;
input rst_n;
input [3:0]row;
output reg key_flag;
output reg [3:0]key_value;
output reg [3:0]col;
reg [3:0]row_r;
reg [4:0]c_state,n_state;
reg [7:0]key_value_r;
reg en_delay;
reg [19:0]delay;
parameter CNT_MAX = 999_999;
localparam
scan = 5'b00001,
judge = 5'b00010,
filter0 = 5'b00100,
down = 5'b01000,
filter1 = 5'b10000;
//寄存行的值
always@(posedge clk or negedge rst_n)
if(!rst_n)
row_r <= 0;
else
row_r <= row;
//状态机第一段
always@(posedge clk or negedge rst_n)
if(!rst_n)
c_state <= scan;
else
c_state <= n_state;
//状态机第二段
always@(*)
begin
n_state = 5'bxxxxx;
case(c_state)
scan: n_state = judge;
judge:
if(row_r != 4'b1111)
n_state = filter0;
else
n_state = scan;
filter0:
if(delay == CNT_MAX)
begin
if(row_r != 4'b1111)
n_state = down;
else
n_state = scan;
end
else
n_state = c_state;
down:
if(row_r == 4'b1111)
n_state = filter1;
else
n_state = c_state;
filter1:
if(delay == CNT_MAX)
begin
if(row_r != 4'b1111)
n_state = down;
else
n_state = scan;
end
else
n_state = c_state;
default:n_state = scan;
endcase
end
//状态机第三段
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
en_delay <= 0;
col <= 4'b1110;
key_flag <= 0;
key_value_r <= 0;
end
else
begin
case(n_state)
scan:
begin
en_delay <= 0;
col <= {col[2:0],col[3]};
end
judge: key_flag <= 0;
filter0:
begin
en_delay <= 1;
if(delay == CNT_MAX-1)
begin
key_flag <= 1;
key_value_r <= {row_r,col};
end
else
begin
key_flag <= 0;
key_value_r <= 0;
end
end
down:
begin
key_flag <= 0;
en_delay <= 0;
key_value_r <= 0;
end
filter1:en_delay <= 1;
default:
begin
en_delay <= 0;
col <= 4'b1110;
key_flag <= 0;
end
endcase
end
//抖动20ms的时间计数
always@(posedge clk or negedge rst_n)
if(!rst_n)
delay <= 0;
else if(en_delay)
if(delay == CNT_MAX)
delay <= 0;
else
delay <= delay + 1'b1;
else
delay <= 0;
//根据行和列的值确定输出按键值
always@(posedge clk or negedge rst_n)
if(!rst_n)
key_value <= 0;
else
begin
case(key_value_r)
8'b1110_1110: key_value <= 4'd0;
8'b1110_1101: key_value <= 4'd1;
8'b1110_1011: key_value <= 4'd2;
8'b1110_0111: key_value <= 4'd3;
8'b1101_1110: key_value <= 4'd4;
8'b1101_1101: key_value <= 4'd5;
8'b1101_1011: key_value <= 4'd6;
8'b1101_0111: key_value <= 4'd7;
8'b1011_1110: key_value <= 4'd8;
8'b1011_1101: key_value <= 4'd9;
8'b1011_1011: key_value <= 4'd10;
8'b1011_0111: key_value <= 4'd11;
8'b0111_1110: key_value <= 4'd12;
8'b0111_1101: key_value <= 4'd13;
8'b0111_1011: key_value <= 4'd14;
8'b0111_0111: key_value <= 4'd15;
default:;
endcase
end
endmodule