clock divider

One, 8 frequency division

An 8x clock divider is a circuit or device that divides the frequency of an incoming clock signal by 1/8. It can be used in digital electronic systems to step down high-frequency clock signals to lower frequencies to meet specific system needs.
In this circuit, CLK is the input clock signal, and CLK_OUT is the output clock signal. With proper circuit design, the 8x clock frequency divider divides the frequency of the input clock signal by 8, and the frequency of the output clock signal obtained is 1/8 of the frequency of the input clock.
During specific implementation, technologies such as counters, frequency dividers, and frequency division can be used to design an 8-times clock frequency divider. A common method is to realize the frequency division function through a counter circuit based on flip-flops (such as D flip-flops). After every 8 input clock pulses, the counter outputs a pulse, thereby generating 1/8 times the output clock signal.
8 frequency division clock design: the clock period is 160ns, and the signal is inverted by counting 4 times.
Code:

/*
 * @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

Test file:

/*
 * @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

insert image description here

Two, n times clock divider

Code:

/*
 * @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

Test file:

/*
 * @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

insert image description here
Improvement:
The blogger found that the above method worked well for even multiples, but poorly for odd multiples, so the blogger made the following changes to the n-fold frequency divider:

/*
 * @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

After this change, both odd and even frequency dividers can be realized, using two signals, one for clock rising edge detection and one for clock falling edge detection.

Guess you like

Origin blog.csdn.net/weixin_53573350/article/details/131867831