FPGA时钟分频器设计与盘古1K开发板实践
2026/7/17 6:35:34 网站建设 项目流程

1. 盘古1K开发板与时钟分频器设计概述

盘古1K开发板作为国产FPGA学习平台,凭借其高性价比和丰富的外设接口,已成为众多电子工程师和FPGA初学者的首选。本次练习聚焦时钟分频器设计这一数字电路基础课题,对于掌握FPGA时序控制至关重要。

时钟信号如同数字系统的心跳,但实际工程中我们往往需要多种频率的时钟信号。以盘古1K为例,其板载晶振可能只提供50MHz单一频率时钟,而实际应用中:

  • UART通信可能需要115200Hz的低速时钟
  • PWM调光可能需要1KHz~1MHz的可调时钟
  • 传感器采样可能需要特定频率的时钟信号

传统解决方案有两种:硬件PLL(锁相环)和软件分频器。PLL虽然精度高但配置复杂,而Verilog实现的数字分频器则具有以下优势:

  1. 灵活可编程:分频系数可动态调整
  2. 资源占用少:仅需少量逻辑单元
  3. 学习价值高:深入理解时序逻辑设计

关键提示:在FPGA设计中,直接使用分频信号作为全局时钟是危险的做法,会导致时序问题。推荐使用时钟使能信号(如后文介绍的clk_flag)配合系统时钟工作。

2. 偶数分频器的实现与优化

2.1 基础6分频器设计

我们先从最简单的6分频(偶数分频)开始。其核心原理是利用计数器对原时钟周期进行计数,在特定计数值翻转输出信号。以下是Verilog实现的关键代码段:

module divider_six( input wire sys_clk, // 50MHz系统时钟 input wire sys_rst_n, // 低电平复位 output reg clk_out // 分频输出 ); reg [1:0] cnt; // 0-2计数器 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin cnt <= 2'b0; clk_out <= 1'b0; end else if(cnt == 2'd2) begin cnt <= 2'b0; clk_out <= ~clk_out; // 计满翻转 end else cnt <= cnt + 1'b1; end endmodule

这段代码会产生8.33MHz(50MHz/6)的方波信号,但存在两个典型问题:

  1. 时钟偏移:分频信号未走全局时钟网络
  2. 毛刺风险:组合逻辑产生的时钟可能存在抖动

2.2 安全降频方案设计

更专业的做法是生成时钟使能脉冲而非直接分频时钟。改进后的方案如下:

module divider_six( input wire sys_clk, input wire sys_rst_n, output reg clk_flag // 时钟使能脉冲 ); reg [2:0] cnt; // 0-5计数器 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin cnt <= 3'b0; clk_flag <= 1'b0; end else begin clk_flag <= (cnt == 3'd4); // 提前一个周期产生脉冲 cnt <= (cnt == 3'd5) ? 3'b0 : cnt + 1'b1; end end endmodule

使用时序逻辑生成的clk_flag信号具有以下特点:

  • 保持与系统时钟同步
  • 每个使能脉冲宽度严格为一个时钟周期
  • 可安全用于后续模块的条件判断

应用示例:

always@(posedge sys_clk) begin if(clk_flag) begin // 每6个时钟周期执行一次 end end

3. 奇数分频器的实现技巧

3.1 5分频器的设计挑战

奇数分频(如5分频)的难点在于要保持50%占空比。单纯使用上升沿计数无法实现对称波形,需要结合双沿触发技术。以下是解决方案:

  1. 分别用上升沿和下降沿生成两个相位差180度的信号
  2. 将两个信号进行逻辑与操作得到最终输出
module divider_five( input wire sys_clk, input wire sys_rst_n, output wire clk_out ); reg [2:0] cnt; reg clk1, clk2; // 上升沿计数 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin cnt <= 3'b0; clk1 <= 1'b1; end else if(cnt == 3'd4) cnt <= 3'b0; else cnt <= cnt + 1'b1; if(cnt == 3'd1) clk1 <= 1'b0; else if(cnt == 3'd3) clk1 <= 1'b1; end // 下降沿计数 always@(negedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) clk2 <= 1'b1; else if(cnt == 3'd1) clk2 <= 1'b0; else if(cnt == 3'd3) clk2 <= 1'b1; end assign clk_out = clk1 & clk2; endmodule

3.2 奇数分频的使能信号实现

同样地,我们可以为奇数分频设计安全的使能信号:

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) begin if(!sys_rst_n) begin cnt <= 3'b0; clk_flag <= 1'b0; end else begin clk_flag <= (cnt == 3'd3); cnt <= (cnt == 3'd4) ? 3'b0 : cnt + 1'b1; end end endmodule

4. 盘古1K开发板上的实现与验证

4.1 工程配置要点

在盘古1K开发板上实现分频器时需注意:

  1. 引脚约束:

    set_location_assignment PIN_E1 -to sys_clk set_location_assignment PIN_M15 -to sys_rst_n set_location_assignment PIN_F15 -to clk_out
  2. 时钟约束:

    create_clock -name sys_clk -period 20 [get_ports sys_clk]
  3. 资源占用评估:

    • 偶数分频:约15个LE
    • 奇数分频:约25个LE
    • 使能信号方案:额外增加3-5个LE

4.2 实测问题排查指南

实际调试中常见问题及解决方案:

现象可能原因解决方法
无输出信号引脚约束错误检查.pin文件配置
分频频率不准计数器位宽不足确保计数器能覆盖最大计数值
输出波形畸变时序违例添加适当的时钟约束
随机复位按键消抖不足增加复位信号滤波电路

4.3 示波器测量技巧

使用示波器验证分频效果时:

  1. 建议使用10:1探头降低负载效应
  2. 触发模式设为边沿触发,触发电平1.65V(3.3V系统)
  3. 测量参数包括:
    • 频率(应为50MHz/N)
    • 占空比(奇数分频需接近50%)
    • 上升时间(应<5ns)

5. 高级应用与扩展练习

5.1 参数化分频器设计

通过parameter实现可配置分频系数:

module divider #( parameter DIV = 6 )( input wire sys_clk, input wire sys_rst_n, output reg clk_flag ); localparam CNT_WIDTH = $clog2(DIV); reg [CNT_WIDTH-1:0] cnt; always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin cnt <= 0; clk_flag <= 0; end else begin clk_flag <= (cnt == DIV-2); cnt <= (cnt == DIV-1) ? 0 : cnt + 1; end end endmodule

5.2 动态重配置分频系数

添加配置接口实现运行时调整:

module dynamic_divider( input wire sys_clk, input wire sys_rst_n, input wire [7:0] div_ratio, // 分频系数 output reg clk_flag ); reg [7:0] cnt; always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin cnt <= 0; clk_flag <= 0; end else begin clk_flag <= (cnt == div_ratio-2); cnt <= (cnt == div_ratio-1) ? 0 : cnt + 1; end end endmodule

5.3 小数分频技术

通过交替使用N和N+1分频实现小数分频比:

module frac_divider #( parameter M = 3, // 分子 parameter N = 2 // 分母 )( input wire sys_clk, input wire sys_rst_n, output reg clk_out ); // 实现3.5分频(即7/2) reg [2:0] cnt; reg phase; always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin cnt <= 0; phase <= 0; clk_out <= 0; end else begin if(phase == 0) begin if(cnt == 3) begin // 4分频 cnt <= 0; phase <= 1; clk_out <= ~clk_out; end else cnt <= cnt + 1; end else begin if(cnt == 2) begin // 3分频 cnt <= 0; phase <= 0; clk_out <= ~clk_out; end else cnt <= cnt + 1; end end end endmodule

在盘古1K上完成基础分频器设计后,建议尝试以下扩展练习:

  1. 设计一个可按键调节分频系数的系统
  2. 实现UART波特率时钟生成模块
  3. 结合PWM模块验证分频时钟精度
  4. 测量不同分频方案下的系统功耗差异

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询