Augus

9.菜鸟初入FPGA之任意等分频和倍频

0
阅读(16941)

 1.分频

    分频在 fpga 的设计中一直都担任着很重要的角色,对于分频,我们通常都是利用计算器来计算达到想要的时钟频率,但是我们可以注意到一个问题,我么平时使用的计数器实现的分频只能实现偶数,假如我们需要计数分频呢?本次笔记,我们同样利用计数器来实现任意奇数的分频.我们看一下实现奇数分频的时序图:

    2016-03-30_161326.jpg

从上面的时序图我们可以知道,奇数分频,其实就是通过主时钟信号上沿跟下沿产生一对脉冲信号,然后把两信号相或门就可以得到奇数分频的结果了


下面我们看一下例程:

module Div_clk(clk,rst_n,out_clk);

	input rst_n,clk;
	output out_clk;
	
	parameter N = 7;//N定义几分频
	
	reg out_clk_1;  //由时钟上沿产生的信号
	reg [9:0]cnt_1;//上沿时钟信号产生的计数器
	
	always @(posedge clk or negedge rst_n)
	begin
		if(!rst_n)begin
			cnt_1 <= 1'd0;
			out_clk_1 <= 1'd0;
		end
		else begin
			
			if(cnt_1 <= (( N-1 )/2)-1)//2
				begin
					cnt_1 <= cnt_1 + 1'd1;
					out_clk_1 <= 1'd1;
				end
			else if(cnt_1 <= N-2)
				begin
					cnt_1 <= cnt_1 + 1'd1;
					out_clk_1 <= 1'd0;
				end
			else begin
				cnt_1 <= 1'd0;
				out_clk_1 <= 1'd0;
			end
		end
	end
	
	reg out_clk_0;  //由时钟上沿产生的信号
	reg [9:0]cnt_0;//上沿时钟信号产生的计数器
	
	always @(negedge clk or negedge rst_n)
	begin
		if(!rst_n)begin
			cnt_0 <= 1'd0;
			out_clk_0 <= 1'd0;
		end
		else begin
		   if(cnt_0 <= (( N-1 )/2)-1)
				begin
					cnt_0 <= cnt_0 + 1'd1;
					out_clk_0 <= 1'd1;
				end
			else if(cnt_0 <= N-2 )
				begin
					cnt_0 <= cnt_0 + 1'd1;
					out_clk_0 <= 1'd0;
				end
			else begin
				cnt_0 <= 1'd0;
				out_clk_0 <= 1'd0;
			end
		end
	end
	
	assign out_clk = out_clk_1 | out_clk_0 ;
	
endmodule

  //---------------------  `tb
  `timescale 1ns/1ns
`define clock_period 20
module Div_clk_tb();
	reg clk,rst_n;
	wire out_clk;
	
	initial clk = 1;
	always #(`clock_period/2)clk = ~clk;
	initial begin
		
		rst_n = 0;
		#20;
		rst_n = 1;
		#(`clock_period*50);
		$stop;

	end
	
	Div_clk 
		#(.N(7))
	Div_clk(.clk(clk),.rst_n(rst_n),.out_clk(out_clk));
endmodule	

仿真波形图:

2016-03-30_162825.jpg

从波形图可以看到我们实现奇数分频的等分频

对于偶数也能实现分频,但是非等分

2016-03-30_163304.jpg


备注:有兴趣的可以做一下任意分频的, 即:判断奇偶后进行等分频

  

2.倍频

接下来我们尝试利用 FPGA 的内部的电路延迟,来搭建一个倍频电路(在后仿真的前提下)

当然我们也可以使用计数器实现倍频

2016-03-30_165324.jpg

我们看一下例程:

module Mul_clk(clk,out_clk);

	input clk;
	output out_clk;
	
	reg clk_a,clk_b;
	wire rst_n;
	
	assign out_clk = clk_a | clk_b;
	assign rst_n = ~out_clk;
	
	always @(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			clk_a <= 1'b0;
		else
			clk_a <= 1'b1;
	end
	
	always @(negedge clk or negedge rst_n)
	begin
		if(!rst_n)
			clk_b <= 1'b0;
		else
			clk_b <= 1'b1;
	end
endmodule

 `timescale 1ns/1ns
`define clock_period 20
module Mul_clk_tb();
	reg clk;
	wire out_clk;
	
	initial clk = 1;
	always #(`clock_period/2)clk = ~clk;
	initial begin
		#(`clock_period*50);
		$stop;

	end
	
	Mul_clk Mul_clk(.clk(clk),.out_clk(out_clk));
endmodule


2016-03-30_172010.jpg\