偶数次分频(占空比50%)
工作原理:
要实现2n分频,使用一个计数器计数到n-1时,输出信号电平翻转。
例:系统时钟50MHz,需要10k的时钟输出。
需要对系统时钟进行5000分频,计数器计数到2499,out信号翻转,即可实现out为10k。
RTL:
module divider_even
#(parameter even_number = 'd5000)
(
input wire clk ,
input wire rst_n,
output reg clkt
);
reg[11:0] cnt;
//counter to even_number-1
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 12'd0;
else if(cnt == even_number/2-1)
cnt <= 12'd0;
else
cnt <= cnt + 1'b1;
end
//clkt logic
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
clkt <= 1'b0;
else if(cnt == even_number/2-1)
clkt <= ~clkt;
else
clkt <= clkt;
end
endmodule
Tb:
`timescale 1ns/1ns
`define clk_period 20
module tb();
reg clk ;
reg rst_n;
wire clkt ;
initial
begin
clk <= 1'b0;
rst_n<= 1'b0;
#50
rst_n<= 1'b1;
#1000
$stop;
end
always #(`clk_period/2) clk <= ~clk;
divider_even
#(.even_number(10))
u1
(
.clk (clk ),
.rst_n(rst_n),
.clkt (clkt )
);
endmodule
Modelsim仿真实现10分频
图1
Quartus综合后的电路
图2
奇数次分频(占空比50%)
原理:
要实现2n+1分频,使用计数器在计数到n和2n时,分别在系统时钟上升沿和下降沿翻转得到两个生成时钟,再将两个时钟做与/或运算,得到分频后的时钟。
例:系统时钟50MHz,需要400k的时钟输出。
需要对系统时钟进行125分频,计数器计数到62,clk1在上升沿翻转,clk2在下降沿翻转,当计数值满时(即124)clk1、clk2再次翻转,将clk1、clk2进行与运算得到400k时钟。
RTL:
module divider_odd
#(parameter odd_number =7'd125)
(
input clk ,
input rst_n,
output clkt
);
reg[6:0] cnt;
reg clk1;
reg clk2;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 'b0;
else if(cnt == odd_number-1)
cnt <= 'b0;
else
cnt <= cnt + 1'b1 ;
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
clk1 <= 'b0;
else if(cnt == odd_number-1 || cnt == (odd_number-1)/2)
clk1 <= ~clk1;
else
clk1 <= clk1;
end
always@(negedge clk or negedge rst_n) begin
if(!rst_n)
clk2 <= 'b0;
else if(cnt == odd_number-1 || cnt == (odd_number-1)/2)
clk2 <= ~clk2;
else
clk2 <= clk2;
end
assign clkt = clk1||clk2 ;
endmodule
Tb:
`timescale 1ns/1ns
`define clk_period 20
module tb();
reg clk;
reg rst_n;
wire clkt;
initial
begin
clk <= 1'b0 ;
rst_n <= 1'b0 ;
#50
rst_n <= 1'b1;
#2000
$stop;
end
always #(`clk_period/2) clk <= ~clk;
divider_odd
#( .odd_number(9))
u1
(
.clk (clk ),
.rst_n(rst_n),
.clkt (clkt )
);
endmodule
modelsim仿真实现9分频
图3
图4
疑惑一:信号赋值时,一个always块中对多个变量赋值和分开赋值一样吗?
综合出来的电路结构是一样的,见图2.
第一种:在同一个always块中赋值
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)begin
cnt <= 12'd0;
clkt <= 1'b0;end
else if(cnt == even_number/2-1)begin
cnt <= 12'd0;
clkt <= ~clkt;end
else begin
cnt <= cnt + 1'b1;clkt <= clkt;end
end
第二种:分别在两个always块中赋值
//counter to even_number-1
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 12'd0;
else if(cnt == even_number/2-1)
cnt <= 12'd0;
else
cnt <= cnt + 1'b1;
end
//clkt logic
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
clkt <= 1'b0;
else if(cnt == even_number/2-1)
clkt <= ~clkt;
else
clkt <= clkt;
end
疑惑二:如果clk不用时序逻辑,会有什么影响?
assign clkt = (cnt == even_number/2-1)?(~clkt):clkt;
综合之后产生Latch,因为在组合逻辑中赋值给自己会产生latch;
产生latch的情况参考:
verilog代码中避免出现latch方法_Jimbo_Zhang的博客-CSDN博客_verilog如何避免latch
图5
仿真出错
图6
踩坑1:quartus中配置仿真文件时(图5),不能带 .v,否则会出现:
Error:Failed to access library 'tb_divider_even' at "tb_divider_even".
图7
踩坑2:文件名(xx.v)要与模块名字(module xx)相同,否则modelsim无法运行。