在数字电路设计中,分频器是一种常见的电路,用于将一个高频的时钟信号分频到一个较低频率的时钟信号。本次将通过一个实际的例子,讲解如何使用Verilog语言设计一个分频器,将系统时钟信号分频到2Hz。
在数字电路系统的设计中, 分频器是一种应用十分广泛的电路, 其功能就是对高频率的信号进行分频。本质上, 分频电路是加法计数器的变种, 其计数值由分频系数N=Fin/Fout决定,其输出不是一般计数器的计数结果, 而是根据分频常数对输出信号的高、低电平进行控制。通常来说, 分频器常用于对数字电路中的时钟信号进行分频, 从而得到较低频率的时钟信号、选通信号、中断信号等。
一、电路符号
二、代码设计
module div_clk( sclk, s_rst_n, clk_2Hz );
// 输入信号
input wire sclk, // 系统时钟信号
s_rst_n; // 复位信号,低电平有效
// 输出信号
output reg clk_2Hz; // 输出的2Hz时钟信号
// 参数定义
parameter CNT_END = 50000000; // 分频计数器的结束值,用于生成2Hz时钟
// 内部信号定义
reg [25:0] div_cnt; // 分频计数器,26位宽,足以容纳CNT_END值
// 分频计数器的时钟上升沿或复位信号下降沿触发
always @(posedge sclk or negedge s_rst_n) begin
if (s_rst_n == 1'b0) begin
div_cnt <= 25'd0; // 如果复位信号为低,则计数器清零
end else if (div_cnt == CNT_END - 1'b1) begin
div_cnt <= 25'd0; // 如果计数器达到CNT_END,则计数器清零
end else begin
div_cnt <= div_cnt + 1'b1; // 否则,计数器加一
end
end
// 输出时钟信号的生成
always @(posedge sclk or negedge s_rst_n) begin
if (s_rst_n == 1'b0) begin
clk_2Hz <= 1'b0; // 如果复位信号为低,则输出时钟信号清零
end else if (div_cnt == (CNT_END >> 1'b1) - 1'b1) begin
clk_2Hz <= 1'b0; // 当计数器达到CNT_END的一半时,输出时钟信号为低
end else if (div_cnt == CNT_END - 1'b1) begin
clk_2Hz <= 1'b1; // 当计数器达到CNT_END时,输出时钟信号为高
end
end
endmodule
代码分析
模块定义:
div_clk
模块有三个端口:sclk
(系统时钟),s_rst_n
(复位信号),和clk_2Hz
(输出的2Hz时钟信号)。参数定义:
CNT_END
定义了分频计数器的结束值,这个值决定了输出时钟的频率。内部信号:
div_cnt
是一个26位的计数器,用于计数输入时钟周期。计数器逻辑:第一个
always
块定义了计数器的行为。当复位信号为低时,计数器清零。否则,如果计数器达到CNT_END
,则清零;否则,计数器加一。输出时钟信号生成:第二个
always
块定义了输出时钟信号的行为。当计数器达到CNT_END
的一半时,输出时钟信号为低;当计数器达到CNT_END
时,输出时钟信号为高。
三、仿真结果
(1)仿真代码
`timescale 1ns/1ns
module div_clk_tb;
// 输入信号
reg sclk; // 系统时钟信号
reg s_rst_n; // 复位信号,低电平有效
// 输出信号
wire clk_2Hz; // 输出的2Hz时钟信号
// 实例化被测模块
div_clk uut (
.sclk(sclk),
.s_rst_n(s_rst_n),
.clk_2Hz(clk_2Hz)
);
initial begin
sclk = 0;
forever #10 sclk = ~sclk;
end
// 测试序列
initial begin
// 初始化
s_rst_n=1;
#100
s_rst_n = 0; // 复位
#100; // 保持复位100ns
s_rst_n = 1; // 释放复位
#50000000; // 等待一段时间,观察输出
$finish;
end
// 观察输出波形
initial begin
$monitor("Time = %t,s_rst_n = %b, clk_2Hz = %b",
$time, s_rst_n, clk_2Hz);
end
endmodule
(2)仿真结果