1. 设计分频器
在数字系统的设计中经常会碰到需要使用多个时钟的情况。时钟信号的产生通常具有两种方法,一种是使用PLL(Phase Locked Loop,锁相环),可生成倍频、分频信号;
另一种则是使用硬件描述语言构建一个分频电路。
(1) 偶数分频
方法:假设为N分频,只需设计一个计数器从0计数到 N/2-1(一共N/2个基准时钟),然后将输出分频时钟翻转、计数器清零,如此循环就可以得到 N分频。
比如要实现4分频,那么使用一个计数器,在计数到1的时候已经过了两个基本时钟的上升沿,此时翻转时钟,最终出来的就是4分频的时钟。
// 使用两个always模块,一直用来控制计数的循环(计数到N/2-1),一个用来产生分频的信号,这种是等占空比的实现方法
module devive_6(
input wire clk, res,
output reg out
);
reg[1:0] count = 2'b00;
always@(posedge clk or negedge res) begin
if (!res) count <= 2b`0;
else if(count == 2b`10) count <= 2b`0;
else count <= count + 1;
end
always @(posedge clk or posedge res) begin
if (!res) out <= 0;
else if (count == 2b`10) out <= ~out;
else out <= out;
end
endmodule
// 若想要实现的是非等占空比的,可以使用标志位的方法
module device_6_flag(
input wire clk,
input wire rst,
output reg flag_clk
);
reg[2:0] count = 3b`0;
always @(posedge clk or posedge rst) begin
if (!rst) begin
// reset
count <= 1b`0;
flag_clk <= 0;
end
// 计数器在0~5之间循环计数
else if (count == 3d`5) count <= 3b`0;
// 当计数到4时,flag_clk跳转到1,这样每个时钟间隔6个clk
// 这里计数到其他数值也有同样的效果,只不过这个通常用来设置计数标志位,
// 应该在计数最大值CNT_MAX-1时将标志位置置1,因为如果根据标志位的高电平来控制输出时,要在下一个时钟到来时才能
else if (count == 3b`4) flag_clk <= 1;
else begin
count <= count + 1b`1;
flag_clk <= 0;
end
end
endmodule
(2) 奇数分频
分频信号是基准时钟信号周期的3倍,那么3分频时钟信号的边沿变化肯定发生在第1.5个时钟周期(第2个时钟周期的下降沿),
同理5分频的边沿变化肯定发生在第2.5个时钟周期(第3个时钟周期的下降沿),同理7分频的边沿变化肯定发生在第3.5个时钟周期(第4个时钟周期的下降沿)。
同时我们会发现既然边沿的变化都发生在0.5个时钟周期,那么肯定要利用到时钟的下降沿。
方法:
第一个always模块控制计数器的循环,计数到N-1,对上升沿敏感;
第二个always模块产生对基准时钟上升沿敏感的时钟,每当计数到(N-1)/2-1时,时钟翻转;计数到计数器最大值时再翻转
第三个always模块产生对基准时钟下降沿敏感的信号,每当计数到(N-1)/2-1时,时钟翻转;计数到计数器最大值时再翻转
将 上升沿敏感的信号和 下降沿敏感的信号相与(&&)即N分频电路
module divider_n(
input wire clk,
input wire rst,
output reg out
);
parameter CNT_MAX = 5;
reg[CNT_MAX-1:0] count;
reg clk1, clk2;
// 第一个always模块控制count的计数
always@(posedge clk or negedge rst) begin
if (!rst) count <= 8d`0;
else if(count == CNT_MAX - 1) count <= 8d`0;
else count <= count + 1;
end
// 第二个always模块控制clk1的分频,高电平3个时间周期,低电平2个时间周期
always @(posedge clk or negedge rst) begin
if (!rst) clk1 <= 0;
else if (count == (CNT_MAX - 1)/2) clk1 <= 0;
else if (count == CNT_MAX - 1) clk1 <= 1;
end
// 第三个always模块控制clk2的分频,高电平3个时间周期,低电平2个时间周期
always @(negedge clk or negedge rst) begin
if (!rst) clk2 <= 0;
else if (c