文章目录
一、8分频
8倍时钟分频器是一种电路或设备,用于将输入时钟信号的频率分成原来的1/8。它可以在数字电子系统中用于将高频时钟信号降低到较低的频率,以满足特定的系统需求。
在这个电路中,CLK是输入的时钟信号,CLK_OUT是输出的时钟信号。通过适当的电路设计,8倍时钟分频器将输入时钟信号的频率除以8,得到的输出时钟信号频率为输入时钟频率的1/8。
具体实现时,可以使用计数器、分频器、频率除法等技术来设计8倍时钟分频器。常见的方法是通过基于触发器(如D触发器)的计数器电路实现分频功能。每经过8个输入时钟脉冲,计数器输出一个脉冲,从而生成1/8倍的输出时钟信号。
8分频时钟设计:时钟周期为160ns,及计数4次对信号进行反转。
代码实现:
verilog
/*
* @Description: 8分频
* @Author: Fu Yu
* @Date: 2023-07-21 15:00:40
* @LastEditTime: 2023-07-21 15:23:59
* @LastEditors: Fu Yu
*/
module time_clk (
input wire clk ,
input wire rst_n ,
output wire clk_4
);
parameter MAX_NUM = 2'd3;//计数最大值4
reg [1:0] cnt;
reg clk_4_r;
wire add_cnt;//开始计数信号
wire end_cnt;//结束计数信号
//计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin//初始化
cnt <= 2'd0;
end
else if(add_cnt) begin
if(end_cnt) begin//计满4个周期,计数器清零
cnt <= 2'd0;
end
else begin
cnt <= cnt + 1'd1;
end
end
else begin
cnt <= cnt;
end
end
assign add_cnt = 1'b1;
assign end_cnt = add_cnt && cnt == MAX_NUM;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin//初始化
clk_4_r <= 1'b1;
end
else if(end_cnt) begin//计满四次输出信号进行一次反转
clk_4_r <= ~clk_4_r;
end
else begin
clk_4_r <= clk_4_r;
end
end
assign clk_4 = clk_4_r;
endmodule //time_clk
测试文件:
verilog
/*
* @Description: 8分频仿真验证
* @Author: Fu Yu
* @Date: 2023-07-21 15:38:35
* @LastEditTime: 2023-07-21 15:49:01
* @LastEditors: Fu Yu
*/
`timescale 1ns/1ns
module time_clk_tb();
//激励信号定义
reg tb_clk;
reg tb_rst_n;
//输出信号定义
wire tb_clk_4;
parameter CYCLE = 20;
always #(CYCLE/2) tb_clk = ~tb_clk;
initial begin
tb_clk = 0;
tb_rst_n = 0;//开始复位
#(CYCLE/2);
tb_rst_n = 1;//结束复位
#(CYCLE*16);
$stop;
end
time_clk u_time_clk(
. clk (tb_clk) ,
. rst_n (tb_rst_n) ,
. clk_4 (tb_clk_4)
);
endmodule
二、n倍时钟分频器
代码实现:
verilog
/*
* @Description: 设计一个可配置的时钟分频器模块,能够将输入时钟信号按照给定的任意分频比例进行分频,并输出分频后的时钟信号。
* @Author: Fu Yu
* @Date: 2023-07-22 10:11:22
* @LastEditTime: 2023-07-22 10:23:12
* @LastEditors: Fu Yu
*/
module CLOCK_N #(parameter N = 8)(
input wire clk ,//时钟输入
input wire rst_n ,//复位信号
output wire clk_n //分频后的信号输出
);
reg [N:0] cnt;//用于记数
reg clk_n_r;//存储当前分频信号的值
wire add_cnt;//开始计数信号
wire end_cnt;//结束计数信号
//计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt <= 26'd0;
end
else if(add_cnt)begin
if(end_cnt)begin
cnt <= 26'd0;
end
else begin
cnt <= cnt + 1'd1;
end
end
else begin
cnt <= cnt;
end
end
assign add_cnt = 1'b1;
assign end_cnt = add_cnt && (cnt == (N-1)/2);//记数到半个时钟周期
//时钟分频
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_n_r <= 1'b1;
end
else if(end_cnt) begin//每到半个时钟周期,将分频信号进行反转
clk_n_r <= ~clk_n_r;
end
else begin
clk_n_r <= clk_n_r;
end
end
assign clk_n = clk_n_r;
endmodule
测试文件:
verilog
/*
* @Description: n倍分频器仿真测试文件
* @Author: Fu Yu
* @Date: 2023-07-22 10:24:59
* @LastEditTime: 2023-07-22 10:43:28
* @LastEditors: Fu Yu
*/
`timescale 1ns/1ns
module clock_n_tb();
parameter CYCLE = 20;//定义时钟周期
parameter N = 10;//任意分频倍数
//定义激励信号
reg tb_clk;
reg tb_rst_n;
//定义输出信号
wire tb_clk_n;
always #(CYCLE/2) tb_clk = ~tb_clk;
initial begin
tb_clk = 0;
tb_rst_n = 0;//开始复位
#(CYCLE/2);
tb_rst_n = 1;//结束复位
#(CYCLE*20);
$stop;
end
//实例化
CLOCK_N #(.N(N)) u_CLOCK_N(
. clk (tb_clk) ,
. rst_n (tb_rst_n) ,
. clk_n (tb_clk_n)
);
endmodule
改进:
博主发现以上方法对偶数倍分频效果很好,但对奇数倍分频效果很差,所以博主对n倍分频器做了以下改动:
verilog
/*
* @Description: 设计一个可配置的时钟分频器模块,能够将输入时钟信号按照给定的任意分频比例进行分频,
并输出分频后的时钟信号。奇偶倍数均可实现
* @Author: Fu Yu
* @Date: 2023-07-24 16:49:26
* @LastEditTime: 2023-07-24 19:51:02
* @LastEditors: Fu Yu
*/
module divede_clk #(parameter N = 8)(
input wire clk ,//系统时钟
input wire rst_n ,//复位信号
output wire clk_out //分频后的信号
);
reg [N:0] cnt_pos;//检测时钟上升沿计数
reg [N:0] cnt_neg;//检测时钟下降沿计数
reg clk1;
reg clk2;
wire add_cnt_pos;//开始计数标志
wire end_cnt_pos;//结束计数标志
wire add_cnt_neg;//开始计数标志
wire end_cnt_neg;//结束计数标志
//时钟上升沿计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_pos <= 'd0;
end
else if(add_cnt_pos) begin
if(end_cnt_pos) begin
cnt_pos <= 'd0;
end
else begin
cnt_pos <= cnt_pos + 1'd1;
end
end
else begin
cnt_pos <= cnt_pos;
end
end
assign add_cnt_pos = 1'b1;
assign end_cnt_pos = add_cnt_pos && cnt_pos == (N - 1);
//对clk1进行赋值
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk1 <= 1'b0;
end
else if(cnt_pos <= (N-1)/2) begin
clk1 <= 1'b1;
end
else begin
clk1 <= 1'b0;
end
end
//时钟下降沿计数器
always @(negedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_neg <= 'd0;
end
else if(add_cnt_neg) begin
if(end_cnt_neg) begin
cnt_neg <= 'd0;
end
else begin
cnt_neg <= cnt_neg + 1'd1;
end
end
else begin
cnt_neg <= cnt_neg;
end
end
assign add_cnt_neg = 1'b1;
assign end_cnt_neg = add_cnt_neg && cnt_neg == (N - 1);
//对clk1进行赋值
always @(negedge clk or negedge rst_n) begin
if(!rst_n) begin
clk2 <= 1'b0;
end
else if(cnt_neg <= N/2) begin
clk2 <= 1'b1;
end
else begin
clk2 <= 1'b0;
end
end
assign clk_out = (N == 1) ? clk : N[0] ? (clk1&clk2) : clk1;
endmodule //divede_clk
此次改动后奇数倍和偶数倍的分频器都能实现,用两个信号一个对于时钟上升沿检测,一个对于时钟下降沿检测。