1. 程式人生 > >【黑金原創教程】【FPGA那些事兒-驅動篇I 】實驗五:按鍵模組④ — 點選,長點選,雙擊

【黑金原創教程】【FPGA那些事兒-驅動篇I 】實驗五:按鍵模組④ — 點選,長點選,雙擊

實驗五:按鍵模組④ — 點選,長點選,雙擊

實驗二至實驗四,我們一共完成如下有效按鍵:

l 點選(按下有效)

l 點選(釋放有效)

l 長擊(長按下有效)

l 雙擊(連續按下有效)

然而,不管哪個實驗都是隻有兩項“功能”的按鍵模組而已,如今我們要建立三項“功能”的按鍵模組,亦即點選(按下有效),長擊,還有雙擊。實驗繼續之前,讓我們先來複習一下各種有效按鍵。

clip_image002

圖5.1 點選(按下有效)。

如圖5.1所示,所謂點選(按下有效)就是按鍵按下以後,isSClick訊號(Single Click)

產生一個高脈衝。

clip_image004

圖5.2 長點選。

如圖5.2所示,所謂長點選就是按鍵按下以後,長達3秒不放,isLClick訊號(Long Click)

就會產生一個高脈衝。

clip_image006

圖5.3 雙點選。

如圖5.3所示,所謂雙點選就是距離第一次“點選(按下有效)”,如果在有效的連擊時限內容完成第二次“點選(按下有效)”,那麼isDClick訊號(Double Click)就會產生一個高脈衝。

話語上,實驗五雖然要整合3項按鍵功能,然而實驗五相較實驗二至實驗四卻有一定程度的難度。那是因為僅有兩項功能的按鍵模組,僅需判斷一次性的有效按鍵而已,反之三項功能的按鍵模組卻要分開二次判斷,而且判斷也要有序。根據實驗五,核心操作會優先判斷按鍵是否“長點選”,然後再來判斷“點選”還是“雙點選”。期間絕對不能搞錯判斷的次序。

具體內容,我們還是直接來看程式碼吧:

clip_image008

圖5.4 實驗五的建模圖。

如圖5.4所示,那是實驗五的按鍵功能模組,輸入端一邊是連線至按鍵資源的KEY訊號,輸出端另一邊則是連線至3位LED資源的LED訊號。

key_funcmod.v
1.    module key_funcmod
2.    (
3.         input CLOCK, RESET,
4.         input KEY,
5.         output [2:0]LED
6.    );

以上為相關的出入端宣告。

7.         parameter T10MS         = 28'd500_000;
8.         parameter T100MS     = 28'd5_000_000; 
9.         parameter T200MS     = 28'd10_000_000; 
10.         parameter T300MS     = 28'd15_000_000; 
11.         parameter T400MS     = 28'd20_000_000; 
12.         parameter T500MS     = 28'd25_000_000; 
13.         parameter T3S        = 28'd150_000_000; 
14.         
15.         /**********************************/ //sub
16.         
17.         reg F2,F1;
18.             
19.         always @ ( posedge CLOCK or negedge RESET )
20.             if( !RESET ) 
21.                  { F2, F1 } <= 2'b11;
22.              else 
23.                  { F2, F1 } <= { F1, KEY };
24.                    
25.         /**********************************/ //core
26.        
27.         wire isH2L = ( F2 == 1 && F1 == 0 );
28.         wire isL2H = ( F2 == 0 && F1 == 1 );

以上內容是時間常量宣告以及周邊操作。第17~23行是檢測電平狀態的周邊操作,第27~28行則是按下事件還有釋放事件的宣告。

29.         reg [3:0]i;
30.         reg isLClick, isDClick,isSClick;
31.         reg [1:0]isTag;
32.         reg [27:0]C1;
33.         
34.         always @ ( posedge CLOCK or negedge RESET )
35.             if( !RESET )
36.                   begin
37.                         i <= 4'd0;
38.                         isLClick <= 1'b0;
39.                         isDClick <= 1'b0;
40.                         isSClick <= 1'b0;
41.                         isTag <= 2'd0;
42.                         C1 <= 28'd0;
43.                     end
44.              else

以上內容為相關的暫存器宣告以及復位操作。i指向步驟,暫存器isLClick,暫存器isDClick,還有暫存器isSClick則是相關的“有效按鍵”標誌。isTag表示“有效按鍵”的標籤,1為“點選”,2為“雙點選”,3為“長點選”。C1用來計數。第35~43行則是相關的復位操作。

45.           case(i)
46.                         
47.                0: // Wait H2L
48.                if( isH2L ) begin i <= i + 1'b1; end
49.                         
50.                1: // H2L debounce
51.                if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end
52.                else C1 <= C1 + 1'b1;
53.                         
54.                2: // Key Tag Check 1
55.                if( isL2H ) begin C1 <= 28'd0; i <= i + 1'b1; end
56.                else if( {F2,F1} == 2'b00 && C1 >= T3S -1 ) begin isTag <= 2'd3; C1 <= 28'd0; i <= 4'd5; end
57.                else C1 <= C1 + 1'b1;    
58.                         
59.                3: // L2H debounce
60.                if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end
61.                else C1 <= C1 + 1'b1;
62.                         
63.                4: // Key Tag Check 2      
64.                if( isH2L && C1 <= T100MS -1 ) begin isTag <= 2'd2; C1 <= 28'd0; i <= i + 1'b1; end
65.                else if( C1 >= T100MS -1) begin isTag <= 2'd1; C1 <= 28'd0; i <= i + 1'b1; end
66.                else C1 <= C1 + 1'b1;    
67.                         
68.                5: // Key trigger press up
69.                if( isTag == 2'd3 ) begin isLClick <= 1'b1; i <= i + 1'b1; end
70.                else if( isTag == 2'd2 ) begin isDClick <= 1'b1; i <= i + 1'b1; end
71.                else if( isTag == 2'd1 ) begin isSClick <= 1'b1; i <= i + 1'b1; end
72.                         
73.                6: // Key trigger pree down
74.                begin { isLClick, isSClick, isDClick } <= 3'b000; i <= i + 1'b1; end
75.                         
76.                7: // L2H deounce check
77.                if( isTag == 2'd1 ) begin isTag <= 2'd0; i <= i + 2'd2; end
78.                else if( isTag == 2'd2 ) begin isTag <= 2'd0; i <= i + 1'b1; end
79.                else if( isTag == 2'd3 ) begin isTag <= 2'd0; i <= i + 1'b1; end
80.                         
81.                8: // Wait L2H
82.                if( isL2H ) begin i <= i + 1'b1; end
83.                             
84.                9: // L2H debounce
85.                if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= 4'd0; end
86.                 else C1 <= C1 + 1'b1;
87.                         
88.          endcase

第45~88行是核心操作,具體的操作過程如下:

步驟0,等待第一次按下事件;

步驟1,過濾抖動;

步驟2,檢測是不是長點選,如果是isTag為3然後出發步驟5,否則等待釋放事件;

步驟3,過濾抖動;

步驟4,檢測是不是雙擊,如果是isTag為2,否則S為1;

步驟5~6,根據isTag內容產生高脈衝;

步驟7,根據isTag內容檢測是否需要過濾抖動,isTag為1直接返回步驟0,其它需要;

步驟8,等待釋放事件;

步驟9,過濾抖動然後返回步驟0.

89.         
90.        /*************************/ // sub-demo            
91.        
92.        reg [2:0]D1;
93.        
94.        always @ ( posedge CLOCK or negedge RESET )
95.            if( !RESET )
96.                 D1 <= 2'd0;
97.             else if( isLClick )
98.                 D12] <= ~D1[2];
99.             else if( isDClick )
100.                 D1[1] <= ~D1[1];
101.             else if( isSClick )
102.                 D1[0] <= ~D1[0];
103.                  
104.        /***************************/
105.             
106.        assign LED = D1;
107.    
108.    endmodule

以上內容為演示用的周邊操作以及輸出驅動。它會根據各種“有效按鍵”翻轉D1的內容。第106行則是輸出驅動的宣告。編譯完後下載程式。

如果筆者點選一下 <KEY1> 建,那麼LED[0] 會點亮,如果筆者雙擊 <KEY1> 建,結果 LED[1] 會點亮,再如果筆者長按 <KEY1> 建 3秒不放,那麼 LED[2] 則會點亮。總結說,一個按鍵資源可以執行3種功能,控制3位LED資源。

細節一:完整的個體模組

clip_image010

圖5.5 完整的按鍵功能模組。

如圖5.5所示,那是完整的按鍵功能模組,它有一位輸入端KEY連線至按鍵資源,然後則有3位觸發訊號,Trig[2]產生“單擊”的個高脈衝,Trig[1] 產生“雙擊”的個高脈衝,Trig[0]產生“長擊”的個高脈衝

key_funcmod.v
1.    module key_funcmod
2.    (
3.         input CLOCK, RESET,
4.         input KEY,
5.         output [2:0]oTrig
6.    );
7.         parameter T10MS         = 28'd500_000;
8.         parameter T100MS     = 28'd5_000_000; 
9.         parameter T200MS     = 28'd10_000_000; 
10.         parameter T300MS     = 28'd15_000_000; 
11.         parameter T400MS     = 28'd20_000_000; 
12.         parameter T500MS     = 28'd25_000_000; 
13.         parameter T3S        = 28'd150_000_000; 
14.         
15.         /**********************************/ //sub
16.         
17.         reg F2,F1;
18.             
19.         always @ ( posedge CLOCK or negedge RESET )
20.             if( !RESET ) 
21.                  { F2, F1 } <= 2'b11;
22.              else 
23.                  { F2, F1 } <= { F1, KEY };
24.                    
25.         /**********************************/ //core
26.        
27.         wire isH2L = ( F2 == 1 && F1 == 0 );
28.         wire isL2H = ( F2 == 0 && F1 == 1 );
29.         reg [3:0]i;
30.         reg isLClick, isDClick,isSClick;
31.         reg [1:0]isTag;
32.         reg [27:0]C1;
33.         
34.         always @ ( posedge CLOCK or negedge RESET )
35.             if( !RESET )
36.                   begin
37.                        i <= 4'd0;
38.                         isLClick <= 1'b0;
39.                         isDClick <= 1'b0;
40.                         isSClick <= 1'b0;
41.                         isTag <= 2'd0;
42.                         C1 <= 28'd0;
43.                     end
44.              else
45.                  case(i)
46.                         
47.                         0: // Wait H2L
48.                         if( isH2L ) begin i <= i + 1'b1; end
49.                         
50.                         1: // H2L debounce
51.                         if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end
52.                         else C1 <= C1 + 1'b1;
53.                         
54.                         2: // Key Tag Check 1
55.                         if( isL2H ) begin C1 <= 28'd0; i <= i + 1'b1; end
56.                         else if( {F2,F1} == 2'b00 && C1 >= T3S -1 ) begin isTag <= 2'd3; C1 <= 28'd0; i <= 4'd5; end
57.                         else C1 <= C1 + 1'b1;    
58.                         
59.                         3: // L2H debounce
60.                         if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end
61.                         else C1 <= C1 + 1'b1;
62.                         
63.                         4: // Key Tag Check 2      
64.                         if( isH2L && C1 <= T100MS -1 ) begin isTag <= 2'd2; C1 <= 28'd0; i <= i + 1'b1; end
65.                         else if( C1 >= T100MS -1) begin isTag <= 2'd1; C1 <= 28'd0; i <= i + 1'b1; end
66.                         else C1 <= C1 + 1'b1;    
67.                         
68.                         5: // Key trigger press up
69.                         if( isTag == 2'd3 ) begin isLClick <= 1'b1; i <= i + 1'b1; end
70.                         else if( isTag == 2'd2 ) begin isDClick <= 1'b1; i <= i + 1'b1; end
71.                         else if( isTag == 2'd1 ) begin isSClick <= 1'b1; i <= i + 1'b1; end
72.                         
73.                         6: // Key trigger pree down
74.                         begin { isLClick, isSClick, isDClick } <= 3'b000; i <= i + 1'b1; end
75.                         
76.                         7: // L2H deounce check
77.                         if( isTag == 2'd1 ) begin isTag <= 2'd0; i <= i + 2'd2; end
78.                         else if( isTag == 2'd2 ) begin isTag <= 2'd0; i <= i + 1'b1; end
79.                         else if( isTag == 2'd3 ) begin isTag <= 2'd0; i <= i + 1'b1; end
80.                         
81.                         8: // Wait L2H
82.                         if( isL2H ) begin i <= i + 1'b1; end
83.                             
84.                         9: // L2H debounce
85.                         if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= 4'd0; end
86.                         else C1 <= C1 + 1'b1;
87.                         
88.                    endcase
89.                  
90.        /***************************/
91.             
92.        assign oTrig = { isSClick,isDClick,isLClick };
93.    
94.    endmodule

相關推薦

黑金原創教程FPGA那些事兒-驅動I 實驗流水燈模組

實驗一:流水燈模組 對於發展商而言,動土儀式無疑是最重要的任務。為此,流水燈實驗作為低階建模II的動土儀式再適合不過了。廢話少說,我們還是開始實驗吧。 圖1.1 實驗一建模圖。 如圖1.1 所示,實驗一有名為 led_funcmod的功能模組。如果無視環境訊號(時鐘訊號還有復位訊號),該功能模組只有

黑金原創教程FPGA那些事兒-驅動I 連載導讀

前言: 無數晝夜的來回輪替以後,這本《驅動篇I》終於編輯完畢了,筆者真的感動到連鼻涕也流下來。所謂驅動就是認識硬體,還有前期建模。雖然《驅動篇I》的硬體都是我們熟悉的老友記,例如UART,VGA等,但是《驅動篇I》貴就貴在建模技巧的昇華,亦即低階建模II。 話說低階建模II,讀過《建模篇》的朋友多少也會面

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組② —

實驗三:按鍵模組② — 點選與長點選 實驗二我們學過按鍵功能模組的基礎內容,其中我們知道按鍵功能模組有如下操作: l 電平變化檢測; l 過濾抖動; l 產生有效按鍵。 實驗三我們也會z執行同樣的事情,不過卻是產生不一樣的有效按鍵: l 按下有效(點選); l 長按下有效(長點選)。 圖3

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組

實驗二:按鍵模組① - 消抖 按鍵消抖實驗可謂是經典中的經典,按鍵消抖實驗雖曾在《建模篇》出現過,而且還惹來一堆麻煩。事實上,筆者這是在刁難各位同學,好讓對方的慣性思維短路一下,但是慘遭口水攻擊 ... 面對它,筆者宛如被甩的男人,對它又愛又恨。不管怎麼樣,如今 I’ll be back,筆者再也不會重複一

黑金原創教程FPGA那些事兒-驅動I 實驗數碼管模組

實驗六:數碼管模組 有關數碼管的驅動,想必讀者已經學爛了 ... 不過,作為學習的新儀式,再爛的東西也要溫故知新,不然學習就會不健全。黑金開發板上的數碼管資源,由始至終都沒有改變過,筆者因此由身懷念。為了點亮多位數碼管從而顯示數字,一般都會採用動態掃描,然而有關動態掃描的資訊請怒筆者不再重複。在此,同樣也是

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組③ — 單

實驗四:按鍵模組③ — 單擊與雙擊 實驗三我們建立了“點選”還有“長點選”等有效按鍵的多功能按鍵模組。在此,實驗四同樣也是建立多功能按鍵模組,不過卻有不同的有效按鍵。實驗四的按鍵功能模組有以下兩項有效按鍵: l 單擊(按下有效); l 雙擊(連續按下兩下有效)。 圖4.1 單擊有效按鍵,時序示意圖

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組④ —

實驗五:按鍵模組④ — 點選,長點選,雙擊 實驗二至實驗四,我們一共完成如下有效按鍵: l 點選(按下有效) l 點選(釋放有效) l 長擊(長按下有效) l 雙擊(連續按下有效) 然而,不管哪個實驗都是隻有兩項“功能”的按鍵模組而已,如今我們要建立三項“功能”的按鍵模組,亦即點選(按下有效),長

黑金原創教程FPGA那些事兒-驅動I 原創教程連載導讀連載完成共二十九章

前言: 無數晝夜的來回輪替以後,這本《驅動篇I》終於編輯完畢了,筆者真的感動到連鼻涕也流下來。所謂驅動就是認識硬體,還有前期建模。雖然《驅動篇I》的硬體都是我們熟悉的老友記,例如UART,VGA等,但是《驅動篇I》貴就貴在建模技巧的昇華,亦即低階建模II。 話說低階建模II,讀過《建模篇》的朋友多少也會面

黑金原創教程FPGA那些事兒-驅動I 實驗二十一SDRAM模組④ — 頁讀寫 β

實驗二十一:SDRAM模組④ — 頁讀寫 β 未進入主題之前,讓我們先來談談一些重要的體外話。《整合篇》之際,筆者曾經比擬Verilog如何模仿for迴圈,我們知道for迴圈是順序語言的產物,如果Verilog要實現屬於自己的for迴圈,那麼它要考慮的東西除了步驟以外,還有非常關鍵的時鐘。 for(

黑金原創教程FPGA那些事兒-驅動I 實驗PS/2模組④ — 普通滑鼠

實驗十:PS/2模組④ — 普通滑鼠 學習PS/2鍵盤以後,接下來就要學習 PS/2 滑鼠。PS/2滑鼠相較PS/2鍵盤,驅動難度稍微高了一點點,因為FPGA(從機)不僅僅是從PS/2滑鼠哪裡讀取資料,FPGA還要往滑鼠裡寫資料 ... 反之,FPGA只要對PS/2鍵盤讀取資料即可。然而,最傷腦筋的地方就在

黑金原創教程FPGA那些事兒-驅動I 實驗十八SDRAM模組① — 單字讀寫

實驗十八:SDRAM模組① — 單字讀寫 筆者與SDRAM有段不短的孽緣,它作為冤魂日夜不斷糾纏筆者。筆者嘗試過許多方法將其退散,不過屢試屢敗的筆者,最終心情像橘子一樣橙。《整合篇》之際,筆者曾經大戰幾回兒,不過內容都是點到即止。最近它破蠱而出,日夜不停:“好~痛苦!好~痛苦!”地呻吟著,嚇得筆者不敢半夜如

黑金原創教程FPGA那些事兒-驅動I 實驗二十七TFT模組

實驗二十七:TFT模組 - 顯示 所謂TFT(Thin Film Transistor)就是眾多LCD當中,其中一種支援顏色的LCD,相較古老的點陣LCD(12864笑),它可謂高階了。黑金的TFT LCD除了320×240大小以外,內建SSD1289控制器,同時也是獨立模組。事實上,無論是驅動點陣LCD還

黑金原創教程FPGA那些事兒-驅動I 實驗十三串列埠模組② — 接收

實驗十三:串列埠模組② — 接收 我們在實驗十二實現了串列埠傳送,然而這章實驗則要實現串列埠接收 ... 在此,筆者也會使用其它思路實現串列埠接收。 圖13.1 模組之間的資料傳輸。 假設我們不考慮波特率,而且一幀資料之間的傳輸也只是發生在FPGA之間,即兩隻模組之間互轉,並且兩塊模組都使用相同的時

黑金原創教程FPGA那些事兒-驅動I 實驗PS/2模組① — 鍵盤

實驗七:PS/2模組① — 鍵盤 實驗七依然也是熟爛的PS/2鍵盤。相較《建模篇》的PS/2鍵盤實驗,實驗七實除了實現基本的驅動以外,我們還要深入解PS/2時序,還有PS/2鍵盤的行為。不過,為了節省珍貴的頁數,怒筆者不再重複有關PS/2的基礎內容,那些不曉得的讀者請複習《建模篇》或者自行谷歌一下。 市場

黑金原創教程FPGA那些事兒-驅動I 實驗PS/2模組③ — 鍵盤與多組合鍵

實驗九:PS/2模組③ — 鍵盤與多組合鍵 筆者曾經說過,通碼除了單位元組以外,也有雙位元組通碼,而且雙位元組通碼都是 8’hE0開頭,別名又是 E0按鍵。常見的的E0按鍵有,<↑>,<↓>,<←>,<→>,<HOME>,<PRTSC>

黑金原創教程FPGA那些事兒-驅動I 實驗二十SDHC模組

實驗二十五:SDHC模組 筆者曾經說過,SD卡發展至今已經衍生許多版本,實驗二十四就是針對版本SDV1.×的SD卡。實驗二十四也說過,CMD24還有CMD17會故意偏移地址29,讓原本範圍指向從原本的232 變成 223,原因是SD卡讀寫一次都有512個位元組。為此我們可以這樣計算: SDV1.x = 2

黑金原創教程FPGA那些事兒-驅動I 實驗二十SDRAM模組③ — 頁讀寫 α

實驗二十:SDRAM模組③ — 頁讀寫 α 完成單字讀寫與多字讀寫以後,接下來我們要實驗頁讀寫。醜話當前,實驗二十的頁讀寫只是實驗性質的東西,其中不存在任何實用價值,筆者希望讀者可以把它當成頁讀寫的熱身運動。 表示20.1 Mode Register的內容。 Mode Register

黑金原創教程FPGA那些事兒-驅動I 實驗二十八TFT模組

實驗二十八:TFT模組 - 觸屏 讀者在上一個實驗所玩弄過的 TFT LCD模組,除了顯示大小為 320 × 240,顏色為16位RGB的影象資訊以外,它還支援觸屏。所謂觸屏就是滑鼠還有鍵盤以外的輸入手段,例如現在流行平板還有智慧手機,觸屏輸入對我們來說,已經成為日常的一部分。描述語言一門偏向硬體的語言

黑金原創教程FPGA那些事兒-驅動I 實驗二十二SDRAM模組⑤ — FIFO讀寫

經過漫長的戰鬥以後,我們終於來到最後。對於普通人而言,頁讀寫就是一名戰士的墓碑(最終戰役) ... 然而,怕死的筆者想透過這個實驗告訴讀者,旅程的終點就是旅程的起點。一直以來,筆者都在煩惱“SDRAM是否應該成為儲存類?”SDRAM作為一介儲存資源(儲存器),它的好處就是大容量空間,壞處則就是麻煩的控制規

黑金原創教程FPGA那些事兒-驅動I 實驗十四儲存模組

實驗十四比起動手筆者更加註重原理,因為實驗十四要討論的東西,不是其它而是低階建模II之一的模組類,即儲存模組。接觸順序語言之際,“儲存”不禁讓人聯想到變數或者陣列,結果它們好比資料的暫存空間。 1. int main() 2. { 3. int VarA; 4.