Verilog RTL 代码实战 03——奇偶分频

1.偶数分频

所谓分频,就是将时钟的频率分下来,比如50MHZ的时钟,二分频就成了25MHZ的时钟,四分频就成了12.5MHZ的时钟,总而言之,N分频就是把50MHZ的时钟分成N分,我取一份;

那么此处的偶数分频,是最简单的分频。举个例子,以100分频为例,我们需要用100个原始的时钟周期T,作为我们分频后新的时钟周期T1,也就是T1 = 100T;那么时钟的占空比都是50%,所以很明显,在50T的时候翻转时钟就行;

利用计数器可以对原始时钟的周期个数的进行计数,在计数到50T,也就是49的时候,新时钟进行反转,得到100分频时钟;

进而得到规律:实现N分频(N为偶数),只需要在计数到N/2-1时翻转新的时钟信号即可;

下面是一个10分频的代码,因此计数到4时时钟翻转:

module div_10
(
	input		clk,
	input		rst_n,
	output reg 	clk_div
);
//参数
parameter N = 4'd10;

//内部信号
reg [3:0]	cnt;

//功能块
always@(posedge clk or negedge rst_n)begin
	if (!rst_n)begin
		cnt <= 0;
	end
	else if(cnt == N - 1 ) begin
		cnt <= 0;
	end
	else begin
		cnt <= cnt + 1;
	end
end

always@(posedge clk or negedge rst_n)begin
	if (!rst_n) begin
		clk_div <= 0;
	end
	else if (cnt <= (N/2)-1) begin
		clk_div <= 1;
	end
	else begin
		clk_div <= 0;
	end
end

endmodule

测试代码如下;

`timescale 1 ns/1 ns     //时间标尺    时间单位/时间精度

module tb_div_10();

//例化的v模块的输入信号
//输入用reg

reg          clk;
reg          rst_n;


//例化的v模块的输出信号
//输出用wire

wire		clk_div;

//时钟周期,单位为ns

parameter CYCLE    = 20;

//生成本地时钟
initial begin
    clk = 0;
    forever
    #(CYCLE/2)
    clk=~clk;
end

//产生复位信号
initial begin
    rst_n = 1;
    #2;
    rst_n = 0;
    #2
    rst_n = 1;
end

//待测试的模块例化

 div_10 u1
(
	.clk		(clk),
	.rst_n		(rst_n),
	.clk_div	(clk_div)
);

//可能还会有其他输入信号赋值
//此例子没有

endmodule

仿真结果;
在这里插入图片描述

2.奇数分频

奇数分频比偶数分频要复杂一点,奇数分频的翻转点在0.5个时钟处,上升沿并不能检测到此处,因此我们需要用到上升沿计数以及下降沿计数;

一个时钟,然后两个计数器分别采样上升沿和下降沿,然后利用偶数分频的办法,得到两个中间时钟,这两个时钟周期为2N+1,N个周期的高电平,N+1个周期的低电平,然后利用两个中间时钟进行相或操作得到奇数分频

做法:对于一个2N+1分频,用两个计数器分别采样上升沿和下降沿个数,计数到2N+1(代码中是2N,因为计算机从0开始数),用两个计数器产生两个时钟,在N+1和2N+1计数处翻转,得到的两个时钟相或,得出2N+1分频时钟

下面我们做一个5分频设计:此时N=2,代码中在N以及2N处对两个时钟反转,实际是在N+1和2N+1处翻转

module div_5
(
	input		clk,
	input		rst_n,
	output wire	clk_div
);

//参数
parameter		N = 2'd2;	
//内部信号
reg [2:0]		cnt_pose;
reg [2:0]		cnt_nege;
reg			clk_pose;
reg			clk_nege;
//功能块
always@(posedge clk or negedge rst_n)begin     // 对上升沿计数
	if(!rst_n)
		cnt_pose <= 0;
	else if(cnt_pose == 2*N)
		cnt_pose <= 0;
	else
		cnt_pose <= cnt_pose + 1;
end

always@(posedge clk or negedge rst_n)begin  // 中间时钟clk_pose
	if(!rst_n)
		clk_pose<=0;
	else if(cnt_pose == N||cnt_pose == 2*N)
		clk_pose <= ~clk_pose;
	else
		clk_pose <= clk_pose;
end

always@(negedge clk or negedge rst_n)begin     // 对下降沿计数
	if(!rst_n)
		cnt_nege <= 0;
	else if(cnt_nege == 2*N)
		cnt_nege <= 0;
	else
		cnt_nege <= cnt_nege + 1;
end

always@(negedge clk or negedge rst_n)begin  // 中间时钟clk_nege
	if(!rst_n)
		clk_nege <= 0;
	else if(cnt_nege == N||cnt_nege == 2*N)
		clk_nege <= ~clk_nege;
	else
		clk_nege <= clk_nege;
end
	
assign clk_div = clk_pose|clk_nege;		   // 2N+1分频时钟输出

endmodule

测试文件:

`timescale 1 ns/1 ns     //时间标尺    时间单位/时间精度

module tb_div_5();

//例化的v模块的输入信号
//输入用reg

reg          clk;
reg          rst_n;


//例化的v模块的输出信号
//输出用wire

wire		clk_div;

//时钟周期,单位为ns

parameter CYCLE    = 20;

//生成本地时钟
initial begin
    clk = 0;
    forever
    #(CYCLE/2)
    clk=~clk;
end

//产生复位信号
initial begin
    rst_n = 1;
    #2;
    rst_n = 0;
    #2
    rst_n = 1;
end

//待测试的模块例化

 div_5 u1
(
	.clk		(clk),
	.rst_n		(rst_n),
	.clk_div	(clk_div)
);

//可能还会有其他输入信号赋值
//此例子没有

endmodule

仿真结果:
在这里插入图片描述

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值