解释:
1、扫描控制:
• scan_cnt 从 0 计数到 49999(共 50000 个周期)
• 每 1ms(1kHz)产生一个 valid_tick 脉冲
2、行切换:
• valid_tick 触发 row_sel 状态机,依次激活 4 行
3、消抖与缓存:
• 每列信号独立消抖( col_flag )
• 在 valid_tick 上升沿将消抖结果写入 key_state 对应行
代码
// 按键消抖模块(单路)
module key_filter #(
parameter CNT_MAX = 20'd999_999 // 约20ms@50MHz
)(
input wire sys_clk,
input wire sys_rst_n,
input wire key_in,
output reg key_flag
);
reg [19:0] cnt_20ms;
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
cnt_20ms <= 20'd0;
else if (key_in)
cnt_20ms <= 20'd0;
else if (cnt_20ms == CNT_MAX)
cnt_20ms <= cnt_20ms;
else
cnt_20ms <= cnt_20ms + 1'b1;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
key_flag <= 1'b0;
else
key_flag <= (cnt_20ms == CNT_MAX - 1'b1);
end
endmodule
// 4x4矩阵键盘扫描与消抖顶层模块
module matrix_keypad #(
parameter CNT_MAX = 20'd999_999, // 消抖计数最大值
parameter SCAN_DIV = 16'd50000 // 扫描分频系数 (50MHz -> 1kHz)
)(
input wire sys_clk, // 50MHz系统时钟
input wire sys_rst_n, // 复位,低有效
input wire [3:0] col_in, // 4列输入(外部上拉)
output wire [3:0] row_out, // 4行输出
output reg [15:0] key_state // 按键状态:1表示按下
);
// 扫描控制信号
reg [15:0] scan_cnt; // 扫描分频计数器 (16位)
reg valid_tick; // 采样有效脉冲
reg [3:0] row_sel; // 当前行选择
// 消抖后列信号
wire [3:0] col_flag;
//===== 扫描控制器 =====//
// 生成1kHz扫描时钟 (50MHz / 50000 = 1kHz)
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
scan_cnt <= 16'd0;
valid_tick <= 1'b0;
end else if (scan_cnt == SCAN_DIV - 1) begin
scan_cnt <= 16'd0;
valid_tick <= 1'b1;
end else begin
scan_cnt <= scan_cnt + 1'b1;
valid_tick <= 1'b0;
end
end
//===== 行选择状态机 =====//
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
row_sel <= 4'b1110; // 默认选中第0行
else if (valid_tick) begin // 每1ms切换一行
case (row_sel)
4'b1110: row_sel <= 4'b1101; // 第0行 → 第1行
4'b1101: row_sel <= 4'b1011; // 第1行 → 第2行
4'b1011: row_sel <= 4'b0111; // 第2行 → 第3行
4'b0111: row_sel <= 4'b1110; // 第3行 → 第0行
default: row_sel <= 4'b1110;
endcase
end
end
assign row_out = row_sel;
//===== 列消抖(复用4个单路消抖模块)=====//
genvar i;
generate
for (i=0; i<4; i=i+1) begin : debounce_inst
key_filter #(.CNT_MAX(CNT_MAX))
u_debounce (
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.key_in(col_in[i]),
.key_flag(col_flag[i])
);
end
endgenerate
//===== 状态缓存 =====//
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
key_state <= 16'd0;
else if (valid_tick) begin // 仅在行切换时更新状态
case (row_sel)
4'b1110: key_state[3:0] <= col_flag; // 第0行状态
4'b1101: key_state[7:4] <= col_flag; // 第1行状态
4'b1011: key_state[11:8] <= col_flag; // 第2行状态
4'b0111: key_state[15:12] <= col_flag; // 第3行状态
endcase
end
end
endmodule
4860

被折叠的 条评论
为什么被折叠?



