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