在verilog程序設計中,我們往往要對一個頻率進行任意分頻,而且占空比也有一定的要求這樣的話,對于程序有一定的要求,現在我在前人經驗的基礎上做一個簡單的總結,實現對一個頻率的任意占空比的任意分頻。
比如:我們FPGA系統時鐘是50M Hz,而我們要產生的頻率是880Hz,那么,我們需要對系統時鐘進行分頻。我們很容易想到用計數的方式來分頻:
50000000/880 = 56818
這個數字不是2的整冪次方,那么怎么辦呢?我們可以設定一個參數,讓它到56818的時候重新計數不就完了嗎?呵呵,程序如下:
module div(clk, clk_div);
input clk;
output clk_div;
reg [15:0] counter;
always @(posedge clk)
if(counter==56817) counter <= 0;
else counter <= counter+1;
assign clk_div = counter[15];
endmodule
下面我們來算一下它的占空比:我們清楚地知道,這個輸出波形在counter為0到32767的時候為低,在32767到56817的時候為高,占空比為40%多一些,如果我們需要占空比為50%,那么怎么辦呢?不用急,慢慢來。
我們再設定一個參數,使它為56817的一半,使達到它的時候波形翻轉,那不就完了嗎?呵呵,再看看:
module div(clk, clk_div); input clk; output clk_div; reg [14:0] counter; always @(posedge clk) if(counter==28408) counter <= 0; else counter <= counter+1; reg clk_div; always @(posedge clk) if(counter==28408) clk_div <= ~clk_div; endmodule
占空比是不是神奇地變成50%了呢?呵呵。
繼續讓我們來看如何實現任意占空比,比如還是由50 M分頻產生880 Hz,而分頻得到的信號的占空比為30%。
56818×30%=17045
module div(clk,reset,clk_div,counter); input clk,reset; output clk_div; output [15:0] counter; reg [15:0] counter; reg clk_div; always @(posedge clk) if(!reset) counter <= 0; else if(counter==56817) counter <= 0; else counter <= counter+1; always @(posedge clk) if(!reset) clk_div <= 0; else if(counter<17045) clk_div <= 1; else clk_div <= 0; endmodule
三分頻的Verilog實現
//很實用也是筆試面試時常考的,已經經過仿真
占空比要求50%和不要求占空比差別會很大,先看一個占空比50%的描述
module div3(CLKIN,CLKOUT,RESETn); input CLKIN,RESETn; output CLKOUT; //internal counter signals reg[1:0] count_a; reg[1:0] count_b; reg CLKOUT; always @(negedge RESETn or posedge CLKIN) begin if (RESETn==1'b0) count_a<=2'b00; else if (count_a==2'b10) count_a<=2'b00; else count_a<=count_a+1; end always @(negedge RESETn or negedge CLKIN) begin if (RESETn==1'b0) count_b<=2'b0; else if (count_b==2'b10) count_b<=2'b00; else count_b<=count_b+1; end always @(count_a or count_b or RESETn) begin if (RESETn==1'b0) CLKOUT=1'b0; else if((count_a+count_b==4)||(count_a+ count_b==1)) CLKOUT=~CLKOUT; end endmodule
0 1 2 0 1 2
/ / / /
0 1 2 0 1 2
下面是一個非50%的描述,只用了上升沿
module div3(CLKIN,CLKOUT,RESETn); input CLKIN,RESETn; output CLKOUT; wire d; reg q1,q2; wire CLKOUT; always @(negedge RESETn or posedge CLKIN) begin if (RESETn==1'b0) q1<=1'b0; else q1<=d; end always @(negedge RESETn or posedge CLKIN) begin if (RESETn==1'b0) q2<=1'b0; else q2<=q1; end assign d=~q1 & ~q2; assign CLKOUT=q2; endmodule
占空比不是50%,只用了單沿觸發器,寄存器輸出。
至于其他奇數要求50%的或者不要求的占空比的,都可以參照上面兩個例子做出。
占空比為50%的一個更好的實現。
module div3(CLKIN,CLKOUT,RESETn); input CLKIN,RESETn; output CLKOUT; //internal counter signals reg[1:0] count_a; reg b,c; //reg CLKOUT; wire CLKOUT; always @(negedge RESETn or posedge CLKIN) begin if (RESETn==1'b0) count_a<=2'b00; else if (count_a==2'b10) count_a<=2'b00; else count_a<=count_a+1; end always @(negedge RESETn or negedge CLKIN) begin if (RESETn==1'b0) b<=1'b0; else if (count_a==2'b01) b<=2'b0; else b<=1'b1; end always @(negedge RESETn or posedge CLKIN) begin if (RESETn==1'b0) c<=1'b0; else if (count_a==2'b10) c<=1'b1; else if (count_a==2'b01) c<=1'b0; end assign CLKOUT=b & c; endmodule
時鐘選擇器的Verilog寫法!
CPRI有3種數據時鐘,61.44M 122.88M 245.76M,需要模塊能夠根據外部的速率指示信號(一個2位的輸入信號,由模塊外部給定)選擇其中的一種時鐘作為模塊的工作時鐘
但由于所選用的FPGA工作頻率關系,不能超過400M,無法通過寄存器方式實現時鐘源的選擇.
使用雙邊觸發的方式將最高的頻率進行分頻,代碼如下,已經通過ModelSim的仿真,可以實現。
module clk_div( reset, //復位信號 data_rate, //數據速率指示 clk2, //245.76M的時鐘輸入 time1, //分頻計數器 clk //選擇后的時鐘輸出 ); input reset; input [1:0] data_rate; input clk2; output [1:0] time1; output clk; reg [1:0] time1; reg clk; always@(clk2 or reset) if(reset) begin time1=2'b00; clk=1'b0; end else begin time1=time1+1'b1; case(data_rate) 2'b00:if(time1==2'b00) clk=~clk; else clk=clk; 2'b01:if(time1[0]==1'b1) clk=~clk; else clk=clk; 2'b10:clk=clk; 2'b11:clk=~clk; endcase end endmodule
verilog 實現gray碼計數器
//16位gray碼計數器,gary碼狀態改變時候每次只改變一個bit //,可以有效防止競爭和毛刺的產生。 module gray_counter(clk,clr,start,stop,q,cout); input clk; input clr; input start,stop; output reg [3:0] q; output reg cout; reg flag=1; reg [3:0] s,next_s; //parameter S0=0, S1=1, S2=2, S3=3, S4=4, S5=5, S6=6, S7=7; //parameter S8=8, S9=9, S10=10, S11=11, S12=12, S13=13, S14=14, S15=15; parameter s0=0000, s1=0001, s2=0011, s3=0010; parameter s4=0110, s5=0111, s6=0101, s7=0100; parameter s8=1100, s9=1101, s10=1111,s11=1110; parameter s12=1010, s13=1011, s14=1001, s15=1000; always @(posedge clk) begin if (clr) s <= s0; else s <= next_s; end /*always @(posedge start or posedge stop) begin if(start) flag=1; else if (stop) flag=0; end*/ always @(s or flag) /*該進程實現狀態的轉換*/ begin case (s) s0: begin if (flag) next_s <=s1; // else next_s <=s0; end s1: begin if (flag) next_s <= s2; end s2: begin if (flag) next_s <=s3; ////else next_s <=s0; end s3: begin if (flag) next_s <=s4; //else next_s <=s3; end s4: begin if (flag) next_s <= s5; end s5: begin if (flag) next_s <=s6; //else next_s <=s0; end s6: begin if (flag) next_s <=s7; //else next_s <=s3; end s7: begin if (flag) next_s <=s8; //else next_s <=s0; end s8: begin if (flag) next_s <= s9; end s9: begin if (flag) next_s <=s10; ////else next_s <=s0; end s10: begin if (flag) next_s <=s11; //else next_s <=s3; end s11: begin if (flag) next_s <= s12; end s12: begin if (flag) next_s <=s13; //else next_s <=s0; end s13: begin if (flag) next_s <=s14; //else next_s <=s3; end s14: begin if (flag) next_s <=s15; ////else next_s <=s0; end s15: begin if (flag) next_s <=s0; //else next_s <=s3; end default: next_s <=s0; /*default語句*/ endcase end always @(s) /*該進程定義組合邏輯(FSM的輸出)*/ begin case(s) s0: q=0; s1: q=4; s2: q=2; s3: q=3; s4: q=4; s5: q=5; s6: q=6; s7: q=7; s8: q=8; s9: q=9; s10: q=10; s11: q=11; s12: q=12; s13: q=13; s14: q=14; s15: q=15; default:q=0; /*default語句,避免鎖存器的產生*/ endcase end always @(s) begin if (s==s15) cout=1;//assign cout=q; else cout=0; end endmodule
審核編輯:郭婷
-
FPGA
+關注
關注
1629文章
21736瀏覽量
603319 -
Verilog
+關注
關注
28文章
1351瀏覽量
110095
原文標題:Verilog_實現任意占空比、任意分頻的方法
文章出處:【微信號:ZYNQ,微信公眾號:ZYNQ】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論