偶分频和奇分频 FPGA verilog 基础练习4

本文详细介绍了在FPGAVerilog中实现偶数和奇数分频的两种方法,通过实例演示了计数器的应用,强调了清零和递增条件的重要性。同时讨论了降频方案和如何利用上升沿和下降沿设计2.5个时钟周期的分频器。
摘要由CSDN通过智能技术生成

偶分频和奇分频 FPGA verilog 基础练习4

发现问题,用技术解决问题。兴趣是自己的源动力 !

前言

分频器的练习就是计数器的一个应用分支,用设立来检验自己对计数器的使用使用熟练。真实上板代码,都是使用IP核来进行的。核心的点就是要明白计数器使用的两个关键:

  • 清零条件
  • 递增条件

一、偶数分频

1.1 分频方案

偶数分频,计数器具有对称性,如果要实现6分频,则计数器只需要计数3个周期即可,即0~2,然后对输出取反。

1.1.1 功能代码

module divider_six
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位

output reg clk_out //对系统时钟6分频后的信号

);

 reg [1:0] cnt; //用于计数的寄存器

 //cnt:计数器从0到2循环计数
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 cnt <= 2'b0;
 else if(cnt == 2'd2)
 cnt <= 2'b0;
 else
 cnt <= cnt + 1'b1;

 //clk_out:6分频50%占空比输出
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 clk_out <= 1'b0;
 else if(cnt == 2'd2)
 clk_out <= ~clk_out;

 endmodule

1.1.2 仿真代码

module tb_top();

reg sys_clk;
reg sys_rst_n;

wire clk_out;

//初始化系统时钟、全局复位
 initial begin
 sys_clk = 1'b1;
 sys_rst_n <= 1'b0;
 #20
 sys_rst_n <= 1'b1;
 end

 //sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
 always #10 sys_clk = ~sys_clk;

 //--------------------divider_sixht_inst--------------------
 divider_six divider_six_inst
 (
 .sys_clk (sys_clk ), //input sys_clk
 .sys_rst_n (sys_rst_n ), //input sys_rst_n

 .clk_out (clk_out ) //output clk_out

 );

 endmodule

1.1.3 仿真结果

在这里插入图片描述

1.2 降频方案

为什么需要降频呢,因为你分频后的时钟其实一般不直接使用的,一般是使用全局时钟网络的时钟,这其实和时钟的布局布线有关(为了时钟到达所有的节点的时间几乎一样)。

1.2.1 功能代码

就是使用系统时钟来输出一个flag信号,这个flag信号的输出就是分频后的输出,且占空比不是50%。注意flag。这里的代码需要注意计数器的清零条件和递增条件。(代码中有注释)

module divider_six
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位

output reg clk_flag //指示系统时钟6分频后的脉冲标志信号

);

 reg [2:0] cnt; //用于计数的寄存器

 //cnt:计数器从0到5循环计数
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 cnt <= 3'b0;
 else if(cnt == 3'd5)
 cnt <= 3'b0;
 else
 cnt <= cnt + 1'b1;

 //clk_flag:脉冲信号指示6分频
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 clk_flag <= 1'b0;
 else if(cnt == 3'd4)  // 注意:这里是4,不是5,因为flag会延迟一拍被时钟采样
 clk_flag <= 1'b1;
 else
 clk_flag <= 1'b0;

 endmodule

1.2.2 tb代码

`timescale 1ns/1ns
module tb_top();

reg sys_clk;
reg sys_rst_n;

wire clk_out;

//初始化系统时钟、全局复位
 initial begin
 sys_clk = 1'b1;
 sys_rst_n <= 1'b0;
 #20
 sys_rst_n <= 1'b1;
 end

 //sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
 always #10 sys_clk = ~sys_clk;

 //-----------------------divider_five_inst------------------------
 divider_five divider_five_inst
 (
 .sys_clk (sys_clk ), //input sys_clk
 .sys_rst_n (sys_rst_n ), //input sys_rst_n

 .clk_flag (clk_out ) //output clk_out

 );

 endmodule

1.2.3 仿真结果

在这里插入图片描述

二、奇数分频

实现一个5分频的方法。如果占空比不要求50%,则很好设计,如下图。(这种使用降频的方法就不展示了,参照偶数分频)
在这里插入图片描述但是,如果占空比要求50%,5分频那就是,2.5个时钟周期一个高电平,2.5个时钟周期一个低电平。

因此如何实现2.5个时钟周期呢?这就是要学习的地方了

  • 使用时钟的上升沿和下降沿。

2.1 分频方案

可以看下图去理解。
在这里插入图片描述

理解:要在一个5clk,里面实现两个2.5clk的高电平和2.5clk的低电平。实现2.5clk,本质就是利用上升沿和下降沿的时间差0.5clk。

2.1.1 分频代码

	

module divider_five
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位

output wire clk_out //对系统时钟5分频后的信号

);

 reg [2:0] cnt;
 reg clk1;
 reg clk2;

 //cnt:上升沿开始从0到4循环计数
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 cnt <= 3'b0;
 else if(cnt == 3'd4)
 cnt <= 3'b0;
 else
 cnt <= cnt + 1'b1;

// 因为是分频5个clk,如何实现2.5个clk呢?可以这里理解 2.5 = 2+0.5,只需要实现两个时钟相加就可以了
 //clk1:上升沿触发,这里先实现一个 2 clk 的低电平,3clk的高电频
 always@(posedge sys_clk or negedge sys_rst_n) begin
	if(sys_rst_n == 1'b0)
		clk1 <= 1'b1;
	else if(cnt == 3'd2)
		clk1 <= 1'b0;
	else if(cnt == 3'd4)
		clk1 <= 1'b1;
	else
		clk1 <= clk1;
 end
 //clk2:下降沿触发,这里先实现一个 2 clk 的低电平,注意是下下降沿,因为要和上升沿错开,获得一个0.5 clk周期
 always@(negedge sys_clk or negedge sys_rst_n) begin
	if(sys_rst_n == 1'b0)
		clk2 <= 1'b1;
	else if(cnt == 3'd2)
		clk2 <= 1'b0;
	else if(cnt == 3'd4)
		clk2 <= 1'b1;
	else
		clk2 <= clk2;
 end	
 
 //clk_out:5分频50%占空比输出
 assign clk_out = clk1 & clk2;

 endmodule

2.1.2 tb代码

`timescale 1ns/1ns
module tb_top();

reg sys_clk;
reg sys_rst_n;

wire clk_out;

//初始化系统时钟、全局复位
 initial begin
 sys_clk = 1'b1;
 sys_rst_n <= 1'b0;
 #20
 sys_rst_n <= 1'b1;
 end

 //sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
 always #10 sys_clk = ~sys_clk;

 //-----------------------divider_five_inst------------------------
 divider_five divider_five_inst
 (
 .sys_clk (sys_clk ), //input sys_clk
 .sys_rst_n (sys_rst_n ), //input sys_rst_n

 .clk_out (clk_out ) //output clk_out

 );

 endmodule

2.1.3 仿真结果

4ca46f070a458d86e32bd1f16aa909.png)

小结:实现2.5个时钟周期,核心只需要记住一点:上升沿和下降沿之间,就是差了0.5个周期,抓住这个点,其他的设计就只需要注意清零条件和拉高条件即可

总结

  • 核心思想:明白如何使用计数器来实现特定的功能,主要是对计数器练习的一个目的
  • 知识点总结:
    1. 如何使用奇分频和偶分频:要点是计数器的清零条件
    2. 全局时钟的理解
    3. 如何产生一个0.5clk
  • 欢迎一起交流学习,如有错误之处,还请各位指正。

参考资料

[1] FPGA系列教学

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值