写在前面的话
在数字逻辑电路设计中,分频器是一种基本的电路单元。通常用来对某个给定频率进行分频,以得到所需的频率。分频在FPGA的设计中一直都担任着很重要的角色,而说到分频,我相信很多人都已经想到了利用计数器计数来得到想要的时钟频率,但问题是仅仅利用计数器来分频,只可以实现偶数分频,而如果需要三分频、五分频、七分频等等奇数类分频,那应该怎么办呢?在这里,梦翼师兄为大家介绍一种可以实现任意整数分频的方法。
实现原理
这种方法同样也是利用了计数器来实现,当然我们是使用状态机来实现的。我们首先定义分频时钟高电平的个数和低电平的个数,在第一个状态,当计数器计数值小于分频时钟低电平个数的时候,输出电平为低电平,等于低电平的个数的时候,输出取反同时计数器清零,跳转到下一个状态。在这个状态当计数器计数小于分频时钟高电平个数的时候,输出电平不变,当计数器数值等于高电平个数的时候,输出取反同时计数器清零,跳转到上一个状态,这样就可以实现任意分频。
系统框架
顶层模块端口描述
端口名 |
端口说明 |
clk |
系统时钟50Mhz |
rst_n |
系统低电平复位信号 |
clk_out |
输出分频时钟 |
代码分析
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function : 任意分频模块 *****************************************************/ 01 module divide( 02 clk, //系统时钟输入 03 rst_n, //系统低电平复位 04 clk_out //分频时钟输出 05 ); 06 07 parameter HW = 3; //输出时钟高电平宽度 08 parameter LW = 2; //输出时钟低电平宽度 09 10 input clk; //系统时钟输入 11 input rst_n; //系统低电平复位 12 output clk_out; //分频时钟输出 13 14 reg clk_out; 15 reg [31:0] count; //计数器 16 reg state; //状态寄存器 17 18 always @ (posedge clk or negedge rst_n) 19 begin 20 if (!rst_n) //异步复位 21 begin 22 clk_out <= 1‘b0; //赋初值 23 count <= 0; 24 state <= 0; 25 end 26 else 27 case (state) 28 0 : if (count < LW-1) //输出低电平个数比较器 29 begin 30 count <= count + 1; 31 state <= 0; 32 end 33 else //输出低电平个数等于设定的低电平个数 34 begin 35 count <= 0; //计数器清零 36 clk_out <= 1‘b1; //输出变为1 37 state <= 1; 38 end 39 40 1 : if (count < HW-1) //输出高电平个数比较器 41 begin 42 count <= count + 1; 43 state <= 1; 44 end 45 else //输出高电平个数等于设定的高电平个数 46 begin 47 count <= 0; //计数器清零 48 clk_out <= 1‘b0; //输出变为0 49 state <= 0; 50 end 51 default : state <= 0; 52 endcase 53 end 54 55 endmodule |
第7~8行定义了2个参数,一个是输出高电平的个数,一个是低电平的个数,比如HW=3,LW=2输出就是一个5分频的时钟,
比如HW=3,LW=3输出就是一个6分频的时钟,可见只要改变HW和LW的值就可以实现任意分频。第18~53行就是利用状态机来实现分频的过程,用2个状态来计数输出高电平个数和低电平个数。
编写测试代码如下:
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function : 任意分频测试模块 *****************************************************/ 01 `timescale 1ns/1ps //仿真时间单位是ns,仿真时间精度是ps 02 module tb; 03 04 reg clk, rst_n; //仿真激励时钟,复位信号 05 06 wire clk_out; //仿真输出分频信号 07 08 initial begin 09 clk = 0; //clk时钟信号初始化 10 rst_n = 0; //rst_n复位信号初始化 11 #200.1 12 rst_n = 1; //200.1ns之后,复位结束 13 end 14 15 always #10 clk = ~clk; //产生50Mhz时钟信号 16 17 divide divide( //把激励信号送进diveder模块 18 .clk(clk), 19 .rst_n(rst_n), 20 .clk_out(clk_out) 21 ); 22 23 endmodule |
仿真分析
我们输入的时钟是50Mhz,一个周期是20ns,输出5分频的时钟,周期是100ns,可见我们的设计是正确的。
我们修改分频模块的参数将HW改为3,LW改为3,仿真波形如下:
同样输入的时钟是50Mhz,一个周期是20ns,输出6分频的时钟,周期是120ns,可见我们的设计是正确的。
原文地址:https://www.cnblogs.com/mengyi1989/p/11518333.html