仿照 正点原子 的 Sample 修改 没有用这个
V2手册 P266
给出的手动按键控制的矩阵模块 为 4*6 矩阵键盘外接模块
每一个按键自带led,所以对应的接口是合并在一起的一个引脚
按下后 LED 亮,vice versa
底部 LED*8 目前不清楚有什么用
或许可以变成 16进制表示灯的位置
like 3 = 2^1 + 2^0, 16 = 2^4 相当于数码管的功能
代码参考
testbench 需要生成 vt 文件 再使用仿真验证
我抛出来的波形有点奇怪 因为没有做时序约束
按键定位思路:
- 矩阵键盘所有 行 信号 3.3V 上拉,4*6 信号全部接到 FPGA 引脚, 具体按键的检测只需要扫描其 行列 序号,
- 给出的分布引脚图中,矩阵信号从左到右也可以算是顺序编码:A1 B1 C1 D1,A2 B2 C2 D2…D6.etc
- 具体按钮x对应的 a 行 b 列 引脚,已知 a 行 & all rows 为高电平,设置 all cols 为低电平
- 当 x being pushed, a & b 导通,a变为低电平, 得到 row 端口;
- due to cols’ outputs are all in low level, scan col 端口,先scan 第一列( col0 ) , 将 col0 保持低电平, col1~3 拉高,看row端口值是否变化, if not, button 列序列号 为 1,else not. only & only if col端口为low时才能拉低其对应row 端口为低电平,else 继续扫描 next col,col2 = 0
代码描述:
module key4x4
//更改为4x6
#(
parameter CNT_MAX=16'd50_000
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [6:0] key_in ,//此信号为从键盘传到FPGA开发板的信号
output reg [6:0] key_out ,//此信号为从FPGA开发板传到键盘上的信号
output reg [6:0] led_out //注意信号灯为低信号时会亮
);
reg [23:0] cnt ;
reg cnt_clk ;
reg [1:0] q ;
always @ (posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt<=24'd0;
else if (cnt==CNT_MAX)
cnt<=24'd0;
else cnt<=cnt+24'd1;
always @ (posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt_clk<=1'b0;
else if (cnt==CNT_MAX-24'd1)
cnt_clk<=1'b1;
else cnt_clk<=1'd0;
always @ (posedge cnt_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
begin
q<=3'd0;
key_out<=6'b111110;
led_out<=6'b111111;
end
else
begin
q<=q+3'd1;
case(q)
//分别对每一行row输入扫描信号
3'd0:key_out<=6'b111110;
3'd1:key_out<=6'b111101;
3'd2:key_out<=6'b111011;
3'd3:key_out<=6'b110111;
3'd4:key_out<=6'b101111;
3'd5:key_out<=6'b011111;
default:key_out<=6'b000000;
endcase
case ({key_out,key_in})
// //按下第1个按键后则全灭,000000 -> 111111,按下第24个按键后全部的灯亮,111111 -> 000000。
// //每一行扫描信号,对应的扫描信号灯输出
//4'b1111......这些还没有修改 应该改为按键旁边对应的led灯
10'b111110_1110:begin led_out<=4'b1111; end
10'b111110_1101:begin led_out<=4'b1110; end
10'b111110_1011:begin led_out<=4'b1101; end
10'b111110_0111:begin led_out<=4'b1100; end
10'b111101_1110:begin led_out<=4'b1011; end
10'b111101_1101:begin led_out<=4'b1010; end
10'b111101_1011:begin led_out<=4'b1001; end
10'b111101_0111:begin led_out<=4'b1000; end
10'b111011_1110:begin led_out<=4'b0111; end
10'b111011_1101:begin led_out<=4'b0110; end
10'b111011_1011:begin led_out<=4'b0101; end
10'b111011_0111:begin led_out<=4'b0100; end
10'b110111_1110:begin led_out<=4'b0011; end
10'b110111_1101:begin led_out<=4'b0010; end
10'b110111_1011:begin led_out<=4'b0001; end
10'b110111_0111:begin led_out<=4'b0000; end
10'b110111_1110:begin led_out<=4'b0011; end
10'b110111_1101:begin led_out<=4'b0010; end
10'b110111_1011:begin led_out<=4'b0001; end
10'b110111_0111:begin led_out<=4'b0000; end
10'b110111_1110:begin led_out<=4'b0011; end
10'b110111_1101:begin led_out<=4'b0010; end
10'b110111_1011:begin led_out<=4'b0001; end
10'b110111_0111:begin led_out<=4'b0000; end
10'b000000_1111:begin led_out<=4'b1111; end
default: begin led_out<=4'b1111; end
endcase
end
endmodule
消抖模块思路:
“按键的值先打一拍(key_reg <=key row),然后检测当前时钟下按键的状态和上一个时钟的状态是否一致,如果不一致则将计数器 delay cnt赋初值 100万,如果一致则计数器从初值开始作减法计数,直到计数器计数到“1”,说明按键的状态一直稳定了 100 万个时钟周期,此时我们认为是一次有效的按键 触发,这时我们就可以拉高消抖完成标志key flag row(注意只拉高一个时钟)”