verilog手撕代码1——分频计数器——偶数、奇数、半整数、任意小数分频
文章目录
- 前言
- 一、偶数分频
- 1、使用D触发器设计一个同时输出2/4/8分频的50%占空比的时钟分频器
- 2、用D触发器带同步高置数和异步高复位端的二分频的电路,画出逻辑电路
- 3、输入频率10MHz,输出频率1MHz,进行分频
- 二、奇数分频
- 1、不要求占空比为50%
- 2、要求占空比接近50%
- 2.1 法一:上升沿和下降沿都计数
- 2.2 法二:上升沿下降沿分开计数再组合逻辑输出
- 三、小数分频
- 1、半整数分频
- 2、任意小数分频
- 四、总结
- 五、testbench
前言
2023.4.8
一、偶数分频
1、使用D触发器设计一个同时输出2/4/8分频的50%占空比的时钟分频器

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;elseclk_out2_r <= ~clk_out2_r;end//四分频是以二分频为时钟,就可以在上升沿的时候四分频也是从0跳转到1//使得二四八分频同时为高电平always@(posedge clk_out2 or negedge rst) begin if(~rst)clk_out4_r <= 0;elseclk_out4_r <= ~clk_out4_r;endalways@(posedge clk_out4 or negedge rst) beginif(~rst)clk_out8_r <= 0;elseclk_out8_r <= ~clk_out8_r;endassign clk_out2 = clk_out2_r;assign clk_out4 = clk_out4_r;assign clk_out8 = clk_out8_r;
endmodule

2、用D触发器带同步高置数和异步高复位端的二分频的电路,画出逻辑电路

reg q;
always@(posedge clk or posedge rst)beginif(rst)q <= 0;else if(set)q <= 1;elseq <= ~q;
end
3、输入频率10MHz,输出频率1MHz,进行分频
分频系数:10,偶数分频,用计数器来实现
reg [3:0] cnt;
parameter CNT_DIV = 5, CNT_MAX = 10;always@(posedge clk or negedge rst_n)beginif(!rst_n)cnt <= 0;else cnt <= (cnt==CNT_MAX-1) ? 0 : cnt+1; //注意计数器最大值为9,不能为10,为10的话下个周期会有问题
endalways@(posedge clk or negedge rst_n)beginif(!rst_n)q <= 0;else if(cnt<CNT_DIV)q <= 1;elseq <= 0;
end

二、奇数分频
1、不要求占空比为50%
原理和偶数分频一样,只不过由于是奇数个周期,可以决定高低电平的占比。例如三分频,占空比可以为1/3或者2/3

//下面是5分频
reg [2:0]cnt;
reg clk_out5_r;always@(posedge clk_in or negedge rst)beginif(!rst)clk_out5_r<=0;else if(cnt==0||cnt==2)clk_out5_r<=~clk_out5_r;else clk_out5_r<=clk_out5_r;
endalways@(posedge clk_in or negedge rst)beginif(!rst)cnt<=0;elsecnt<=(cnt==4)?0:cnt+1;
end

2、要求占空比接近50%
2.1 法一:上升沿和下降沿都计数
这种写法应该要避免,无法综合,前面学习verilog语法的时候说过,混合使用上升沿和下降沿触发的触发器。
parameter MAX = 7;
always@(posedge clk_in or negedge clk_in)beginif(!rst)begincnt<=0;clk_out7_r<=0;endelse if(cnt==MAX-1)begincnt<=0;clk_out7_r<=~clk_out7_r;endelsecnt<=cnt+1;
end
2.2 法二:上升沿下降沿分开计数再组合逻辑输出
如果奇数分频输出时钟的高低电平只差一个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;elsecnt <= (cnt==MAX-1) ? 0 : cnt+1;endalways@(posedge clk_in or negedge rst_n)beginif(!rst_n)clk_div1 <= 0;else if(cnt<(MAX-1)/2)clk_div1 <= 1;elseclk_div1 <= 0;end always@(negedge clk_in or negedge rst_n)beginif(!rst_n)clk_div2 <= 0;else if(cnt<(MAX-1)/2)clk_div2 <= 1;elseclk_div2 <= 0;end assign clk_out = clk_div1 | clk_div2 ;
endmodule

always@(posedge clk_in or negedge rst_n)beginif(!rst_n)cnt <= 0;elsecnt <= (cnt==MAX-1) ? 0 : cnt+1;endalways@(posedge clk_in or negedge rst_n)beginif(!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)beginif(!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

三、小数分频
1、半整数分频
利用时钟的双边沿逻辑,可以对时钟进行半整数的分频。半整数分频的占空比不可能是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)beginif(!rst_n)cnt <= 0;elsecnt <= (cnt==MAX-1) ? 0 : cnt+1;endalways@(posedge clk_in or negedge rst_n)beginif(!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)beginif(!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)beginif(!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)beginif(!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

2、任意小数分频
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-86reg [3:0]cnt1; //分频计数器reg flag; //时钟分频切换标志reg clk_out_r;always@(posedge clk_in or negedge rst)beginif(!rst)cnt0<=0;elsecnt0<=(cnt0==M_N-1)? 0 : cnt0+1;endalways@(posedge clk_in or negedge rst)beginif(!rst)flag<=0;elseflag<=(cnt0==c89-1||cnt0==M_N-1)? ~flag : flag;end//flag=0,八分频,flag=1,九分频always@(posedge clk_in or negedge rst)beginif(!rst)cnt1<=0;else if(!flag)cnt1<=(cnt1==div_e-1) ? 0 : cnt1+1;elsecnt1<=(cnt1==div_o-1) ? 0 : cnt1+1; endalways@(posedge clk_in or negedge rst)beginif(!rst)clk_out_r<=0;else if(!flag)clk_out_r<=(cnt1<4) ? 1 : 0;elseclk_out_r<=(cnt1<4) ? 1 : 0; endassign clk_out=clk_out_r;
endmodule

四、总结
对于绝大多数的触发器,其实只需要用到时钟的上升沿触发,很少用到下降沿。在这种情况下,只要上升沿和时钟频率有关系,什么时候来下降沿不重要。所以50%的占空比不是必须的。
因此在小数分频器中关注的是得到一个尽量均匀的分频信号,而不是得到一个绝对50%占空比的分频信号。
五、testbench
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 beginclk_in = 0;rst_n = 0;//q = 0;#10;rst_n = 1;endalways #5 clk_in = ~clk_in;
endmodule
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
