13-分频器-奇分频

发布时间 2023-05-27 10:29:14作者: Icer_Newer

1. 奇分频

实现将一个系统时钟进行 5 分频的奇数分频的功能。可以用于将高频的时钟降低为低频的时钟工作使用。

1.1 框图及波形

  • 在偶数分频方法中,波形绘制时,计数器只要计数到M/2-1,计数器清零;但是在奇数分频时,不能用这样的方式(不存在1.5、2.5个周期计数)奇数分频直接计数到M(计数的最大值)

五分频时钟,计数到四,输出信号可以在0-2的时候保持低电平,3-4保持高电平,此时采用的是上升沿采样,占空比不是50%

采用下降沿采样,相当于将上升沿采样的波形向左移动半个时钟周期,占空比也不是50%,不是我们想要的波形

将上面的波形进行或运算,可以得到五分频时钟,编写代码的时候,上升沿和下降沿采用的波形可以作为中间变量

1.2 RTL

module divider_five(
  input wire sys_clk,
  input wire sys_rst_n,
  
  output wire clk_out  
);

  reg [2:0] cnt;
  reg clk_1;
  reg clk_2;

  // 计数器变量赋值
  always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
      cnt <= 3'd0;
    else if(cnt == 3'd4)
      cnt <= 3'd0;
    else 
      cnt <= cnt + 3'd1;

  // clk_1变量赋值
  always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
      clk_1 <= 1'b0;
    else if(cnt == 3'd2)
      clk_1 <= 1'b1;
    else if(cnt == 3'd4)
      clk_1 <= 1'b0;
    else 
      clk_1 <= clk1;

  // clk_2变量赋值,时钟下降沿触发,需要修改敏感列表
  always@(negedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
      clk_2 <= 1'b0;
    else if(cnt == 3'd2)
      clk_2 <= 1'b1;
    else if(cnt == 3'd4)
      clk_2 <= 1'b0;
    else 
      clk_2 <= clk1;

  // 输出信号
  assign clk_out = clk_1 | clk2;
endmodule
  • 创建quartus工程,添加代码,进行代码编译

1.3 Testbench

`timescale 1ns/1ns
module tb_divider_five();
  reg sys_clk;
  reg sys_rst_n;  

  wire [1:0] clk_out;

  // 初始化时钟和复位信号
  initial begin
    sys_clk = 1'b0;
    sys_rst_n = 1'b0;
    #20;
    sys_rst_n = 1'b1;
  end
    
  // 模拟时钟信号
  always #10 sys_clk = ~sys_clk;
  
  // 模块的实例化
  divider_six divider_five_inst(
    .sys_clk (sys_clk),
    .sys_rst_n (sys_rst_n),
    .clk_out (clk_out)
  );
endmodule
  • 添加仿真文件,进行仿真设置,进行仿真

1.4 优化(设置标志位)

  • 在计数器最大值减一之后产生一个周期脉冲然后计数器重新开始进行计数
module divider_five(
  input wire sys_clk,
  input wire sys_rst_n,
  output reg clk_flag
);
  
  reg [2:0] cnt;
  
  always @ (posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
      cnt <= 3'd0;
    else if(cnt == 3'd4)
      cnt <= 3'd0;
    else
      cnt <= cnt + 3'd1;

  always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
      cnt_flag <= 1'b0;
    else if(cnt == 3'd3)
      cnt_flag <= 1'b1;
    else 
      cnt_flag <= 1'b0;
endmodule

`timescale 1ns/1ns
module tb_divider_five();
  reg sys_clk;
  reg sys_rst_n;  

  wire [2:0] clk_flag;

  // 初始化时钟和复位信号
  initial begin
    sys_clk = 1'b0;
    sys_rst_n = 1'b0;
    #20;
    sys_rst_n = 1'b1;
  end
    
  // 模拟时钟信号
  always #10 sys_clk = ~sys_clk;
  
  // 模块的实例化
  divider_six divider_six_inst(
    .sys_clk (sys_clk),
    .sys_rst_n (sys_rst_n),
    .clk_flag (clk_flag)
  );
endmodule

  • 用两个计数器,一个由输入时钟上升沿触发,一个由输入时钟下降沿触发,最后将两个计数器的输出相或,即可得到占空比为50%的方波波形。(尽量避免将分频后时钟用作module内的后级时钟输入,但可以用于其他module的时钟输入)
  • 若要实现N分频,只需在计数器计数到N-1(重新从0开始计数)时,输出分频标志即可。