写在前面的话 在数字逻辑电路设计中,分频器是一种基本的电路单元。通常用来对某个给定频率进行分频,以得到所需的频率。分频在FPGA的设计中一直都担任着很重要的角色,而说到分频,我相信很多人都已经想到了利用计数器计数来得到想要的时钟频率,但问题是仅仅利用计数器来分频,只可以实现偶数分频,而如果需要三分频、五分频、七分频等等奇数类分频,那应该怎么办呢?在这里,梦翼师兄为大家介绍一种可以实现任意整数分频的方法。 实现原理 这种方法同样也是利用了计数器来实现,当然我们是使用状态机来实现的。我们首先定义分频时钟高电平的个数和低电平的个数,在第一个状态,当计数器计数值小于分频时钟低电平个数的时候,输出电平为低电平,等于低电平的个数的时候,输出取反同时计数器清零,跳转到下一个状态。在这个状态当计数器计数小于分频时钟高电平个数的时候,输出电平不变,当计数器数值等于高电平个数的时候,输出取反同时计数器清零,跳转到上一个状态,这样就可以实现任意分频。 系统框架
顶层模块端口描述 端口名
| 端口说明
| clk
| 系统时钟50Mhz
| rst_n
| 系统低电平复位信号
| clk_out
| 输出分频时钟
|
代码分析 /****************************************************
* Engineer : 梦翼师兄
* 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 : 梦翼师兄
* 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,可见我们的设计是正确的。
|