1設(shè)計背景: 矩陣鍵盤在工程設(shè)計越來越多的被用到,已然成為了我們做開發(fā)接觸到的不可缺少的小型項目,利于我們理解設(shè)計方向的原理為以后的強化學(xué)習(xí)打好了堅實的基礎(chǔ)。 2設(shè)計原理: 在使用按鍵的時候,如果按鍵不多的話,我們可以直接按鍵與FPGA相連接,但是如果按鍵比較多的時候,如何還繼續(xù)使用直接按鍵與FPGA相連接的話,所會大量增加FPGA端口的消耗,為了減少FPGA端口的消 耗,我們可以把按鍵設(shè)計成矩陣的形式,就如下圖所示: 由上圖可以知道,矩陣鍵盤的行row(行)與col(列)的交點,都是通過一個按鍵來相連接。 傳統(tǒng)的一個按鍵一個端口的方法,若要實現(xiàn)16個按鍵,則需要16個端口,而現(xiàn)在這個矩陣鍵盤的設(shè)計,16個按鍵,僅僅需要8個端口,如果使用16個端口來做矩陣鍵盤的話,可以識別64個按鍵,端口的利用率遠(yuǎn)遠(yuǎn)比傳統(tǒng)的設(shè)計好的多,所以如果需要的按鍵少的話,可以選擇傳統(tǒng)的按鍵設(shè)計,如果需要的按鍵比較多的話,可以采用這種矩陣鍵盤的設(shè)計。 而我們現(xiàn)在就以掃描法為例來介紹矩陣鍵盤的工作原理。 首先col(列)是FPGA給矩陣鍵盤輸出的掃描信號,而row(行)是矩陣鍵盤反饋給FPGA的輸入信號,用于檢測哪一個按鍵被按下來,如下圖所示: 詳細(xì)如上圖所示,F(xiàn)PGA給出掃描信號COL[3:0],COL = 4’b0111,等下一個時鐘周期COL = 4’b1011,再等下一個時鐘周期COL =4’b1101,再等下一個時鐘周期COL = 4’b1110,再等下一個時鐘周期COL = 4’b0111,COL就是這樣不斷循環(huán),給矩陣鍵盤一個低電平有效的掃描信號,當(dāng)FPGA給矩陣鍵盤COL掃描信號的同時,F(xiàn)PGA也要在檢測矩陣鍵盤給FPGA的的反饋信號ROW,舉個例子,假若矩陣鍵盤中的9號案件被按下了: 當(dāng) COL = 4’b1101,ROW =4’b1011 ; 當(dāng)9號按鍵被按下的時候,9號按鍵的電路就會被導(dǎo)通,掃描電路COL開始掃描,當(dāng)掃描到COL[1]的時候,由于9號按鍵的電路被導(dǎo)通了,COL[1]的電壓等于ROW[2]的電壓,所以會出現(xiàn)當(dāng)COL = 4’b1101的時候ROW = 4’b1011;然后我們就可以利用這一種現(xiàn)象,來設(shè)計一個識別按鍵的電路。 3設(shè)計架構(gòu)圖: 4設(shè)計代碼: 設(shè)計模塊 0 module key_borad(clk,rst_n,row,col,key_num); 1 input clk; 2 input rst_n; 3 input [3:0] row; //輸入反饋信號 4 5 6 output reg [3:0] col; //輸出掃描信號 7 output reg [3:0] key_num; //按鍵值得輸除 8 9 reg [15:0] count; 10 11 parameter T1ms = 50000; //掃描的時間間隔 50000 * 20ns 12 //parameter T1ms = 5; 13 14 reg flag; 15 always @ (posedge clk or negedge rst_n) 16 if(!rst_n) 17 begin 18 count <> 19 flag <> 20 end 21 else 22 begin 23 if(count < t1ms - 1) > t1ms - 1) > 24 begin 25 count <> 26 flag <> 27 end 28 else 29 begin 30 flag <= 1'b1; >= 1'b1; > 31 count <> 32 end 33 end 34 always @ (posedge clk or negedge rst_n) 35 if(!rst_n) 36 begin 37 col <> 38 end 39 else 40 begin 41 if(flag) 42 col <= {col[2:0],col[3]}; >= {col[2:0],col[3]}; > 43 else 44 col <> 45 end 46 47 //鍵值得翻譯模塊 48 always @ (posedge clk or negedge rst_n) 49 if(!rst_n) 50 key_num = 4'd0; 51 else 52 case ({row,col}) //位拼接行和列的信號,翻譯出對應(yīng)的鍵值 53 8'b0111_0111:key_num = 4'hf; 54 8'b0111_1011:key_num = 4'he; 55 8'b0111_1101:key_num = 4'hd; 56 8'b0111_1110:key_num = 4'hc; 57 58 8'b1011_0111:key_num = 4'hb; 59 8'b1011_1011:key_num = 4'ha; 60 8'b1011_1101:key_num = 4'h9; 61 8'b1011_1110:key_num = 4'h8; 62 63 8'b1101_0111:key_num = 4'h7; 64 8'b1101_1011:key_num = 4'h6; 65 8'b1101_1101:key_num = 4'h5; 66 8'b1101_1110:key_num = 4'h4; 67 68 8'b1110_0111:key_num = 4'h3; 69 8'b1110_1011:key_num = 4'h2; 70 8'b1110_1101:key_num = 4'h1; 71 8'b1110_1110:key_num = 4'h0; 72 default: ; 73 endcase 74 endmodule 測試模塊 0 `timescale 1ns/1ps 1 2 module key_borad_tb(); 3 reg clk; 4 reg rst_n; 5 reg [4:0] pressnum; //按鍵的值 6 wire [3:0] row; 7 8 wire [3:0] col; 9 wire [3:0] key_num; //輸出的值 10 11 initial begin 12 clk = 1'b1; 13 rst_n = 1'b0; 14 pressnum = 5'd16; 15 16 #200.1 17 rst_n = 1'b1; 18 #1000 19 pressnum = 5'd16; 20 21 #1000 22 pressnum = 5'd8; 23 24 #1000 25 pressnum = 5'd16; 26 27 #1000 28 pressnum = 5'd15; 29 #1000 30 pressnum = 5'd16; 31 #1000 32 $stop; 33 34 end 35 always #10 clk = ~clk; 36 //例化對應(yīng)的模塊 37 key_top borad_dut( 38 .clk(clk), 39 .rst_n(rst_n), 40 .row(row), 41 .col(col), 42 .key_num(key_num) 43 ); 44 yingjian yingjian_dut( //硬件檢測電路 //此模塊自己可以設(shè)計 45 .clk(clk), 46 .rst_n(rst_n), 47 .col(col), 48 .row(row), 49 .pressnum(pressnum) 50 ); 51 endmodule 仿真圖: 在仿真圖中可以清晰的看出當(dāng)按鍵按下的時候為8,顯示出來的鍵值也為8,當(dāng)抬起的時候為16,那么鍵值就保持不變,在設(shè)置的時候我們設(shè)置的是按鍵抬起為16,通過驗證我們得到我們的設(shè)計是正確的。 |
|