戳這裡下載下傳整個項目包(已上傳到CSDN資源庫)
一、實驗裝置
FPGA開發平台、計算機、其它外接器件
二、需求分析(選題的意義、功能要求等。。。這裡有點水,小夥伴們可以選擇性跳過)
選題的意義:個人認為本項目(《數字時鐘》)的選題意義有二,其一,時鐘和鬧鐘早已是老生常談的日常工具,利用課堂上所學習的知識貫通運用到現實生活中,作為操作實踐,具有一定的現實意義;其二,數字時鐘的功能設計囊括了數位管、LCD屏、開關運用、管教配置設定等知識,能夠對本學期所學的實驗知識做一個挽接,在知識的總結上也具備一定意義;
功能要求:
1.用數位管顯示時、分、秒:分為兩個界面,即時鐘界面以及鬧鐘設定界面,顯示時鐘的時分秒以及鬧鐘的時分秒,可以通過開關切換顯示,是項目的基本功能;
2.能按比例縮短時間調試:調控時鐘或鬧鐘的頻跳速度,友善示範和調試;
3.鬧鐘功能:使用者可以通過sw8切換進入鬧鐘界面,再利用sw1-3設定具體的鬧鐘時間,到點即響,同樣是項目的基本功能;
4.用LCD屏顯示日期(年月日)以及祝福語:作為時鐘,顯示年月日的功能個人覺得也是有必要的,另外關于祝福語,我們對實驗和知識的學習其實本身就是快樂的過程,生活也沒有必要每天都過得毫無色彩、千篇一律,是以懷揣着這份情懷呢,我在本項目中加了一個顯示祝福語的功能,意在表達自己的這份對科學和生活的熱愛以及學習的熱情。
三、系統架構介紹(系統結構圖,各子產品的功能及端口介紹,等)
系統結構圖如下所示:

系統結構圖
各子產品的功能及端口介紹:
(這裡的子產品功能和端口做簡要的介紹,詳細的用法請移步至《設計思路》部分)
1.Digital_CLK_Top(clk_50M, Reset_n, seg7,ledcom,key,beep,
LCD_ON1,LCD_BLON1,LCD_RS1,LCD_RW1,LCD_EN1,LCD_DATA1);
功能:頂層子產品,調用其他子子產品,統籌整個系統的功能;
端口:
clk_50M, //系統時鐘輸入
Reset_n, //系統複位輸入
seg7, //數位管顯示輸出位
ledcom, //數位管位置調控輸出位
key, //開關輸入号位,主要使用于CLKcounter_60BCD
beep, //蜂鳴器輸出信号
LCD_ON1, //LCD供電電源開關
LCD_BLON1, //LCD背景電源開關
LCD_RS1, //寄存器選擇信号
LCD_RW1, //液晶讀寫信号
LCD_EN1, //液晶時鐘信号
LCD_DATA1, //LCD的資料端口
2.lcd_ori(LCD_ON,LCD_BLON,LCD_RS,LCD_RW,LCD_EN,LCD_DATA,CLK);
功能:LCD屏顯示控制子產品,用于控制LCD屏顯示年月日以及祝福語;
LCD_ON, //LCD供電電源開關
LCD_BLON, //LCD背景電源開關
LCD_RS, //寄存器選擇信号
LCD_RW, //液晶讀寫信号
LCD_EN, //液晶時鐘信号
LCD_DATA, //LCD的資料端口
CLK, //子產品時鐘輸入(項目中輸入的是clk_50M)
3.seg_display(clk,rst_n,mimute_cnt,second_cnt,hour_cnt,ledcom,seg7);
功能:基于視覺暫留知識,控制時鐘界面數位管的顯示;
clk, //子產品時鐘輸入
rst_n, //複位信号輸入
mimute_cnt, //分鐘位資料輸入
second_cnt, //秒位資料輸入
hour_cnt, //時位資料輸入
4.counter_60BCD(clk, rst, couter_o,flag);
功能:在頂層子產品調用,根據輸入的時鐘和時|分|秒位資料進行對應的加一計算和進位計算,并在溢出(分秒59加一溢出,時23加一溢出)時傳回一個flag供頂層子產品使用;
rst, //複位信号輸入
couter_o, //數字時鐘部分的時|分|秒位資料輸出
flag, //輸出一個溢出進位标志
5.clk_gen(clk_in,rst,clk_out); //clk_in=50MHz
功能:對輸入的50MHz的系統時鐘分頻,調用時根據CLK_DIV變量的複用情況進行運算并傳回對應的時鐘分頻結果;
clk_in, //子產品時鐘輸入,在頂層子產品
clk_out, //時鐘分頻結果輸出
6.CLKseg_display(clk,rst_n,mimute_cnt,second_cnt,
hour_cnt,CLKmimute_cnt,CLKsecond_cnt,CLKhour_cnt,ledcom,seg7,sw8);
功能:基于視覺暫留知識,控制鬧鐘設定界面數位管的顯示,并基于sw8的狀态控制切換數位管屏顯示;
mimute_cnt, //分鐘位資料輸入(時鐘)
second_cnt, //秒位資料輸入(時鐘)
hour_cnt, //時位資料輸入(時鐘)
CLKmimute_cnt,//分鐘位資料輸入(鬧鐘設定)
CLKsecond_cnt,//秒位資料輸入(鬧鐘設定)
CLKhour_cnt, //時位資料輸入(鬧鐘設定)
sw8 //開關8的輸入信号
7.CLKcounter_60BCD(clk, rst, couter_o,flag,sw);
功能:在頂層子產品調用,根據輸入的時鐘頻率clk和時|分|秒位資料進行對應的加一計算和進位計算,并在溢出(分秒59加一溢出,時23加一溢出)時傳回一個flag供頂層子產品使用;
couter_o, //數字鬧鐘設定部分的時|分|秒位資料輸出
sw //開關輸入位,作為key的接收變量
四、設計思路(每個子產品的設計思路,文字結合示意圖等進行介紹)
LCD_ON1,LCD_BLON1,LCD_RS1,LCD_RW1,LCD_EN1,LCD_DATA1);
思路:
A.複用兩次分頻子產品clk_gen,産生兩個速度不一樣的時鐘頻——clk_second和clk_second2,分别用來驅動數字時鐘和數字鬧鐘設定;
B.複用三次時鐘控制子產品counter_60BCD:
第一次,用clk_second作為時鐘頻輸入,傳入second_cnt給couter_o作為秒位資料承載,MODULEofCNT設定為60,子產品每溢出一次(即每計數到60個秒),産生一個flag,即flag_min;
第二次,用flag_min作為時鐘頻輸入,傳入minute_cnt給couter_o作為秒位資料承載,MODULEofCNT設定為60,子產品每溢出一次(即每計數到60個分),産生一個flag,即flag_hour;
第三次,用flag_hour作為時鐘頻輸入,傳入hour_cnt給couter_o作為秒位資料承載,MODULEofCNT設定為24,子產品每計數到24個時溢出一次;
C.複用三次鬧鐘控制子產品CLKcounter_60BCD:
第一次,用clk_second2作為時鐘頻輸入,傳入CLKsecond_cnt給couter_o作為秒位資料承載,MODULEofCNT設定為60,sw位傳入key[2]信号,即sw3的狀态信号;
第二次,用clk_second2作為時鐘頻輸入,傳入CLKminute_cnt給couter_o作為秒位資料承載,MODULEofCNT設定為60,sw位傳入key[1]信号,即sw2的狀态信号;
第三次, 用clk_second2作為時鐘頻輸入,傳入CLKhour_cnt給couter_o作為秒位資料承載,MODULEofCNT設定為24,sw位傳入key[0]信号,即sw1的狀态信号;
D.複用LCD屏控制顯示子產品lcd_ori,根據本函數定義的變量複用對應的參數;
E.複用鬧鐘數位管控制顯示子產品CLKseg_display,根據本函數定義的變量複用對應的參數;
F.接下來,編寫了一個狀态機,主要設定并使用了state0、state1、state2等三個狀态;
state0狀态:使用if判斷語句
if(second_cnt==CLKsecond_cnt&&minute_cnt==CLKminute_cnt&&hour_cnt==CLKhour_cnt)
等一個在鬧鐘界面子產品設定的時分秒數列,等到這個數列的時候轉跳到state1或state2,并設定好蜂鳴器鳴響的延時時間到變量cnt_2;
state1、state2:在計數變量cnt_2歸零之前,一直給蜂鳴器管腳輸出高電平,直到計數變量cnt_2歸零,輸出為低電平,停止蜂鳴器鳴響;
A.将年月日以及祝福語分别編寫成字元串,再分别付給變量lcd_buf_first、data_first和lcd_buf_second、data_second;
B.準備好狀态參數常量——
clear_lcd、
set_disp_mode、
disp_on、
shift_down、
write_data_first、
write_data_second;
基于狀态機思想,并用current_state變量承載狀态常量;
C.初始化LCD子產品;
D.clear_lcd狀态, 清屏并光标複位 ;
set_disp_mode: 設定顯示模式:8位2行5x8點陣;
disp_on: 顯示器開、光标不顯示、光标不允許閃爍 ;
shift_down: 文字不動,光标自動右移;data_first指派給lcd_buf_first;
write_data_first、write_data_second: 用于寫入資料
default: 若current_state為其他值,則将current_state置為clear_lcd;
A.複用分頻子產品clk_gen分頻出一個時鐘clk_div,周期約為0.1s;
B.設定一個8位的變量cnt,基于clk_div進行遞加一,并在0到滿位溢出之間循環(滿位溢出時将之歸零,再繼續加一處理);
C.基于快速遞加一的變量cnt,在每個clk時鐘上升沿來的是時候,取其低三位(八個數位管格位,剛好三位二進制數可以完整表示)進行case處理,
每個case的子狀态中,根據cnt低三位的值,把對應的表示數位管位置的二進制數指派給ledcom,用于選擇數位管格位;再把對應的資料(如秒位資料的低四位second_cnt[3:0],高四位second_cnt[7:4]等)傳給dis變量; dis的用法是在下一個always子產品裡面,case判斷dis的值,根據dis的值把對應的二進制數傳給seg7變量,用于基于ledcom選擇數位管格位之後,顯示格位裡面的内容;
由此,基于快速跳變的clk時鐘和clk_div時鐘,ledcom的值也不斷地快速變換,由此數位管的每個格位都在被快速地選擇和顯示,于是這樣便是通過了視覺暫留效應,實作了數位管時鐘的顯示;
A.将MODULEofCNT(分别通過/10和%10運算)切成5/2和9/3兩個數,并分别付給變量a和b;
B.通過a和b判斷是對分秒位資料(MODULEofCNT為60)還是對時位資料(MODULEofCNT為24)進行計算;
若是分秒位資料:先對couter_o[7:4]進行判斷,若小于5,則對couter_o[3:0]判斷,若couter_o[3:0]小于9,則couter_o[3:0]資料加一,若couter_o[3:0]不小于于9,則couter_o[3:0]歸零處理,couter_o[7:4]加一;若couter_o[7:4]不小于5,則對couter_o[3:0]判斷,若couter_o[3:0]小于a(9),則couter_o[3:0]資料加一,若couter_o[3:0]不小于于a(9),則couter_o八個位都歸零,并傳回一個溢出進位flag(flag<=1);
若是時位資料:邏輯同上,隻将b替換為2,将a替換為3進行處理即可;
思路:簡單地基于系統時鐘clk_in以及可複用的參數CLK_DIV實作分頻的功能;
B.(基于sw8的狀态控制切換數位管屏顯示)If語句判斷sw8時候為高電平,如果是,則将CLKsecond_cnt、CLKmimute_cnt、CLKhour_cnt系列資料付給dis變量,如果不是則将second_cnt系統資料付給dis變量;細節處如cnt、ledcom、dis、case(cnt[2:0])等用法則跟seg_display子產品的設計思路相同;
思路:同counter_60BCD子產品的設計思路;
五、實驗結果
1.開機狀态,初始為數字時鐘界面,下圖為數位管上規則地顯示閃動的時鐘,通過分頻子產品的參數調改可以改變其速度;
LCD屏上顯示具體的日期(年月日)以及祝福語(Wish you happy/happiness——祝你幸福),開關狀态為全數低電平:
2.上推sw8,令之輸出為高電平,數位管即切換到鬧鐘設定界面:
3.上推sw1,令之輸出為高電平,數位管鬧鐘界面上“時”數位持續加一(圖中已加到06):
4.上推sw2,令之輸出為高電平,數位管鬧鐘界面上“分”數位持續加一(圖中已加到04):
5.上推sw3,令之輸出為高電平,數位管鬧鐘界面上“秒”數位持續加一(圖中已加到05):
6.數位管停留在設定鬧鐘界面的時候,數字時鐘一直也在背景跑動,當我們設定完鬧鐘,将開關全數歸為低電平時,數位管界面回切到數字時鐘界面,數字時鐘上的時間到達鬧鐘設計的點時,會啟動蜂鳴器,産生一個時長為三秒(可以在程式中設定時長)的鳴響作為鬧鐘。
六、實驗項目代碼清單
1.Digital_CLK_Top.v
頂層檔案,用于調用諸多要使用的子產品;
2.Tcl_2c35_script1.tcl
管教配置設定的腳本檔案,描述管教的配置設定;
3.lcd_ori.v
LCD屏子產品,實作LCD屏顯示年月日以及祝福語的功能;
4.seg_ex.v
5.seg_display.v
時鐘子產品的數位管顯示的相關子產品檔案;
6.counter_60BCD.v
關于實作時鐘界面顯示的背景數字計算(相關變量的加一和進位操作等)的檔案;
7.clk_gen.v
時鐘分頻子產品,用于實作各種參數頻率的分頻;
8.CLKseg_display.v
鬧鐘子產品的數位管管顯示的相關子產品檔案;
9.CLKcounter_60BCD.v
關于實作鬧鐘界面顯示的背景數字計算(相關變量的加一和進位操作等)的檔案。