news 2026/1/29 4:29:18

Vivado使用实战案例:PWM信号生成电路设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vivado使用实战案例:PWM信号生成电路设计

从零开始用FPGA生成PWM:Vivado实战手记

你有没有试过在FPGA上点亮一个LED,却发现它只能“全亮”或“全灭”,没法像调光台灯那样平滑过渡?
或者想控制电机转速,却受限于微控制器的定时器资源,无法实现多路独立输出?

其实,解决这些问题的关键,就是脉宽调制(PWM)。而最灵活、最高效的实现方式之一,正是借助Xilinx的Vivado平台,在FPGA中用硬件逻辑直接构建PWM发生器。

今天,我们就以一款常见的Artix-7开发板为背景,带你一步步从创建工程到下载运行,亲手打造一个可动态调节占空比的PWM信号发生器。不讲空话,全程实操,连仿真波形和常见坑点都给你列清楚了。


为什么选择FPGA来做PWM?

在进入正题之前,先回答一个问题:既然STM32、Arduino都能生成PWM,为什么还要费劲用FPGA?

因为FPGA不一样——它是真正的并行系统

  • MCU靠中断+定时器生成PWM,本质是“时间片轮询”,存在延迟;
  • FPGA则是纯硬件电路,所有操作同步进行,响应速度达到纳秒级;
  • 更重要的是,你可以同时生成几十路互不干扰的PWM通道,每一路频率、相位、占空比都可以独立配置;
  • 而且还能无缝集成到更大的数字系统中,比如做电机驱动、电源管理、音频合成等。

换句话说,MCU是在“模拟”PWM;而FPGA是在“原生生成”PWM。

这就好比用软件播放音乐 vs 用专用音频芯片——体验完全不同。


PWM是怎么“造”出来的?计数器+比较器就够了

别被名字吓到,PWM的核心原理非常简单:用一个不断递增的计数器,去跟目标值比大小,决定输出高低电平。

想象你在跑步机上跑步:
- 每一圈代表一个周期;
- 当你跑的距离小于设定目标时,灯亮;
- 超过目标后,灯灭;
- 目标越靠前,灯亮的时间就越长——这就是占空比的变化。

在FPGA里,这个“跑步过程”由一个N位计数器完成。假设我们使用8位计数器:

计数值: 0 → 1 → 2 → ... → 254 → 255 → 回到0(循环)

如果我们将比较值设为191,那么每当计数器值 < 191 时,输出高电平,否则低电平。这样就得到了约75% 占空比的方波。

📌 公式小贴士:
- PWM频率 = 系统时钟 / (2^N)
(例如:100MHz时钟 + 8位计数器 → 390.625kHz)
- 占空比 = 比较值 / 最大计数值 × 100%

这种结构不仅资源消耗极低(只需要几个触发器和一位比较逻辑),而且完全同步,抗干扰能力强,非常适合上板验证。


手把手教你用Vivado搭出PWM模块

第一步:创建工程,选对器件

打开Vivado,点击“Create Project”:

  1. 给项目命名(如pwm_demo);
  2. 选择“RTL Project”,勾选“Do not specify sources at this time”;
  3. 添加器件型号——如果你用的是Digilent Nexys A7或Basys 3,就选xc7a35tcpg236-1(Artix-7系列);
  4. 完成创建。

⚠️ 提示:务必确认你的开发板实际使用的FPGA型号,避免引脚不匹配导致下载失败。

第二步:写Verilog代码 —— 核心就在两个always块

新建一个Verilog文件pwm_generator.v,内容如下:

module pwm_generator #( parameter CNT_WIDTH = 8 )( input clk, input rst_n, input [CNT_WIDTH-1:0] duty_setting, output reg pwm_out ); localparam MAX_COUNT = (1 << CNT_WIDTH) - 1; reg [CNT_WIDTH-1:0] counter; // 计数器:自动循环递增 always @(posedge clk or negedge rst_n) begin if (!rst_n) counter <= 0; else if (counter == MAX_COUNT) counter <= 0; else counter <= counter + 1; end // 输出逻辑:比较当前计数值与设定值 always @(posedge clk or negedge rst_n) begin if (!rst_n) pwm_out <= 0; else pwm_out <= (counter < duty_setting); end endmodule

📌 关键设计说明:
- 使用参数化设计(parameter CNT_WIDTH),方便后续扩展为10位、12位高精度PWM;
- 所有逻辑均为同步设计,复位信号也尽量采用同步释放处理(建议外加去抖);
-(counter < duty_setting)是关键判断条件,无需额外状态机,简洁高效。


写Testbench验证功能:别跳过这一步!

很多初学者喜欢跳过仿真,直接烧进板子看结果。但问题是——一旦出错,你就分不清是代码问题、约束问题还是接线问题。

所以,仿真必须做

新建测试文件tb_pwm.v

`timescale 1ns / 1ps module tb_pwm; parameter CNT_WIDTH = 8; localparam CLK_PERIOD = 10; // 100MHz reg clk; reg rst_n; reg [7:0] duty_setting; wire pwm_out; // 实例化待测模块 pwm_generator #(.CNT_WIDTH(CNT_WIDTH)) uut ( .clk(clk), .rst_n(rst_n), .duty_setting(duty_setting), .pwm_out(pwm_out) ); // 生成时钟 initial begin clk = 0; forever #(CLK_PERIOD/2) clk = ~clk; end // 测试流程 initial begin rst_n = 0; duty_setting = 8'd0; #20 rst_n = 1; // 释放复位 // 测试不同占空比 duty_setting = 8'd64; // ~25% #1000; duty_setting = 8'd128; // ~50% #1000; duty_setting = 8'd192; // ~75% #1000; $finish; end endmodule

在Vivado中点击Run Simulation > Run Behavioral Simulation,你会看到类似下面的波形:

clk _|‾|_|‾|_|‾|_|‾|... rst_n ________|‾‾‾‾‾‾‾‾‾... duty_set XXXXX 64 -> 128 -> 192 pwm_out ___|¯¯¯¯¯¯¯|___|¯¯¯¯|... (脉宽逐渐变宽)

✅ 验证要点:
- 复位期间输出是否为低?
- 切换占空比后,下一个周期是否立即生效?
- 波形周期是否稳定?宽度是否符合预期?

只有仿真通过,才能放心综合。


上板实操:让LED呼吸起来

添加XDC约束文件:告诉工具“哪个信号连哪根线”

新建pwm.xdc文件,加入以下内容(以Basys3为例):

set_property PACKAGE_PIN G14 [get_ports pwm_out] # 连接到LED0 set_property IOSTANDARD LVCMOS33 [get_ports pwm_out] set_property PACKAGE_PIN W5 [get_ports clk] # 板载100MHz时钟 set_property IOSTANDARD LVCMOS33 [get_ports clk]

🔍 注意事项:
- 引脚名称需参考开发板用户手册;
- 若未正确绑定引脚,Vivado会报[DRC NSTD-1]警告;
- 建议统一命名风格,避免大小写混淆。

综合 → 实现 → 生成比特流 → 下载

四个步骤一气呵成:
1.Synthesis:检查语法错误,生成逻辑网表;
2.Implementation:布局布线,分配物理资源;
3.Generate Bitstream:产出.bit文件;
4. 打开Hardware Manager,连接JTAG,下载程序。

几分钟后,你会发现板上的LED不再是闪烁,而是呈现出明显的亮度变化!


常见问题排查清单(亲测有效)

现象可能原因解决方法
LED完全不亮引脚未约束或反了检查XDC中get_ports拼写,确认是pwm_out不是pwm_out[0]
亮度不变duty_setting固定为0或255在testbench中增加打印$display("Duty: %d", duty_setting);
频率异常高计数器位宽写错检查MAX_COUNT是否等于2^N - 1,防止符号扩展
仿真卡住不结束缺少$finish务必在激励末尾添加终止语句
多次修改无效输入信号未同步加入同步寄存器链防亚稳态

💡 秘籍一条:
如果你想让占空比平滑变化(比如做一个“呼吸灯”),可以在顶层模块里加个计数器,缓慢改变duty_setting的值:

reg [7:0] cnt_up_down = 0; reg up = 1'b1; always @(posedge clk) begin if (up) cnt_up_down <= cnt_up_down + 1; else cnt_up_down <= cnt_up_down - 1; if (cnt_up_down == 255) up <= 0; if (cnt_up_down == 0) up <= 1; end assign duty_setting = cnt_up_down;

这样就能看到LED像呼吸一样明暗交替了。


进阶思路:不只是点亮LED

虽然现在只是一个基础PWM模块,但它已经具备向复杂系统演进的潜力:

  • 多通道PWM:实例化多个模块,共享时钟,各自独立控制;
  • 死区控制:用于H桥驱动,防止上下桥臂直通;
  • 与AXI总线对接:作为MicroBlaze软核的外设,通过C代码配置;
  • 结合ADC采样:构成闭环调光或恒温控制系统;
  • IP封装复用:右键模块 → Create and Package New IP,以后一键调用。

这些,都是建立在你现在掌握的“计数器+比较”思想之上的自然延伸。


写在最后:动手才是最好的学习

你看,整个设计流程并不复杂:
- 理解原理 → 写代码 → 仿真验证 → 约束引脚 → 下载观察。

但正是这样一个小小的PWM模块,让你走完了FPGA开发的完整闭环:从想法到硬件落地

下次当你需要做电机控制、风扇调速、音效生成时,你会意识到——原来这些都不是难题。因为你已经有了自己的“数字信号发生器”。

而这,就是FPGA的魅力所在:你不是在编程,而是在创造电路

如果你正在学习FPGA,不妨就从这个PWM开始练起。把代码敲一遍,波形跑一遍,亲眼看着LED随着你的逻辑慢慢变亮……那种成就感,远胜于任何理论讲解。

欢迎在评论区分享你的实验截图或遇到的问题,我们一起debug!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/27 11:56:14

百度网盘下载加速:告别龟速下载的终极解决方案

百度网盘下载加速&#xff1a;告别龟速下载的终极解决方案 【免费下载链接】baidu-wangpan-parse 获取百度网盘分享文件的下载地址 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wangpan-parse 你是否曾经面对百度网盘那令人绝望的下载速度&#xff0c;看着进度条…

作者头像 李华
网站建设 2026/1/22 15:11:24

vivado2021.1安装教程:工控领域新手入门必看

从零开始搭建FPGA开发环境&#xff1a;vivado2021.1安装实战全记录 你是不是也曾在搜索引擎里反复输入“ vivado2021.1安装教程 ”&#xff0c;只为让那个进度条顺利走完&#xff1f; 你是不是也曾面对“No license found”或“Failed to extract file”的报错&#xff0c;…

作者头像 李华
网站建设 2026/1/27 21:32:09

【计算机毕设】基于Django框架的多功能校园网站的设计与实现

&#x1f49f;博主&#xff1a;程序员小俊&#xff1a;CSDN作者、博客专家、全栈领域优质创作者 &#x1f49f;专注于计算机毕业设计&#xff0c;大数据、深度学习、Java、小程序、python、安卓等技术领域 &#x1f4f2;文章末尾获取源码数据库 &#x1f308;还有大家在毕设选题…

作者头像 李华
网站建设 2026/1/22 2:31:34

【计算机毕设】Django高校后勤报修系统设计与实现

&#x1f49f;博主&#xff1a;程序员小俊&#xff1a;CSDN作者、博客专家、全栈领域优质创作者 &#x1f49f;专注于计算机毕业设计&#xff0c;大数据、深度学习、Java、小程序、python、安卓等技术领域 &#x1f4f2;文章末尾获取源码数据库 &#x1f308;还有大家在毕设选题…

作者头像 李华
网站建设 2026/1/22 15:38:23

古迹修复参考:GLM-4.6V-Flash-WEB比对历史照片变化

古迹修复中的AI之眼&#xff1a;用GLM-4.6V-Flash-WEB比对历史影像变迁 在山西某处千年古寺的修复现场&#xff0c;专家们正围坐在一张长桌前&#xff0c;面前摊开几十张泛黄的老照片和近年拍摄的实景图。他们反复比对屋檐角度、斗拱形制、墙面裂痕——这是一项极其耗时的工作&…

作者头像 李华
网站建设 2026/1/24 16:57:29

30分钟打造你的第一个电源管理APP

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 快速开发一个基础电源管理工具原型&#xff0c;功能包括&#xff1a;1. 显示当前电源方案 2. 提供3种预设模式切换 3. 电池状态监测 4. 简易设置界面 5. 操作记录。使用PythonTkin…

作者头像 李华