时钟分频器

一、8分频

8倍时钟分频器是一种电路或设备,用于将输入时钟信号的频率分成原来的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

在这里插入图片描述

二、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

此次改动后奇数倍和偶数倍的分频器都能实现,用两个信号一个对于时钟上升沿检测,一个对于时钟下降沿检测。

猜你喜欢

转载自blog.csdn.net/weixin_53573350/article/details/131867831