設計要求
1:能實作0到59秒的自動周而複始計時
2:通過鍵盤能暫停計時
3:通過鍵盤能倒計時59到0
4: 通過鍵盤能複位計時從0開始
5: 計時結果通過兩位七段碼顯示
可選拓展設計
1:實作小時、分鐘、秒的全部顯示
2:能設定初始時間
3:整點報時
4:自行設計其他功能,如閃爍顯示等
五、實驗步驟與實驗結果
1、編寫一個程式,實作實驗的要求,我們實作的功能如下,可以重置,可以計數(從0開始),可以倒計時(59到0),計時結束蜂鳴器會響,可以當電子表使用,用6個數位位顯示,區分小時,分鐘和秒數,可以通過按鍵進行調時間。實作的結果見附件一。
16代表的是小時
.用來分割時分秒
25代表的是分
32代表的是秒
可以根據圖2-2給出的變量清單實作不同的操作
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicWZwpmLhFWYiJWYhNDNiFjNzcTZ4MGN3QTM4kjZlRWNzITOzgzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpeg)
圖1 測試1運作結果圖
2、實驗準備。變量聲明和引腳聲明,我将此系統定義為mysystem,定義了8個輸入變量,3個輸出變量,端口和變量聲明清單見圖2-1變量清單,mysystem的原理圖見圖2-2。
端口 | 引腳 | 作用 |
clkin | 16 | 20mhz時鐘的輸入 |
rst_n | 51 | 置0 |
zt | 52 | 暫停計數和計時工作,此時可以調時間 |
jishu | 52 | 計數開始 |
jishi | 53 | 倒計時開始 |
thour | 48 | 調小時0-23 |
tmin | 49 | 調分鐘0-59 |
tsecond | 50 | 調秒0-59 |
fm | 79 | 蜂鳴器,倒計時結束會響 |
dig_sel_n | 111-114,129-132 | 控制數位位,隻用1到6,7-8長暗,1和2代表秒,3和4代表分鐘,5和6代表小時,中間有“.”來區分小時,分鐘和秒數 |
seg_out | 125-128,119-122 | 控制7段碼 |
圖2-1 變量清單
圖2-2 mysystem的原理圖
3、總體的實作過程。我們通過分塊解決的方案,逐漸實作所有功能,先實作的計數再實作的倒計時,再實作的計數結束後蜂鳴器響,再實作的計數器可以最大顯示24小時再實作可以調時間,最後實作用“.“區分秒數分鐘和小時。圖3-1mysystem總體實作思路
圖3-1 mysystem總體實作思路
4、分頻器的實作。用到的需要分頻成1s和1ms的兩個分頻器,前者給計數器使用,後者給7段碼顯示用,7段碼顯示的原理就是通過人眼的視覺停留快速重新整理達到不動的效果。子產品實作圖4-1
圖4-1 兩個分頻器的實作
5、計數器子產品的實作。計數器内部分為計數和倒計時,實作的思路見圖5-1。實作的時候會通過jishu和jishi這兩個引腳的情況進行選擇是倒計時還是計數,倒計時的時候數從59記到0的時候蜂鳴器會響。對于内部計數的時候要注意,計數的時候需要注意秒-分-小時之間的換算,當夠60秒時分鐘會進1,分鐘夠60的時候會進一,小時夠24會清零,調時間的時候會搭配其餘三個小子產品進行工作。
圖5-1 mysystem的原理圖
6、段碼顯示子產品。7段碼譯碼器子產品和輸出子產品并用,實作的思路見圖6-1。
圖6-1 7段碼子產品
六、實驗讨論與總結
1.做數字系統設計的時候一定要注意系統和原理圖設計的不同,本次實驗是純verilog代碼,需要有完整的思路,學會的是自頂向下的設計思路,先從一個簡單的小子產品開始設計,逐漸的增加功能
2.代碼中的最需要注意的問題一定要設定好變量的寬度,盡量可以大一點但堅決不能小了,完美起見還是用多大設定多大,設計小了錯誤還不容易找錯誤
3.命名要符合代碼的規範,要聲明好輸入的變量和輸出的變量的,要設定好位數,位數比對也是需要注意的
4.分頻器子產品的設定,1s的和1ms的異曲同工,差別在于分出來大小的不同
5.調時間的輸入端口要連接配接在47-50這幾個消抖的按鈕上,不然調時間輸入的時候會一下跳好幾個數
6.計數器的設計是本實驗的重點。在計數器設計上要明确設計的思路,倒計時和計數功能分開實作的同時要注意兩者的共性
7.段碼顯示也是一個重點,需要用到譯碼器,附件一的代碼通過設定一個譯碼器功能的函數,将資料的個位和十位分離進行調用處理,我還對段碼顯示的小點點進行了處理,也就是對小時分鐘秒數進行了分割,便于觀看
8.實驗的優缺點:實驗要求的基本功能全部實驗,擴充功能也基本實作。後期會對寫的Verilog程式進一步優化設計,進一步添加需要的功能,比如說在一個按鍵重複使用,我本次實驗用到的端口比較多,解決這個問題會進一步節省端口。
附件一:程式源代碼
1、mysystem程式清單如下:
//定義了一個子產品系統,20mhz時鐘脈沖,重置,暫停,蜂鳴器,計數(0-59),計時(倒計時),調時間,7段碼,數位位
module mysystem (clkin,rst_n,zt,fm,jishu,jishi,thour,tmin,tsecond,seg_out,dig_sel_n);
//輸入端口
input clkin,rst_n,zt,jishu,jishi,thour,tmin,tsecond;
//1ms的分頻器
reg clk1ms;
//計數用
reg [17:0] cnt2;
//1ms----20MHZ入1000HZ輸出
always @(posedge clkin or negedge rst_n)
begin
//如果重置的話
if(!rst_n)
cnt2 <=0;
//如果不重置的話
else
begin
if(cnt2 == 19_999)
cnt2 <=0;
else
cnt2 <= cnt2 + 1;
if (cnt2 <10_000)
clk1ms <= 1'b1;
else
clk1ms <= 1'b0;
end
end
//分頻得到1s的輸出,七段碼更替會用到
reg clk1S;
reg [24:0]cnt1;
//1s----20MHZ入1HZ輸出
always @(posedge clkin or negedge rst_n)
begin
if(!rst_n)
cnt1 <= 0;
else
begin
if(cnt1 == 19_999_999)
cnt1 <=0;
else
cnt1 <= cnt1 + 1;
if (cnt1 <10_000_000)
clk1S <= 1'b1;
else
clk1S <= 1'b0;
end
end
//6進制選擇器,實作六個數位位的交替
reg [2:0]cnt22;
always @(posedge clk1ms)
begin
if(!rst_n)
cnt22 <= 0;
else
begin
if(cnt22 == 5)
cnt22 <=0;
else
cnt22 <= cnt22 + 1;
end
end
//時間調節
reg [5:0] cnt60_s;
reg [5:0] co1;
reg [4:0] myhour1;
always @(posedge thour or negedge rst_n)
begin
if(!rst_n)
myhour1<=0;
else if(thour)
begin
if(myhour1==23)
myhour1<=0;
else
myhour1<=myhour1+1;
end
end
always @( posedge tmin or negedge rst_n)
begin
if(!rst_n)
co1<=0;
else if(tmin)
begin
if(co1==59)
co1<=0;
else
co1<=co1+1;
end
end
always @(posedge tsecond or negedge rst_n)
begin
if(!rst_n)
cnt60_s<=0;
else if(tsecond)
begin
if(cnt60_s==59)
cnt60_s<=0;
else
cnt60_s<=cnt60_s+1;
end
end
//******************計數器(0-59)秒(重複進行)******倒計時59-0(不重複)
output reg fm;//這是一個蜂鳴器
reg [5:0] rcnt60=6'b11_1011;//定義59
reg [5:0] cnt60;//記錄秒數
reg [5:0] co;//記錄分鐘
reg [4:0] myhour;//記錄小時
always @(posedge clk1S or negedge rst_n or posedge zt)
begin
//置零的時候會實作cnt60(0-59計數器)清0,實作rcnt60(計時器)恢複59,而且不響鈴
if(!rst_n)
begin cnt60 <= 0;rcnt60<=6'b11_1011;fm<=0;co<=0;myhour<=0;end
//暫停計時和計數
else if(zt)
begin cnt60 <= cnt60; rcnt60<=rcnt60;
if(thour)
myhour<=myhour1;
if(tmin)
co<=co1;
if(tsecond)
cnt60<=cnt60_s;
end
else
//看看是計時還是計數
case({jishu,jishi})
//當是00的時候處于暫停的狀态,此時會把蜂鳴器fm設定為0,不響的狀态
2'b00:begin fm<=0;end
//倒計時
2'b01:begin
if(rcnt60 == 0)
begin rcnt60<=0;fm<=1;cnt60<=rcnt60; end
else
begin rcnt60 <= rcnt60 - 1;cnt60<=rcnt60; fm<=0;end
end
//計數器
2'b10: begin
if(cnt60 == 59)
begin cnt60<=0;
if(co==59)
begin
co<=0;
if(myhour==23)
myhour<=0;
else
myhour<=myhour+1;
end
else
co<=co+1;
end
else begin cnt60 <= cnt60 + 1; fm<=0; end
end
endcase
end
//7段碼譯碼器,這是定義了一個函數,4位的輸入8位的輸出
//4位會對應0到9,0000~1001,seg7就是七段碼的輸出,從後往前對應a,b,c,d,e,f,g,dp,fpga實驗闆是共陽極,也就是說輸入0的時候才是有效的
output reg [7:0] seg_out;
output reg [7:0] dig_sel_n;
function [7:0] seg7;
input [3:0] data;
begin
case(data)
0: seg7= 8'b11000000;
1: seg7= 8'b11111001;
2: seg7= 8'b10100100;
3: seg7= 8'b10110000;
4: seg7= 8'b10011001;
5: seg7= 8'b10010010;
6: seg7= 8'b10000010;
7: seg7= 8'b11111000;
8: seg7= 8'b10000000;
9: seg7= 8'b10010000;
default: seg7= 8'b11111111;
endcase
end
endfunction
//用來顯示小點點,便于區分小時,分鐘和秒
function [7:0] seg77;
input [3:0] data_2;
begin
case(data_2)
0: seg77= 8'b01000000;
1: seg77= 8'b01111001;
2: seg77= 8'b00100100;
3: seg77= 8'b00110000;
4: seg77= 8'b00011001;
5: seg77= 8'b00010010;
6: seg77= 8'b00000010;
7: seg77= 8'b01111000;
8: seg77= 8'b00000000;
9: seg77= 8'b00010000;
default: seg77= 8'b01111111;
endcase
end
endfunction
always @(cnt22 ,cnt60,rst_n,myhour,co)
begin
if(!rst_n)
begin dig_sel_n <= 8'b11111111; seg_out <=8'b11111111; end
else
begin
case(cnt22)
//對計數器的十位和個位進行分離,交替閃爍
0: begin dig_sel_n <= 8'b11111110; seg_out <= seg7(cnt60%10); end
1: begin dig_sel_n <= 8'b11111101; seg_out <= seg7(cnt60/10);end
2: begin dig_sel_n <= 8'b11111011; seg_out <= seg77(co%10); end
3: begin dig_sel_n <= 8'b11110111; seg_out <= seg7(co/10);end
4: begin dig_sel_n <= 8'b11101111; seg_out <= seg77(myhour%10); end
5: begin dig_sel_n <= 8'b11011111; seg_out <= seg7(myhour/10);end
default:
begin dig_sel_n <= 8'b11111111; seg_out <= 8'b11111111;end
endcase
end
end
endmodule