关于时钟的分频,博主曾经分享过相关的文章,FPGA 实现任意分频系数和占空比的时钟输出。本篇文章将从另一个角度实现时钟的奇分频和偶分频,占空比为 50%。
偶分频
6 分频为例。
偶分频是最简单的,通过下图就可以很好的理解,其中只需要两个 always 块,其中一个用来计数,计数器每次计数到 5,然后清零重新计数,第二个 always 块用来产生分频时钟,假设初始状态为高电平,当计数到 2 时,将信号拉低,当计数到 5 时,将信号拉高。

那么对于任意的偶分频,如何确定 cnt 的最大值,如何确定 div_clk 信号什么时候拉低,什么时候拉高呢,通过 6 分频的分析,我们看到,当 cnt 计数到 6-1 时,给 cnt 信号清零,并且当 cnt=6-1 时将 div_clk 拉高,当计数到(6-1)/2 时,将 div_clk 拉低。因此,假设现在要进行 n 分频,n 为偶数,则 cnt 的最大值为 n-1,当 cnt 计数到 n-1 时,将 div_clk 拉高,当 cnt 计数到(n-1)/2 时,将 div_clk 拉低。
代码如下:
// ----------------------------------------------------------------------------- // Copyright (c) 2014-2021 All rights reserved // ----------------------------------------------------------------------------- // Author : dongtaolv // Email : tdlv@stu.xidian.edu.cn // File : even_divider.v // Create : 2021-04-26 19:59:35 // Revise : 2021-04-26 19:59:35 // Editor : sublime text3, tab size (4) // ----------------------------------------------------------------------------- module even_divider #( parameter DIVIDER_NUMBER = 6 )( input wire clk, input wire rst, output wire div_clk ); reg [3:0] cnt; //当分频数大于 15 时,此值的位数需要扩展 reg div_clk_r; assign div_clk = div_clk_r; always @(posedge clk)begin if(rst)begin cnt <= 'd0; end else if(cnt == DIVIDER_NUMBER - 1'b1)begin cnt <= 'd0; end else begin cnt <= cnt + 1'b1; end end always @(posedge clk)begin if(rst)begin div_clk_r <= 1'b1; end else if(cnt == ((DIVIDER_NUMBER - 1'b1) >> 1))begin div_clk_r <= 1'b0; end else if(cnt == DIVIDER_NUMBER - 1'b1)begin div_clk_r <= 1'b1; end end endmodule
6 分频仿真如下:

奇分频
奇分频相对于偶分频来说比较复杂,我们首先给出 5 分频的图。

其中 div_clk 信号就是我们的 5 分频产生的时钟,我们可以看到,这需要在系统时钟 clk 的上升沿和下降沿都工作,所以,我们使用三个 always 块。
其中,一个 always 块和偶分频一样,用来产生计数器 cnt,这个计数器在 clk 的上升沿计数,每次计数到 4 时清零。
第二个 always 块用来产生 clk,初始为高电平,该信号在 clk 的上升沿产生,当 cnt 计数到 2 时,将 clk1 信号拉低,当计数到 4 时,将 clk1 信号拉高,这个信号和偶分频产生类似。
第三个 always 块就有区别了,他是通过 clk 的下降沿来产生的,也就是图中的 clk2 信号,初始状态为高电平,当 cnt 计数到 2 并且 clk 的下降沿到来时,我们将 clk2 信号拉低,当 cnt 计数到 4 并且 clk 的下降沿到来时,我们将 clk2 信号拉高。
最后得到的分频时钟 div_clk 可以通过组合逻辑得到,我们直接将 clk1 和 clk2 求与运算就可以得到 div_clk 信号。
代码如下:
// ----------------------------------------------------------------------------- // Copyright (c) 2014-2021 All rights reserved // ----------------------------------------------------------------------------- // Author : dongtaolv // Email : tdlv@stu.xidian.edu.cn // File : odd_divider.v // Create : 2021-04-26 19:59:35 // Revise : 2021-04-26 19:59:35 // Editor : sublime text3, tab size (4) // ----------------------------------------------------------------------------- module odd_divider #( parameter DIVIDER_NUMBER = 5 )( input wire clk, input wire rst, output wire div_clk ); reg [3:0] cnt; //当分频数大于 15 时,此值的位数需要扩展 reg clk1; reg clk2; always @(posedge clk)begin if(rst)begin cnt <= 'd0; end else if(cnt == DIVIDER_NUMBER - 1'b1)begin cnt <= 'd0; end else begin cnt <= cnt + 1'b1; end end always @(posedge clk)begin if(rst)begin clk1 <= 1'b1; end else if(cnt == ((DIVIDER_NUMBER - 1'b1) >> 1))begin clk1 <= 1'b0; end else if(cnt == DIVIDER_NUMBER - 1'b1)begin clk1 <= 1'b1; end end always @(negedge clk)begin if(rst)begin clk2 <= 1'b1; end else if(cnt == ((DIVIDER_NUMBER - 1'b1) >> 1))begin clk2 <= 1'b0; end else if(cnt == DIVIDER_NUMBER - 1'b1)begin clk2 <= 1'b1; end end assign div_clk = clk1 && clk2; endmodule
5 分频仿真如下:

任意分频
在知道如何任意奇分频和任意偶分频之后,只需要将两个结合就可以得到任意整数分频,具体代码如下:
// ----------------------------------------------------------------------------- // Copyright (c) 2014-2021 All rights reserved // ----------------------------------------------------------------------------- // Author : dongtaolv // Email : tdlv@stu.xidian.edu.cn // File : random_divider.v // Create : 2021-04-26 19:59:35 // Revise : 2021-04-26 19:59:35 // Editor : sublime text3, tab size (4) // ----------------------------------------------------------------------------- module random_divider #( parameter DIVIDER_NUMBER = 5 )( input wire clk, input wire rst, output wire div_clk ); reg [3:0] cnt; //当分频数大于 15 时,此值的位数需要扩展 reg div_clk_r; reg clk2; always @(posedge clk)begin if(rst)begin cnt <= 'd0; end else if(cnt == DIVIDER_NUMBER - 1'b1)begin cnt <= 'd0; end else begin cnt <= cnt + 1'b1; end end always @(posedge clk)begin if(rst)begin div_clk_r <= 1'b1; end else if(cnt == ((DIVIDER_NUMBER - 1'b1) >> 1))begin div_clk_r <= 1'b0; end else if(cnt == DIVIDER_NUMBER - 1'b1)begin div_clk_r <= 1'b1; end end always @(negedge clk)begin if(rst)begin clk2 <= 1'b1; end else if(cnt == ((DIVIDER_NUMBER - 1'b1) >> 1) && DIVIDER_NUMBER % 2 == 1'b1)begin clk2 <= 1'b0; end else if(cnt == DIVIDER_NUMBER - 1'b1 && DIVIDER_NUMBER % 2 == 1'b1)begin clk2 <= 1'b1; end end assign div_clk = ( DIVIDER_NUMBER % 2) ? div_clk_r && clk2 : div_clk_r; endmodule
tb 文件如下:
// ----------------------------------------------------------------------------- // Copyright (c) 2014-2021 All rights reserved // ----------------------------------------------------------------------------- // Author : dongtaolv // Email : tdlv@stu.xidian.edu.cn // File : tb_random_divider.v // Create : 2021-04-26 20:39:48 // Revise : 2021-04-26 20:39:48 // Editor : sublime text3, tab size (4) // ----------------------------------------------------------------------------- `timescale 1ns/1ps module tb_random_divider; reg clk; reg rst; wire div_clk; initial begin clk = 0; rst = 1; #100 rst = 0; end always #10 clk = ~clk; random_divider #( .DIVIDER_NUMBER(7) //通过设置此值来确定几分频 ) random_divider_inst( .clk (clk ), .rst (rst ), .div_clk (div_clk) ); endmodule
扫码关注尚为网微信公众号

原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/1253.html