verilog代码:
module div_3#(parameter DIV = 7)( //改变参数DIV的值就可以改变分频时钟的频率
input clk ,//时钟
input rst_n ,//复位
//输出信号定义
output wire clk_out
);
//信号定义
reg [3:0] cnt0 ;//15分频以上需要改变计数器的位宽
wire add_cnt0 ;
wire end_cnt0 ;
reg [3:0] cnt1 ;
wire add_cnt1 ;
wire end_cnt1 ;
//计数器
always @(posedge clk or negedge rst_n)begin //对系统时钟上升沿计数
if(!rst_n)begin
cnt0 <= 0;
end
else if(add_cnt0)begin
if(end_cnt0)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1;
end
end
assign add_cnt0 = 1'b1;
assign end_cnt0 = add_cnt0 && cnt0 == DIV-1;
always @(negedge clk or negedge rst_n)begin //对系统时钟下降沿计数
if(!rst_n)begin
cnt1 <= 0;
end
else if(add_cnt1)begin
if(end_cnt1)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1;
end
end
assign add_cnt1 = 1'b1;
assign end_cnt1 = add_cnt1 && cnt1 == DIV-1;
assign clk_out = cnt0 > (DIV>>1) | cnt1 > (DIV>>1);//DIV>>1,将DIV除以2,我们这里进行7分频,由于N-1/2,故clk_out = (cnt0 > 3) | (cnt1 > 3);
//cnt0>3 | cnt0>3 //由于将上升沿和下降沿计数值进行或操作,故7分频后得到的clk_out,高低电平各持续3.5周期
//0~6
endmodule
TestBench编写:
`timescale 1 ns/1 ns //时间单位,时间精度
module div_3_tb();
//时钟和复位
reg clk ;
reg rst_n;
//输出信号
wire clk_out;
parameter CYCLE = 20;//时钟周期,单位为ns,可在此修改时钟周期。
parameter RST_TIME = 3 ;//复位时间,此时表示复位3个时钟周期的时间。
//待测试的模块例化
div_3 div_3(
.clk (clk ),
.rst_n (rst_n ),
.clk_out (clk_out )
);
defparam div_3.DIV = 7;
//生成本地时钟50M
initial clk = 0;
always #(CYCLE/2) clk=~clk;
//产生复位信号
initial begin
rst_n = 1;
#2;
rst_n = 0;
#(CYCLE*RST_TIME);//RST_TIME个时钟周期后
rst_n = 1;
#(CYCLE*100);//运行100个周期
$stop;//退出
end
endmodule
从modelsim中可以观察仿真结果