亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> Verilog

Verilog 时钟发生器

时钟是构建数字电路的基础,因为它允许不同的模块相互同步。

时钟的属性

数字时钟的关键属性是它的频率 决定时钟周期 , 它的占空比时钟相位 相对于其他时钟。

时钟周期

频率表示在某个时间段内可以找到多少个周期。因此时钟周期是完成 1 个周期所用的时间。

<无脚本>

时钟占空比

时钟与其时间周期相比处于高电平的时间量定义了占空比。

<无脚本>

时钟相位

如果一个时钟的一个周期可以看成一个360度的完整圆,那么另一个时钟可以相对放置在圆的不同位置,占据不同的相位。例如,同一时间周期的另一个时钟右移了其周期的1/4,可以说是相差90度。

<无脚本>

Verilog 时钟发生器

模拟需要在给定的时间尺度上运行,该时间尺度具有由 timescale 指令指定的有限精度。因此,重要的是时间刻度的精度足以代表一个时钟周期。例如,如果时钟的频率设置为 640000 kHz,则其时钟周期将为 1.5625 ns,此时 1ps 的时间刻度精度将不够,因为要表示一个额外的点。因此,模拟将四舍五入最后一位数字以适应 3 点时间刻度精度。这会将时钟周期提高到 1.563,实际上代表 639795 kHz!

下面的 Verilog 时钟发生器模块具有三个参数来调整上述三个不同的属性。该模块有一个输入使能,允许根据需要禁用和启用时钟。当多个时钟由一个共同的使能信号控制时,它们可以相对容易地进行定相。

  
  
`timescale 1ns/1ps

module clock_gen (	input      enable,
  					output reg clk);
  
  parameter FREQ = 100000;  // in kHZ
  parameter PHASE = 0; 		// in degrees
  parameter DUTY = 50;  	// in percentage 
  
  real clk_pd  		= 1.0/(FREQ * 1e3) * 1e9; 	// convert to ns
  real clk_on  		= DUTY/100.0 * clk_pd;
  real clk_off 		= (100.0 - DUTY)/100.0 * clk_pd;
  real quarter 		= clk_pd/4;
  real start_dly     = quarter * PHASE/90;
  
  reg start_clk;
  
  initial begin    
    $display("FREQ      = %0d kHz", FREQ);
    $display("PHASE     = %0d deg", PHASE);
    $display("DUTY      = %0d %%",  DUTY);
    
    $display("PERIOD    = %0.3f ns", clk_pd);    
    $display("CLK_ON    = %0.3f ns", clk_on);
    $display("CLK_OFF   = %0.3f ns", clk_off);
    $display("QUARTER   = %0.3f ns", quarter);
    $display("START_DLY = %0.3f ns", start_dly);
  end
  
  // Initialize variables to zero
  initial begin
    clk <= 0;
    start_clk <= 0;
  end
  
  // When clock is enabled, delay driving the clock to one in order
  // to achieve the phase effect. start_dly is configured to the 
  // correct delay for the configured phase. When enable is 0,
  // allow enough time to complete the current clock period
  always @ (posedge enable or negedge enable) begin
    if (enable) begin
      #(start_dly) start_clk = 1;
    end else begin
      #(start_dly) start_clk = 0;
    end      
  end
  
  // Achieve duty cycle by a skewed clock on/off time and let this
  // run as long as the clocks are turned on.
  always @(posedge start_clk) begin
    if (start_clk) begin
      	clk = 1;
      
      	while (start_clk) begin
      		#(clk_on)  clk = 0;
    		#(clk_off) clk = 1;
        end
      
      	clk = 0;
    end
  end 
endmodule

  

具有不同时钟频率的测试台

  
  
module tb;
  wire clk1;
  wire clk2;
  wire clk3;
  wire clk4;
  reg  enable;
  reg [7:0] dly;
  
  clock_gen u0(enable, clk1);
  clock_gen #(.FREQ(200000)) u1(enable, clk2);
  clock_gen #(.FREQ(400000)) u2(enable, clk3);
  clock_gen #(.FREQ(800000)) u3(enable, clk4);
  
  initial begin
    enable <= 0;
    
    for (int i = 0; i < 10; i= i+1) begin
      dly = $random;
      #(dly) enable <= ~enable;      
      $display("i=%0d dly=%0d", i, dly);
      #50;
    end
    
    #50 $finish;
  end
endmodule

  
<无脚本> 模拟日志
xcelium> run
FREQ      = 100000 kHz
PHASE     = 0 deg
DUTY      = 50 %
PERIOD    = 10.000 ns
CLK_ON    = 5.000 ns
CLK_OFF   = 5.000 ns
QUARTER   = 2.500 ns
START_DLY = 0.000 ns
FREQ      = 200000 kHz
PHASE     = 0 deg
DUTY      = 50 %
PERIOD    = 5.000 ns
CLK_ON    = 2.500 ns
CLK_OFF   = 2.500 ns
QUARTER   = 1.250 ns
START_DLY = 0.000 ns
FREQ      = 400000 kHz
PHASE     = 0 deg
DUTY      = 50 %
PERIOD    = 2.500 ns
CLK_ON    = 1.250 ns
CLK_OFF   = 1.250 ns
QUARTER   = 0.625 ns
START_DLY = 0.000 ns
FREQ      = 800000 kHz
PHASE     = 0 deg
DUTY      = 50 %
PERIOD    = 1.250 ns
CLK_ON    = 0.625 ns
CLK_OFF   = 0.625 ns
QUARTER   = 0.312 ns
START_DLY = 0.000 ns
i=0 dly=36
i=1 dly=129
i=2 dly=9
i=3 dly=99
i=4 dly=13
i=5 dly=141
i=6 dly=101
i=7 dly=18
i=8 dly=1
i=9 dly=13
Simulation complete via $finish(1) at time 1110 NS + 0

具有不同时钟相位的测试台

  
  
module tb;
  wire clk1;
  wire clk2;
  reg  enable;
  reg [7:0] dly;
  
  clock_gen u0(enable, clk1);
  clock_gen #(.FREQ(50000), .PHASE(90)) u1(enable, clk2);
  
  initial begin
    enable <= 0;
    
    for (int i = 0; i < 10; i=i+1) begin
      dly = $random;
      #(dly) enable <= ~enable;      
      $display("i=%0d dly=%0d", i, dly);
    end
    
    #50 $finish;
  end

endmodule

  
<无脚本> 模拟日志
xcelium> run
FREQ      = 100000 kHz
PHASE     = 0 deg
DUTY      = 50 %
PERIOD    = 10.000 ns
CLK_ON    = 5.000 ns
CLK_OFF   = 5.000 ns
QUARTER   = 2.500 ns
START_DLY = 0.000 ns
FREQ      = 100000 kHz
PHASE     = 90 deg
DUTY      = 50 %
PERIOD    = 10.000 ns
CLK_ON    = 5.000 ns
CLK_OFF   = 5.000 ns
QUARTER   = 2.500 ns
START_DLY = 2.500 ns
FREQ      = 100000 kHz
PHASE     = 180 deg
DUTY      = 50 %
PERIOD    = 10.000 ns
CLK_ON    = 5.000 ns
CLK_OFF   = 5.000 ns
QUARTER   = 2.500 ns
START_DLY = 5.000 ns
FREQ      = 100000 kHz
PHASE     = 270 deg
DUTY      = 50 %
PERIOD    = 10.000 ns
CLK_ON    = 5.000 ns
CLK_OFF   = 5.000 ns
QUARTER   = 2.500 ns
START_DLY = 7.500 ns
i=0 dly=36
i=1 dly=129
i=2 dly=9
i=3 dly=99
i=4 dly=13
i=5 dly=141
i=6 dly=101
i=7 dly=18
i=8 dly=1
i=9 dly=13
Simulation complete via $finish(1) at time 1110 NS + 0

具有不同占空比的测试台

  
  
module tb;
  wire clk1;
  wire clk2;
  wire clk3;
  wire clk4;
  reg  enable;
  reg [7:0] dly;
  
  clock_gen u0(enable, clk1);
  clock_gen #(.DUTY(25)) u1(enable, clk2);
  clock_gen #(.DUTY(75)) u2(enable, clk3);
  clock_gen #(.DUTY(90)) u3(enable, clk4);
  
  initial begin
    enable <= 0;
    
    for (int i = 0; i < 10; i= i+1) begin
      dly = $random;
      #(dly) enable <= ~enable;      
      $display("i=%0d dly=%0d", i, dly);
      #50;
    end
    
    #50 $finish;
  end
endmodule

  
<无脚本> 模拟日志
xcelium> run
FREQ      = 100000 kHz
PHASE     = 0 deg
DUTY      = 50 %
PERIOD    = 10.000 ns
CLK_ON    = 5.000 ns
CLK_OFF   = 5.000 ns
QUARTER   = 2.500 ns
START_DLY = 0.000 ns
FREQ      = 100000 kHz
PHASE     = 0 deg
DUTY      = 25 %
PERIOD    = 10.000 ns
CLK_ON    = 2.500 ns
CLK_OFF   = 7.500 ns
QUARTER   = 2.500 ns
START_DLY = 0.000 ns
FREQ      = 100000 kHz
PHASE     = 0 deg
DUTY      = 75 %
PERIOD    = 10.000 ns
CLK_ON    = 7.500 ns
CLK_OFF   = 2.500 ns
QUARTER   = 2.500 ns
START_DLY = 0.000 ns
FREQ      = 100000 kHz
PHASE     = 0 deg
DUTY      = 90 %
PERIOD    = 10.000 ns
CLK_ON    = 9.000 ns
CLK_OFF   = 1.000 ns
QUARTER   = 2.500 ns
START_DLY = 0.000 ns
i=0 dly=36
i=1 dly=129
i=2 dly=9
i=3 dly=99
i=4 dly=13
i=5 dly=141
i=6 dly=101
i=7 dly=18
i=8 dly=1
i=9 dly=13
Simulation complete via $finish(1) at time 1110 NS + 0

切换启用以启动/停止时钟

下面的波形显示,当 enable 为低电平时时钟停止,当 enable 设置为高电平时时钟开始。

<无脚本>

Verilog

  1. Verilog 简介
  2. Verilog 教程
  3. Verilog 连接
  4. Verilog 作业
  5. Verilog 阻塞和非阻塞
  6. Verilog 函数
  7. Verilog 任务
  8. Verilog 数学函数
  9. Verilog 时间格式
  10. Verilog 时间刻度范围
  11. Verilog 文件 IO 操作
  12. Verilog Hello World