好久不见,因为博主最近两个月有点事情,加上接着考试,考完试也有点事情要处理,最近才稍微闲了一些,这才赶紧记录分享一篇博文。FPGA驱动4x4矩阵键盘。这个其实原理是十分简单,但是由于博主做的时候遇到了一些有意思的情况,所以我个人觉得值得记录分享一下。
首先找了本书看了下矩阵键盘的驱动原理,一般来说4x4矩阵键盘的原理图如下,有四根行线和四根列线,行选通和列选通可以确定键盘上的一个位置。从原理图上看出,在没有操作的情况下,行线上接了一个10K的上拉电阻接vcc,这使得键盘在没有按下时,四根行线始终是高电平。
列线是由处理器输入给矩阵键盘,空闲状态下保持为0。也就是行空闲时输出给处理器为四个1,列空闲时由处理器输入给四个0。
当按下按键时,比如第一行第一个按键,对应的那一行导通输出为0,即row_data = 0111,此时由处理器逐渐输入列扫描信号由col_data = 0111——1110,当所按下按键为对应的那一行列的按键,矩阵键盘的行才会导通输出为0,否则会回到1111。其他按键类似,就是利用这个原理来驱动矩阵键盘。
最后FPGA部分模块引脚设计如图,我们需要对按键进行消抖,和普通按键一样,采用20ms的延时对按键进行消抖,分为按下消抖和松开消抖,中间的状态转移,因为列信号需要输出判断行信号的变化,所以状态机状态转移用两个系统时钟周期跳转。采用状态机进行描述,状态转移图如下。
代码如下:(点击阅读原文查看博客)
1 `timescale 1ns/1ps 2 // ********************************************************************************* 3 // Project Name : 4 // Author : NingHeChuan 5 // Email : ninghechuan@foxmail.com 6 // Blogs : http://www.cnblogs.com/ninghechuan/ 7 // File Name : Matrix_Key_Scan.v 8 // Module Name : 9 // Called By : 10 11 // Abstract : 12 // 13 // CopyRight(c) 2018, NingHeChuan Studio.. 14 // All Rights Reserved 15 // 16 // ********************************************************************************* 17 // Modification History: 18 // Date By Version Change Description 19 // ----------------------------------------------------------------------- 20 // 2018/7/28 NingHeChuan 1.0 Original 21 // 22 // ********************************************************************************* 23 24 module Matrix_Key_Scan( 25 input clk, //50Mhz 26 input rst_n, 27 input [3:0] row_data, 28 output key_flag, 29 output reg [3:0] key_value, 30 output reg [3:0] col_data 31 ); 32 33 //FSM state 34 parameter SCAN_IDLE = 8'b0000_0001; 35 parameter SCAN_JITTER1 = 8'b0000_0010; 36 parameter SCAN_COL1 = 8'b0000_0100; 37 parameter SCAN_COL2 = 8'b0000_1000; 38 parameter SCAN_COL3 = 8'b0001_0000; 39 parameter SCAN_COL4 = 8'b0010_0000; 40 parameter SCAN_READ = 8'b0100_0000; 41 parameter SCAN_JITTER2 = 8'b1000_0000; 42 // 43 parameter DELAY_TRAN = 2; 44 parameter DELAY_20MS = 1000_000; 45 //parameter DELAY_20MS = 100;//just test 46 reg [20:0] delay_cnt; 47 wire delay_done; 48 // 49 reg [7:0] pre_state; 50 reg [7:0] next_state; 51 reg [20:0] tran_cnt; 52 wire tran_flag; 53 // 54 reg [3:0] row_data_r; 55 reg [3:0] col_data_r; 56 // 57 58 //------------------------------------------------------- 59 //delay 20ms 60 always @(posedge clk or negedge rst_n)begin 61 if(rst_n == 1'b0)begin 62 delay_cnt <= 'd0; 63 end 64 else if(delay_cnt == DELAY_20MS) 65 delay_cnt <= 'd0; 66 else if(next_state == SCAN_JITTER1 | next_state == SCAN_JITTER2) begin 67 delay_cnt <= delay_cnt + 1'b1; 68 end 69 else 70 delay_cnt <= 'd0; 71 end 72 73 assign delay_done = (delay_cnt == DELAY_20MS - 1'b1)? 1'b1: 1'b0; 74 75 76 //------------------------------------------------------- 77 //delay 2clk 78 always @(posedge clk or negedge rst_n)begin 79 if(rst_n == 1'b0)begin 80 tran_cnt <= 'd0; 81 end 82 else if(tran_cnt == DELAY_TRAN)begin 83 tran_cnt <= 'd0; 84 end 85 else 86 tran_cnt <= tran_cnt + 1'b1; 87 end 88 89 assign tran_flag = (tran_cnt == DELAY_TRAN)? 1'b1: 1'b0; 90 91 92 //------------------------------------------------------- 93 //FSM step1 94 always @(posedge clk or negedge rst_n)begin 95 if(rst_n == 1'b0)begin 96 pre_state <= SCAN_IDLE; 97 end 98 else if(tran_flag)begin 99 pre_state <= next_state; 100 end 101 else pre_state <= pre_state; 102 end 103 104 //FSM step2 105 always @(*)begin 106 next_state = SCAN_IDLE; 107 case(pre_state) 108 SCAN_IDLE: 109 if(row_data != 4'b1111) 110 next_state = SCAN_JITTER1; 111 else 112 next_state = SCAN_IDLE; 113 SCAN_JITTER1: 114 if(row_data != 4'b1111 && delay_done == 1'b1) 115 next_state = SCAN_COL1; 116 else 117 next_state = SCAN_JITTER1; 118 SCAN_COL1: 119 if(row_data != 4'b1111)//如果row_data是全1,说明不是列扫描没有对应到该行 120 next_state = SCAN_READ; 121 else 122 next_state = SCAN_COL2; 123 SCAN_COL2: 124 if(row_data != 4'b1111) 125 next_state = SCAN_READ; 126 else 127 next_state = SCAN_COL3; 128 SCAN_COL3: 129 if(row_data != 4'b1111) 130 next_state = SCAN_READ; 131 else 132 next_state = SCAN_COL4; 133 SCAN_COL4: 134 if(row_data != 4'b1111) 135 next_state = SCAN_READ; 136 else 137 next_state = SCAN_IDLE; 138 SCAN_READ: 139 if(row_data != 4'b1111) 140 next_state = SCAN_JITTER2; 141 else 142 next_state = SCAN_IDLE; 143 SCAN_JITTER2: 144 if(row_data == 4'b1111 && delay_done == 1'b1) 145 next_state = SCAN_IDLE; 146 else 147 next_state = SCAN_JITTER2; 148 default:next_state = SCAN_IDLE; 149 endcase 150 end 151 152 //FSM step3 153 always @(posedge clk or negedge rst_n)begin 154 if(rst_n == 1'b0)begin 155 col_data <= 4'b0000; 156 row_data_r <= 4'b0000; 157 col_data_r <= 4'b0000; 158 end 159 else if(tran_flag) begin 160 case(next_state) 161 SCAN_COL1:col_data <= 4'b0111; 162 SCAN_COL2:col_data <= 4'b1011; 163 SCAN_COL3:col_data <= 4'b1101; 164 SCAN_COL4:col_data <= 4'b1110; 165 SCAN_READ:begin 166 col_data <= col_data; 167 row_data_r <= row_data; 168 col_data_r <= col_data; 169 end 170 default: col_data <= 4'b0000; 171 endcase 172 end 173 else begin 174 col_data <= col_data; 175 row_data_r <= row_data_r; 176 col_data_r <= col_data_r; 177 end 178 end 179 180 //这个状态表明是扫开消完抖动的那一瞬间 181 assign key_flag = (next_state == SCAN_IDLE && pre_state == SCAN_JITTER2 && tran_flag)? 1'b1: 1'b0; 182 183 //------------------------------------------------------- 184 //decode key_value 185 always @(posedge clk or negedge rst_n)begin 186 if(rst_n == 1'b0)begin 187 key_value <= 'd0; 188 end 189 else if(key_flag == 1'b1)begin 190 case({row_data_r, col_data_r}) 191 8'b0111_0111: key_value <= 4'h1; 192 8'b0111_1011: key_value <= 4'h2; 193 8'b0111_1101: key_value <= 4'h3; 194 8'b0111_1110: key_value <= 4'ha; 195 8'b1011_0111: key_value <= 4'h4; 196 8'b1011_1011: key_value <= 4'h5; 197 8'b1011_1101: key_value <= 4'h6; 198 8'b1011_1110: key_value <= 4'hb; 199 8'b1101_0111: key_value <= 4'h7; 200 8'b1101_1011: key_value <= 4'h8; 201 8'b1101_1101: key_value <= 4'h9; 202 8'b1101_1110: key_value <= 4'hc; 203 8'b1110_0111: key_value <= 4'hf; 204 8'b1110_1011: key_value <= 4'h0; 205 8'b1110_1101: key_value <= 4'he; 206 8'b1110_1110: key_value <= 4'hd; 207 default : key_value <= key_value; 208 endcase 209 end 210 else 211 key_value <= key_value; 212 end 213 214 215 endmodule