1. 程式人生 > >FPGA模擬擲骰子

FPGA模擬擲骰子

設計效果

       每按同一個按鍵時會隨機得到一個1—6中的一個隨機數字,並用數碼管顯示得到的數值。對兩次按鍵得到的數值進行比較,若前者大,則最低兩位LED顯示為“亮”、“滅”,後者較大,則最後兩位LED顯示狀態改為“滅”、“亮”。

設計方案

       本次課程設計的實質是使數碼管隨機顯示一個數字,以達擲骰子時隨機出數的效果,因此在小組討論並查閱資料後我們總結出以下兩種方案:

1.     查詢FPGA中是否含有類似於C語言中rand()的隨機函式,並搞清楚其用法和效果,弄清楚後進行實驗,並在按下按鍵後使隨機函式發生作用,並顯示該資料,再將資料存入內部變數,並在其內部進行比較,將比較結果對映到LED最後兩位進行顯示。

2.     類似於老虎機一樣,讓數碼管顯示1~6六個數字,並高速滾動,然後通過按鍵暫停並顯示,由於數碼管顯示數字在高速滾動狀態下,人眼無法準確分清楚此時是什麼數字,所以根據概率學來說六個數字每個具有等可能性,這樣就能保證暫停的數字具有隨機性,儲存和比較模組原理與方案1相似。

方案選擇

       由於第一種方案在實施起來時沒有像第二種的老虎機一樣,使人感覺有互動性,並且用函式隨機顯示數字會讓人感覺突兀,並像是在“出千”。因此我們選用第二種方案進行本次課程設計

程式模組原理介紹:

分頻器

由於cyclone IV板載系統時鐘為50MHz,時鐘頻率過大,無法表現出程式效果(或者效果不明顯),所以我們需要分頻。

分頻器原理:以系統時鐘上升沿為標準,對系統時鐘的上升沿計數,並給出一個訊號變數(或普通變數)給出初值,計夠一定次數以後對其變數電平反轉,即通過電平反轉重新造出來一個方波,以達到分頻的目的。例如:對50MHz時鐘二分頻,就是對系統時鐘上升沿計數,當機構2499999個數時對電平變數chz1進行反轉,即可得到一個以0.5ms為週期的方波,則分頻計算公式:

分頻器程式:

       ck:PROCESS(CLK)                            --分頻器程式

       BEGIN

       IFRISING_EDGE(CLK) THEN

              IFT="0000011010111100000111111" THEN—此處數值沒有具體計算

                 T<="0000000000000000000000000";

                            CLK1HZ<=NOTCLK1HZ;

              ELSE

                     T<=T+1;

              ENDIF;

       ENDIF;

END PROCESS CK;

數字掃描模組

結構體中數字掃描:將數字掃描模組寫在結構體中,使FPGA在執行程式時能夠迴圈掃描數字,使數碼管高速滾動數字。達到每個在暫停時,停止的每個數字具有等可能性。

結構體中數字掃描:

OUTPUT<="1111001"WHENINPUT="0001"ELSE—本程式寫在結構體的begin下

              "0100100"WHENINPUT="0010"ELSE

              "0110000"WHENINPUT="0011"ELSE

              "0011001"WHENINPUT="0100"ELSE

              "0010010"WHENINPUT="0101"ELSE

              "0000011"WHENINPUT="0110";

程序中數字掃描:定義中間變數,對其進行1-6的迴圈加一計數,然後再將其送到數碼管顯示。

程序中數字掃描:

IF (CLK1HZ'EVENT AND CLK1HZ='1')THEN

       IF(A='1' AND B='1') THEN

              TMP:=TMP+1;

              IF(TMP=7) THEN

              TMP:=1;

              ENDIF;

          CASE TMP IS

                WHEN 1=> INPUT<="0001";

                WHEN 2=> INPUT<="0010";

                WHEN 3=> INPUT<="0011";

                                    WHEN 4=> INPUT <="0100";

                WHEN 5=> INPUT<="0101";

                WHEN 6=> INPUT<="0110";

                WHEN OTHERS => INPUT<="0000";

          END CASE;

       ENDIF;

END IF;

按鍵暫停模組

本次課程設計我們想用撥碼開關以代替按鍵,本以為撥碼開關不需要按鍵消抖但最終的實驗效果卻不盡如人意,仍需要按鍵消抖,所以本次設計時我們改了一下,利用兩個按鍵對其進行暫停。如果用一個按鍵或撥碼開關,必須要加按鍵消抖,否則會有一定干擾。

消抖原理:類似於51微控制器按鍵消抖,先檢驗其是否按下,若被按下則延時一定時間,將其電平振盪的時間“濾”掉(在FPGA則數5ms的系統時鐘過濾掉電平振盪的時間)。

按鍵暫停以及儲存程式:

       IF(A='0') THEN

       TIM:=TIM+1;

              IF(TIM=1) THEN

                     RAN1<=TMP;

              ELSIF(TIM=2) THEN

                     RAN2<=TMP;

              ENDIF;

       ENDIF;

注意:本模組程式未加按鍵消抖程式,如用單一按鍵需對按鍵加消抖程式。

一個按鍵的暫停草稿程式(加有消抖,但並未實踐)

       IF(A='0') THEN

              IFRISING_EDGE(CLK) THEN

                     IFT="0010011010111100000111111" THEN--此處數值沒有具體計算

                       T<="0000000000000000000000000";

              ELSE

                     T<=T+1;

              ENDIF;

       ENDIF;

       WAITUNTIL(T=”0010011010111100000111111”);

       IF(A=”0”)THEN

       TIM:=TIM+1;

              IF(TIM=1) THEN

                     RAN1<=TMP;

              ELSIF(TIM=2) THEN

                     RAN2<=TMP;

              ENDIF;

       ENDIF;

END IF

比較模組

在程式內部定義兩個變數(由於總開關為閉合狀態所以不用考慮掉電保護問題),用於儲存先後兩次按鍵按下的數字,然後對其變數進行比較若前者較大對映到LED則最後兩個燈顯示為“亮”、“滅”,反之後者大則LED顯示為“滅”、“亮”。

比較模組程式:

compare:PROCESS(RAN1,RAN2)

BEGIN

IF (RAN1>RAN2) THEN

       LED<="01";

ELSIF (RAN1<RAN2) THEN

       LED<="10";

ELSIF (RAN1=RAN2) THEN

       LED<="00";

END IF;

END PROCESS compare;

反思

在本次設計中,我們對兩種方案進行考量,最終選擇較為方便實現的方案,並且具有一定互動性。個人認為該方案的實現效果更好,但唯一的遺憾就是沒有用一個按鍵實現數字暫停。因為在當時的情況下本人事情較多,無法考慮更多的情況,對於消抖的延時沒有想清楚原理,所以沒有大膽的實踐。時間緊任務重只能選擇最優方案。