08_分频器

本文介绍了如何设计和实现偶数与奇数分频器,包括理论基础、实验目标以及两种不同的实现方法。在RTL层面,展示了偶数分频器和奇数分频器的Verilog代码实现,同时提供了对应的testbench用于验证设计的正确性。
摘要由CSDN通过智能技术生成

1. 理论学习

在这里插入图片描述
例子:
50MHZ 变成 25MHZ 。50MHZ一个的时钟周期为20ns,而25MHZ一个的时钟周期为40ns,则要用50MHZ 产生 25MHZ的频率就需要使用计数器。 40/20 = 2 。则 2 个 50MHZ的时钟周期,产生一个25MHZ的时钟周期。这里需要 计数器数到 2 进行操作,从而进行分频的操作。

2. 实验目标

分频器分为偶数分频器和奇数分频器

3. 波形图绘制

3.1 偶数分频器

3.1.1 方法 1 实现:仅实现分频功能

在这里插入图片描述

3.1.2 方法 2 实现:实用的降频方法

在这里插入图片描述

3.2 奇数分频器

3.2.1 方法 1 实现:仅实现分频功能

在这里插入图片描述

3.2.2 方法 2 实现:实用的降频方法

在这里插入图片描述

4. RTL

4.1 偶数分频器

module divider_six
// 端口的定义
(
	input   wire  sys_clk, //系统时钟 50Mh  
                           //根据频率的转换 一个时钟周期20ns 0.5s 就是 25_000_000
	input   wire  sys_rst_n,
	
	output  reg   flag_out //对系统时钟 6 分频后的信号
);
/*
//---------------方法 1 实现:仅实现分频功能---------------
reg [3:0] cnt; // 定义计数器
//cnt:计数器从 0 到 2 循环计数
always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(sys_rst_n == 1'b0)
			begin
				cnt <= 4'd0;
			end
		else if(cnt == 4'd2)
			begin
				cnt <= 4'd0;
			end
		else
			begin
				cnt <= cnt + 4'd1;
			end
	end
//clk_out:6 分频 50%占空比输出
always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(sys_rst_n == 1'b0)
			begin
				clk_out <= 1'b0;
			end
		else if(cnt == 4'd2)
			begin
				clk_out <= ~clk_out;
			end
	end
*/
//---------------方法 2 实现:实用的降频方法---------------
reg [3:0] cnt; // 定义计数器

//cnt:计数器从 0 到 2 循环计数
always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(sys_rst_n == 1'b0)
			begin
				cnt <= 4'd0;
			end
		else if(cnt == 4'd5)
			begin
				cnt <= 4'd0;
			end
		else
			begin
				cnt <= cnt + 4'd1;
			end
	end
//clk_out:6 分频 50%占空比输出
always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(sys_rst_n == 1'b0)
			begin
				flag_out <= 1'b0;
			end
		else if(cnt == 4'd4)
			begin
				flag_out <= 1'b1;
			end
		else
			begin
				flag_out <= 1'b0;
			end
	end


endmodule




4.2 奇数分频器

module divider_five
// 端口的定义
(
	input   wire  sys_clk, //系统时钟 50Mh  
                           //根据频率的转换 一个时钟周期20ns 0.5s 就是 25_000_000
	input   wire  sys_rst_n,
	
	output  wire  clk_out //对系统时钟 5 分频后的信号
);

reg [3:0] cnt; // 定义计数器
reg       clk1;
reg       clk2;

//cnt:上升沿开始从 0 到 4 循环计数
always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(sys_rst_n == 1'b0)
			begin
				cnt <= 4'd0;
			end
		else if(cnt == 4'd4)
			begin
				cnt <= 4'd0;
			end
		else
			begin
				cnt <= cnt + 4'd1;
			end
	end
///clk1:上升沿触发,占空比高电平维持 2 个系统时钟周期,低电平维持 3 个系统时钟周期
always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(sys_rst_n == 1'b0)
			begin
				clk1 <= 1'b1;
			end
		else if(cnt == 4'd2)
			begin
				clk1 <= 1'b0;
			end
		else if(cnt == 4'd4)
			begin
				clk1 <= 1'b1;
			end
	end

//clk1:上升沿触发,占空比高电平维持 2 个系统时钟周期,低电平维持 3 个系统时钟周期
always@(negedge sys_clk or negedge sys_rst_n)
	begin
		if(sys_rst_n == 1'b0)
			begin
				clk2 <= 1'b1;
			end
		else if(cnt == 4'd2)
			begin
				clk2 <= 1'b0;
			end
		else if(cnt == 4'd4)
			begin
				clk2 <= 1'b1;
			end
	end
clk_out:5 分频 50%占空比输出

assign clk_out = clk1 & clk2;


endmodule




5. testbench

5.1 偶分频器

`timescale 1ns/1ns
// 在这里面不需要对端口进行定义
module tb_divider_six();

//因为 testbench 不对外进行信号的输入输出,只是自己产生
//激励信号提供给内部实例化待测 RTL 模块使用,所以端口列表
//中没有内容,只是列出“()”,当然可以将“()”省略,括号
//后有个“;”不要忘记
//要在 initial 块和 always 块中被赋值的变量一定要是 reg 型
//在 testbench 中待测试 RTL 模块的输入永远是 reg 型变量


 //输出信号,我们直接观察,也不用在任何地方进行赋值
 //所以是 wire 型变量(在 testbench 中待测试 RTL 模块的输出永远是 wire 型变量)

reg sys_clk;
reg sys_rst_n;

 //输出信号,我们直接观察,也不用在任何地方进行赋值
 //所以是 wire 型变量(在 testbench 中待测试 RTL 模块的输出永远是 wire 型变量)
wire flag_out;

//初始化值在没有特殊要求的情况下给 0 或 1 都可以。如果不赋初值,仿真时信号
//会显示为不定态(ModelSim 中的波形显示红色)

initial
//initial 只在通电执行一次
//在仿真中 begin...end 块中的内容都是顺序执行的,
//在没有延时的情况下几乎没有差别,看上去是同时执行的,
//如果有延时才能表达的比较明了;
//而在 rtl 代码中 begin...end 相当于括号的作用, begin...end 在 Testbench 中的用法及意义(区别   -----------------------------------------------------)
//在同一个 always 块中给多个变量赋值的时候要加上
	begin 
		sys_clk = 1'b1; //时钟信号的初始化为 1,且使用“=”赋值,
                        //其他信号的赋值都是用“<=”
		sys_rst_n <= 1'b0; //因为低电平复位,所以复位信号的初始化为 0
		#20 //延时20ns
		sys_rst_n <= 1'b1; //初始化 20ns 后,复位释放,因为是低电平复位	
	end
// always语句 一直在执行
sys_clk:模拟系统时钟,每 10ns 电平翻转一次,周期为 20ns,频率为 50Mhz
always #10 sys_clk = ~sys_clk;//取模求余数,产生随机数 1'b0、1'b1//每隔 10ns 产生一次随机数
//key_in:产生输入随机数,模拟按键的输入情况

//下面的语句是为了在 ModelSim 仿真中直接打印出来信息便于观察信号变化的状态
//也可以不使用下面的语句而直接观察仿真出的波形

//------------------------------------------------------------
//待测试 RTL 模块的实例化,相当于将待测试模块放到测试模块中,并将输入输出对应连接上
//测试模块中产生激励信号给待测试模块的输入,以观察待测试模块的输出信号是否正确
//------------------------------------------------

divider_six divider_six_inst
(
	//前面的“in1”表示被实例化模块中的信号,后面的“in1”表示实例化该模块并要和这个
	//模块的该信号相连接的信号(可以取名不同,一般取名相同,方便连接和观察)
	//“.”可以理解为将这两个信号连接在一起
	.sys_clk(sys_clk),
	.sys_rst_n(sys_rst_n), 

	.flag_out(flag_out)
);

endmodule						 

5.2 奇分频器

`timescale 1ns/1ns
// 在这里面不需要对端口进行定义
module tb_divider_five();

//因为 testbench 不对外进行信号的输入输出,只是自己产生
//激励信号提供给内部实例化待测 RTL 模块使用,所以端口列表
//中没有内容,只是列出“()”,当然可以将“()”省略,括号
//后有个“;”不要忘记
//要在 initial 块和 always 块中被赋值的变量一定要是 reg 型
//在 testbench 中待测试 RTL 模块的输入永远是 reg 型变量


 //输出信号,我们直接观察,也不用在任何地方进行赋值
 //所以是 wire 型变量(在 testbench 中待测试 RTL 模块的输出永远是 wire 型变量)

reg sys_clk;
reg sys_rst_n;

 //输出信号,我们直接观察,也不用在任何地方进行赋值
 //所以是 wire 型变量(在 testbench 中待测试 RTL 模块的输出永远是 wire 型变量)
wire clk_out;

//初始化值在没有特殊要求的情况下给 0 或 1 都可以。如果不赋初值,仿真时信号
//会显示为不定态(ModelSim 中的波形显示红色)

initial
//initial 只在通电执行一次
//在仿真中 begin...end 块中的内容都是顺序执行的,
//在没有延时的情况下几乎没有差别,看上去是同时执行的,
//如果有延时才能表达的比较明了;
//而在 rtl 代码中 begin...end 相当于括号的作用, begin...end 在 Testbench 中的用法及意义(区别   -----------------------------------------------------)
//在同一个 always 块中给多个变量赋值的时候要加上
	begin 
		sys_clk = 1'b1; //时钟信号的初始化为 1,且使用“=”赋值,
                        //其他信号的赋值都是用“<=”
		sys_rst_n <= 1'b0; //因为低电平复位,所以复位信号的初始化为 0
		#20 //延时20ns
		sys_rst_n <= 1'b1; //初始化 20ns 后,复位释放,因为是低电平复位	
	end
// always语句 一直在执行
sys_clk:模拟系统时钟,每 10ns 电平翻转一次,周期为 20ns,频率为 50Mhz
always #10 sys_clk = ~sys_clk;//取模求余数,产生随机数 1'b0、1'b1//每隔 10ns 产生一次随机数
//key_in:产生输入随机数,模拟按键的输入情况

//下面的语句是为了在 ModelSim 仿真中直接打印出来信息便于观察信号变化的状态
//也可以不使用下面的语句而直接观察仿真出的波形

//------------------------------------------------------------
//待测试 RTL 模块的实例化,相当于将待测试模块放到测试模块中,并将输入输出对应连接上
//测试模块中产生激励信号给待测试模块的输入,以观察待测试模块的输出信号是否正确
//------------------------------------------------

divider_five divider_five_inst
(
	//前面的“in1”表示被实例化模块中的信号,后面的“in1”表示实例化该模块并要和这个
	//模块的该信号相连接的信号(可以取名不同,一般取名相同,方便连接和观察)
	//“.”可以理解为将这两个信号连接在一起
	.sys_clk(sys_clk),
	.sys_rst_n(sys_rst_n), 

	.clk_out(clk_out)
);

endmodule						 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@大宁字

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值