PS:目前手上仍然沒有板子,按照野火視頻的講解,目前我們只能做到前面六步(其實第一步設計規劃也是需要看板子的硬件的,但是現在沒有板子就完全與野火傳授的板子一致來看)

FPGA學習篇——Verilog學習之分頻器的實現 - 教程_上升沿

1 設計規劃及波形繪製

1.1 分頻器的原理:

分頻器就是把輸入信號的頻率成倍數的降低後再進行輸出。

比如説4分頻器,就是把輸入信號頻率降低4倍再輸出,可以理解成輸入4個週期對應輸出1個週期:

FPGA學習篇——Verilog學習之分頻器的實現 - 教程_上升沿_02

同理,12分頻器,把輸入信號頻率降低12倍再輸出,即輸入12個週期對應輸出1個週期。

FPGA學習篇——Verilog學習之分頻器的實現 - 教程_上升沿_03

倍頻器原理:與分頻器對應的就是倍頻器,它是把輸入信號的頻率成倍數的升高後再進行輸出(即即可以理解成N倍頻器就是輸入1個週期對應輸出N個週期)

1.2 分頻器的分類:

以倍數的奇偶分成奇分頻器(3,5,7,9...)+偶分頻器(2,4,6,8...)

1.3 波形繪製

1.3.1偶分頻器

以4分頻器為例(偶數分頻器),按照偶分頻器的原理可以看到,輸出一個週期等於輸入四個週期(圖中紅色虛線框起來部分),如何實現呢?

還記得我們上一節實現的計數器嗎?看計數器的波形圖(圖1),其實就是一個分頻器!輸入25000000個週期等於一個輸出週期!因此,我們可以仿照這個思想,通過計數來實現分頻!調節計數值就可形成對應的分頻器!

FPGA學習篇——Verilog學習之分頻器的實現 - 教程_sed_04

圖1 

那麼按照上述思想,我們使得計數器取0~3(對應輸入四個週期),又因為剛好為偶數,實際計數器取0和1即可,每到1的上升沿翻轉一次,得到輸出信號,如下圖2所示。

FPGA學習篇——Verilog學習之分頻器的實現 - 教程_ide_05

圖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的上升沿各翻轉一次,也能得到輸出波形

FPGA學習篇——Verilog學習之分頻器的實現 - 教程_sed_06

圖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

由下列波形圖可以看到,仿真驗證通過。

FPGA學習篇——Verilog學習之分頻器的實現 - 教程_sed_07