PS:目前手上仍然沒有板子,按照野火視頻的講解,目前我們只能做到前面六步(其實第一步設計規劃也是需要看板子的硬件的,但是現在沒有板子就完全與野火傳授的板子一致來看)
1 設計規劃及波形繪製
1.1 分頻器的原理:
分頻器就是把輸入信號的頻率成倍數的降低後再進行輸出。
比如説4分頻器,就是把輸入信號頻率降低4倍再輸出,可以理解成輸入4個週期對應輸出1個週期:
同理,12分頻器,把輸入信號頻率降低12倍再輸出,即輸入12個週期對應輸出1個週期。
倍頻器原理:與分頻器對應的就是倍頻器,它是把輸入信號的頻率成倍數的升高後再進行輸出(即即可以理解成N倍頻器就是輸入1個週期對應輸出N個週期)
1.2 分頻器的分類:
以倍數的奇偶分成奇分頻器(3,5,7,9...)+偶分頻器(2,4,6,8...)
1.3 波形繪製
1.3.1偶分頻器
以4分頻器為例(偶數分頻器),按照偶分頻器的原理可以看到,輸出一個週期等於輸入四個週期(圖中紅色虛線框起來部分),如何實現呢?
還記得我們上一節實現的計數器嗎?看計數器的波形圖(圖1),其實就是一個分頻器!輸入25000000個週期等於一個輸出週期!因此,我們可以仿照這個思想,通過計數來實現分頻!調節計數值就可形成對應的分頻器!
圖1
那麼按照上述思想,我們使得計數器取0~3(對應輸入四個週期),又因為剛好為偶數,實際計數器取0和1即可,每到1的上升沿翻轉一次,得到輸出信號,如下圖2所示。
圖2
1.3.2 奇分頻器
同樣,我們使用計數的原理來實現奇分頻器,但這裏有一個問題,以5分頻器為例,計數器取0~4(對應輸入五個週期),我們要使得輸出在2.5週期處翻轉一次(這樣輸出在0~4才能形成一個週期),但我們計數cnt無法記到小數,那該怎麼辦呢?
這裏有兩種實現方法:
由圖3波形圖可以看到,如果在2的上升沿和4的上升沿各翻轉一次,得到Out1,輸出的週期佔空比就不是50%,同樣,在2的下降沿和4的下降沿各翻轉一次,得到Out2,輸出的週期佔空比也不是50%
(1)但是!若Out1或上Out2(即Out1 | Out2),就可以得到Out,滿足輸出佔空比50%的週期
(2)或者,直接看Out,使得輸出在2的下降沿和4的上升沿各翻轉一次,也能得到輸出波形
圖3
2 代碼編寫
2.1 偶分頻器
module Divider_4(
input sys_clk,
input sys_rst_n,
output reg Out
);
reg cnt ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 0)
cnt <= 2'd0;
else if(cnt == 2'd1)
cnt <= 2'd0;
else
cnt <= cnt + 1;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 0)
Out <= 1'b0;
else if(cnt == 2'd1)
Out <= ~Out;
else
Out <= Out;
end
endmodule
2.2 奇分頻器
方法(1):
module Divider_5(
input sys_clk ,
input sys_rst_n ,
output Out
);
reg [2:0] cnt;
reg Out1;
reg Out2;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 3'd0;
else if(cnt == 3'd4)
cnt <= 3'd0;
else
cnt <= cnt + 1;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
Out1 <= 1'd0;
else if(cnt == 3'd2)
Out1 <= ~Out1;
else if(cnt == 3'd4)
Out1 <= ~Out1;
else
Out1 <= Out1;
end
always @(negedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
Out2 <= 1'd0;
else if(cnt == 3'd2)
Out2 <= ~Out2;
else if(cnt == 3'd4)
Out2 <= ~Out2;
else
Out2 <= Out2;
end
assign Out = (Out1 | Out2);
endmodule
方法(2):
module Divider_5(
input sys_clk ,
input sys_rst_n ,
output reg Out
);
reg [2:0] cnt;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 3'd0;
else if(cnt == 3'd4)
cnt <= 3'd0;
else
cnt <= cnt + 1;
end
always @(negedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
Out <= 1'b0;
else if(cnt == 3'd2)
Out <= 1'b1;
else
Out <= Out;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
Out <= 1'b0;
else if(cnt == 3'd4)
Out <= 1'b0;
else
Out <= Out;
end
endmodule
3 邏輯仿真及波形驗證
之前我們説到tb文件相當於模擬模塊的輸入情況,由於這裏的4分頻(偶數)和5分頻(奇數)的輸入都只有兩個信號,並且情況一樣,所以代碼完全一致,修改對應的名稱即可。
以下代碼以5分頻的仿真為例:
module tb_Divider_5();
reg tb_sys_clk ;
reg tb_sys_rst_n ;
wire tb_Out ;
initial begin
tb_sys_clk <= 1'b0;
tb_sys_rst_n <= 1'b0;
#10
tb_sys_rst_n <= 1'b1;
end
always #20 tb_sys_clk <= ~tb_sys_clk;
// output declaration of module Divider_5
Divider_5 u_Divider_5(
.sys_clk (tb_sys_clk ),
.sys_rst_n (tb_sys_rst_n ),
.Out (tb_Out )
);
endmodule
由下列波形圖可以看到,仿真驗證通過。