基于FPGA的PWM波发生器设计与实现指南

二牛学FPGA
文章2026-04-30
49

Quick Start(快速上手)

本指南将引导你完成一个基于FPGA的PWM波发生器设计,从新建工程到上板验证,共十个步骤。整个流程在Vivado 2020.1环境下完成,目标器件为Xilinx Artix-7 (XC7A35T)。

  1. 新建Vivado工程,选择目标器件(如xc7a35ticsg324-1L)。
  2. 创建顶层模块pwm_generator_top,定义输入clk、rst_n,输出pwm_out。
  3. 编写PWM核心模块,包含一个计数器counter和比较器,实现占空比可调。
  4. 添加时钟分频模块(如将50MHz分频至1kHz),用于设定PWM周期。
  5. 编写Testbench,模拟输入时钟和复位,观察pwm_out波形。
  6. 运行行为仿真,验证PWM波形周期和占空比是否符合预期(如周期1ms,占空比50%)。
  7. 添加XDC约束文件,分配时钟引脚和输出引脚。
  8. 综合、实现并生成比特流,下载到FPGA开发板。
  9. 用示波器或逻辑分析仪测量输出引脚,观察PWM波形。
  10. 调整占空比参数(如修改比较值),重新编译下载,验证波形变化。

前置条件与环境

项目推荐值说明/替代方案
器件/板卡Xilinx Artix-7 (XC7A35T)其他7系列或Spartan-6,需调整引脚约束
EDA版本Vivado 2020.1 或更高ISE 14.7(仅支持旧器件)
仿真器Vivado Simulator (xsim)ModelSim/QuestaSim
时钟/复位板载50MHz晶振,低电平有效复位其他频率需调整分频系数
接口依赖至少1个GPIO输出引脚LED也可作为简易指示
约束文件XDC文件,包含时钟周期和引脚分配UCF(旧工具)
开发板Nexys A7-50T 或类似任何带FPGA的板卡

目标与验收标准

本设计的目标是实现一个参数化的PWM波发生器,具备以下功能点和验收标准:

  • 功能点:产生频率可调、占空比可调的PWM信号,频率范围为1Hz~1MHz(取决于时钟和计数器宽度)。
  • 性能指标:输出频率误差小于5%,占空比分辨率不低于1%(8位计数器可达到0.39%)。
  • 资源/Fmax:在Artix-7上综合后LUT消耗小于50,FF消耗小于30,最大工作频率不低于200MHz。
  • 关键波形/日志:仿真波形显示pwm_out周期稳定,占空比与设定值一致;上板后示波器测量结果匹配。

实施步骤

工程结构推荐

pwm_generator/ ├── rtl/ │   ├── pwm_core.v │   ├── clk_div.v │   └── pwm_top.v ├── sim/ │   └── tb_pwm.v ├── constr/ │   └── pwm.xdc └── vivado/     └── pwm.xpr

顶层模块pwm_top.v例化pwm_core和clk_div,clk_div将50MHz分频至1kHz作为pwm_core的时钟。

关键模块代码

以下为pwm_core.v的核心代码,实现计数器与比较器:

module pwm_core #( parameter WIDTH = 8, parameter DIV_CLK = 50000 // 分频系数,用于产生PWM周期时钟 )( input wire clk, input wire rst_n, input wire [WIDTH-1:0] duty, // 占空比设定值,0~2^WIDTH-1 output reg pwm_out ); reg [WIDTH-1:0] counter; reg clk_div_en; // 时钟分频逻辑(略,可独立为clk_div模块) // 计数器 always @(posedge clk or negedge rst_n) begin if (!rst_n) counter <= 0; else if (clk_div_en) counter <= counter + 1; end // 比较器 always @(posedge clk or negedge rst_n) begin if (!rst_n) pwm_out <= 0; else if (counter < duty) pwm_out <= 1; else pwm_out <= 0; end endmodule

该模块采用计数器与比较器结构:计数器在每个分频时钟使能时递增,当计数值小于占空比设定值duty时输出高电平,否则输出低电平。通过修改duty值即可改变占空比。

时钟分频模块

时钟分频模块clk_div.v将50MHz输入时钟分频至目标PWM周期时钟。例如,若要产生1kHz的PWM周期,需将50MHz分频50000次。分频系数可通过参数传递,便于复用。

module clk_div #( parameter DIV_FACTOR = 50000 )( input wire clk, input wire rst_n, output reg clk_out ); reg [15:0] cnt; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cnt <= 0; clk_out <= 0; end else if (cnt == DIV_FACTOR-1) begin cnt <= 0; clk_out <= 1; end else begin cnt <= cnt + 1; clk_out <= 0; end end endmodule

Testbench编写

Testbench用于验证PWM波形的正确性。以下为tb_pwm.v的核心结构:

module tb_pwm; reg clk; reg rst_n; wire pwm_out; // 实例化顶层模块 pwm_generator_top uut ( .clk(clk), .rst_n(rst_n), .pwm_out(pwm_out) ); // 时钟生成 initial begin clk = 0; forever #10 clk = ~clk; // 50MHz end // 复位与激励 initial begin rst_n = 0; #100 rst_n = 1; #2000 $stop; end // 波形观察 initial begin $monitor("Time=%0t, pwm_out=%b", $time, pwm_out); end endmodule

约束文件(XDC)

约束文件pwm.xdc用于分配时钟和输出引脚,并指定时钟周期。以下为示例:

# 时钟约束 create_clock -period 20.000 -name sys_clk [get_ports clk] # 引脚分配 set_property PACKAGE_PIN E3 [get_ports clk] set_property IOSTANDARD LVCMOS33 [get_ports clk] set_property PACKAGE_PIN C2 [get_ports rst_n] set_property IOSTANDARD LVCMOS33 [get_ports rst_n] set_property PACKAGE_PIN J15 [get_ports pwm_out] set_property IOSTANDARD LVCMOS33 [get_ports pwm_out]

验证结果

完成仿真后,观察pwm_out波形。若设置duty=128(8位计数器,占空比50%),且分频后周期为1ms,则pwm_out应输出500μs高电平、500μs低电平的方波。仿真波形应显示周期稳定、占空比准确。上板后,用示波器测量输出引脚,波形应与仿真一致。

排障指南

  • 仿真无波形:检查Testbench中时钟和复位信号是否正常;确认模块实例化端口连接正确。
  • 占空比错误:检查duty值是否在0~2^WIDTH-1范围内;确认比较器逻辑正确。
  • 上板无输出:检查XDC引脚分配是否正确;确认比特流已正确下载;用万用表测量引脚电平。
  • 频率偏差大:检查时钟分频系数计算;确认输入时钟频率准确。

扩展建议

  • 多通道PWM:例化多个pwm_core模块,每个使用独立的duty值,可生成多路PWM信号。
  • 动态调节:通过UART或SPI接口接收外部命令,实时更新duty值,实现动态占空比调节。
  • 死区插入:在PWM输出中加入死区时间,适用于H桥电机驱动等应用。

参考资源

  • Xilinx Vivado Design Suite User Guide
  • Artix-7 FPGA Data Sheet
  • PWM基本原理与应用文档

附录

附录A:完整工程源码(含所有RTL文件、Testbench和约束文件)可从相关技术社区获取。附录B:常见问题解答(FAQ)持续更新中。

分类
技术分享
标签
fpgaPWM波发生器
浏览 49
分享:

相关推荐

同频道 · 相近分类

暂无相关推荐

作者

二牛学FPGA查看主页

同分类阅读

文章

延伸阅读与实操

  • 文章 + 课程联动深度文章常对应体系课章节,可一键选课。
  • 学习产出可参考笔记与作业案例在学习产出广场持续更新。

探索全站