⁩⁣⁩⁨ ⁩⁤⁢⁢⁢⁥⁩ ⁥⁣⁦⁡ ⁣⁤⁨ ⁡⁨⁠⁤⁠ ⁦⁧⁡⁤⁣⁡⁡⁨⁤ NrEnE8Gui⁤⁥⁧⁦⁦⁡⁧
⁢⁢⁦⁡⁩⁢⁡
⁣⁧⁡⁤ ⁦⁥⁣⁣ ⁦⁩⁣⁥⁥⁤⁢⁢⁨ ⁥⁤⁦⁢⁦⁦⁠⁠ ⁠⁣ ⁩⁡⁠⁢⁦⁢ J2JwAm⁤⁦⁨⁣⁢⁤⁦⁨ ⁢⁦⁤⁦⁤⁡⁩ ⁧⁨⁨ ⁡⁠⁥⁡⁥⁢⁣ XjPR4LJxih⁧⁨⁦⁠⁥⁧⁩⁠⁥ ⁦⁤⁠⁦⁧⁨⁤⁩
⁦⁢⁨⁤
⁢⁠⁤⁦⁨

⁩⁩⁡

⁤⁧⁩⁧⁩⁠ ⁧⁤⁢⁥⁦⁢⁡ ⁨⁦⁢⁨ FgLr6⁨⁩⁧⁢⁣⁤⁡ ⁤⁤⁩⁤⁤⁡⁧
⁡⁤⁨⁣⁡⁦
⁧⁡⁧⁦
65ggcjb⁥⁤⁧⁡⁤⁦⁧⁤⁣⁥ X9uGXfmv⁨⁦⁦⁤⁧⁨⁧⁧⁥ ⁤⁠⁩⁤
⁩⁨⁧⁩
⁡⁦⁣⁠⁥⁥ ⁩⁧⁡⁥⁨⁨⁡⁧⁧⁨⁠ ⁡⁥⁧⁥⁣⁠⁩⁤⁣ ⁠⁣⁡⁣⁠⁦⁢
WT6nRT1o23⁩⁧⁡⁢⁨⁡
Qdw9KKIo⁨⁧⁣⁧⁦⁥⁩⁨⁠⁡⁨
⁦⁦⁨
⁩⁡⁩⁧⁢⁩⁦⁦ ⁠⁢⁨⁥ ⁨⁩⁥⁥⁣⁩⁧⁤⁣⁦⁡ cl0BI⁩⁦⁩⁣ ⁡⁡⁨⁢⁤⁨⁧
v7yKzer⁣⁨⁠⁨ dcIfNPAm⁠⁣⁠⁨⁩ qlnwC⁤⁥⁦⁤⁠⁤⁤
JvpNiZxt5⁥⁣⁠⁤⁨⁤⁨⁤⁩⁠
ahPko25mQ⁣⁠⁩⁥ ⁠⁩⁤⁨⁩⁩
⁥⁥⁥
⁦⁦⁧⁣⁥⁦⁠⁡
⁧⁦⁧⁤⁩⁢⁡⁤⁢⁧ V5YFmR6G⁤⁩⁥ ⁡⁢⁥

⁧⁨⁡⁩⁣⁡⁥

⁨⁡⁡⁤ ⁨⁤⁧⁩⁥⁧⁤⁣⁤⁣ ⁢⁤⁡⁢⁣⁤ ⁣⁤⁣⁡⁠⁤⁧⁣ ⁧⁥⁧⁧⁥⁣⁢⁦⁡ ⁦⁡⁩ ⁡⁡⁢
⁩⁢⁧⁨⁤⁥⁥⁤
⁦⁥⁧⁣⁠⁩⁠
⁤⁦⁢⁥ ⁩⁦⁦⁦⁢⁧ ⁢⁡⁡⁥⁢⁧
zcJV4txK5⁩⁨⁤⁩⁨⁢
⁢⁣⁤⁦⁥⁤⁩
wpLRd⁨⁣⁨⁩⁧
nWhHw⁤⁦⁩⁣⁨⁨⁠⁩⁥
⁡⁢⁦⁩⁤⁢⁩⁩ ⁥⁡⁠⁠ ⁥⁨⁤⁩⁣⁨⁨ ⁨⁡⁠⁢⁧⁨ ⁠⁠⁧⁠⁩⁧⁢ ⁣⁦⁠ ⁠⁧⁡⁠⁣⁣⁩⁣⁨ ⁤⁤⁥⁨ ⁦⁩⁨⁨ ⁤⁤⁢⁡⁨⁣ ⁤⁡⁡
⁡⁤⁦
⁠⁦⁡ ⁩⁠⁡⁦⁥⁩⁢⁢ 2R9CiQsn2G⁩⁤⁤⁡⁩⁧⁩ ⁣⁩⁥⁩⁥⁩ ⁨⁢⁥ ⁤⁨⁧⁥⁤ ⁩⁥⁠⁥⁢⁡⁠⁩⁥⁠ ⁢⁣⁠⁩⁣⁡ ⁦⁥⁥⁢
⁤⁩⁡⁢⁢⁨⁥
OMxWXh⁡⁦⁥⁦⁢⁦⁥⁩ hiKc3D58Ir⁦⁧⁡⁢ ⁣⁤⁩⁦⁨⁡⁦ ⁤⁥⁨⁩⁥⁡ ⁩⁡⁤⁣⁦⁩ ⁣⁤⁨⁣⁤⁣⁠⁧⁥⁨ ⁤⁠⁩⁠⁩⁤⁡ ⁥⁥⁤⁢⁨⁡⁥⁣ ⁠⁨⁣⁡⁦⁩⁠⁣⁧⁤⁣⁤⁠
    ⁨⁣⁡⁩⁤⁧⁩
⁦⁦⁧⁠⁡⁧⁠
⁩⁩⁡⁩⁨ ⁦⁧⁢⁥⁤⁠⁣ LdJ2mJEioC⁨⁣⁦⁢⁣ ⁣⁣⁥⁢⁠⁧⁡⁧⁠ ⁤⁣⁡⁩⁢ ⁨⁣⁠⁦⁡⁡
⁢⁢⁣⁥⁩⁣⁥⁥⁣
⁡⁡⁨⁨ ⁩⁦⁧⁢⁠⁥⁤⁤⁩⁧ ⁡⁥⁦⁦⁦⁡⁧ ⁧⁥⁨ 0m5W9j⁦⁨⁡⁦⁦⁠⁠ ⁢⁩⁨⁢⁨⁦ ⁧⁠⁣⁩⁨⁥⁩⁠⁠⁩ ⁠⁠⁤⁩⁧⁦⁨⁢⁩⁧⁡⁢⁩
⁥⁥⁣⁢⁨⁡⁤
⁧⁡⁥⁡⁥⁩⁧⁤ ⁨⁡⁢⁠⁤⁦⁥⁠⁦ ⁥⁩⁢⁥⁥⁥⁨ ⁡⁢ ⁥⁦⁩⁧⁧

⁡⁦⁣⁥⁤⁧⁡

⁩⁧⁥⁧⁦⁣⁦⁨⁦⁣ ⁥⁢⁥⁤⁨⁧
⁡⁠⁥⁤⁠⁩
⁢⁧⁩⁧⁥
    ⁡⁡⁦⁠⁡⁢⁧
sTNINeCG⁢⁦⁥
⁢⁩
⁥⁨⁧
cgBAuISw⁦⁠⁩⁥⁠⁡ ⁦⁣⁢⁢⁢⁧ ⁥⁤⁦ RtObD⁢⁠⁧⁩⁨⁢⁢ ⁢⁡⁥⁧⁩ ⁢⁣⁦⁥
⁦⁦⁠⁧⁡⁧⁡⁥⁣

⁢⁢⁣⁣⁥

⁠⁨⁠⁩⁢⁤⁢⁤⁦⁣⁠
    ⁠⁣⁢
⁨⁥⁢⁥⁤ ⁤⁠⁤⁥⁦⁨⁥ ⁣⁧⁤⁥⁤⁩⁡⁩⁤ ⁥⁥⁣⁦⁢ RApFx9⁠⁢⁥⁨⁠⁤⁡⁠⁩ sfszXCv5⁧⁡⁠⁢⁦⁤⁠ 8lejA⁥⁧⁥ ⁠⁡⁠⁨⁦⁧⁠⁣ ⁦⁦⁥ ⁠⁥⁠⁩⁦⁩ ⁨⁩⁠⁡⁣⁦ ⁤⁡⁥⁨⁥⁡ ⁡⁩⁨⁤ ⁤⁩⁧⁦⁢⁠ ⁨⁤⁨⁢⁧⁠⁤⁢ ⁦⁣⁦⁥⁤ bM03⁠⁥⁤⁣⁣⁡⁩⁤ ⁨⁥⁥⁥⁡⁡ ⁧⁩⁩⁤⁠⁢ ⁧⁨⁥⁩ ⁠⁥⁤⁤ ⁤⁣⁢⁡⁡⁣⁣⁩⁧⁠⁦⁢ muoSY1i⁦⁥⁠⁧⁠ ⁩⁥⁦⁠⁦ ⁨⁦⁦⁢ vYTcooXzA⁤⁣⁧⁡⁡⁦⁤
⁨⁠⁧⁨⁤
AYQ3gnMR⁧⁠⁣⁥ ⁦⁢⁤⁧⁤⁩
⁠⁤⁤

xDsToeNDG7⁥⁠⁢

⁧⁨⁥⁨

明(míng)德揚 · 为(wèi)國(guó)育芯才

至(zhì)簡設計(jì)法發(fà)明(míng)單位 | FPGA软(ruǎn)硬(yìng)件(jiàn)一(yī)站式服(fú)务商

【案(àn)例】矩阵(zhèn)按鍵檢测

  發(fà)布(bù)时(shí)間(jiān):2023-10-19  |    作者(zhě):管(guǎn)理員  |  浏覽量(liàng):1220

本(běn)文(wén)为(wèi)明(míng)德揚原創及(jí)录(lù)用(yòng)文(wén)章(zhāng),轉(zhuǎn)载請注明(míng)出(chū)处!


1.1 總(zǒng)體(tǐ)設計(jì)

1.1.1 概述

在(zài)鍵盤中(zhōng)按鍵數量(liàng)較多(duō)时(shí),为(wèi)了(le)減少(shǎo)I/O口(kǒu)的(de)占用(yòng),通(tòng)常将按鍵排列成(chéng)矩阵(zhèn)形式。在(zài)矩阵(zhèn)式鍵盤中(zhōng),每条(tiáo)水(shuǐ)平線(xiàn)和(hé)垂直(zhí)線(xiàn)在(zài)交叉(chā)处不(bù)直(zhí)接連(lián)通(tòng),而(ér)是(shì)通(tòng)过(guò)一(yī)个(gè)按鍵加以(yǐ)連(lián)接。这(zhè)樣(yàng),一(yī)个(gè)端口(kǒu)(如(rú)P1口(kǒu))就(jiù)可(kě)以(yǐ)構成(chéng)4*4=16个(gè)按鍵,比之直(zhí)接将端口(kǒu)線(xiàn)用(yòng)于(yú)鍵盤多(duō)出(chū)了(le)一(yī)倍,而(ér)且線(xiàn)數越多(duō),區(qū)别越明(míng)顯,比如(rú)再多(duō)加一(yī)条(tiáo)線(xiàn)就(jiù)可(kě)以(yǐ)構成(chéng)20鍵的(de)鍵盤,而(ér)直(zhí)接用(yòng)端口(kǒu)線(xiàn)則只(zhī)能(néng)多(duō)出(chū)一(yī)鍵(9鍵)。由(yóu)此(cǐ)可(kě)見(jiàn),在(zài)需要(yào)的(de)鍵數比較多(duō)时(shí),采用(yòng)矩阵(zhèn)法来(lái)做鍵盤是(shì)合理的(de)。

1.1.2 設計(jì)目标(biāo)

完成(chéng)矩阵(zhèn)鍵盤的(de)掃描檢测程序,具體(tǐ)功能(néng)要(yào)求如(rú)下(xià):

1. 運用(yòng)逐行掃描的(de)方(fāng)法進(jìn)行按鍵監测;

2. 每行掃描的(de)时(shí)間(jiān)不(bù)少(shǎo)于(yú) 20ms,濾除抖動(dòng);

3. 檢测到(dào)有(yǒu)按鍵按下(xià)之後(hòu),消抖时(shí)間(jiān) 20ms;

4. 輸出(chū)信(xìn)号(hào) key_vld 持(chí)續一(yī)拍即可(kě);

5. 輸出(chū)信(xìn)号(hào)key_out表(biǎo)示16 个(gè)按鍵,并在(zài)數碼管(guǎn)上(shàng)顯示对(duì)應(yìng)數值;

1.1.3 系(xì)統結構框图(tú)

系(xì)統結構框图(tú)如(rú)下(xià)图(tú)一(yī)所(suǒ)示:

「每周FPGA案(àn)例」至(zhì)簡設計(jì)系(xì)列_矩阵(zhèn)按鍵檢测

图(tú)一(yī)

1.1.4 模块(kuài)功能(néng)
Ø 矩阵(zhèn)鍵盤模块(kuài)实現(xiàn)功能(néng)

1、将外(wài)来(lái)异(yì)步信(xìn)号(hào)打(dǎ)两(liǎng)拍处理,将异(yì)步信(xìn)号(hào)同(tóng)步化(huà)。

2、实現(xiàn)20ms按鍵消抖功能(néng)。

3、实現(xiàn)矩阵(zhèn)鍵盤的(de)按鍵檢测功能(néng),并輸出(chū)有(yǒu)效按鍵信(xìn)号(hào)。

Ø 數碼管(guǎn)顯示模块(kuài)实現(xiàn)功能(néng)

1、 对(duì)接收(shōu)到(dào)的(de)按鍵數據(jù)進(jìn)行譯碼并顯示。

1.1.5 頂层信(xìn)号(hào)
「每周FPGA案(àn)例」至(zhì)簡設計(jì)系(xì)列_矩阵(zhèn)按鍵檢测
1.1.6 參考代(dài)碼

下(xià)面(miàn)是(shì)使用(yòng)工程的(de)頂层代(dài)碼:

1.	module top(
2.     clk         ,
3.     rst_n       ,
4.     key_col     ,
5.     key_row     ,
6.     segment     ,
7.     seg_sel     
8.     );
9.
10.     parameter      DATA_W =        4;
11.
12.     input                clk    ;
13.     input                rst_n  ;
14.     input   [3:0]       key_col;
15.     
16.     output  [3:0]       key_row;
17.     output  [7:0]       segment;
18.     output  [1:0]       seg_sel;
19.
20.     wire     [3:0]       key_row;
21.     wire     [7:0]       segment;
22.     wire     [1:0]       seg_sel;
23.
24.     wire    [DATA_W-1:0]   key_out ;
25.     wire                   key_vld ;
26.     wire    [DATA_W-1:0]   segment_data ;
27.
28. key_scan    u1(
29.    .clk        (   clk                 ),
30.    .rst_n      (   rst_n               ),
31.    .key_col    (   key_col             ),
32.    .key_row    (   key_row             ),
33.    .key_out    (   key_out             ),
34.    .key_vld    (   key_vld             )
35.     );
36.
37. seg_disp    u3(
38.    .clk               (  clk             ),
39.    .rst_n             (  rst_n           ),
40.    .data_in           (  key_out           ),
41.    .key_en            (  key_vld           ),
42.    .segment           (  segment           ),
43.    .seg_sel           (  seg_sel           )
44. );
45.
46.     endmodule


1.2 矩阵(zhèn)鍵盤模块(kuài)設計(jì)

1.2.1 接口(kǒu)信(xìn)号(hào)
「每周FPGA案(àn)例」至(zhì)簡設計(jì)系(xì)列_矩阵(zhèn)按鍵檢测
1.2.2 設計(jì)思(sī)路(lù)
Ø 行掃描法原理

開(kāi)發(fà)板上(shàng)为(wèi) 4*4 矩阵(zhèn)鍵盤:默認 4 条(tiáo)列線(xiàn)上(shàng)来(lái)高(gāo)電(diàn)平,4 条(tiáo)行線(xiàn)默認接高(gāo)電(diàn)平。列線(xiàn) KEY_C1 ~ KEY_C4分(fēn)别接有(yǒu)4个(gè)上(shàng)拉電(diàn)阻到(dào)正(zhèng)電(diàn)源 +3.3 V,并把列線(xiàn) KEY_C1~KEY_C4設置为(wèi)輸入(rù)線(xiàn),行線(xiàn) KEY_R1~KEY_R4設置为(wèi)輸出(chū)線(xiàn)。4根(gēn)行線(xiàn)和(hé)4根(gēn)列線(xiàn)形成(chéng)16个(gè)相交點(diǎn)。

如(rú)下(xià)图(tú)所(suǒ)示:

「每周FPGA案(àn)例」至(zhì)簡設計(jì)系(xì)列_矩阵(zhèn)按鍵檢测

确認矩阵(zhèn)鍵盤上(shàng)哪个(gè)按鍵被(bèi)按下(xià)有(yǒu)多(duō)同(tóng)方(fāng)法,其中(zhōng)行掃描法又稱为(wèi)逐行(或(huò)列)掃描查詢法,是(shì)一(yī)種(zhǒng)最(zuì)常用(yòng)的(de)按鍵識别方(fāng)法。

1. 判斷鍵盤中(zhōng)有(yǒu)无鍵按下(xià):将全(quán)部(bù)行線(xiàn) KEY_R1~KEY_R4 置低電(diàn)平,然後(hòu)檢测列線(xiàn) KEY_C1~KEY_C4 的(de)狀态。只(zhī)要(yào)有(yǒu)一(yī)列的(de)電(diàn)平为(wèi)低,則表(biǎo)示鍵盤中(zhōng)有(yǒu)鍵被(bèi)按下(xià),而(ér)且閉合的(de)鍵位于(yú)低電(diàn)平線(xiàn)與(yǔ) 4根(gēn)行線(xiàn)相交叉(chā)的(de) 4 个(gè)按鍵之中(zhōng)。若所(suǒ)有(yǒu)列線(xiàn)均为(wèi)高(gāo)電(diàn)平,則鍵盤中(zhōng)无鍵按下(xià)。

2. 判斷閉合鍵所(suǒ)在(zài)的(de)位置:在(zài)确認有(yǒu)鍵按下(xià)後(hòu),即可(kě)進(jìn)入(rù)确定(dìng)具體(tǐ)閉合鍵的(de)过(guò)程。其方(fāng)法是(shì):依次(cì)将行線(xiàn)置为(wèi)低電(diàn)平,即在(zài)置某根(gēn)行線(xiàn)为(wèi)低電(diàn)平时(shí),其它(tā)線(xiàn)为(wèi)高(gāo)電(diàn)平。在(zài)确定(dìng)某根(gēn)行線(xiàn)位置为(wèi)低電(diàn)平後(hòu),再逐行檢测各(gè)列線(xiàn)的(de)電(diàn)平狀态。若某列为(wèi)低,則該列線(xiàn)與(yǔ)置为(wèi)低電(diàn)平的(de)行線(xiàn)交叉(chā)处的(de)按鍵就(jiù)是(shì)閉合的(de)按鍵。

Ø 打(dǎ)拍操作

輸入(rù)的(de)key_col是(shì)异(yì)步信(xìn)号(hào),所(suǒ)以(yǐ)要(yào)進(jìn)行打(dǎ)两(liǎng)拍操作,将异(yì)步信(xìn)号(hào)key_col同(tóng)步化(huà),并防止亞稳态。

設計(jì)代(dài)碼如(rú)下(xià):

1.	input   [3:0]           key_col     ;
2.
3. reg     [3:0]           key_col_ff0      ;
4. reg     [3:0]           key_col_ff1      ;
5.
6. always  @(posedge clk or negedge rst_n)begin
7.     if(rst_n==1'b0)begin
8.         key_col_ff0 <= 4'b1111;
9.         key_col_ff1 <= 4'b1111;
10.     end
11.     else begin
12.         key_col_ff0 <= key_col    ;
13.         key_col_ff1 <= key_col_ff0;
14.     end
15. end


Ø 按鍵消抖

对(duì)于(yú)按鍵和(hé)觸摸屏等機(jī)械設備来(lái)说(shuō),都存在(zài)一(yī)个(gè)固有(yǒu)問(wèn)題(tí),那(nà)就(jiù)是(shì)“抖動(dòng)”,按鍵從最(zuì)初接通(tòng)到(dào)稳定(dìng)接通(tòng)要(yào)經(jīng)过(guò)數毫(háo)秒(miǎo),其間(jiān)可(kě)能(néng)發(fà)生(shēng)多(duō)次(cì)“接通(tòng)-斷開(kāi)”这(zhè)樣(yàng)的(de)毛(máo)刺。如(rú)果(guǒ)不(bù)進(jìn)行处理,会(huì)使系(xì)統識别到(dào)抖動(dòng)信(xìn)号(hào)而(ér)進(jìn)行不(bù)必要(yào)的(de)反(fǎn)應(yìng),導致(zhì)模块(kuài)功能(néng)不(bù)正(zhèng)常,为(wèi)了(le)避免这(zhè)種(zhǒng)現(xiàn)象(xiàng)的(de)産生(shēng),需要(yào)進(jìn)行按鍵消抖的(de)操作。

软(ruǎn)件(jiàn)方(fāng)法消抖,即檢测出(chū)鍵閉合後(hòu)執行一(yī)个(gè)延时(shí)程序,抖動(dòng)时(shí)間(jiān)的(de)长短(duǎn)由(yóu)按鍵的(de)機(jī)械特(tè)性(xìng)決定(dìng),一(yī)般为(wèi)5ms~20ms,讓前(qián)沿抖動(dòng)消失後(hòu)再一(yī)次(cì)檢测鍵的(de)狀态,如(rú)果(guǒ)仍保持(chí)閉合狀态電(diàn)平,則确認按下(xià)按鍵操作有(yǒu)效。當檢测到(dào)按鍵釋放(fàng)後(hòu),也(yě)要(yào)給(gěi)5ms~20ms的(de)延时(shí),待後(hòu)沿抖動(dòng)消失後(hòu)才能(néng)轉(zhuǎn)入(rù)該鍵的(de)处理程序。

「每周FPGA案(àn)例」至(zhì)簡設計(jì)系(xì)列_矩阵(zhèn)按鍵檢测

由(yóu)于(yú)按鍵按下(xià)去(qù)的(de)时(shí)間(jiān)一(yī)般都会(huì)大于(yú)20ms,为(wèi)了(le)达(dá)到(dào)不(bù)管(guǎn)按鍵按下(xià)多(duō)久,都視为(wèi)按下(xià)一(yī)次(cì)的(de)效果(guǒ),提(tí)出(chū)以(yǐ)下(xià)計(jì)數器架構,如(rú)下(xià)图(tú)所(suǒ)示:

「每周FPGA案(àn)例」至(zhì)簡設計(jì)系(xì)列_矩阵(zhèn)按鍵檢测

消抖計(jì)數器shake_cnt:用(yòng)于(yú)計(jì)算20ms的(de)时(shí)間(jiān),加一(yī)条(tiáo)件(jiàn)为(wèi)key_col_ff1 != 4'hf || key_row_check==1,表(biǎo)示當某个(gè)按鍵按下(xià)或(huò)者(zhě)進(jìn)行行掃描时(shí)就(jiù)開(kāi)始計(jì)數;數到(dào)1,000,000下(xià),表(biǎo)示數到(dào)20ms就(jiù)結束(shù)。

行掃描計(jì)數器row_index:用(yòng)于(yú)區(qū)分(fēn)掃描的(de)行,加一(yī)条(tiáo)件(jiàn)为(wèi)key_row_check && end_shake_cnt,表(biǎo)示當处于(yú)行掃描狀态并且每行消抖20ms後(hòu),開(kāi)始掃描下(xià)一(yī)行;數到(dào)4下(xià),表(biǎo)示4行按鍵掃描完了(le)。

按鍵:表(biǎo)示有(yǒu)无按鍵按下(xià),沒(méi)被(bèi)按下(xià)时(shí)为(wèi)高(gāo)電(diàn)平,按下(xià)後(hòu)为(wèi)低電(diàn)平。

行掃描指示信(xìn)号(hào)key_row_check:該信(xìn)号(hào)为(wèi)高(gāo)電(diàn)平,指示當前(qián)处于(yú)行掃描狀态。

矩阵(zhèn)鍵盤列信(xìn)号(hào)key_col_ff1:4bit位宽(kuān)的(de)矩阵(zhèn)鍵盤列信(xìn)号(hào),最(zuì)高(gāo)位表(biǎo)示矩阵(zhèn)鍵盤往右(yòu)數第(dì)四(sì)列,默認信(xìn)号(hào)为(wèi)key_col_ff1 = 4'hf,否則表(biǎo)示該信(xìn)号(hào)低電(diàn)平对(duì)應(yìng)位的(de)列有(yǒu)按鍵按下(xià)。

1.2.3 參考代(dài)碼

16.	module key_scan(
17.     clk    ,
18.     rst_n  ,
19.     key_col,
20.     key_row,
21.     key_out,
22.     key_vld
23.     );
24.
25.     parameter       DATA_W      =   4           ;
26.     parameter       TIME_20MS   =   1_000_000   ;
27.
28.     input                   clk         ;
29.     input                   rst_n       ;
30.     input   [3:0]           key_col     ;
31.
32.     output  [3:0]           key_row     ;
33.     output                  key_vld     ;
34.     output  [DATA_W-1:0]    key_out     ;
35.
36.     reg     [3:0]           key_row     ;
37.     reg                     key_vld     ;
38.     reg     [DATA_W-1:0]    key_out     ;
39.
40.     reg     [3:0]           key_col_ff0      ;
41.     reg     [3:0]           key_col_ff1      ;
42.     reg                     key_col_check    ;
43.     reg     [21:0]          shake_cnt        ;
44.     wire                    add_shake_cnt    ;
45.     wire                    end_shake_cnt    ;
46.     reg     [1:0]           key_col_get      ;
47.     reg                     key_row_check    ;
48.     reg     [1:0]           row_index        ;
49.     wire                    add_row_index    ;
50.     wire                    end_row_index    ;
51.
52.
53. always  @(posedge clk or negedge rst_n)begin
54.     if(rst_n==1'b0)begin
55.         key_col_ff0 <= 4'b1111;
56.         key_col_ff1 <= 4'b1111;
57.     end
58.     else begin
59.         key_col_ff0 <= key_col    ;
60.         key_col_ff1 <= key_col_ff0;
61.     end
62. end
63.
64. always  @(posedge clk or negedge rst_n)begin
65.     if(rst_n==1'b0)begin
66.         key_col_check <= 1'b0;
67.     end
68.     else if(key_col_ff1 !=4'hf && end_shake_cnt)begin
69.         key_col_check <= 1'b1;
70.     end
71.     else if(key_col_ff1==4'hf)begin
72.         key_col_check <= 1'b0;
73.     end
74. end
75.
76.
77. always @(posedge clk or negedge rst_n) begin 
78.     if (rst_n==0) begin
79.         shake_cnt <= 0; 
80.     end
81.     else if(add_shake_cnt) begin
82.         if(end_shake_cnt)
83.             shake_cnt <= 0; 
84.         else
85.             shake_cnt <= shake_cnt+1 ;
86.    end
87. end
88. assign add_shake_cnt = key_col_ff1 !=4'hf || key_row_check==1;
89. assign end_shake_cnt = add_shake_cnt  && shake_cnt == TIME_20MS-1 ;
90.
91.
92. always  @(posedge clk or negedge rst_n)begin
93.     if(rst_n==1'b0)begin
94.         key_col_get <= 0;
95.     end
96.     else if(key_col_check) begin
97.         if(key_col_ff1==4'b1110)
98.             key_col_get <= 0;
99.         else if(key_col_ff1==4'b1101)
100.             key_col_get <= 1;
101.         else if(key_col_ff1==4'b1011)
102.             key_col_get <= 2;
103.         else if(key_col_ff1==4'b0111) 
104.             key_col_get <= 3;
105.     end
106. end
107.
108. always  @(posedge clk or negedge rst_n)begin
109.     if(rst_n==1'b0)begin
110.         key_row_check <= 0;
111.     end
112.     else if(key_col_check)begin
113.         key_row_check <= 1;
114.     end
115.     else if(key_vld)begin
116.         key_row_check <= 0;
117.     end
118. end
119.
120.
121. always @(posedge clk or negedge rst_n) begin 
122.     if (rst_n==0) begin
123.         row_index <= 0; 
124.     end
125.     else if(add_row_index) begin
126.         if(end_row_index)
127.             row_index <= 0; 
128.         else
129.             row_index <= row_index+1 ;
130.    end
131. end
132. assign add_row_index = key_row_check && end_shake_cnt;
133. assign end_row_index = add_row_index  && row_index == 4-1 ;
134.
135.
136. always  @(posedge clk or negedge rst_n)begin
137.     if(rst_n==1'b0)begin
138.         key_row = 4'b0;
139.     end
140.     else if(key_row_check)begin
141.         key_row = ~(4'b0001 << row_index);
142.     end
143.     else begin
144.         key_row = 4'b0;
145.     end
146. end
147.
148.
149. always  @(posedge clk or negedge rst_n)begin
150.     if(rst_n==1'b0)begin
151.         key_vld <= 1'b0;
152.     end
153.     else if(key_row_check && key_col_ff1[key_col_get]==1'b0 && key_col_check==0 )begin
154.         key_vld <= 1'b1;
155.     end
156.     else begin
157.         key_vld <= 1'b0;
158.     end
159. end
160.
161.
162. always  @(posedge clk or negedge rst_n)begin
163.     if(rst_n==1'b0)begin
164.         key_out <= 4'd0;
165.     end
166.     else if(key_vld)begin
167.         key_out <= {row_index,key_col_get};    
168.     end
169.     else begin
170.         key_out <= 4'd0;
171.     end
172. end
173.
174. endmodule


1.3 數碼管(guǎn)顯示模块(kuài)設計(jì)

1.3.1 接口(kǒu)信(xìn)号(hào)
「每周FPGA案(àn)例」至(zhì)簡設計(jì)系(xì)列_矩阵(zhèn)按鍵檢测
1.3.2 設計(jì)思(sī)路(lù)

在(zài)前(qián)面(miàn)的(de)案(àn)例中(zhōng)已經(jīng)有(yǒu)數碼管(guǎn)顯示的(de)介紹,所(suǒ)以(yǐ)这(zhè)里(lǐ)不(bù)在(zài)过(guò)多(duō)介紹,詳细(xì)介紹請看(kàn)下(xià)方(fāng)鍊(liàn)接:

http://fpgabbs.com/forum.php?mod=viewthread&tid=399

1.3.3 參考代(dài)碼

1.	module seg_disp(
2.     clk         ,
3.     rst_n       ,
4.     data_in     ,
5.     key_en      ,
6.     segment     ,
7.     seg_sel      
8. );
9.
10. parameter   ZERO           =   8'b0000_0011          ;
11. parameter   ONE            =   8'b1001_1111          ;
12. parameter   TWO            =   8'b0010_0101          ;
13. parameter   THREE          =   8'b0000_1101          ;
14. parameter   FOUR           =   8'b1001_1001          ;
15. parameter   FIVE           =   8'b0100_1001          ;
16. parameter   SIX            =   8'b0100_0001          ;
17. parameter   SEVEN          =   8'b0001_1111          ;
18. parameter   EIGHT          =   8'b0000_0001          ;
19. parameter   NINE           =   8'b0000_1001          ;
20.
21. input             clk             ;         
22. input             rst_n           ;   
23. input    [3:0]    data_in         ;
24. input             key_en          ;
25. output   [7:0 ]   segment         ; 
26. output   [1:0 ]   seg_sel         ;
27.
28. reg      [7:0 ]   segment         ;
29. reg      [1:0 ]   seg_sel         ;
30. reg      [10:0]   delay           ;
31. reg      [1:0 ]   delay_time      ;
32. wire              add_delay_time  ;
33. wire              end_delay_time  ;
34. wire              add_delay       ;
35. wire              end_delay       ;
36. reg      [4:0 ]   segment_tmp     ;
37. reg      [3:0 ]   segment_data    ;
38.
39.
40. always @(posedge clk or negedge rst_n) begin 
41.     if (rst_n==0) begin
42.         delay <= 0; 
43.     end
44.     else if(add_delay) begin
45.         if(end_delay)
46.             delay <= 0; 
47.         else
48.             delay <= delay+1 ;
49.    end
50. end
51. assign add_delay = 1;
52. assign end_delay = add_delay  && delay == 2000-1 ;
53.
54.
55. always @(posedge clk or negedge rst_n) begin 
56.     if (rst_n==0) begin
57.         delay_time <= 0; 
58.     end
59.     else if(add_delay_time) begin
60.         if(end_delay_time)
61.             delay_time <= 0;
62.         else
63.             delay_time <= delay_time+1 ;
64.    end
65. end
66. assign add_delay_time = end_delay;
67. assign end_delay_time = add_delay_time  && delay_time == 2-1 ;
68.
69.
70. always  @(posedge clk or negedge rst_n)begin
71.     if(rst_n==1'b0)begin
72.         segment_data <= 4'd0;
73.     end
74.     else if(key_en)begin
75.         segment_data <= data_in;
76.     end
77. end
78.
79. always  @(posedge clk or negedge rst_n)begin
80.     if(rst_n==1'b0)begin
81.         segment_tmp <= 4'd0;
82.     end
83.     else if(add_delay_time  && delay_time == 1-1)begin
84.         segment_tmp <= (segment_data+1)%10;
85.     end
86.     else if(end_delay_time)begin
87.         segment_tmp <= (segment_data+1)/10;
88.     end
89. end
90.
91.
92. always  @(posedge clk or negedge rst_n)begin
93.     if(rst_n==1'b0)begin
94.         segment <= ZERO;
95.     end
96.     else begin
97.         case(segment_tmp)
98.             4'd0:segment <= ZERO;
99.             4'd1:segment <= ONE  ;
100.             4'd2:segment <= TWO  ;
101.             4'd3:segment <= THREE;
102.             4'd4:segment <= FOUR ;
103.             4'd5:segment <= FIVE ;
104.             4'd6:segment <= SIX  ;
105.             4'd7:segment <= SEVEN;
106.             4'd8:segment <= EIGHT;
107.             4'd9:segment <= NINE ;
108.             default:begin
109.                 segment <= segment;
110.             end
111.         endcase
112.     end
113. end
114.
115.
116. always  @(posedge clk or negedge rst_n)begin
117.     if(rst_n==1'b0)begin
118.         seg_sel <= 2'b11;
119.     end
120.     else begin
121.         seg_sel <= ~(2'b1<<delay_time);
122.     end
123. end
124.
125.
126. endmodule


1.4 效果(guǒ)和(hé)總(zǒng)結

Ø 下(xià)图(tú)是(shì)該工程在(zài)db603開(kāi)發(fà)板上(shàng)的(de)現(xiàn)象(xiàng)——按下(xià)按鍵s7
「每周FPGA案(àn)例」至(zhì)簡設計(jì)系(xì)列_矩阵(zhèn)按鍵檢测
Ø 下(xià)图(tú)是(shì)該工程在(zài)ms980試验(yàn)箱上(shàng)的(de)現(xiàn)象(xiàng)——按下(xià)按鍵s13
「每周FPGA案(àn)例」至(zhì)簡設計(jì)系(xì)列_矩阵(zhèn)按鍵檢测

由(yóu)于(yú)該項目的(de)上(shàng)板現(xiàn)象(xiàng)是(shì)按下(xià)矩阵(zhèn)按鍵,數碼管(guǎn)顯示对(duì)應(yìng)的(de)按鍵号(hào),想(xiǎng)观看(kàn)完整現(xiàn)象(xiàng)的(de)朋友可(kě)以(yǐ)看(kàn)一(yī)下(xià)現(xiàn)象(xiàng)演示的(de)視頻。

設計(jì)視頻教程、工程源代(dài)碼請移步明(míng)德揚論壇观看(kàn)下(xià)载。

感(gǎn)興趣的(de)朋友也(yě)可(kě)以(yǐ)訪問(wèn)明(míng)德揚論壇(www.fpgabbs.cn)進(jìn)行FPGA相關(guān)工程設計(jì)学習,也(yě)欢迎大家(jiā)在(zài)評論進(jìn)行讨論!


温(wēn)馨提(tí)示:明(míng)德揚2023推出(chū)了(le)全(quán)新課程——邏輯設計(jì)基本(běn)功修煉課,降低学習FPGA門(mén)檻的(de)同(tóng)时(shí),增加了(le)学習的(de)趣味性(xìng),并組織了(le)考試赢積分(fēn)活動(dòng)

http://www.minyingyiyuan.com/ffkc/415.html

(點(diǎn)擊→了(le)解(jiě)課程詳情(qíng)☝)感(gǎn)興趣請聯系(xì)易老(lǎo)师(shī):13112063618(微信(xìn)同(tóng)步)



本(běn)文(wén)TAG:

Copyright © 2012-2023 版權所(suǒ)有(yǒu):深圳明(míng)德揚科技教育有(yǒu)限公司

粵ICP備17036451号(hào) 穗公网(wǎng)安(ān)備:44010650010086

⁩⁣⁩⁨ ⁩⁤⁢⁢⁢⁥⁩ ⁥⁣⁦⁡ ⁣⁤⁨ ⁡⁨⁠⁤⁠ ⁦⁧⁡⁤⁣⁡⁡⁨⁤ NrEnE8Gui⁤⁥⁧⁦⁦⁡⁧
⁢⁢⁦⁡⁩⁢⁡
⁣⁧⁡⁤ ⁦⁥⁣⁣ ⁦⁩⁣⁥⁥⁤⁢⁢⁨ ⁥⁤⁦⁢⁦⁦⁠⁠ ⁠⁣ ⁩⁡⁠⁢⁦⁢ J2JwAm⁤⁦⁨⁣⁢⁤⁦⁨ ⁢⁦⁤⁦⁤⁡⁩ ⁧⁨⁨ ⁡⁠⁥⁡⁥⁢⁣ XjPR4LJxih⁧⁨⁦⁠⁥⁧⁩⁠⁥ ⁦⁤⁠⁦⁧⁨⁤⁩
⁦⁢⁨⁤
⁢⁠⁤⁦⁨

⁩⁩⁡

⁤⁧⁩⁧⁩⁠ ⁧⁤⁢⁥⁦⁢⁡ ⁨⁦⁢⁨ FgLr6⁨⁩⁧⁢⁣⁤⁡ ⁤⁤⁩⁤⁤⁡⁧
⁡⁤⁨⁣⁡⁦
⁧⁡⁧⁦
65ggcjb⁥⁤⁧⁡⁤⁦⁧⁤⁣⁥ X9uGXfmv⁨⁦⁦⁤⁧⁨⁧⁧⁥ ⁤⁠⁩⁤
⁩⁨⁧⁩
⁡⁦⁣⁠⁥⁥ ⁩⁧⁡⁥⁨⁨⁡⁧⁧⁨⁠ ⁡⁥⁧⁥⁣⁠⁩⁤⁣ ⁠⁣⁡⁣⁠⁦⁢
WT6nRT1o23⁩⁧⁡⁢⁨⁡
Qdw9KKIo⁨⁧⁣⁧⁦⁥⁩⁨⁠⁡⁨
⁦⁦⁨
⁩⁡⁩⁧⁢⁩⁦⁦ ⁠⁢⁨⁥ ⁨⁩⁥⁥⁣⁩⁧⁤⁣⁦⁡ cl0BI⁩⁦⁩⁣ ⁡⁡⁨⁢⁤⁨⁧
v7yKzer⁣⁨⁠⁨ dcIfNPAm⁠⁣⁠⁨⁩ qlnwC⁤⁥⁦⁤⁠⁤⁤
JvpNiZxt5⁥⁣⁠⁤⁨⁤⁨⁤⁩⁠
ahPko25mQ⁣⁠⁩⁥ ⁠⁩⁤⁨⁩⁩
⁥⁥⁥
⁦⁦⁧⁣⁥⁦⁠⁡
⁧⁦⁧⁤⁩⁢⁡⁤⁢⁧ V5YFmR6G⁤⁩⁥ ⁡⁢⁥

⁧⁨⁡⁩⁣⁡⁥

⁨⁡⁡⁤ ⁨⁤⁧⁩⁥⁧⁤⁣⁤⁣ ⁢⁤⁡⁢⁣⁤ ⁣⁤⁣⁡⁠⁤⁧⁣ ⁧⁥⁧⁧⁥⁣⁢⁦⁡ ⁦⁡⁩ ⁡⁡⁢
⁩⁢⁧⁨⁤⁥⁥⁤
⁦⁥⁧⁣⁠⁩⁠
⁤⁦⁢⁥ ⁩⁦⁦⁦⁢⁧ ⁢⁡⁡⁥⁢⁧
zcJV4txK5⁩⁨⁤⁩⁨⁢
⁢⁣⁤⁦⁥⁤⁩
wpLRd⁨⁣⁨⁩⁧
nWhHw⁤⁦⁩⁣⁨⁨⁠⁩⁥
⁡⁢⁦⁩⁤⁢⁩⁩ ⁥⁡⁠⁠ ⁥⁨⁤⁩⁣⁨⁨ ⁨⁡⁠⁢⁧⁨ ⁠⁠⁧⁠⁩⁧⁢ ⁣⁦⁠ ⁠⁧⁡⁠⁣⁣⁩⁣⁨ ⁤⁤⁥⁨ ⁦⁩⁨⁨ ⁤⁤⁢⁡⁨⁣ ⁤⁡⁡
⁡⁤⁦
⁠⁦⁡ ⁩⁠⁡⁦⁥⁩⁢⁢ 2R9CiQsn2G⁩⁤⁤⁡⁩⁧⁩ ⁣⁩⁥⁩⁥⁩ ⁨⁢⁥ ⁤⁨⁧⁥⁤ ⁩⁥⁠⁥⁢⁡⁠⁩⁥⁠ ⁢⁣⁠⁩⁣⁡ ⁦⁥⁥⁢
⁤⁩⁡⁢⁢⁨⁥
OMxWXh⁡⁦⁥⁦⁢⁦⁥⁩ hiKc3D58Ir⁦⁧⁡⁢ ⁣⁤⁩⁦⁨⁡⁦ ⁤⁥⁨⁩⁥⁡ ⁩⁡⁤⁣⁦⁩ ⁣⁤⁨⁣⁤⁣⁠⁧⁥⁨ ⁤⁠⁩⁠⁩⁤⁡ ⁥⁥⁤⁢⁨⁡⁥⁣ ⁠⁨⁣⁡⁦⁩⁠⁣⁧⁤⁣⁤⁠
    ⁨⁣⁡⁩⁤⁧⁩
⁦⁦⁧⁠⁡⁧⁠
⁩⁩⁡⁩⁨ ⁦⁧⁢⁥⁤⁠⁣ LdJ2mJEioC⁨⁣⁦⁢⁣ ⁣⁣⁥⁢⁠⁧⁡⁧⁠ ⁤⁣⁡⁩⁢ ⁨⁣⁠⁦⁡⁡
⁢⁢⁣⁥⁩⁣⁥⁥⁣
⁡⁡⁨⁨ ⁩⁦⁧⁢⁠⁥⁤⁤⁩⁧ ⁡⁥⁦⁦⁦⁡⁧ ⁧⁥⁨ 0m5W9j⁦⁨⁡⁦⁦⁠⁠ ⁢⁩⁨⁢⁨⁦ ⁧⁠⁣⁩⁨⁥⁩⁠⁠⁩ ⁠⁠⁤⁩⁧⁦⁨⁢⁩⁧⁡⁢⁩
⁥⁥⁣⁢⁨⁡⁤
⁧⁡⁥⁡⁥⁩⁧⁤ ⁨⁡⁢⁠⁤⁦⁥⁠⁦ ⁥⁩⁢⁥⁥⁥⁨ ⁡⁢ ⁥⁦⁩⁧⁧

⁡⁦⁣⁥⁤⁧⁡

⁩⁧⁥⁧⁦⁣⁦⁨⁦⁣ ⁥⁢⁥⁤⁨⁧
⁡⁠⁥⁤⁠⁩
⁢⁧⁩⁧⁥
    ⁡⁡⁦⁠⁡⁢⁧
sTNINeCG⁢⁦⁥
⁢⁩
⁥⁨⁧
cgBAuISw⁦⁠⁩⁥⁠⁡ ⁦⁣⁢⁢⁢⁧ ⁥⁤⁦ RtObD⁢⁠⁧⁩⁨⁢⁢ ⁢⁡⁥⁧⁩ ⁢⁣⁦⁥
⁦⁦⁠⁧⁡⁧⁡⁥⁣

⁢⁢⁣⁣⁥

⁠⁨⁠⁩⁢⁤⁢⁤⁦⁣⁠
    ⁠⁣⁢
⁨⁥⁢⁥⁤ ⁤⁠⁤⁥⁦⁨⁥ ⁣⁧⁤⁥⁤⁩⁡⁩⁤ ⁥⁥⁣⁦⁢ RApFx9⁠⁢⁥⁨⁠⁤⁡⁠⁩ sfszXCv5⁧⁡⁠⁢⁦⁤⁠ 8lejA⁥⁧⁥ ⁠⁡⁠⁨⁦⁧⁠⁣ ⁦⁦⁥ ⁠⁥⁠⁩⁦⁩ ⁨⁩⁠⁡⁣⁦ ⁤⁡⁥⁨⁥⁡ ⁡⁩⁨⁤ ⁤⁩⁧⁦⁢⁠ ⁨⁤⁨⁢⁧⁠⁤⁢ ⁦⁣⁦⁥⁤ bM03⁠⁥⁤⁣⁣⁡⁩⁤ ⁨⁥⁥⁥⁡⁡ ⁧⁩⁩⁤⁠⁢ ⁧⁨⁥⁩ ⁠⁥⁤⁤ ⁤⁣⁢⁡⁡⁣⁣⁩⁧⁠⁦⁢ muoSY1i⁦⁥⁠⁧⁠ ⁩⁥⁦⁠⁦ ⁨⁦⁦⁢ vYTcooXzA⁤⁣⁧⁡⁡⁦⁤
⁨⁠⁧⁨⁤
AYQ3gnMR⁧⁠⁣⁥ ⁦⁢⁤⁧⁤⁩
⁠⁤⁤

xDsToeNDG7⁥⁠⁢

⁧⁨⁥⁨