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

Verilog 时钟发生器设计与实现指南

时钟是构建数字电路的基础,使不同模块能相互同步。

时钟特性

数字时钟的关键特性包括频率(决定时钟周期)、占空比和相对于其他时钟的相位。

时钟周期

频率表示单位时间内的周期数,时钟周期即完成 1 个周期所需时间。

Verilog 时钟发生器设计与实现指南

时钟占空比

时钟高电平持续时间与周期之比定义占空比。

Verilog 时钟发生器设计与实现指南

时钟相位

若将一个时钟周期视为 360 度圆,另一时钟可相对偏移不同相位。例如同周期时钟右移 1/4 周期,相位差 90 度。

Verilog 时钟发生器设计与实现指南

Verilog 时钟发生器

仿真在指定精度的 timescale 上运行,故 timescale 精度必须足以表示时钟周期。例如频率 640000 kHz,周期 1.5625 ns,若 timescale 精度 1ps 无法表示额外小数位,仿真会舍入最后一位,导致周期变为 1.563 ns(实际 639795 kHz)。

下面的时钟发生器模块有三个参数调节上述三特性。模块有输入 enable 控制时钟启停。多个时钟共用同一 enable 信号可轻松实现相对相位控制。

 `timescale 1ns/1ps module clock_gen ( input enable, output reg clk); parameter FREQ = 100000; // kHz parameter PHASE = 0; // 度 parameter DUTY = 50; // 百分比 real clk_pd = 1.0/(FREQ * 1e3) * 1e9; // 转 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 // 初始化变量为零 initial begin clk <= 0; start_clk <= 0; end // 时钟使能时,延迟驱动时钟以实现相位效应 // start_dly 配置为相位对应延迟。enable 为 0 时,允许完成当前周期 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 // 通过不对称开/关时间实现占空比,只要时钟开启就持续运行 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 

Verilog 时钟发生器设计与实现指南

仿真日志

 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 

Verilog 时钟发生器设计与实现指南

仿真日志

 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 

Verilog 时钟发生器设计与实现指南

仿真日志

 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 为低时时钟停止,enable 置高时时钟启动。

Verilog 时钟发生器设计与实现指南

Verilog

  1. Verilog基础:设计你的第一个与门
  2. Verilog 入门:数字电路设计完整教程
  3. 掌握 Verilog 拼接操作:实用指南
  4. 深入理解 Verilog 赋值语句:类型、语法与最佳实践
  5. Verilog阻塞与非阻塞赋值:关键区别详解
  6. 掌握Verilog函数:高效RTL设计的复用利器
  7. 理解Verilog任务:函数vs任务、语法与用法全解析
  8. 掌握 Verilog 数学函数:高效硬件设计的利器
  9. 掌握 Verilog $timeformat:精度控制与显示格式化
  10. 理解与打印 Verilog 任意作用域下的 Timescale
  11. 掌握 Verilog 文件 I/O:打开、读取、写入和关闭
  12. Verilog 入门指南:Hello World 示例