[笔记].驱动4x4矩阵键盘的思路.[Verilog]
SCH
图1 4x4矩阵键盘的SCH(箭头表示输入输出方向)
如图1所示,将ROW[3:0]设为输入,COL[3:0]设为输出。如果没有任何键被按下,则ROW[3:0]一直被上拉为高电平。只有当有键被按下,且COL[3:0]中有低电平输出,ROW[3:0]中才有可能有低电平输入,也可说是被动地输入。
流程图
图2 流程图
HDL
module matrixKeyboard_drive( input i_clk, input i_rst_n, input [3:0] row, // 矩阵键盘 行 output reg [3:0] col, // 矩阵键盘 列 output reg [3:0] keyboard_val // 键盘值 ); //++++++++++++++++++++++++++++++++++++++ // 分频部分 开始 //++++++++++++++++++++++++++++++++++++++ reg [19:0] cnt; // 计数子 always @ (posedge i_clk, negedge i_rst_n) if (!i_rst_n) cnt <= 0; else cnt <= cnt + 1'b1; wire key_clk = cnt[19]; // (2^20/50M = 21)ms //-------------------------------------- // 分频部分 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 状态机部分 开始 //++++++++++++++++++++++++++++++++++++++ // 状态数较少,独热码编码 parameter NO_KEY_PRESSED = 6'b000_001; // 没有按键按下 parameter SCAN_COL0 = 6'b000_010; // 扫描第0列 parameter SCAN_COL1 = 6'b000_100; // 扫描第1列 parameter SCAN_COL2 = 6'b001_000; // 扫描第2列 parameter SCAN_COL3 = 6'b010_000; // 扫描第3列 parameter KEY_PRESSED = 6'b100_000; // 有按键按下 reg [5:0] current_state, next_state; // 现态、次态 always @ (posedge key_clk, negedge i_rst_n) if (!i_rst_n) current_state <= NO_KEY_PRESSED; else current_state <= next_state; // 根据条件转移状态 always @ * case (current_state) NO_KEY_PRESSED : // 没有按键按下 if (row != 4'hF) next_state = SCAN_COL0; else next_state = NO_KEY_PRESSED; SCAN_COL0 : // 扫描第0列 if (row != 4'hF) next_state = KEY_PRESSED; else next_state = SCAN_COL1; SCAN_COL1 : // 扫描第1列 if (row != 4'hF) next_state = KEY_PRESSED; else next_state = SCAN_COL2; SCAN_COL2 : // 扫描第2列 if (row != 4'hF) next_state = KEY_PRESSED; else next_state = SCAN_COL3; SCAN_COL3 : // 扫描第3列 if (row != 4'hF) next_state = KEY_PRESSED; else next_state = NO_KEY_PRESSED; KEY_PRESSED : // 有按键按下 if (row != 4'hF) next_state = KEY_PRESSED; else next_state = NO_KEY_PRESSED; endcase reg key_pressed_flag; // 键盘按下标志 reg [3:0] col_val, row_val; // 列值、行值 // 根据次态,给相应寄存器赋值 always @ (posedge key_clk, negedge i_rst_n) if (!i_rst_n) begin col <= 4'h0; key_pressed_flag <= 0; end else case (next_state) NO_KEY_PRESSED : // 没有按键按下 begin col <= 4'h0; key_pressed_flag <= 0; // 清键盘按下标志 end SCAN_COL0 : // 扫描第0列 col <= 4'b1110; SCAN_COL1 : // 扫描第1列 col <= 4'b1101; SCAN_COL2 : // 扫描第2列 col <= 4'b1011; SCAN_COL3 : // 扫描第3列 col <= 4'b0111; KEY_PRESSED : // 有按键按下 begin col_val <= col; // 锁存列值 row_val <= row; // 锁存行值 key_pressed_flag <= 1; // 置键盘按下标志 end endcase //-------------------------------------- // 状态机部分 结束 //-------------------------------------- //++++++++++++++++++++++++++++++++++++++ // 扫描行列值部分 开始 //++++++++++++++++++++++++++++++++++++++ always @ (posedge key_clk, negedge i_rst_n) if (!i_rst_n) keyboard_val <= 4'h0; else if (key_pressed_flag) case ({col_val, row_val}) 8'b1110_1110 : keyboard_val <= 4'h0; 8'b1110_1101 : keyboard_val <= 4'h4; 8'b1110_1011 : keyboard_val <= 4'h8; 8'b1110_0111 : keyboard_val <= 4'hC; 8'b1101_1110 : keyboard_val <= 4'h1; 8'b1101_1101 : keyboard_val <= 4'h5; 8'b1101_1011 : keyboard_val <= 4'h9; 8'b1101_0111 : keyboard_val <= 4'hD; 8'b1011_1110 : keyboard_val <= 4'h2; 8'b1011_1101 : keyboard_val <= 4'h6; 8'b1011_1011 : keyboard_val <= 4'hA; 8'b1011_0111 : keyboard_val <= 4'hE; 8'b0111_1110 : keyboard_val <= 4'h3; 8'b0111_1101 : keyboard_val <= 4'h7; 8'b0111_1011 : keyboard_val <= 4'hB; 8'b0111_0111 : keyboard_val <= 4'hF; endcase //-------------------------------------- // 扫描行列值部分 结束 //-------------------------------------- endmodule