基本理论
数字电路中时钟占有很重要的地位,时间的计算都要以时钟作为基本的单元。一般来 说我们使用的开发板上面只有一个晶振,即只有一种频率的时钟。但在数字系统设计中, 经常需要对基准时钟进行不同倍数的分频而得到各模块所需的时钟频率,若是想得到比固 定的时钟频率更慢的时钟,可以将该固定时钟进行分频,若是想得到比固定时钟频率更快 的时钟,则可以在固定时钟频率的基础上进行倍频。无论分频和倍频,我们都有两种方式 可以选择,一种是器件厂商提供的锁相环(PLL),另一种是自己动手 来用 Verilog 代码描述。 而我们用 Verilog 代码描述的往往是分频电路,即分频器。
分频器是数字系统设计中最 常见的基本电路之一。所谓“分频”,就是把输入信号的频率变成成倍数地低于输入频率 的输出信号。它的原理是:把输入的信号作为计数脉冲,由于计数器的输出端口是按一定 规律输出脉冲的,所以对不同的端口输出的信号脉冲,就可以看作是对输入信号的“分 频”。至于分频频率是怎样的,由选用的计数器所决定。如果是十进制的计数器那就是十 分频,如果是二进制的计数器那就是二分频,还有四进制、八进制、十六进制等等以此类 推。 分频器是和计数器非常类似的功能,与计数器的内容有异曲同工之妙,可以观察我们的仿真波形,对比下时钟信号 sys_clk 和 led_out 信 号的关系,你会发现 led_out 信号实际上就是对时钟信号 sys_clk 进行了分频。
模块框图
波形绘制
与之前计数器思路部分相同,计数到某一值后反转输出,这里实现六分频所以只需计数到2即可。
方式一:仅实现分频功能
方式二:推荐的降频方法(标志信号)
代码实现
方式一:仅实现分频功能
module divider
(
input wire sys_clk,
input wire sys_rst_n,
output reg clk_out
);
reg [2:0] cnt;
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 + 2'd1;
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;
else
clk_out <= clk_out;
endmodule
仿真结果:
方式二:推荐的降频方法
module divider
(
input wire sys_clk,
input wire sys_rst_n,
output reg clk_flag
);
reg [2:0] cnt;
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 + 3'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
clk_flag <= 1'b0;
else if(cnt == 3'd4)
clk_flag <= 1'b1;
else
clk_flag <= 1'b0;
endmodule
仿真结果:
使用方法:
方式一:仅实现分频功能
后级模块使用方法 1 clk_out 作为时钟信号工作的情况
always@(posedge clk_out or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
A <= 4'b0;
else
A <= A + 1'b1;
方式二:推荐的降频方法
后级模块使用方法 2 sys_clk 系统时钟继续作为工作时钟的情况
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
A <= 4'b0;
else if(clk_flag == 1'b1)
A <= A + 1'b1;
总结
上面两种例子实现的最终效果都是相同的,而方法 2 中的信号 A 是在 sys_clk 系统时 钟的控制下产生的,和所有在 sys_clk 系统时钟下产生的信号都保持几乎相同的时钟关系, 方法更优,推荐大家在以后的设计中都使用方法 2。