• <li id="00i08"><input id="00i08"></input></li>
  • <sup id="00i08"><tbody id="00i08"></tbody></sup>
    <abbr id="00i08"></abbr>
  • 新聞中心

    EEPW首頁 > 嵌入式系統 > 設計應用 > Lattice MXO2: 時鐘分頻

    Lattice MXO2: 時鐘分頻

    作者: 時間:2023-10-27 來源:電子森林 收藏


    在之前的實驗中我們已經熟悉了的各種外設,掌握了verilog的組合邏輯設計,接下來我們將學習的設計。

    本文引用地址:http://www.czjhyjcfj.com/article/202310/452151.htm

    硬件說明


    時鐘信號的處理是的特色之一,因此分頻器也是設計中使用頻率非常高的基本設計之一。一般在中都有集成的鎖相環可以實現各種時鐘的分頻和倍頻設計,但是通過語言設計進行是最基本的訓練,在對時鐘要求不高的設計時也能節省鎖相環資源。在本實驗中我們將實現任意整數的分頻器,分頻的時鐘保持50%占空比。

    1,偶數分頻:偶數倍分頻相對簡單,比較容易理解。通過計數器計數是完全可以實現的。如進行N倍偶數分頻,那么通過時鐘觸發計數器計數,當計數器從0計數到N/2-1時,輸出時鐘進行翻轉,以此循環下去。

    2,奇數分頻: 如果要實現占空比為50%的奇數倍分頻,不能同偶數分頻一樣計數器記到一半的時候輸出時鐘翻轉,那樣得不到占空比50%的時鐘。以待分頻時鐘CLK為例,如果以偶數分頻的方法來做奇數分頻,在CLK上升沿觸發,將得到不是50%占空比的一個時鐘信號(正周期比負周期多一個時鐘或者少一個時鐘);但是如果在CLK下降沿也觸發,又得到另外一個不是50%占空比的時鐘信號,這兩個時鐘相位正好相差半個CLK時鐘周期。通過這兩個時鐘信號進行邏輯運算我們可以巧妙的得到50%占空比的時鐘。

    總結如下:對于實現占空比為50%的N倍奇數分頻,首先進行上升沿觸發進行模N計數,計數選定到某一個值進行輸出時鐘翻轉,然后經過(N-1)/2再次進行翻轉得到一個占空比非50%奇數n分頻時鐘。再者同時進行下降沿觸發的模N計數,到和上升沿觸發輸出時鐘翻轉選定值相同值時,進行輸出時鐘時鐘翻轉,同樣經過(N-1)/2時,輸出時鐘再次翻轉生成占空比非50%的奇數n分頻時鐘。兩個占空比非50%的n分頻時鐘進行邏輯運算(正周期多的相與,負周期多的相或),得到占空比為50%的奇數n分頻時鐘。


    Verilog代碼


    // ********************************************************************
    // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
    // ********************************************************************
    // File name    : divide.v
    // Module name  : divide
    // Author       : STEP
    // Description  : clock divider
    // Web          : www.stepfpga.com 
    // 
    // --------------------------------------------------------------------
    // Code Revision History : 
    // --------------------------------------------------------------------
    // Version: |Mod. Date:   |Changes Made:
    // V1.0     |2017/03/02   |Initial ver
    // --------------------------------------------------------------------
    // Module Function:任意整數 
    module divide (	clk,rst_n,clkout);         
    input 	clk,rst_n;                       //輸入信號,其中clk連接到FPGA的C1腳,頻率為12MHz
            output	clkout;                          //輸出信號,可以連接到LED觀察分頻的時鐘         
            
            //parameter是verilog里常數語句
            
    	parameter	WIDTH	= 3;             //計數器的位數,計數的最大值為 2**WIDTH-1
    	parameter	N	= 5;             //分頻系數,請確保 N < 2**WIDTH-1,否則計數會溢出 	
    	reg 	[WIDTH-1:0]	cnt_p,cnt_n;     //cnt_p為上升沿觸發時的計數器,cnt_n為下降沿觸發時的計數器
    	reg			clk_p,clk_n;     //clk_p為上升沿觸發時分頻時鐘,clk_n為下降沿觸發時分頻時鐘 	
    	
    	//上升沿觸發時計數器的控制
    	
    	always @ (posedge clk or negedge rst_n )         //posedge和negedge是verilog表示信號上升沿和下降沿
                                                             //當clk上升沿來臨或者rst_n變低的時候執行一次always里的語句
    		begin
    			if(!rst_n)
    				cnt_p<=0;
    			else if (cnt_p==(N-1))
    				cnt_p<=0;
    			else cnt_p<=cnt_p+1;             //計數器一直計數,當計數到N-1的時候清零,這是一個模N的計數器
    		end          //上升沿觸發的分頻時鐘輸出,如果N為奇數得到的時鐘占空比不是50%;如果N為偶數得到的時鐘占空比為50%
             always @ (posedge clk or negedge rst_n)
    		begin
    			if(!rst_n)
    				clk_p<=0;
    			else if (cnt_p<(N>>1))          //N>>1表示右移一位,相當于除以2去掉余數
    				clk_p<=0;
    			else 
    				clk_p<=1;               //得到的分頻時鐘正周期比負周期多一個clk時鐘
    		end         //下降沿觸發時計數器的控制        	
    	always @ (negedge clk or negedge rst_n)
    		begin
    			if(!rst_n)
    				cnt_n<=0;
    			else if (cnt_n==(N-1))
    				cnt_n<=0;
    			else cnt_n<=cnt_n+1;
    		end         //下降沿觸發的分頻時鐘輸出,和clk_p相差半個時鐘
    	always @ (negedge clk)
    		begin
    			if(!rst_n)
    				clk_n<=0;
    			else if (cnt_n<(N>>1))  
    				clk_n<=0;
    			else 
    				clk_n<=1;                //得到的分頻時鐘正周期比負周期多一個clk時鐘
    		end         assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p;      //條件判斷表達式
                                                        //當N=1時,直接輸出clk
                                                       //當N為偶數也就是N的最低位為0,N(0)=0,輸出clk_p
                                                      //當N為奇數也就是N最低位為1,N(0)=1,輸出clk_p&clk_n。正周期多所以是相與
            endmodule

    測試文件,進行功能仿真時需要編寫testbench測試文件。verilog里的testbench文件和源文件一樣也是.v文件,仿真能讓我們更直觀的觀察信號波形,可以先閱讀Diamond的使用了解如何使用Diamond中集成的仿真工具。

    // ********************************************************************
    // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
    // ********************************************************************
    // File name    : divide_tb.v
    // Module name  : divide_tb
    // Author       : STEP
    // Description  : clock divider
    // Web          : www.stepfpga.com 
    // 
    // --------------------------------------------------------------------
    // Code Revision History : 
    // --------------------------------------------------------------------
    // Version: |Mod. Date:   |Changes Made:
    // V1.0     |2017/03/02   |Initial ver
    // --------------------------------------------------------------------
    // Module Function:divide.v時鐘分頻器的測試文件           
              `timescale 1ns/100ps                             //仿真時間單位/時間精度,時間單位要大于或者等于時間精度           
              module divide_tb();                              //測試文件也是一個module,因為用于仿真所以無需輸入輸出信號
              reg    clk,rst_n;                                //需要產生的激勵信號定義,激勵信號需要過程塊產生所以定義為reg型變量
                     wire   clkout;                                   //需要觀察的輸出信號定義,定義為wire型變量           
                    
                     //初始化過程塊
                     
              initial 
    	  begin 
    		 clk = 0;
    		 rst_n = 0;
    		 #25                                      //#表示延時25個時間單位
    		 rst_n = 1;                               //產生了一個初始25ns低電平,然后變高電平的復位信號
    	  end           
    	  always #10 clk = ~clk;                          
    	  //每隔10ns翻轉一次clk信號,也就是產生一個時鐘周期20ns的clk,頻率為50MHz             
    	  
    	  //module調用例化格式
    	  
              divide  #(.WIDTH(4),.N(11))  u1 (                         
              //#后面的()中為參數傳遞,如果不傳遞參數就是所調用模塊中的參數默認值
             //divide表示所要例化的module名稱,u1是我們定義的例化名稱,必須以字母開頭
    						.clk	(clk),     //輸入輸出信號連接。 .clk表示module本身定義的信號名稱;(clk)表示我們在這里定義的激勵信號
    						.rst_n	(rst_n),   //在testbench里定義的信號名稱可以與所要調用module的端口信號名稱不同
    						.clkout	(clkout)   
    					  );
             endmodule

    引腳分配


    上的系統時鐘連接到FPGA的C1腳,時鐘為12MHz。你可以通過仿真波形觀察分頻時鐘(注意仿真的時間是有限的,所以分頻時鐘頻率需要較高)。如果我們想通過眼睛觀察LED的閃爍,那么需要設置參數N和WIDTH得到一個頻率較低的時鐘(例如N=12000000,WIDTH=24,分頻時鐘周期為1秒)。

    信號引腳
    clkC1
    rst_nL14
    clkoutN13

    修改程序中的分頻系數和計數器位數就能夠調整LED閃爍速度(注意計數的最大值一定要保證超過分頻系數N)。

    小結


    在本實驗學習了如何進行任意整數的分頻設計,我們產生各種時鐘,通過修改程序還能實驗調整輸出時鐘的頻率、相位以及占空比,非常靈活。同時學習了如何編寫testbench文件,了解verilog中如何例化module,在后面的學習中將會經常用到。在下個實驗我們將進一步了解,如何利用時鐘來進一步設計,請看最常見的流水燈。



    評論


    相關推薦

    技術專區

    關閉
    主站蜘蛛池模板: 甘南县| 洛隆县| 茌平县| 乌兰浩特市| 华容县| 五指山市| 施甸县| 固镇县| 威信县| 黎城县| 洛阳市| 从化市| 海口市| 凭祥市| 石河子市| 西宁市| 玛纳斯县| 峨眉山市| 广元市| 长葛市| 四子王旗| 辽阳市| 祁阳县| 南召县| 府谷县| 枣阳市| 伊宁市| 临安市| 开化县| 夏邑县| 凤山县| 巧家县| 金塔县| 洛扎县| 叙永县| 恩平市| 芦溪县| 额敏县| 湘西| 沅陵县| 三门县|