FPGA学习笔记(2)——分频器(任意偶分频、任意奇分频)

偶数次分频(占空比50%)

工作原理:

要实现2n分频,使用一个计数器计数到n-1时,输出信号电平翻转。

例:系统时钟50MHz,需要10k的时钟输出。

需要对系统时钟进行5000分频,计数器计数到2499,out信号翻转,即可实现out为10k。

RTL:

module divider_even
#(parameter	even_number = 'd5000)
(
	input	wire		clk  ,
	input	wire		rst_n,

	output	reg		clkt 
);
	reg[11:0]	cnt;
//counter to even_number-1	
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		cnt <= 12'd0;
	else if(cnt == even_number/2-1)
		cnt <= 12'd0;
	else
		cnt <= cnt + 1'b1;
end

//clkt logic
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		clkt <= 1'b0;
	else if(cnt == even_number/2-1)
		clkt <= ~clkt;
	else
		clkt <= clkt;
end
endmodule

Tb:

`timescale 1ns/1ns
`define	clk_period 20
module tb();
reg	clk  ;
reg	rst_n;
wire	clkt ;
initial
begin
	clk  <= 1'b0;
	rst_n<= 1'b0;
	#50
	rst_n<= 1'b1;
	#1000
	$stop;
end
always #(`clk_period/2) clk <= ~clk;

divider_even
#(.even_number(10))
u1
(
	.clk  (clk  ),
	.rst_n(rst_n),
         
	.clkt (clkt )
);
endmodule

Modelsim仿真实现10分频

图1

Quartus综合后的电路

图2

奇数次分频(占空比50%)

原理:

要实现2n+1分频,使用计数器在计数到n和2n时,分别在系统时钟上升沿和下降沿翻转得到两个生成时钟,再将两个时钟做与/或运算,得到分频后的时钟。

例:系统时钟50MHz,需要400k的时钟输出。

需要对系统时钟进行125分频,计数器计数到62,clk1在上升沿翻转,clk2在下降沿翻转,当计数值满时(即124)clk1、clk2再次翻转,将clk1、clk2进行与运算得到400k时钟。

RTL:

module divider_odd
#(parameter	odd_number =7'd125)
(
	input	clk  ,
	input	rst_n,

	output	clkt 
);
	reg[6:0]	cnt;
	reg		clk1;
	reg		clk2;

always@(posedge clk or negedge rst_n) begin
	if(!rst_n)
		cnt <= 'b0;
	else if(cnt == odd_number-1)
		cnt <= 'b0;
	else 
		cnt <= cnt + 1'b1 ;
end
always@(posedge clk or negedge rst_n) begin
	if(!rst_n)
		clk1 <= 'b0;
	else if(cnt == odd_number-1 || cnt == (odd_number-1)/2)
		clk1 <= ~clk1;
	else
		clk1 <= clk1;
end

always@(negedge clk or negedge rst_n) begin
	if(!rst_n)
		clk2 <= 'b0;
	else if(cnt == odd_number-1 || cnt ==  (odd_number-1)/2)
		clk2 <= ~clk2;
	else
		clk2 <= clk2;
end

assign	clkt = clk1||clk2 ;

endmodule 

Tb:

`timescale 1ns/1ns
`define clk_period 20
module tb();
reg	clk;
reg	rst_n;
wire	clkt;
initial
begin
	clk   <= 1'b0 ;
	rst_n <= 1'b0 ;
	#50
	rst_n <= 1'b1;
	#2000
	$stop;
end
always #(`clk_period/2) clk <= ~clk;

divider_odd
#(	.odd_number(9))
u1
(
	.clk  (clk  ),
	.rst_n(rst_n),
                    
	.clkt (clkt )
);
endmodule

modelsim仿真实现9分频

图3

图4

疑惑一:信号赋值时,一个always块中对多个变量赋值和分开赋值一样吗?

综合出来的电路结构是一样的,见图2.

第一种:在同一个always块中赋值

always@(posedge clk or negedge rst_n)

begin

    if(!rst_n)begin

       cnt <= 12'd0;

       clkt <= 1'b0;end

       else if(cnt == even_number/2-1)begin

       cnt <= 12'd0;

       clkt <= ~clkt;end

       else begin

       cnt <= cnt + 1'b1;clkt <= clkt;end

end

第二种:分别在两个always块中赋值

//counter to even_number-1 

always@(posedge clk or negedge rst_n)

begin

    if(!rst_n)

       cnt <= 12'd0;

    else if(cnt == even_number/2-1)

       cnt <= 12'd0;

    else

       cnt <= cnt + 1'b1;

end

//clkt logic

always@(posedge clk or negedge rst_n)

begin

    if(!rst_n)

       clkt <= 1'b0;

    else if(cnt == even_number/2-1)

       clkt <= ~clkt;

    else

       clkt <= clkt;

end

疑惑二:如果clk不用时序逻辑,会有什么影响?

assign clkt = (cnt == even_number/2-1)?(~clkt):clkt;

综合之后产生Latch,因为在组合逻辑中赋值给自己会产生latch;

产生latch的情况参考:

verilog代码中避免出现latch方法_Jimbo_Zhang的博客-CSDN博客_verilog如何避免latch

图5

仿真出错

图6

踩坑1:quartus中配置仿真文件时(图5),不能带 .v,否则会出现:

Error:Failed to access library 'tb_divider_even' at "tb_divider_even".

图7

踩坑2:文件名(xx.v)要与模块名字(module xx)相同,否则modelsim无法运行。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值