可配置的PWM外设模块

🔧 可配置的PWM外设模块

基于FPGA的PWM信号发生器,支持 动态周期与占空比配置,无需外部控制信号,适用于 LED 呼吸灯、舵机控制、电机驱动等场景。

仿真波形

参数修改后会晚一个pwm周期才生效
在这里插入图片描述


📌 模块功能

  • 🧮 支持以微秒为单位动态设置周期 i_period_us
  • 💡 支持以微秒为单位动态设置高电平时间 i_high_us
  • 🧠 自动检测参数变化,内部锁存、乘法,仅更新一次

⚙️ 参数定义

名称默认值说明
P_CLK_FREQ_MHZ50时钟频率(单位 MHz)
P_COUNTER_WIDTH 32位宽
P_DEFAULT_PERIOD_US1000默认周期(1ms)
P_DEFAULT_HIGH_US500默认高电平时间(0.5ms)

🧷 接口定义

信号名方向位宽说明
i_clkin1 bit系统时钟
i_rst_nin1 bit异步复位(启停PWM)
i_period_usin32 bitPWM 周期(单位:微秒)
i_high_usin32 bit高电平时间(单位:微秒)
o_pwm_outout1 bitPWM 输出信号
o_param_err out1 bit参数错误标志

⚠️ 使用注意事项

  1. 参数更新顺序要求:

    • ⚠️ 在动态修改 PWM 参数时,务必先更新 i_period_us,再更新 i_high_us,并保持一个pwm周期。
    • 原因是模块在每个pwm周期结束时检测参数变更并更新内部寄存器。
    • 若先设置高电平时间,可能导致短暂出现 i_high_us > i_period_us 将导致该周期输出恒为高电平,可能不是你想要的占空比
  2. 参数变化生效时机:

    • 模块在pwm周期结束时检测到参数变更后立即生效,无需显式控制信号。
    • 建议在两个周期之间或计数归零时刻修改参数,以避免中途跳变导致输出毛刺。
  3. 默认输出行为:

    • 若输入未初始化或刚上电,模块内部默认配置:
      • i_period_us = 1000 → 周期 1ms
      • i_high_us = 500 → 高电平 0.5ms(50% 占空比)
  4. 停止输出:

    • i_rst_n 拉低,可立即停止 PWM 输出并复位内部状态。
    • 拉高 i_rst_n,PWM 将按当前配置重新开始输出。

pwm.v

module pwm #(parameter P_CLK_FREQ_MHZ      = 50,    // 输入时钟频率(单位 MHz)parameter P_COUNTER_WIDTH     = 32,    // 计数器位宽parameter P_DEFAULT_PERIOD_US = 1000,  // 默认周期(单位 us)parameter P_DEFAULT_HIGH_US   = 500    // 默认高电平时间(单位 us)
)(input  wire                         i_clk        , // 时钟input  wire                         i_rst_n      , // 异步复位,低有效input  wire [P_COUNTER_WIDTH-1:0]   i_period_us  , // PWM 周期(单位:us)input  wire [P_COUNTER_WIDTH-1:0]   i_high_us    , // 高电平时间(单位:us)output reg                          o_pwm_out    , // PWM 输出output reg                          o_param_err    // 参数错误标志
);// ==================================================// 常量与默认值(以 clock cycles 表示)// ==================================================localparam L_CYCLE_MAX_VAL         = (1 << P_COUNTER_WIDTH) - 1;localparam L_DEFAULT_PERIOD_CYCLES = P_CLK_FREQ_MHZ * P_DEFAULT_PERIOD_US;localparam L_DEFAULT_HIGH_CYCLES   = P_CLK_FREQ_MHZ * P_DEFAULT_HIGH_US;// ==================================================// 输入 us → clock cycles 转换(组合逻辑)// ==================================================wire [P_COUNTER_WIDTH-1:0] w_period_cycles = P_CLK_FREQ_MHZ * i_period_us;wire [P_COUNTER_WIDTH-1:0] w_high_cycles   = P_CLK_FREQ_MHZ * i_high_us;// ==================================================// 寄存器定义// ==================================================reg [P_COUNTER_WIDTH-1:0] r_cnt;             // 主计数器reg [P_COUNTER_WIDTH-1:0] r_period_cycles;   // 周期最大值(锁存)reg [P_COUNTER_WIDTH-1:0] r_high_cycles;     // 高电平持续周期数(锁存)reg [P_COUNTER_WIDTH-1:0] r_period_us_d;     // 上一次周期值(us)reg [P_COUNTER_WIDTH-1:0] r_high_us_d;       // 上一次高电平值(us)// ==================================================// 参数合法性检查// ==================================================always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n) begino_param_err <= 1'b0;end else begino_param_err <= (i_period_us == 0) ||(w_period_cycles > L_CYCLE_MAX_VAL) ||(w_high_cycles   > L_CYCLE_MAX_VAL);endend// ==================================================// 周期结束时更新锁存周期/高电平(单位 clk)// ==================================================always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n) beginr_period_us_d   <= P_DEFAULT_PERIOD_US;r_high_us_d     <= P_DEFAULT_HIGH_US;r_period_cycles <= L_DEFAULT_PERIOD_CYCLES;r_high_cycles   <= L_DEFAULT_HIGH_CYCLES;end else if (r_cnt == r_period_cycles - 1 && !o_param_err) beginif ((i_period_us != r_period_us_d) || (i_high_us != r_high_us_d)) beginr_period_us_d   <= i_period_us;r_high_us_d     <= i_high_us;r_period_cycles <= w_period_cycles;r_high_cycles   <= w_high_cycles;endendend// ==================================================// 主计数器逻辑// ==================================================always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n) beginr_cnt <= 0;end else if (o_param_err) beginr_cnt <= r_cnt;  // 可省略end else if (r_cnt == r_period_cycles - 1) beginr_cnt <= 0;end else beginr_cnt <= r_cnt + 1;endend// ==================================================// PWM输出逻辑// ==================================================always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n)o_pwm_out <= 1'b0;else if (o_param_err)o_pwm_out <= 1'b0;else if (r_high_cycles >= r_period_cycles)o_pwm_out <= 1'b1;else if (r_cnt < r_high_cycles)o_pwm_out <= 1'b1;elseo_pwm_out <= 1'b0;endendmodule

tb.v

`timescale 1ns/1nsmodule tb;// ==================================================// 参数定义// ==================================================parameter P_CLK_FREQ_MHZ = 50;parameter CLK_PERIOD_NS  = 1000 / P_CLK_FREQ_MHZ;// ==================================================// 信号定义// ==================================================reg         i_clk;reg         i_rst_n;reg  [31:0] i_period_us;reg  [31:0] i_high_us;wire        o_pwm_out;wire        o_param_err;// ==================================================// 实例化 DUT// ==================================================pwm #(.P_CLK_FREQ_MHZ(P_CLK_FREQ_MHZ),.P_COUNTER_WIDTH(32),.P_DEFAULT_PERIOD_US(1000),.P_DEFAULT_HIGH_US(500)) dut (.i_clk       (i_clk),.i_rst_n     (i_rst_n),.i_period_us (i_period_us),.i_high_us   (i_high_us),.o_pwm_out   (o_pwm_out),.o_param_err (o_param_err));// ==================================================// 时钟生成// ==================================================always #(CLK_PERIOD_NS / 2) i_clk = ~i_clk;// ==================================================// 初始过程// ==================================================initial begin$display(">>> Start PWM Testbench");i_clk       = 0;i_rst_n     = 0;i_period_us = 1000;  // 1ms周期i_high_us   = 200;   // 初始20%#500;i_rst_n = 1;// 维持一段时间后改变占空比为 50%#(3000 * 1000);i_high_us = 500;// 再一段时间后改为 80%#(3000 * 1000);i_high_us = 800;// 再观察一段时间#(3000 * 1000);$display(">>> Finish PWM Testbench");$finish;endendmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916677.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916677.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零到一:我是如何用深度学习打造高性能书籍推荐系统的

作者&#xff1a;笙囧同学 | 发布时间&#xff1a;2025年7月28日 | 阅读时长&#xff1a;15分钟 &#x1f3af; 前言&#xff1a;为什么要做这个项目&#xff1f; 大家好&#xff0c;我是笙囧同学&#xff01;最近在学习《机器学习基础》课程时&#xff0c;被推荐系统的魅力深…

OpenRLHF:面向超大语言模型的高性能RLHF训练框架

“四模型协同调度破资源壁垒&#xff0c;让70B模型RLHF训练触手可及” OpenRLHF 是由 OpenLLMAI 团队于2024年推出的开源强化学习人类反馈&#xff08;RLHF&#xff09;框架&#xff0c;旨在解决大语言模型&#xff08;LLM&#xff09;对齐训练中的多模型协调瓶颈与超大规模扩展…

DMETL安装流程及简单使用

目录 安装调度器 安装执行器 安装管理器 启动服务 进入web管理端 创建数据源 ​编辑 添加表 添加影子表增量 节点监控 DMETL工程流搭建实践 创建表/视图 添加sql脚本 添加数据清洗与转换模块 添加排序模块 创建输出表 连接各模块并启动 查看验证结果 监控管理 …

如何通过代码操作文件?

1. 为什么使用文件不使用文件&#xff0c;我们所写的程序存在电脑内存中&#xff0c;程序结束&#xff0c;内存回收&#xff0c;数据就丢失了。再次运行程序也是看不到上次运行时的数据的&#xff0c;如果想要将数据进行持久化保存&#xff0c;就需要使用文件。2. 文件分类&…

unbuntn 22.04 coreutils文件系统故障

文章目录核心思路具体操作步骤&#xff08;需借助 Ubuntu Live USB&#xff09;1. 准备 Ubuntu Live USB2. 从 Live USB 启动并挂载系统分区3. 从安装包中提取完好的 /bin/dir 文件并替换4. 重启系统并验证总结前提说明具体操作步骤&#xff08;分阶段执行&#xff09;阶段1&am…

若依【(前后端分离版)SpringBoot+Vue3】

文章目录什么是若依使用若依验证码的前端实现&#x1f4cc; 前后端验证码流程说明文档1、前端初始化验证码2、前端界面显示3、后端生成验证码接口&#xff08;GET /captchaImage&#xff09;4、用户提交登录信息5、后端验证验证码逻辑&#xff08;POST /login&#xff09;6、登…

Ubuntu24安装MariaDB/MySQL后不知道root密码如何解决

Ubuntu 24.04 安装 MariaDB 后 root 密码未知&#xff1f;解决方案在此在 Ubuntu 24.04 上新安装 MariaDB 后&#xff0c;许多用户会发现自己不知道 root 用户的密码&#xff0c;甚至在安装过程中也没有提示设置密码。这是因为在较新的 MariaDB 版本中&#xff0c;默认情况下 r…

Cloudflare CDN 中设置地域限制并返回特定界面

文章目录 什么是CDN 什么是Cloudflare 注册Cloudflare 账号,添加域名、修改DNS并激活邮箱 阻止或允许特定国家或地区访问 常见规则表达式 WAF自定义规则 + 自定义错误页面 使用Workers脚本 什么是CDN CDN 是一种优化网站请求处理的机制。它是在用户访问网站 (服务器) 时用户与…

Ubuntu高频实用命令大全

Ubuntu系统中高频实用命令 以下为Ubuntu系统中高频实用命令的分类整理,涵盖系统管理、文件操作、网络配置等场景,每个命令附带简要说明: 系统信息与管理 uname -a 显示系统内核版本、主机名等详细信息。 lsb_release -a 查看Ubuntu发行版版本信息。 uptime 显示系统运行时…

关于C#的编程基础:数据类型与变量全解析

一.基本的数据类型 1.什么是数据类型 在编程语言中&#xff0c;数据类型&#xff08;Data Type&#xff09; 是对变量存储的 “数据的种类” 的定义&#xff0c;它决定了&#xff1a; 变量可以存储哪些值&#xff08;例如整数、文本、布尔值&#xff09;。这些值在内存中如何…

深入解析 Spring 获取 XML 验证模式的过程

关键要点Spring 的 XML 验证模式&#xff1a;Spring 框架在加载 XML 配置文件时&#xff0c;会根据文件内容判断使用 DTD&#xff08;文档类型定义&#xff09;或 XSD&#xff08;XML 模式定义&#xff09;进行验证。自动检测机制&#xff1a;Spring 默认使用自动检测&#xff…

复现《Local GDP Estimates Around the World》论文的完整指南

复现《Local GDP Estimates Around the World》论文的完整指南 1. 引言 1.1 论文概述 《Local GDP Estimates Around the World》是一篇重要的经济地理学研究论文&#xff0c;作者提出了一种创新的方法来估计全球范围内次国家层面的GDP数据。这项工作填补了全球经济发展研究中子…

Sql注入 之sqlmap使用教程

一、安装sqlmap 浏览器访问SQLmap官网 即可下载工具&#xff1b;需要说明的是&#xff0c;SQLmap运行依赖于python环境&#xff0c;所以在下载使用前务必在电脑及终端上安装好python环境。 通过网盘分享的文件&#xff1a;sqlmap-master.zip链接: https://pan.baidu.com/s/1YZi…

安宝特案例丨户外通信机房施工革新:AR+作业流技术破解行业难题

在数字化浪潮席卷各行各业的今天&#xff0c;传统户外通信机房建设领域正经历一场静悄悄的变革。作为信息社会的“神经枢纽”&#xff0c;户外机房的质量直接关系到通信网络的稳定性&#xff0c;但长期以来&#xff0c;这一领域却深受施工标准化不足、质量管控难、验收追溯复杂…

在 CentOS 中安装 MySQL 的过程与问题解决方案

MySQL 是一款广泛使用的开源关系型数据库管理系统&#xff0c;在 CentOS 系统中安装 MySQL 是很多开发者和运维人员常做的工作。下面将详细介绍安装过程以及可能遇到的问题和解决方案。 一、安装前的准备工作 在安装 MySQL 之前&#xff0c;需要做好一些准备工作&#xff0c;…

阿里 Qwen3 四模型齐发,字节 Coze 全面开源,GPT-5 8 月初发布!| AI Weekly 7.21-7.27

&#x1f4e2;本周AI快讯 | 1分钟速览&#x1f680;1️⃣ &#x1f9e0; 阿里 Qwen3 全系列爆发 &#xff1a;一周内密集发布四款新模型&#xff0c;包括 Qwen3-235B-A22B-Thinking-2507、Qwen3-Coder 和 Qwen3-MT&#xff0c;MMLU-Pro 成绩超越 Claude Opus 4&#xff0c;百万…

C语言第 9 天学习笔记:数组(二维数组与字符数组)

C语言第09天学习笔记&#xff1a;数组&#xff08;二维数组与字符数组&#xff09; 内容提要 数组 二维数组字符数组二维数组 定义 二维数组本质上是一个行列式组合&#xff0c;由行和列两部分组成&#xff0c;属于多维数组&#xff0c;通过行和列解读&#xff08;先行后列&…

使用OpenCV做个图片校正工具

昨天有位兄台给我发了个文件&#xff0c;是下面这个样子的&#xff1a;那一双小脚既没有裹成三寸金莲&#xff0c;又没有黑丝&#xff0c;这图片肯定不符合我的要求。我要的是这个样子的好不好&#xff1a;让他拿扫描仪重新给我规规矩矩扫一个发过来&#xff1f;他要能用扫描仪…

《不只是接口:GraphQL与RESTful的本质差异》

RESTful API凭借其与HTTP协议的天然融合&#xff0c;以资源为核心的架构理念&#xff0c;在过去十余年里构建了Web数据交互的基本秩序&#xff1b;而GraphQL的出现&#xff0c;以“按需获取”为核心的查询模式&#xff0c;打破了传统的请求-响应逻辑&#xff0c;重新定义了前端…

博士招生 | 香港大学 招收人工智能和网络安全方向 博士生

学校简介香港大学创立于 1911 年&#xff0c;是香港历史最悠久的高等学府&#xff0c;QS 2025 世界排名第 17 位。计算机科学学科在 QS 2025 学科排名中位列全球第 31 位、亚洲第 5 位。计算机系&#xff08;Department of Computer Science&#xff09;下设系统、人工智能、数…