記事ディレクトリ
1、8分周
8x クロック分周器は、入力クロック信号の周波数を 1/8 で分周する回路またはデバイスです。デジタル電子システムで使用すると、特定のシステムのニーズを満たすために高周波クロック信号をより低い周波数に下げることができます。
この回路では、CLK が入力クロック信号、CLK_OUT が出力クロック信号です。適切な回路設計を行うと、8 倍クロック分周器は入力クロック信号の周波数を 8 で分周し、得られる出力クロック信号の周波数は入力クロックの周波数の 1/8 になります。
特定の実装では、カウンター、分周器、分周器などのテクノロジを使用して、8 倍のクロック分周器を設計できます。分周機能をフリップフロップ(Dフリップフロップなど)によるカウンタ回路で実現する方法が一般的です。8 入力クロック パルスごとにカウンタはパルスを出力し、それによって出力クロック信号の 1/8 倍が生成されます。
8分周クロック設計:クロック周期は160nsで、4回のカウントで信号が反転します。
コード:
/*
* @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
テストファイル:
/*
* @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
2、n 倍のクロック分周器
コード:
/*
* @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
テストファイル:
/*
* @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 倍周波数分周器に次の変更を加えました。
/*
* @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
この変更後は、クロックの立ち上がりエッジ検出用とクロック立ち下がりエッジ検出用の 2 つの信号を使用して、奇数と偶数の両方の分周器を実現できます。