设计之前,我们首先要明白“分频器是什么?为什么要设计分频器?”
在硬件电路设计中时钟信号是最重要的信号之一,而在数字电路中,常需要对较高频率的时钟进行分频操作,得到较低频率的时钟信号,分频器就扮演着这个角色,从而才有了分频器的设计。
那好,理解了分频器的大致原理,我们就从最简单的分频器设计开始,逐步深入、触类旁通,带领你设计出实战项目中所需的每一种分频器,得到你想要的分频器(毕竟需要,才想要,(#^.^#))。
一、2的整数次幂的偶数分频器——2、4、8、16分频器
用VerilogHDL语言完成对时钟信号 CLK 的 2 分频, 4 分频, 8 分频, 16 分频,即:(n为整数)。 这也是最简单的分频电路,只需要一个计数器即可 。
/*2的整数次幂偶数分频器:2、4、8、16分频器*/
module freq_div(clk,rst,clk2,clk4,clk8,clk16);
input rst,clk;
output clk2,clk4,clk8,clk16;
wire clk2,clk4,clk8,clk16; //用"assign"语句赋值的变量,需定义为wire型
reg [3:0] cnt;
always@(posedge clk or posedge rst) //上升沿触发,只有复位才会重置为零的计数器
begin
if(rst==1'b1)
cnt <= 4'b0000;
else
cnt <= cnt+1;
end
assign clk2 = cnt[0]; //取出计数变量cnt的相应位的0、1状态作为本身的0、1状态
assign clk4 = cnt[1];
assign clk8 = cnt[2];
assign clk16 = cnt[3];
endmodule
仿真结果:
二、不为2的整数次幂的偶数分频器——6分频器(10分频、12分频等同理)
对于分频倍数不为(n为整数)的情况,我们只需要对源代码中的计数器进行一下计数控制就可以了,如下代码,用VHDL设计一个对时钟信号进行 6 分频的分频器。
/*不为2的整数次幂的偶数分频器————6分频器*/
module freq_div(clk,rst,clk6);
input rst,clk;
output clk6;
reg clk6;
reg [1:0] cnt;
always@(posedge clk or posedge rst)
begin
if(rst == 1'b1)
begin
cnt <= 2'b00;
clk6 <= 2'b00;
end
else if(cnt == 2) //00 01 10 -- 00 01 10 -- 00 01 10 -- 00 01 10 ···
begin
cnt <= 2'b00;
clk6 <= ~clk6;
end
else cnt<=cnt+1;
end
endmodule
仿真结果:
三、 占空比不为50%的分频器——占空比为2:14的16分频器
在进行硬件设计的时候,往往要求得到一个占空比不是 1:1 的分频信号,这时仍采用计数器的方法来产生占空比不是 1:1 的分频信号。
下面源代码描述的是这样一个分频器:将输入的时钟信号进行 16 分频,分频信号的占空比为 2:14 ,也就是说,其中高电位的脉冲宽度为输入时钟信号的一个周期。
/*占空比不为50%的分频器————2:14占空比16分频器*/
module freq_div(clk,rst, clk2_14);
input clk,rst;
output reg clk2_14;
reg [3:0] cnt;
always@(posedge clk or posedge rst) //上升沿触发,只有复位才会重置为零的计数器
begin
if(rst == 1'b1)
cnt <=4'b0000; //重置计数变量cnt为0
else
cnt <= cnt + 1;
end
always@(posedge clk or posedge rst)
begin
if(rst == 1'b1)
clk2_14 <= 1'b0; //rst重置clk2_14为0(低电平)
else if(cnt ==13 || cnt == 14)
clk2_14 <= 1'b1; //当rst==0、上升沿到来,且cnt已经计数到13或14时,将clk2_14置为1(高电平)
else
clk2_14=1'b0; //当rst==0、上升沿到来,且cnt没有计数到13、14,clk2_14置为0(低电平)
end
endmodule
仿真结果:
四、 奇数分频器——5分频器(3分频、7分频、9分频等同理)
/*奇数分频器——5分频器*/
module freq_div(clk, rst, clk_5);
input clk, rst;
output clk_5;
wire clk_5; //用"assign"语句赋值的变量,需定义为wire型
reg [2:0] cnt_pre, cnt_later;
reg clk_5_pre, clk_5_later;
always@(posedge clk or posedge rst) // 上升沿触发,5进制计数器。范围:000、001、010、011、100
if(rst == 1)
cnt_pre 000 001 010 011 100 --> 001 010 011 100 --> ···
cnt_pre <= 3'b000;
else
cnt_pre <= cnt_pre + 1;
always@(posedge clk or posedge rst) //上升沿触发,占空比为2:3的分频器
if(rst == 1)
clk_5_pre <= 0;
else if(cnt_pre == 3'b000 || cnt_pre == 3'b100) // 在上升沿到来时,计数到000或100之后这样判断为1,才会置为1(高电平)
clk_5_pre <= 1;
else
clk_5_pre =0;
always@(negedge clk or posedge rst) // 下降沿触发,5进制计数器。范围:000、001、010、011、100
if(rst == 1)
cnt_later 000 001 010 011 100 --> 001 010 011 100 --> ···
cnt_later <= 3'b000;
else
cnt_later <= cnt_later + 1;
always@(negedge clk or posedge rst) //下降沿触发,占空比为2:3的分频器
if(rst == 1)
clk_5_later <= 0;
else if(cnt_later == 3'b000 || cnt_later == 3'b100) // 在下降沿到来时,计数到000或100之后这样判断为1,才会置为1(高电平)
clk_5_later <= 1;
else
clk_5_later =0;
assign clk_5 = clk_5_pre | clk_5_later;
endmodule
仿真结果:
作者:Xin~So