想說的話...
本次實現的是一個24秒倒計時器,功能顧名思義,進行一個24秒的倒計時操作,本文先給出一個簡單樣例,並結合仿真驗證功能,再對樣例進行拓展,成為一個可以被調用的模塊.
本文未涉及顯示模塊.
樣例_邊沿檢測計數器
代碼講解
首先給出樣例代碼.
module CntDwn
(input CK//Clock
,output[4:0]CD//CountDown
);
parameter[4:0]cd=5'd24;//Define a parameter which can be modified when called
reg[4:0]dif=0;//Difference
always@(posedge CK)
if(dif==cd)
dif<=0;
else
dif<=dif+1;
assign CD=cd-dif;
endmodule
這段代碼非常簡單,原理即利用了一個邊沿檢測計數器直接實現計時功能,邏輯為每檢測到一個升沿,差(dif)自增1,若差滿,即和倒計時數相等,則差清零.
在這段代碼里將倒計時數初始化為24,這個倒計時數在被其他模塊調用的時候可以被修改,可移植性好.
仿真演示
`timescale 1 ns/ 1 ns
module CntDwn_vlg_tst();
reg CK;
wire[4:0]CD;
CntDwn i1 (.CD(CD),.CK(CK));
initial begin
CK=0;
end
always begin
#1 CK<=~CK;
end
endmodule
以上是樣例代碼的一個仿真文件(.vt),通過ModelSim仿真后波形如下圖
如果在仿真文件調用時修改傳遞參數,將Line 5改為
CntDwn #(.cd(10)) i1 (.CD(CD),.CK(CK));
則波形如下圖
可見,本樣例代碼成功實現了倒計時功能,接下來進行樣例代碼的拓展.
拓展_自定義倒計時數和倒計時間隔
代碼講解
module CntDwn
(input CK//Clock
,output[4:0]CD//CountDown
);
parameter[4:0]cd=5'd24;//Define a parameter which can be modified when called
parameter[25:0]div=26'd50;//Frequency Division
reg[25:0]cnt=0;//Timer.Control the period
reg[4:0]dif=0;//Difference
always@(posedge CK)
if(cnt==div)begin
cnt<=0;
dif<=dif+1;
end
else if(dif==cd)
dif<=0;
else
cnt<=cnt+1;
assign CD=cd-dif;
endmodule
這是拓展后的代碼,加入了分頻,可以自定義倒計時的間隔,在調用時修改傳遞參數來達到自定義間隔和倒計時數的功能.
代碼中已經為分頻參數初始化為50,方便下面仿真調試.
仿真演示
仿真文件如下
`timescale 1 ns/ 1 ns
module CntDwn_vlg_tst();
reg CK;
wire[4:0]CD;
CntDwn i1 (.CD(CD),.CK(CK));
initial begin
CK=0;
end
always begin
#1 CK<=~CK;
end
endmodule
波形如下
由於分頻參數為50,相當於比樣例滿了50倍,所以等尺寸縮放后時鍾信號已經密密麻麻的(甚至密集到只能顯示為一條粗粗的線),倒計時仍然功能正常,說明間隔功能無誤.
總結
本文概述了如何通過Verilog實現倒計時器,並且加入了波形仿真的知識,方便驗證和調試,還考慮到了參數調用的思想,增強代碼的可讀性,可維護性和可移植性.
值得說明的是,本文代碼仍有缺漏,例如在調用時如果需要倒計時數大於32(5位寬),頂層代碼中的參數位寬就要手動修改,不是很方便,一個解決方案就是將倒計時數的位寬也定義為一個WIDTH參數,使之也能夠被傳遞不同的參數.分頻參數已經定義為26位寬,基本能滿足大多數情況的需求,一般不需要進行修改位寬的操作.
如果要實現秒倒計時器,在仿真層面可以將分頻參數和自己的激勵時鍾信號周期相匹配,達到間隔為1秒的效果;如果要在開發板上實現,則需要考慮板載晶振的參數,計算分頻參數,在調用時傳遞參數或直接修改參數來達到1秒間隔.
實例_24秒倒計時器
module CntDwn_24s
(input CK//Clock
,output[4:0]CD//CountDown
);
parameter[4:0]cd=5'd24;//Define a parameter which can be modified when called
parameter[25:0]div=26'd12000000;//Frequency Division,12M
reg[25:0]cnt=0;//Timer.Control the period
reg[4:0]dif=0;//Difference
always@(posedge CK)
if(cnt==div)begin
cnt<=0;
dif<=dif+1;
end
else if(dif==cd)
dif<=0;
else
cnt<=cnt+1;
assign CD=cd-dif;
endmodule
此段代碼在板載晶振為12M的情況下正常運行.