
1、 整数倍分频为 2、 4、 8, 这种 2^n 次方倍数关系的分频最容易实现, 所以我们可以把这 3 种分频方式归为一类。
2、 3 分频是奇数倍分频, 这种分频比较麻烦, 对于初学者肯定得思考一番。
3、 2HZ 和前文中流水灯的延迟控制方法一样, 只要实现每过 500ms 对寄存器取反操作
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2026 All rights reserved
// -----------------------------------------------------------------------------
// Author : lvjitao lvjitao_o@163.com
// File : Clk_Divider.v
// Create : 2026-03-14 14:36:38
// Revise : 2026-03-14 15:58:50
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
`timescale 1ns/1ps
module Clk_Divider#(
parameter Debug_Enble = 1'b1,
parameter Ref_clk = 32'd100000000
)
(
input wire clk_i,
input wire rst_n_i,
output reg div2_o,
output reg div3_o,
output reg div4_o,
output reg div8_o,
output reg div2hz_o
);
//2分频
reg div2_cnt;
always @(posedge clk_i or negedge rst_n_i) begin
if(~rst_n_i) begin
div2_cnt <= 0;
end
else begin
div2_cnt <= ~div2_cnt;
end
end
//4\8分频计数器
reg[1:0] div4_8_cnt;
always @(posedge clk_i or negedge rst_n_i) begin
if(~rst_n_i) begin
div4_8_cnt <= 0;
end else begin
div4_8_cnt <= div4_8_cnt + 1'b1;
end
end
//4,8fanzhuang
reg div4_cnt;
reg div8_cnt;
always @(posedge clk_i or negedge rst_n_i) begin : proc_
if(~rst_n_i) begin
div4_cnt <= 0;
div8_cnt <= 0;
end else if (div4_8_cnt == 2'b00 || div4_8_cnt == 2'b10) begin
div4_o <= ~div4_o;
end
else if (div4_8_cnt == 2'b00) begin
/* code */
div8_o <= ~div8_o;
end
else begin
div8_o <= div8_o;
div4_o <= div4_o;
end
end
//3 分频的本质是我们需要在每次 1.5 倍的时钟周期的时候实现 3 分频寄存器的翻转, 但是我们无法直接实现 1.5 倍的分频。
//因此采取分别采取 2 个计数器 pos_cnt 和 neg_cnt, 分别对上升沿和下降沿计数。 计数周期是 0-1-2, 共计 3 个时钟周期。
//我们取 pos_cnt == 2'd1 的时候 div3_o_r0 输出高电平, neg_cnt == 2'd1 的时候 div3_o_r1 输出高电平。
//由于 div3_o_r0 和 div3_o_r1 输出 1 个时钟的高电平, 但是相位相差 180°,
//因此只要执行 div3_o = div3_o_r0 | div3_o_r1运算,就能实现 1.5 倍周期的输出高电平, 那么剩余的 1.5 倍源时钟周期就是输出低电平了。
reg [1:0] pos_cnt;
reg [1:0] neg_cnt;
always @(posedge clk_i or negedge rst_n_i) begin
if(~rst_n_i) begin
pos_cnt <= 'd0;
end else if(pos_cnt == 2'd2) begin
pos_cnt <= 2'b00;
end
else begin
pos_cnt <= pos_cnt + 1'b1;
end
end
always @(posedge clk_i or negedge rst_n_i) begin
if(~rst_n_i) begin
neg_cnt <= 'd0;
end else if(neg_cnt == 2'd2) begin
neg_cnt <= 2'b00;
end
else begin
neg_cnt <= neg_cnt + 1'b1;
end
end
reg div3_o_r0;
reg div3_o_r1;
always @(posedge clk_i or negedge rst_n_i) begin
if(~rst_n_i) begin
div3_o_r0 <= 0;
end else if(pos_cnt <2'd1) begin
div3_o_r0 <= 1'b1;
end
else
div3_o_r0 <= 1'b0;
end
always @(posedge clk_i or negedge rst_n_i) begin
if(~rst_n_i) begin
div3_o_r1 <= 0;
end else if(neg_cnt < 2'd1) begin
div3_o_r1 <= 1'b1;
end
else
div3_o_r1 <= 1'b0;
end
reg div2hz_o_r;
reg [25:0] div2hz_cnt;
wire ms250_en = (div2hz_cnt == Ref_clk/4 - 1'b1);
always @(posedge clk_i or negedge rst_n_i) begin
if(~rst_n_i) begin
div2hz_cnt <= 0;
end else if(div2hz_cnt < Ref_clk/4 - 1'b1) begin
div2hz_cnt <= div2hz_cnt + 1'b1;
end
else
div2hz_cnt <= 0;
end
always @(posedge clk_i or negedge rst_n_i) begin
if(~rst_n_i) begin
div2hz_o_r <= 0;
end else if(ms250_en) begin
div2hz_o_r <= ~div2hz_o_r;
end
else
div2hz_o_r <= div2hz_o_r;
end
assign div2_o = div2hz_o_r;
assign div3_o = div3_o_r0 | div3_o_r1;
assign div4_o = div4_cnt;
assign div8_o = div8_cnt;
assign div2hz_o = div2hz_o_r;
endmodule