基於VHDL語言的數字電子鍾設計


這是在2021年10月底完成的一次VHDL課程設計,全程自己設計組裝完成,現作為記錄存檔發布,大家也可以借鑒本文來完成自己的課程設計。(建議使用電腦閱讀,本文有修改)

源碼:digitalClock-VHDL

基於VHDL語言的數字電子鍾設計

【內容摘要】 數字電子鍾是一種用數字顯示秒、分、時的記時裝置,該數字電子鍾的功能和特點有:時鍾源產生1Hz時鍾脈沖,用以提供“秒”的計數;設計兩個六十進制的計數器對“分”、“秒”信號計數,二十四進制計數器對“時”信號計數;通過“時”、“分”校正電路進行時間的校正;通過組合邏輯電路實現報時功能和鬧鈴功能,由蜂鳴器發出提醒。本次課程設計使用Quartus II軟件進行設計,所采用的硬件語言是VHDL

【關鍵詞】電子鍾 計數器 數字電子技術 EDA VHDL

1 課程設計和方案設計

1.1 EDA課程設計的目的與意義

電子技術是一門實踐性很強的課程,加強工程訓練,特別是技能的培養,對於培養工程人員的素質和能力具有十分重要的作用。在電子信息類本科教學中,電子技術課程設計是一個重要的實踐環節,它包括選擇課題、電子電路設計、組裝、調試和編寫總結報告等實踐內容。

通過 EDA 課程設計,要實現以下兩個目標:第一,讓學生初步掌握 EDA 電子線路的試驗、設計方法。即學生根據設計要求和性能參數,查閱文獻資料,收集、分析類似電路的性能,並通過組裝調試等實踐活動,使電路達到性能指標;第二,課程設計為后續的畢業設計打好基礎。畢業設計是系統的工程設計實踐,而課程設計的着眼點是讓學生開始從理論學習的軌道上逐漸引向實際運用,從已學過的定性分析、定量計算的方法,逐步掌握工程設計的步驟和方法,了解科學實驗的程序和實施方法,同時,課程設計報告的書寫,為今后從事技術工作撰寫科技報告和技術資料打下基礎。

1.2 本次課程設計的學習目標

1)掌握電子鍾的設計、組裝與調試方法。

2)熟悉Quartus II軟件的使用方法。

3)提高動手能力,學會將理論知識與實踐相結合,充分發揮個人與團隊協作的能力。

1.3 設計任務與要求

1)時鍾顯示功能,能夠以十進制顯示“時”、“分”、“秒”。

2)具有校准時、分、秒的功能。

3)整點自動報時,在整點時,便自動發出鳴叫。

4)具有鬧鈴功能,可設置鬧鈴時間,到時便發出鳴叫。

2 基本實現思路及系統框圖

2.1 基本實現思路

數字電子鍾的計時功能由三個計數器實現,其中分、秒計時分別為60進制計數,小時計時為24進制計數器,且采用進位級聯方式連接。

數字電子鍾的校時功能由三個按鍵實現,秒校時是按下置零,分校時和時校時是通過長按按鍵以加快時鍾頻率來實現。

數字電子鍾的整點報時功能需要檢測時間是否到達整點,若是,則揚聲器工作,否則,揚聲器不工作。

數字電子鍾的鬧鈴功能需要三個按鍵和另外三個計數器實現,即分、秒計時分別為60進制計數,小時計時為24進制計數器,但並不采用級聯方式連接。三個按鍵連接計數器,設置時間是通過長按按鍵來實現。鬧鈴的檢測實現思路與整點檢測的類似。

數字電子鍾的數碼管需要顯示正常時間或鬧鈴時間,為此可添加一個按鍵用以切換正常界面和鬧鈴界面。按鍵可作為二選一選擇器的位選信號,數碼管通過選擇器來決定顯示哪個時間,同時又不影響時間的計時。

2.2 電路整體控制邏輯

image

圖2-1 數字電子鍾整體邏輯框圖

電路的整體邏輯框圖如上圖所示,這里需要做些說明:

一個具有計時、校時、報時、顯示等基本功能的數字鍾主要由分頻器、計數器、顯示器、校時、報時、鬧鈴等模塊組成。
原始時鍾信號經過分頻器得到秒脈沖,秒脈沖送入計數器計數,計數結果通過“時”、“分”、“秒”譯碼器譯碼,並通過顯示器顯示時間。

按鍵A用來切換界面,可切換正常界面和鬧鈴界面。按鍵B、C、D用來調整時、分、秒,當位於正常界面時是用於校時的,當位於鬧鈴界面時是用於調整鬧鈴的。通過一個組合邏輯模塊,便可以分辨按鍵在不同界面下的不同功能(限於篇幅,該模塊在圖中並未畫出)。因此,這三個按鍵具有復用的功能。

報時模塊接收來自上面三個正常時間計數器的輸出,鬧鈴模塊接收來自下面三個鬧鈴時間計數器的輸出,它們均會持續檢測是否滿足響鈴要求。

3 模塊電路設計和仿真

3.1 分頻器模塊

分頻器的作用是將原始時鍾頻率分為兩種頻率,前者供給正常時鍾的時鍾源,后者供給設置鬧鈴和校時的時鍾源。

3.1.1 代碼實現

實現原理是每隔N個原始時鍾周期,輸出的時鍾信號將翻轉一次,這樣就得到新的時鍾頻率。完整代碼如下:

【代碼3-1 分頻器】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

-- 分頻器

entity diver is
	port(
		clk:	in std_logic;	-- 原始時鍾頻率
		clk0:	out std_logic;	-- 正常計時分頻
		clk1:	out std_logic	-- 設置鬧鈴和校時分頻
	);
end diver;
 
architecture a of diver is
	signal m_clk0: std_logic;
	signal m_clk1: std_logic;
	constant c_cnt_0: integer:= 10;
	constant c_cnt_1: integer:= 50;
begin
	clk0 <= m_clk0;
	clk1 <= m_clk1;
	process(clk)
		variable cnt_0: integer range 0 to c_cnt_0;	
		variable cnt_1: integer range 0 to c_cnt_1; 	
	begin
		if (clk'event and clk = '1') then
			cnt_0:= cnt_0 + 1;
			cnt_1:= cnt_1 + 1;
			if (cnt_0 = c_cnt_0) then
				m_clk0 <= not m_clk0;
				cnt_0:= 0;
			end if;
			if (cnt_1 = c_cnt_1) then
				m_clk1 <= not m_clk1;
				cnt_1:= 0;
			end if;
		end if;
	end process;
end a;

3.1.2 仿真結果

使用軟件自帶仿真結果如下:

image

圖3-1 分頻器模塊的仿真結果

可見,原始時鍾在經過分頻后產生了兩種不同的時鍾頻率信號,說明達到預期效果,仿真成功。不過分頻因子有待后續調試階段作進一步調整。

3.2 計數器模塊

時鍾和鬧鈴的計數器,均由一個24進制計數器和兩個60進制計數器組成。因此,時鍾和鬧鈴計數器放在本節內容一並說明。

3.2.1 代碼實現

計數器為含異步清零和同步使能的加法計數器,輸入端有三個:輸入時鍾信號clk、異步清零端rst、同步使能端en;輸出端為個位和十位的二進制數q0q1,以及進位信號cout

以下是秒/分計數器的完整代碼:

【代碼3-2 秒/分計數器】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

-- 秒計時器

entity count_sec is
	port(
		clk, rst, en: in std_logic;				
		q0, q1: buffer std_logic_vector(3 downto 0); 
		cout: out std_logic
	);
end count_sec;

architecture a of count_sec is
	signal m_clk: std_logic;
	signal num0, num1: std_logic_vector(3 downto 0);
begin
	cout <= '1' when (num0 = "1001" and num1 = "0101" and en = '1') else '0';
	process (rst, clk)
	begin
		m_clk <= clk;
		if (rst = '0') then
			num0 <= "0000";
			num1 <= "0000";
		elsif (m_clk'event and m_clk = '0') then
			if (en = '1') then
				if (num0 = "1001") then
					num0 <= "0000";
					if (num1 = "0101") then
						num1 <= "0000";
					else
						num1 <= num1 + 1;
					end if;
				else
					num0 <= num0 + 1;
				end if;
			end if;
		end if;
	end process;
	q0 <= num0;
	q1 <= num1;
end a;

以下是時計數器的完整代碼:

【代碼3-3 時計數器】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

-- 時計時器

entity count_hour is
	port(
		clk, rst, en: in std_logic;				
		q0, q1: buffer std_logic_vector(3 downto 0); 
		cout: out std_logic
	);
end count_hour;

architecture a of count_hour is
	signal m_clk: std_logic;
	signal num0, num1: std_logic_vector(3 downto 0);
begin
	cout <= '1' when (num0 = "0011" and num1 = "0010" and en = '1') else '0';
	process (rst, clk)
	begin
		m_clk <= clk;
		if (rst = '1') then
			num0 <= "0000";
			num1 <= "0000";
		elsif (m_clk'event and m_clk = '0') then
			if (en = '1') then
				if ((num0 = "0011") and (num1 = "0010")) then
					num0 <= "0000";
					num1 <= "0000";
				elsif (num0 = "1001") then
					num0 <= "0000";
					num1 <= num1 + 1;
				else
					num0 <= num0 + 1;
				end if;
			end if;
		end if;
	end process;
	q0 <= num0;
	q1 <= num1;
end a;

3.2.2 仿真結果

下面是秒計數器和分計數器(60進制計數器)的仿真結果:

image

圖3-2 秒計數器和分計數器的仿真結果

下面是時計數器(24進制計數器)的仿真結果:

image

圖3-3 時計數器的仿真結果

可見,兩者均實現了預期效果,仿真成功。

3.3 校時模塊

校時功能的具體實現是,當長按下調整按鍵時,時鍾頻率(即計數頻率)加快,待時鍾跳轉到想要的時間時,松開按鍵,這樣就完成了一次校時。

校時功能的實現原理十分巧妙,是通過一個二選一選擇器來實現的,位選信號s連接到調整按鍵,兩路信號ab分別是來自低級計數器的進位信號和較快頻率的時鍾信號,而輸出端則連到計數器的進位信號。

這樣,當不按按鍵時,選擇器輸出a信號,此時計數器以正常頻率計數;當按下按鍵時,選擇器輸出b信號,此時計數器以較快頻率計數,以便使用者進行校時。

3.3.1 代碼實現

校時模塊的本質即是二選一選擇器,完整代碼如下:

【代碼3-4 校時模塊】

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

ENTITY mux21a IS
	PORT ( a, b, s: IN  STD_LOGIC;
			y : OUT STD_LOGIC  );
END ENTITY mux21a;

ARCHITECTURE one OF mux21a IS
BEGIN
	PROCESS (a,b,s)
	BEGIN
		IF s = '0'  THEN  y <= a ; ELSE y <= b ;
		END IF;
	END PROCESS;
END ARCHITECTURE one ;

3.3.2 仿真結果

使用軟件自帶仿真結果如下:

image

圖3-4 校時模塊的仿真結果

可見其實現了預期效果,仿真成功。

3.4 報時模塊

報時模塊的具體實現是,當檢測到分達到59,秒達到53、55、57、59時,蜂鳴器各響一次。

3.4.1 代碼實現

輸入端是來自時鍾計數器的分和秒,輸出端連接到蜂鳴器。代碼的實現只需檢測是否符合分達到59,秒達到53、55、57、59的情況,若是,則蜂鳴器信號為高電平,否則為低電平。完整代碼如下:

【代碼3-5 報時模塊】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

entity baoshi is
	port ( min0 ,min1 , sec0, sec1 :in std_logic_vector ( 3 downto 0 );
			speak: out std_logic );
end baoshi;

architecture cml of baoshi is
begin
	speak <= '1'	-- min1=5, min0=9, sec1=5  and  sec0=3, sec0=5, sec0=7, sec0=9
			when (min1="0101" and min0 ="1001" and sec1="0101")and ( sec0="0011" or sec0 ="0101" or sec0 ="0111" or sec0="1001") 
	else '0';
end cml;

3.4.2 仿真結果

使用軟件自帶仿真結果如下:

image

圖3-5 報時模塊的仿真結果

可見其實現了預期效果,仿真成功。

3.5 模式切換模塊(按鍵復用模塊)

之前已經提到,我們所設計的系統中有三個按鍵是用來調整時、分、秒的,由於系統有兩種模式,若每種模式均配備三個按鍵就顯得有些冗余了(這樣就一共需要六個按鍵了)。

為了減少按鍵的個數,我們希望這三個按鍵可以在不同模式下設置正常時間和鬧鈴時間,此所謂“按鍵復用”。而且這樣做還有一個好處是,不必擔心在正常顯示時間的狀態下誤觸了設置鬧鈴的按鍵。為了實現以上功能,需要設計一個邏輯電路用來辨別是調整正常時間還是調整鬧鈴時間。

3.5.1 代碼實現

輸入端是來自模式切換按鍵key和調整時間按鍵的信號s,輸出端有兩個,一個連接到正常時間的部分s1,另一個連接到鬧鈴時間的部分s2。實現思路是:當s為高電平時,s2通過而s1屏蔽,此時按下key則是調整s2;當s為低電平時,s1通過而s2屏蔽,此時按下key則是調整s1。通過邏輯表,可以很容易得出代碼如下:

【代碼3-6 模式切換模塊】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

entity switch is
	port(
		key, s: in std_logic;
		s1, s2: out std_logic
	);
end switch;

architecture a of switch is
begin
	s1 <= key and (not s);
	s2 <= key and s;
end a;

3.5.2 仿真結果

使用軟件自帶仿真結果如下:

image

圖3-6 模式切換模塊的仿真結果

可見其實現了預期效果,仿真成功。

3.6 模式狀態維持模塊

由於我們希望按下切換按鍵時,模式狀態就會切換且維持不變,所以我們使用了T觸發器來對按鍵信號進行處理。當來自按鍵的輸入信號為高電平時,輸出信號q就會翻轉一次信號;當來自按鍵的輸入信號為低電平時,輸出信號q狀態不變。

3.6.1 代碼實現

輸入端有時鍾clk和信號t,輸出端為信號q。當時鍾的上升沿來臨時,若t為高電平,則信號q翻轉一次;否則,信號q維持不變。完整代碼如下:

【代碼3-7 模式狀態維持模塊】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
Use IEEE.STD_LOGIC_ARITH.ALL;
Use IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY trigger IS
	port (t, clk: in std_logic;
			q: out std_logic);
end entity;

architecture bhv of trigger is
	signal temp: std_logic;
begin
	process(clk, t)
	begin
		if clk'event and clk='1' then
			if t='1' then
				temp <= not temp;
			else 
				temp <= temp;
			end if;
		end if;
		q <= temp;
	end process;
end bhv;

3.6.2 仿真結果

使用軟件自帶仿真結果如下:

image

圖3-7 模式狀態維持模塊的仿真結果

可見其實現了預期效果,仿真成功。

3.7 鬧鈴檢測模塊

鬧鈴檢測模塊的具體實現是,當檢測到時、分、秒均達到預設時間時,蜂鳴器響一次。

3.7.1 代碼實現

輸入端分別是來自時鍾的時、分計數器(min/hour)和來自鬧鈴的時、分計數器(amin/ahour),輸出端則連接到蜂鳴器。當檢測到時、分、秒均達到預設時間時,蜂鳴器響一次。完整代碼如下:

【代碼3-8 鬧鈴檢測模塊】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

entity alarm is
	port(
		--sec0, sec1: in std_logic_vector(3 downto 0); 
		min0, min1: in std_logic_vector(3 downto 0); 
		hour0, hour1: in std_logic_vector(3 downto 0); 
		--asec0, asec1: in std_logic_vector(3 downto 0); 
		amin0, amin1: in std_logic_vector(3 downto 0); 
		ahour0, ahour1: in std_logic_vector(3 downto 0); 
		speak: out std_logic
	);
end alarm;

architecture a of alarm is
begin
	speak <= '1' when(min0=amin0 and min1=amin1 
						and hour0=ahour0 and hour1=ahour1)
		else '0';
end a;

3.7.2 仿真結果

假設鬧鈴設置為23:57:00,現實時間從23:57:00過渡到23:58:00,使用軟件自帶仿真結果如下:

image

圖3-8 鬧鈴檢測模塊的仿真結果

可見,當現實時間到了23:57:00時,speak為高電平,此時蜂鳴器工作;當現實時間到了23:58:00時,speak為低電平,此時蜂鳴器不工作,說明實現了預期效果,仿真成功。

3.8 數碼管顯示切換模塊

該模塊的作用是,通過二選一選擇器,數碼管可以切換顯示正常時間和鬧鈴時間。

3.8.1 代碼實現

這是一個二選一選擇器,輸入信號有三個,位選信號來自切換模式按鍵,其余兩個為a和b,分別來自正常計數器和鬧鈴計數器的輸出q0和q1。完整代碼如下:

【代碼3-9 數碼管顯示切換模塊】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

ENTITY mmux21a IS
	PORT ( a, b: in std_LOGIC_vector (3 downto 0);
			s: IN  STD_LOGIC;
			y : OUT std_LOGIC_vector (3 downto 0)  
		);
END ENTITY mmux21a;

ARCHITECTURE one OF mmux21a IS
BEGIN
	PROCESS (a,b,s)
	BEGIN
		IF s = '0'  THEN  y <= a ; ELSE y <= b ;
		END IF;
	END PROCESS;
END ARCHITECTURE one ;

3.8.2 仿真結果

使用軟件自帶仿真結果如下:

image

圖3-9 數碼管顯示切換模塊的仿真結果

可見其實現了預期效果,仿真成功。

4 頂層電路設計、仿真和調試

4.1 頂層電路設計

在各個模塊都設計完成、仿真通過、達到預期效果以后,在頂層文件將模塊實例化,接着以一定的方式連接起來。如下代碼定義了整個系統的輸入和輸出的端口:

【代碼4-1 頂層電路輸入輸出端口定義】
entity clock_top_1 is
	port(
		clk: in std_LOGIC;  --時鍾源
		key_sec, key_min, key_hour: in std_LOGIC;  --校時設置/鬧鈴設置按鍵
		sec0, sec1: buffer std_logic_vector(3 downto 0); --顯示時
		min0, min1: buffer std_logic_vector(3 downto 0); --顯示分
		hour0, hour1: buffer std_logic_vector(3 downto 0); --顯示秒
		key_shift: in std_LOGIC; --切換功能
		speak: out std_LOGIC --整點響鈴/鬧鈴響鈴
	);
end clock_top_1;

4.1.1 時鍾源部分

創建兩個信號,分別提供正常時鍾頻率(normal_clk)和較快時鍾頻率(fast_clk,用於校時和設置鬧鈴)。摘錄代碼如下:

【代碼4-2 分頻器實例化】
signal normal_clk, fast_clk : std_LOGIC;

--------分頻---------
U1: diver port map (clk=>clk, clk0=>normal_clk, clk1=>fast_clk);

4.1.2 正常時間計數部分

定義信號,用於數碼管的顯示信號(sec0_n, sec1_n, min0_n, min1_n, hour0_n, hour1_n)(但並不是真的顯示,因為還要通過模式切換模塊來判斷顯示哪個界面);定義兩個進位信號(min_clk, hour_clk),用於提供下一級計數器的時鍾;三個計數器采取級聯方式,進位信號作為下一級計數器的時鍾源。

注意,除了秒計數器的rst端外,其他計數器都接入了低電平(復位端為高電平有效),這是因為秒計數器的校時方式只有復位方式。摘錄代碼如下:

【代碼4-3 正常時間計數部分實例化】
signal min_clk, hour_clk : std_LOGIC;
signal sec0_n, sec1_n, min0_n, min1_n, hour0_n, hour1_n: std_logic_vector(3 downto 0);

--------正常時間計數器---------
U2: count_sec port map (clk=>normal_clk, rst=>key_sec_n, en=>'1', q0=>sec0_n, q1=>sec1_n, cout=>sec_cout);
U3: count_min port map (clk=>min_clk, rst=>'0', en=>'1', q0=>min0_n, q1=>min1_n, cout=>min_cout);
U4: count_hour port map (clk=>hour_clk, rst=>'0', en=>'1', q0=>hour0_n, q1=>hour1_n);

4.1.3 校時部分

位選信號s連接到調整按鍵(key_min_nkey_hour_n),兩路信號a和b分別是來自低級計數器的進位信號(sec_coutmin_cout)和較快頻率的時鍾信號(fast_clk),而輸出端則連到計數器的進位信號(min_clkhour_clk)。摘錄代碼如下:

【代碼4-4 校時部分實例化】
signal key_sec_n, key_min_n, key_hour_n: std_LOGIC;

--------校時---------
U5: mux21a port map (a=>sec_cout, b=>fast_clk, s=>key_min_n, y=>min_clk);
U6: mux21a port map (a=>min_cout, b=>fast_clk, s=>key_hour_n, y=>hour_clk);

4.1.4 鬧鈴設置部分

定義了三個按鍵信號(key_sec_a, key_min_a, key_hour_a),用於設置鬧鈴時間;定義了用於數碼管的顯示信號(min0_a, min1_a, hour0_a, hour1_a)。

該部分與正常時間計數部分的接法類似,所不同的是,三個計數器的rst端均為低電平,且en端均接了按鍵信號,在高電平狀態下就會計數。摘錄代碼如下:

【代碼4-5 鬧鈴設置部分實例化】
signal sec0_a, sec1_a, min0_a, min1_a, hour0_a, hour1_a: std_logic_vector(3 downto 0);
signal key_sec_a, key_min_a, key_hour_a: std_LOGIC;

--------鬧鍾計數器---------
U17: count_sec port map (clk=>fast_clk, rst=>'0', en=>key_sec_a, q0=>sec0_a, q1=>sec1_a);
U18: count_min port map (clk=>fast_clk, rst=>'0', en=>key_min_a, q0=>min0_a, q1=>min1_a);
U19: count_hour port map (clk=>fast_clk, rst=>'0', en=>key_hour_a, q0=>hour0_a, q1=>hour1_a);

4.1.5 模式切換部分

T觸發器是對模式狀態起保持作用,其實例化如下:

【代碼4-6 T觸發器實例化】
signal key_shift1: std_LOGIC;

--------模式狀態保持--------
U21: trigger port map (clk=>clk, t=>key_shift, q=>key_shift1);

輸入端是模式切換按鍵key(key_shift1)和調整時間按鍵的信號s(key_sec, key_min, key_hour),輸出端有兩個,一個連接到正常時間的部分s1(key_sec_n, key_min_n, key_hour_n),另一個連接到鬧鈴時間的部分s2(key_sec_a, key_min_a, key_hour_a)。摘錄代碼如下:

【代碼4-7 模式切換部分實例化】
--------模式切換(三按鍵復用)---------
U8: switch port map (key=>key_sec, s=>key_shift1, s1=>key_sec_n,s2=>key_sec_a);
U9: switch port map (key=>key_min, s=>key_shift1, s1=>key_min_n,s2=>key_min_a);
U10: switch port map (key=>key_hour, s=>key_shift1, s1=>key_hour_n, s2=>key_hour_a);

4.1.6 數碼管顯示切換部分

該部分對鬧鈴和正常時間部分的時、分、秒輸出進行分辨后,選擇顯示兩者之一的輸出。摘錄代碼如下:

【代碼4-8 數碼管顯示切換部分實例化】
--------數碼管顯示切換(二選一)---------
U11: mmux21a port map (s=>key_shift1, a=>sec0_n, b=>sec0_a, y=>sec0);
U12: mmux21a port map (s=>key_shift1, a=>sec1_n, b=>sec1_a, y=>sec1);
U13: mmux21a port map (s=>key_shift1, a=>min0_n, b=>min0_a, y=>min0);
U14: mmux21a port map (s=>key_shift1, a=>min1_n, b=>min1_a, y=>min1);
U15: mmux21a port map (s=>key_shift1, a=>hour0_n, b=>hour0_a, y=>hour0);
U16: mmux21a port map (s=>key_shift1, a=>hour1_n, b=>hour1_a, y=>hour1);

4.1.7 整點檢測和鬧鈴檢測部分

由於蜂鳴器的輸入來源有兩個,一是來自整點報時,二是來自鬧鈴,因此為解決兩者沖突的矛盾,引入了或門。摘錄代碼如下:

【代碼4-9 揚聲器選擇代碼】
signal speak_a, speak_zd: std_LOGIC; --鬧鈴(a)/整點(zd)

--------揚聲器--------
speak <= speak_a or speak_zd;

整點檢測和鬧鈴檢測的實例化代碼如下:

【代碼4-10 整點檢測和鬧鈴檢測的實例化】
--------整點檢測---------
U7: baoshi port map (min0=>min0, min1=>min1, sec0=>sec0, sec1=>sec1, speak=>speak_zd);
--------鬧鈴檢測---------
U20: alarm port map (min0=>min0_n, min1=>min1_n, hour0=>hour0_n, hour1=>hour1_n,
	amin0=>min0_a, amin1=>min1_a, ahour0=>hour0_a, ahour1=>hour1_a,
	speak=>speak_a );

至此,已完成所有模塊的實例化和連接。

4.2 頂層電路仿真

使用軟件仿真結果如下:

image

圖4-1 頂層電路的仿真結果

從左到右:

(1)在圖中的第一部分測試的是校時模塊。在正常時間界面顯示時,按下時校時按鍵和分校時按鍵時,分、時的計數頻率加快了。松開按鍵后計數器正常計數。同時,剛開始時由於是整點,所以speak為高電平。

(2)在圖中的第二部分測試的是鬧鈴模塊。按下切換按鍵(key_shift)然后松開,數碼管會切換顯示鬧鈴的時間,按下時校時按鍵和分校時按鍵時,分、時計數器開始計數。松開校時按鍵,計數器停止計數。

(3)在圖中的第三部分,再次按下切換按鍵,發現數碼管又切換為正常時間,而且之前調鬧鈴的時候沒有影響到正常時間的計數。

(4)在圖中的最后一部分,再次按下切換按鍵進入鬧鈴模式,發現數碼管顯示的是之前已調好的鬧鈴時間。

總體來看,仿真結果基本符合預期。

4.3 頂層電路調試

4.3.1 管腳分配

引腳鎖定如下圖:

image

圖4-2 引腳分配圖

4.3.2 調試結果

將程序下載、進行硬件測試,下圖是調試過程中的實驗現象:

image

圖4-3 硬件調試過程中的照片

通過一系列的測試,能正常計時、調整時間、報時響鈴、以及鬧鈴響鈴,實驗現象基本符合預期。

5 總結

5.1 缺陷與不足

這次的課設存在以下幾個缺陷與不足:

(1)秒表功能未實現,數字鍾的功能未完善;

(2)調整時間的設計方法還不太好,我們的方案是按下按鍵,計數頻率就會加快,而后來經過老師提醒,其實還可以將按鍵直接接在下一級的計數器上,這樣按下一次按鍵就能調整時間,顯然這個方案更加簡潔;

(3)鬧鈴的響聲到點只有一次,且聲音很小。

而且我們沒想到的是(或者說沒有注意到),實驗室板子的按鍵原本就有狀態保持的功能,而我們卻為了實現這個功能,多此一舉地專門設計了一個模塊,反而影響了最后的實驗效果。可惜礙於時間關系就無法使其臻於完美了。總之,雖然主要功能實現了,但這次課設設計我們還不是特別滿意。

5.2 心得體會

通過此次數字模擬電路課程設計,從最開始的選題,到最后的仿真結束,我們更深刻地掌握了數字鍾設計的原理與過程。盡管課題所給出的各個題目相對簡單,但一開始難免有些無從下手,畢竟課程設計不同於實驗課,代碼與邏輯圖都需要我們自己思考並動手設計實踐的。平常我們所學的基礎課程與實驗,都在此次實踐當中將理論與實踐相結合,它不但能鞏固我們已經所學的理論知識,而且能提高我們的電子電路的設計水平,還能加強我們綜合分析問題與解決問題的能力,進一步培養我們的實驗技能和動手能力,啟發我們的創新意識和創新思維。

我們在着手設計時,着重邏輯,將整個系統根據不同功能化分為多個模塊,之后逐個攻破,最后再將其整合,這也是從此次課設所學習到的一種重要方法。所以之后靜下心來,通過查找課本與課外資料,再加上指導老師所給的提示內容,我們仔細分析題目並思考后,大家互相協助,各抒己見,很快地就完成了課題。

經過這幾周的 VHDL 課設,我們最終做出了數字鍾電路,雖然過程比較艱辛,但這其中的興奮自然是無法用言語表達的。在整個電路設計的過程中,我逐漸加強了對數字電路和 EDA 設計的了解和運用能力,對課本知識以及以前學過的知識有了一個更好的總結與理解。通過這次設計,我深刻體會到理論與實踐的區別,了解了理論知識和實踐相結合的重要意義,只有當我們親自動手,將理論付之於實現,才能夠將理論知識內化成自己的一部分。在這個過程中,我的動手能力和理論知識的掌握程度有了很大的提高,這將為自己今后的學習和工作打好了堅實的基礎。最后,感謝同學和老師的點撥和幫助!

附錄

模塊清單

模塊名稱 功能 個數
diver 分頻器 1
count_hour 時計數器 2
count_min 分計數器 2
count_hour 時計數器 2
mux21a 二選一選擇器(校時模塊用) 2
mmux21a 二選一選擇器(數碼管顯示用) 6
baoshi 整點檢測 1
alarm 鬧鈴檢測 1
switch 模式切換 3
trigger T觸發器 1

模塊總數:21

參考文獻

[1] 閻石主編.數字電子技術基礎[M].6版.北京:高等教育出版社,2016.

[2] 閻石,王紅編.數字電子技術基礎學習輔導與習題解答[M].6版.北京:高等教育出版社,2016.

[3] 潘松,黃繼業編.EDA技術實用教程:VHDL版[M].6版.北京:科學出版社,2018.

[4] 江國強編.現代數字電路與系統設計:VHDL版[M]. 6版.北京:電子工業出版社,2018.

[5] 劉炳海編.從零開始學電子電路設計[M].北京:化學工業出版社,2019.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM