赞
踩
2023.4.8
module even_div ( input wire rst , input wire clk_in, output wire clk_out2, output wire clk_out4, output wire clk_out8 ); reg clk_out2_r, clk_out4_r, clk_out8_r; always@(posedge clk_in or negedge rst) begin //二分频是最简单的,直接把~Q接到D端就可以了 if(~rst) clk_out2_r <= 0; else clk_out2_r <= ~clk_out2_r; end //四分频是以二分频为时钟,就可以在上升沿的时候四分频也是从0跳转到1 //使得二四八分频同时为高电平 always@(posedge clk_out2 or negedge rst) begin if(~rst) clk_out4_r <= 0; else clk_out4_r <= ~clk_out4_r; end always@(posedge clk_out4 or negedge rst) begin if(~rst) clk_out8_r <= 0; else clk_out8_r <= ~clk_out8_r; end assign clk_out2 = clk_out2_r; assign clk_out4 = clk_out4_r; assign clk_out8 = clk_out8_r; endmodule
reg q;
always@(posedge clk or posedge rst)begin
if(rst)
q <= 0;
else if(set)
q <= 1;
else
q <= ~q;
end
分频系数:10,偶数分频,用计数器来实现
reg [3:0] cnt; parameter CNT_DIV = 5, CNT_MAX = 10; always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 0; else cnt <= (cnt==CNT_MAX-1) ? 0 : cnt+1; //注意计数器最大值为9,不能为10,为10的话下个周期会有问题 end always@(posedge clk or negedge rst_n)begin if(!rst_n) q <= 0; else if(cnt<CNT_DIV) q <= 1; else q <= 0; end
原理和偶数分频一样,只不过由于是奇数个周期,可以决定高低电平的占比。例如三分频,占空比可以为1/3或者2/3
//下面是5分频 reg [2:0]cnt; reg clk_out5_r; always@(posedge clk_in or negedge rst)begin if(!rst) clk_out5_r<=0; else if(cnt==0||cnt==2) clk_out5_r<=~clk_out5_r; else clk_out5_r<=clk_out5_r; end always@(posedge clk_in or negedge rst)begin if(!rst) cnt<=0; else cnt<=(cnt==4)?0:cnt+1; end
这种写法应该要避免,无法综合,前面学习verilog语法的时候说过,混合使用上升沿和下降沿触发的触发器。
parameter MAX = 7;
always@(posedge clk_in or negedge clk_in)begin
if(!rst)begin
cnt<=0;
clk_out7_r<=0;
end
else if(cnt==MAX-1)begin
cnt<=0;
clk_out7_r<=~clk_out7_r;
end
else
cnt<=cnt+1;
end
如果奇数分频输出时钟的高低电平只差一个cycle ,则可以利用源时钟双边沿特性并采用"与操作
"或"或操作
"的方式将分频时钟占空比调整到50%。
如果是高电平少,就是相或;如果高电平多,就是相与。
module oushu_div( input clk_in, input rst_n, output clk_out //这里输出默认是wire类型 ); parameter MAX = 7; reg [2:0] cnt1; reg clk_div1, clk_div2; always@(posedge clk_in or negedge rst_n)begin //用一个计数器计数 if(!rst_n) cnt <= 0; else cnt <= (cnt==MAX-1) ? 0 : cnt+1; end always@(posedge clk_in or negedge rst_n)begin if(!rst_n) clk_div1 <= 0; else if(cnt<(MAX-1)/2) clk_div1 <= 1; else clk_div1 <= 0; end always@(negedge clk_in or negedge rst_n)begin if(!rst_n) clk_div2 <= 0; else if(cnt<(MAX-1)/2) clk_div2 <= 1; else clk_div2 <= 0; end assign clk_out = clk_div1 | clk_div2 ; endmodule
always@(posedge clk_in or negedge rst_n)begin if(!rst_n) cnt <= 0; else cnt <= (cnt==MAX-1) ? 0 : cnt+1; end always@(posedge clk_in or negedge rst_n)begin if(!rst_n) clk_div1 <= 0; else if(cnt==(MAX-1)/2) //这样写就使得0-3为高电平,4-8为低电平 clk_div1 <= 0; else if(cnt==(MAX-1)) clk_div1 <= 1; end always@(negedge clk_in or negedge rst_n)begin if(!rst_n) clk_div2 <= 0; else if(cnt==(MAX-1)/2) clk_div2 <= 0; else if(cnt==(MAX-1)) clk_div2 <= 1; end assign clk_out = clk_div1 & clk_div2 ; endmodule
利用时钟的双边沿逻辑,可以对时钟进行半整数的分频。半整数分频的占空比不可能是50%。
例如5.5分频,2.75个周期为高电平,2.75个周期为低电平,不可能实现占空比为50%。
module banzhengshushu_div( input clk_in, input rst_n, output clk_out ); parameter MAX = 11; reg [3:0] cnt; reg clk_div1, clk_div2; always@(posedge clk_in or negedge rst_n)begin if(!rst_n) cnt <= 0; else cnt <= (cnt==MAX-1) ? 0 : cnt+1; end always@(posedge clk_in or negedge rst_n)begin if(!rst_n) clk_div1 <= 0; else if(cnt==0) clk_div1 <= 1; else if(cnt==2) clk_div1 <= 0; else if(cnt==6) clk_div1 <= 1; else if(cnt==8) clk_div1 <= 0; end always@(negedge clk_in or negedge rst_n)begin if(!rst_n) clk_div2 <= 0; else if(cnt==1) clk_div2 <= 1; else if(cnt==3) clk_div2 <= 0; else if(cnt==6) clk_div2 <= 1; else if(cnt==8) clk_div2 <= 0; end assign clk_out = clk_div1 | clk_div2 ; endmodule
画波形图然后写的代码,可以实现接近50%占空比的5.5分频(11个半周期,5个高电平,6个低电平)
先画出目标波形,再调整clk1和clk2。(从计数值1开始画波形比较方便写代码)
下面代码这样写,占空比就不是接近50%,但是是5.5分频
always@(posedge clk_in or negedge rst_n)begin if(!rst_n) clk_div1 <= 0; else if(cnt==0) clk_div1 <= 1; else if(cnt==(MAX+1)/2) clk_div1 <= 1; else clk_div1 <= 0; end always@(negedge clk_in or negedge rst_n)begin if(!rst_n) clk_div2 <= 0; else if(cnt==1) clk_div2 <= 1; else if(cnt==(MAX+1)/2) clk_div2 <= 1; else clk_div2 <= 0; end
8.7分频 :1个目标周期 = 8.7个原周期
相当于 :87个原周期 = 10个目标周期,去计算除有多少个8分频和9分频
module div_M_N( input wire clk_in, input wire rst, output wire clk_out ); parameter M_N = 8'd87; parameter c89 = 8'd24; // 8/9时钟切换点 parameter div_e = 5'd8; //偶数周期 parameter div_o = 5'd9; //奇数周期 reg [6:0]cnt0; //总计数器0-86 reg [3:0]cnt1; //分频计数器 reg flag; //时钟分频切换标志 reg clk_out_r; always@(posedge clk_in or negedge rst)begin if(!rst) cnt0<=0; else cnt0<=(cnt0==M_N-1)? 0 : cnt0+1; end always@(posedge clk_in or negedge rst)begin if(!rst) flag<=0; else flag<=(cnt0==c89-1||cnt0==M_N-1)? ~flag : flag; end //flag=0,八分频,flag=1,九分频 always@(posedge clk_in or negedge rst)begin if(!rst) cnt1<=0; else if(!flag) cnt1<=(cnt1==div_e-1) ? 0 : cnt1+1; else cnt1<=(cnt1==div_o-1) ? 0 : cnt1+1; end always@(posedge clk_in or negedge rst)begin if(!rst) clk_out_r<=0; else if(!flag) clk_out_r<=(cnt1<4) ? 1 : 0; else clk_out_r<=(cnt1<4) ? 1 : 0; end assign clk_out=clk_out_r; endmodule
对于绝大多数的触发器,其实只需要用到时钟的上升沿触发,很少用到下降沿。在这种情况下,只要上升沿和时钟频率有关系,什么时候来下降沿不重要。所以50%的占空比不是必须的。
因此在小数分频器中关注的是得到一个尽量均匀的分频信号,而不是得到一个绝对50%占空比的分频信号。
module jishu_div_testbench (); reg clk_in; reg rst_n; wire clk_out; jishu_div jishu_div_i( .clk_in(clk_in), .rst_n(rst_n), .clk_out(clk_out) ); initial begin clk_in = 0; rst_n = 0; //q = 0; #10; rst_n = 1; end always #5 clk_in = ~clk_in; endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。