基于Verilog的偶数、奇数、半整数分频以及任意分频器设计

在FPGA的学习过程中,最简单最基本的实验应该就是分频器了。由于FPGA的晶振频率都是固定值,只能产生固定频率的时序信号,但是实际工程中我们需要各种各样不同频率的信号,这时候就需要对晶振产生的频率进行分频。比如如果FPGA芯片晶振的频率为50MHz,而我们希望得到1MHz的方波信号,那么就需要对晶振产生的信号进行50分频。

分频器的设计虽然是FPGA学习过程中最简单的实验,但是真正想要把分频器的来龙去脉弄清楚,还是需要花费一番功夫的。下面先介绍一下最常见的几种分频器写法:

1.偶数分频器

相信大多数朋友在学习FPGA过程中接触到的第一个实验应该就是偶数分频器了,偶数分频器的设计较为简单,用一个简单的计数器就可以实现。比如要实现一个N分频(N为偶数)的分频器,可以先写一个计数器,当计数到(N/2-1)时,让输出状态翻转,并将计数器清零,这样输出的信号就是输入时钟的N分频了。具体代码如下:

偶数分频器示例,20分频即N=20,占空比50%

module clk_div(clk_out, clk, rst_n);

input clk, rst_n;
output clk_out;

reg clk_out;
reg [4:0] cnt;

always @(posedge clk or negedge rst_n)
if(!rst_n)
    begin
    cnt <= 5‘b0;
    clk_out <= 1‘b0;
    end
else if(cnt == 4‘d9)
    begin
    cnt <= 5‘b0;
    clk_out <= ~clk_out;
    end
else cnt <= cnt + 1‘b1;

endmodule
 
2.奇数分频器
 

奇数分频器的设计比偶数分频器复杂一些,特别是占空比为50%的奇数分频器。如果对占空比没有明确的要求,则可以直接对上升沿计数,计数到(N-1)/2 时让输出翻转,计数到(N-1)时让输出状态再次翻转,并将计数器清零,这样就可以得到一个占空比为2:3的N分频(N为奇数)的分频器。而如果要实现50%的占空比,可以通过“错位相或”的方法实现。具体方法是用刚才的方法先通过对上升沿计数产生一个占空比为不是50%的N分频器,再用同样的方法对下降沿计数产生一个占空比也不是50%的N分频器,最后将这两个分频器的输出进行“或”运算,就可以得到占空比为50%的奇数N分频器,具体实现代码如下:

 
奇数分频器示例,5分频,占空比50%
module div_odd(clk_out, clk, rst_n);

input clk, rst_n;
output clk_out;

reg clk_p, clk_n;
reg [4:0] cnt1, cnt2;  //注意根据实际需要调整位宽

parameter N = 5;  //此处N可以设为任意奇数

//用上升沿产生非50%占空比的分频信号clk_p
always @(posedge clk or negedge rst_n)
if(!rst_n)
    begin
    cnt1 <= 0;
    clk_p <= 0;
    end
else if(cnt1 == 5‘b10)        //cnt_p == (N-1)/2,翻转
    begin
    cnt1 <= cnt1 + 1‘b1;
    clk_p <= ~clk_p;
    end
else if(cnt1 == 5‘b100)        //cnt_p == N-1,翻转
    begin
    cnt1 <= 1‘b0;
    clk_p <= ~clk_p;
    end
else cnt1 <= cnt1 +1‘b1;

//用下降沿产生非50%占空比的分频信号clk_n
always @(negedge clk or negedge rst_n)
if(!rst_n)
    begin
    cnt2 <= 0;
    clk_n <= 0;
    end
else if(cnt2 == 5‘b10)        //cnt_n == (N-1)/2,翻转
    begin
    cnt2 <= cnt2 + 1‘b1;
    clk_n <= ~clk_n;
    end
else if(cnt2 == 5‘b100)        //cnt_n == N-1,翻转
    begin
    cnt2 <= 1‘b0;
    clk_n <= ~clk_n;
    end
else cnt2 <= cnt2 +1‘b1;

//相与运算,得到50%占空比的分频信号
assign clk_out = clk_p | clk_n;

endmodule
3.半分频器(N+0.5分频)
   在实际工程中,我们还经常会遇到半分频器。比如要得到2MHz的时钟信号,而系统晶振频率为25MHz,这时候就需要对系统时钟作12.5分频。那么这种半分频器又该如何实现呢?最直接的办法当然还是用计数器了,由于半整数分频无法实现50%的占空比(因为50%占空比就要求一个周期内高低电平都是6.25个系统时钟周期,这个0.25是不可能实现的),我们只能让占空比尽可能接近50%。以12.5分频为例,可以对系统时钟计数,在前6.5个周期输出低电平,后6个周期输出高电平,依次循环,就可以实现12.5分频,占空比为(6.5/12.5),接近50%。在计数时涉及到0.5个周期,因此对上升沿和下降沿都要计数。具体代码如下:
 
半分频器,以12.5分频为例,占空比(6.5/12.5)
module clk_half(clk_out, clk1, clk, rst_n);

input clk,rst_n;
output clk_out,clk1;

parameter N = 13; //以12.5分频为例,N=13

wire clk1;
reg clk_out;
reg[4:0] cnt;
reg flag = 1‘b0;

//系统时钟clk计数器
always @(negedge clk or negedge rst_n)
if(!rst_n) flag <= 1‘b0;
else if(cnt == 5‘d6) flag <= ~flag;

//在第五个时钟结束后立即将 clk1 状态翻转
assign clk1 = (flag)? ~clk:clk;

//时钟 clk1 计数器,模为N
always @(posedge clk1 or negedge rst_n)
if(!rst_n) cnt <= 5‘b0;
else if(cnt == 5‘d12) cnt <= 5‘b0;
else cnt <= cnt + 1‘b1;

//前6.5个周期为低电平,后6个周期为高电平,
//即为12.5分频
always @(posedge clk1 or negedge rst_n)
if(!rst_n) clk_out <= 1‘b0;
else if(cnt == 5‘d0) clk_out <= 1‘b0;
else if(cnt == 5‘d7) clk_out <= 1‘b1;
else clk_out <= clk_out;

endmodule
网上还有许多其他大神写的半分频程序,比如:
http://www.cnblogs.com/yuzeren48/p/3965003.html
 
4.任意分频——基于相位累加原理

相位累加器主要用在直接数字频率合成器(DDS)中,其中的几个主要的参数为输入频率fc,输出频率fo,计数器位宽N,频率控制字K(即计数器递增步长)。它们之间的关系为:fo=(fc*K)/(2^N)。假设输入频率fc为50MHz,计数器位宽N为32,要产生1kHz的信号,则K=(fo*2^N)/fc=85.9*fo=85900。当计数值小于等于((2^N)/2)时,输出低电平,当计数值大于((2^N)/2)时,输出高电平,依次循环,就可以产生占空比为50%的1kHz信号了。据此可以设计如下程序:

 
任意分频示例,输出1kHz,占空比50%
/***************************************
晶振频率 fc = 50MHz
输出频率 fo = 1kHz(根据需要可以设为任意值)
控制参数 K  = (fo*2^N)/fc
参数 N = 2^32,(32为计数器的位宽)

****************************************/
module div_free(clk_out, clk, rst_n);

input clk, rst_n;
output clk_out;

reg clk_out;
reg [31:0] cnt;

always @(posedge clk or negedge rst_n)
if(!rst_n)
    cnt <= 0;
else cnt <= cnt + 32‘d85900;  //计数器步长 K

always @(posedge clk or negedge rst_n)
if(!rst_n)
    begin
    clk_out <= 1‘b0;
    end
else if(cnt < 32‘h7FFF_FFFF)
    clk_out <= 1‘b0;
else clk_out <= 1‘b1;

endmodule
时间: 2024-08-01 12:43:20

基于Verilog的偶数、奇数、半整数分频以及任意分频器设计的相关文章

基于verilog的分频器设计(半整数分频,小数分频:下)

半整数分频器:计数器是通过上升沿触发,故在计数为N-1时对计数触发进行翻转,时钟的下降沿变为上升沿,因此计数值为0,所以每产生n+0.5分频时钟的周期,触发时钟都要翻转一次.如图所示,采用异或门和2分频模块设计脉冲扣除电路,脉冲扣除是输入频率和2分频输出相异或的结果. module fenpin(clk,rst_n,clk_out); input clk; input rst_n; output clk_out; reg clk_out2; wire clk_out1; reg [1:0] cn

任意整数分频与半整数分频

任意整数: http://www.cnblogs.com/qiweiwang/archive/2010/12/17/1909482.html 半整数: http://www.cnblogs.com/qiweiwang/archive/2010/11/30/1892169.html

基于verilog的分频器设计(奇偶分频原理及其电路实现:上)

在一个数字系统中往往需要多种频率的时钟脉冲作为驱动源,这样就需要对FPGA的系统时钟(频率太高)进行分频.分频器主要分为奇数分频,偶数分频,半整数分频和小数分频,在对时钟要求不是很严格的FPGA系统中,分频器通常都是通过计数器的循环来实现的. 偶数分频:假设为N分频,由待分频的时钟触发计数器计数,当计数器从0计数到N/2-1时,输出时钟进行翻转,并给计数器一个复位信号,使得下一个时钟从零开始计数.以此循环下去.这种方法可以实现任意的偶数分频.如图所示,两个D触发器级联实现四分频电路,原理:来一个

基于Verilog的奇数偶数小数分频器设计

今天呢,由泡泡鱼工作室发布的微信公共号“硬件为王”(微信号:king_hardware)正式上线啦,关注有惊喜哦.在这个普天同庆的美好日子里,小编脑洞大开,决定写一首诗赞美一下我们背后伟大的团队,虽然连上我只有两个人,但丝毫不影响我们的工作热情和创业野心.合抱之木,生于毫末:九层之台,起于垒土:千里之行,始于足下! 首先小编在这里分享一个基于Verilog语言的分频器设计,该分频器实现了奇数.偶数.小数(0.5)分频,可综合,能跑700M左右的时钟,基本能够满足大部分应用需求. 一:背景 前天,

任意整数分频Verilog(占空比50%)

程序实现任意整数分频的功能,已在modelsim中通过验证. 1 //`define N 5 2 module div_N ( 3 input CLK, // 基准时钟 4 output CLK_div_N, // N分频后得到的时钟 5 input rst 6 ); 7 wire [31:0] N=5; // ★ N为分频系数,N≥2即可,N的值为CLK除以CLK_div_N后取整(四舍五入) 8 9 /******************** 产生备用时钟1 ***************/

基于Verilog HDL整数乘法器设计与仿真验证

基于Verilog HDL整数乘法器设计与仿真验证 1.预备知识 整数分为短整数,中整数,长整数,本文只涉及到短整数.短整数:占用一个字节空间,8位,其中最高位为符号位(最高位为1表示为负数,最高位为0表示为正数),取值范围为-127~127. 负数的表示方法为正值的求反又加1.例如: 8’b0000_0100; //表示值:4,正值求反为:8’b1111_1011:再加1表示为:8’b1111_1100,这样便得到了-4的表示方法为:8’b1111_1100. 同理,负值变成正值的方法为:负值

[Verilog]任意整数(奇数,整数)分频器设计, 50%占空比

module div_clk(clk_in, divisor, clk_out); input clk_in; input divisor; output clk_out; reg clk_out = 0; wire clk_in; reg [7 : 0] count = 0; wire [7 : 0] divisor; wire odd; assign odd = divisor & 1; always @(clk_in) begin if (count == 0 && clk_

基于Verilog的带FIFO输出缓冲的串口接收接口封装

一.模块框图及基本思路 rx_module:串口接收的核心模块,详细介绍请见"基于Verilog的串口接收实验" rx2fifo_module:rx_module与rx_fifo之间的控制模块,其功能是不断接收并将数据写入rx_fifo rx_interface:串口接收接口封装,也就是前两个模块的组合 rx_interface_control:串口接收接口控制模块,每隔1s读取一次串口rx_fifo,并将数据的低四位用Led显示出来 rx_interface_top:串口接收接口顶层

基于Verilog的CRC-CCITT校验

由于笔者在自己设计CRC模块时遇到很多问题,在网上并未找到一篇具有实际指导意义的文章,在经过多次仿真修改再仿真之后得到了正确的结果,故愿意在本文中为大家提供整个设计流程供大家快速完成设计.本文章主要针对具体的实际应用给出一套亲测可行的实现办法,给出设计代码并提供仿真结果,供各位参考. 一.CRC概述 CRC(Cyclic Redundancy Check),循环冗余校验,是一种数字通信中的常用查错校验码.其特征是信息段和校验字段的长度可以任意选定. 校验方法为发送方对信息数据执行约定好除数的二进