首页/新闻资讯/正文详情

NodeMCU PWM2 模块实战指南:基于 TIMER1 软中断的高频、多引脚软件 PWM

发布时间:2026/9/27 7:58:22 来源:云帆数科 栏目:资讯中心
NodeMCU PWM2 模块实战指南:基于 TIMER1 软中断的高频、多引脚软件 PWM
物联网嵌入式【免费下载链接】nodemcu-firmwareLua based interactive firmware for ESP8266, ESP8285 and ESP32项目地址https://gitcode.com/gh_mirrors/no/nodemcu-firmware点击查看免费下载PWM2 是 NodeMCU 固件中一个独立的软件 PWM 模块Lua 绑定源码底层驱动源码它基于 ESP8266 的软中断定时器 TIMER1 FRC1 生成 PWM 波形支持从 1 脉冲/53 秒的亚赫兹信号到约 125kHz 的高频信号并可同时对几乎所有 GPIO 引脚输出不同频率的 PWM。读完本文你将掌握 PWM2 的完整 API 用法、频率换算与精度边界理解其独占 TIMER1 的底层机制并学会用get_timer_data()/get_pin_data()排查看门狗超时与多频率混用问题。模块概览PWM2 与 PWM 的定位差异NodeMCU 仓库中同时存在两个 PWM 模块pwm传统硬件驱动最高 1kHz、最多 6 个引脚、10bit 占空比与pwm2。PWM2 的目标是突破 PWM 模块的频率上限与引脚数量限制其核心特点包括支持频率范围约 120kHz50% 占空比到 1 脉冲/53 秒CPU160 时为 250kHz 与 26 秒支持频率分数表达如 100.1Hz即使固件编译为纯整数运算也能表达支持除引脚 0 之外的所有 GPIO 引脚且可同时输出互不相同的 PWM 信号同时支持 CPU80MHz 与 CPU160MHz 两种主频频率边界不变但 CPU160 下中断开销占比更小可在生成 PWM 的同时承担更多其他工作独占使用 TIMER1 FRC1软中断信号质量比共享模式下更有保障但也因此无法与pwm、pcm、ws2812等同样使用该定时器的模块并发使用。在固件构建层面PWM2 通过app/include/user_modules.h中的//#define LUA_USE_MODULES_PWM2开关启用默认处于注释状态需要按 NodeMCU 编译流程打开该宏并重新编译固件后方可使用pwm2Lua API。快速上手一个典型的使用流程文档给出的典型用法可以直接运行用pwm2.setup_pin_hz()在多个引脚上配置不同频率启动后动态调整占空比最后停止释放资源。pwm2.setup_pin_hz(3,250000,2,1) -- 引脚3PWM频率250kHz脉冲周期2步初始占空比1个周期步 pwm2.setup_pin_hz(4,1,2,1) -- 引脚4PWM频率1Hz脉冲周期2步初始占空比1个周期步 pwm2.start() -- 启动PWM内部LED以0.5秒间隔闪烁 ... pwm2.set_duty(4, 2) -- LED完全熄灭引脚输出高电平 ... pwm2.set_duty(4, 0) -- LED完全点亮引脚输出低电平 ... pwm2.stop() -- 停止PWM释放GPIO引脚与TIMER1注意示例中 250kHz 是 CPU80 下接近极限的频率见下文“频率精度与极限”若系统还有其他负载应适当降低。set_duty(4, 2)表示占空比等于脉冲周期周期 2对应 100% 占空比引脚常高set_duty(4, 0)表示 0% 占空比引脚常低这与 PWM 模块的占空比语义一致。频率表达与换算原理以 CPU 周期为统一单位PWM2 内部把所有频率与周期统一换算成 CPU ticksCPU 周期数换算公式为cpuTicksPerSecond / (frequencyHz * period)其中cpuTicksPerSecond system_get_cpu_freq() * 1000000见 驱动实现。例如 CPU80MHz 下1kHz 频率配合 1000 的周期每个脉冲周期为 80 个 CPU ticks即 1 微秒。频率分数frequencyDivisor为了更精细地调频setup_pin_hz()和setup_pin_sec()都支持可选的frequencyDivisor参数将频率表达为两个整数之比实际频率 frequencyAsHz / frequencyDivisor例如要表达 100.1Hz只需指定frequency1001、divisor10。在驱动层该参数对应pwm2_setup_pin()中的divisableFreq与freqDivisor最终通过enduserFreqToCPUTicks()计算每个脉冲周期的 CPU ticksapp/driver/pwm2.creturn (getCPUTicksPerSec() / (freqDivisor * resolution)) * divisableFreq;亚赫兹频率setup_pin_sec对于周期长达数秒的亚赫兹信号直接用 Hz 表达很不直观PWM2 提供了按“每个脉冲耗时秒数”来配置的setup_pin_sec()。其换算公式为cpuTicksPerSecond * frequencySec / period例如pwm2.setup_pin_sec(4, 2, 2, 1)表示引脚 4 输出周期为 2 秒的 PWM 信号。最大脉冲时长受 ESP 内部 32 位 CPU ticks 计数器的回绕限制CPU80 下约每 53 秒回绕一次CPU160 下约减半26 秒。频率精度与极限TIMER1 FRC1 以固定的 5MHz 频率工作因此单次中断的精度理论上为 200ns但该极限无法实际达到OS 定时器中断处理代码本身存在内部开销自动装载auto-load中断模式约为 50 个 CPU ticks短周期下可达到约 1MHz 的中断频率但此时看门狗会介入PWM2 自身中断处理程序的开销为 162 个 CPU ticks外加每个使用中的引脚 12 个 CPU ticks见 timerInterruptHandler 每次中断遍历所有启用引脚累加掩码的实现。据此推算的最快配置配置可达到的 PWM 频率CPU80、1 个引脚、50% 占空比脉冲周期 2约 125kHzCPU80、12 个引脚降至约 100kHzCPU160、1 个引脚可达约 220kHz由于频率先在 CPU ticks 中表达再转换为 TIMER1 ticks而 TIMER1 频率是 CPU 频率的 1/16对应驱动中的PWM2_TMR_MAGIC_80MHZ16与PWM2_TMR_MAGIC_160MHZ32除数见 app/driver/pwm2.c转换时会损失部分精度。调用pwm2.get_timer_data()可直接查看实际使用的值interruptTimerCPUTicks表示期望的中断周期CPU ticksinterruptTimerTicks表示实际装载的中断周期TIMER1 ticks为 CPU ticks 的 1/16。多频率混用公共中断周期的自动推导当多个引脚同时工作时PWM2 会自动推导合适的底层中断频率它计算所有已配置引脚脉冲周期以 CPU ticks 表示的最大公约数GCD并将其作为所有引脚共用的中断周期。这一逻辑体现在findCommonCPUTicksDivisor()与findGreatesCommonDividerForTimerTicks()中app/driver/pwm2.c每配置一个引脚都会触发reCalculateCommonToAllPinsData()重算。由此带来两条实战经验同频多引脚所有引脚使用同一频率时只需微调其中任一引脚的频率即可保证精度异频多引脚必须密切关注各引脚周期CPU ticks的最大公约数。例如 100kHz周期 2与 0.5Hz周期 2混用底层中断周期为 800 CPU ticks可行但改成 100kHz1 后公约数会退化为 1这是明显的不可用组合。120kHz周期 2每周期 333 CPU ticks与 1Hz周期 2混用同样会使公约数变为 1。遇到此类问题时最佳做法是用pwm2.get_timer_data()观察interruptTimerCPUTicks与interruptTimerTicks随输入的变化提前判断组合是否可用。独占 TIMER1 的机制与限制PWM2 使用软中断定时器 TIMER1 FRC1 的独占模式。在 hw_timer.c 中platform_hw_timer_init_exclusive()会先检查定时器是否已被共享使用或已被其他模块独占if (active || inactive) return false; if (reserved_exclusively) return false;成功后才设置reserved_exclusively true并直接绑定 PWM2 的中断回调。pwm2_start()正是通过它注册timerInterruptHandlerapp/driver/pwm2.cpwm2_stop()则调用platform_hw_timer_close_exclusive()释放。独占模式的两点含义信号质量相对更好中断路径上没有其他共享用户的调度开销互斥限制独占期间pwm、pcm、ws2812等同样使用 TIMER1 的模块无法工作。若pwm2.start()时 TIMER1 已被其他模块占用Lua 层会报错并返回false见 Lua 绑定。另外要特别说明由于 TIMER1 的软中断可能被系统其他部分屏蔽例如 OS 的某些临界区操作PWM2 的输出信号并非高精度信号且受影响程度取决于 ESP 内除 PWM2 之外的其他活动。这是该模块的固有特性不应期待它产生如硬件定时器般的严格波形。排查看门狗超时看门狗中断通常由两类情况触发单引脚频率与周期过高即定时器 ticks 值过小。CPU80 下阈值约在 125kHz周期 2、单引脚、系统负载不大时CPU160 下约为 225kHz多引脚时混用了互不兼容的频率导致公共中断周期过小参见上文“多频率混用”。两种情况都建议用pwm2.get_timer_data()观察interruptTimerCPUTicks与interruptTimerTicks对 CPU80interruptTimerCPUTicks在1/12引脚配置下低于约330/630时就需要特别警惕。PWM2 与 PWM 模块的差异对照能力PWM2PWMTIMER1 使用方式独占信号质量可能更好共享频率范围1 脉冲/53 秒 ~ 125kHzCPU16026 秒 ~ 225kHz最高 1kHz频率分数支持如 1001kHz 表达 100.1kHz不支持CPU160支持不支持同时支持的 GPIO几乎所有引脚最多 6 个占空比分辨率由pulsePeriod决定可远高于 10bit10bit0~1023与其他模块并发独占 TIMER1不可与gpio.pulse等并发可与gpio.pulse等同时使用API 参考pwm2.setup_pin_hz()以 Hz 为单位为指定引脚配置 PWM 频率适合 ≥ 1Hz 的频率范围。pwm2.setup_pin_hz(pin, frequencyAsHz, pulsePeriod, initialDuty [, frequencyDivisor])参数说明pin1~12GPIO 索引frequencyAsHz期望频率Hz如 1000 表示 1kHzpulsePeriod单个 PWM 脉冲内的离散步数如 100initialDuty初始占空比以脉冲周期步数计如 100 分辨率下 50 表示 50%frequencyDivisor整数用于表达频率分数频率/除数默认 1可省略返回nil。注意pulsePeriod与initialDuty的边界约束见 Lua 绑定参数校验resolution 0、0 initDuty resolution、freqDivisor 0。pwm2.setup_pin_sec()以“每个脉冲的秒数”为引脚配置 PWM 频率适合 0 频率 1Hz 的亚赫兹场景。例如 0.5Hz 可表达为 2 秒的脉冲。pwm2.setup_pin_sec(pin, frequencyAsSec, pulsePeriod, initialDuty [, frequencyDivisor])参数说明pin1~12GPIO 索引frequencyAsSec每个脉冲持续的秒数如 2 表示脉冲长 2 秒pulsePeriod单个 PWM 脉冲内的离散步数initialDuty初始占空比以脉冲周期步数计frequencyDivisor频率分数除数默认 1可省略返回nil。setup_pin_hz与setup_pin_sec在驱动层的区别仅是频率参数交换了divisableFreq与freqDivisor的位置app/modules/pwm2.c。pwm2.start()启动所有已配置引脚的 PWM。启动时 GPIO 引脚被设为输出TIMER1 被本模块保留若 TIMER1 已被其他模块保留会抛出 Lua 错误并返回false。ok pwm2.start()返回booltrue表示启动成功false表示 TIMER1 被其他模块占用。重复调用start()不会报错驱动层会直接返回trueapp/driver/pwm2.c。pwm2.stop()停止所有引脚的 PWM释放全部 GPIO 引脚与 TIMER1。停止后可立即调用pwm2.start()以上次的引脚设置恢复输出。pwm2.stop()返回nil。pwm2.set_duty()设置一个或多个引脚的占空比对正在进行的 PWM 输出立即生效。pwm2.set_duty(pin, duty [, pin, duty]*)pin1~12IO 索引duty0~period占空比以脉冲周期步数计。支持一次传入多组pin, duty对Lua 绑定通过循环解析可变参数实现app/modules/pwm2.c。返回nil。驱动层set_duty()会同步更新中断计数器中“关断中断计数”offInterruptCounterapp/driver/pwm2.c。pwm2.release_pin()释放某个已完成配置的引脚。该方法仅在 PWM 停止状态下可用启动中调用会报 Lua 错误见 app/modules/pwm2.c且释放并非必需——它主要用于“启动-停止-再启动”过程中引脚集合发生变化的情形。pwm2.release_pin(pin)pin1~12IO 索引。返回nil。pwm2.get_timer_data()输出与定时器相关的内部数据结构用于排查频率相关的副作用。isStarted, interruptTimerCPUTicks, interruptTimerTicks pwm2.get_timer_data()返回值说明isStartedboolPWM2 是否已启动interruptTimerCPUTicks期望的定时器中断周期CPU ticksinterruptTimerTicks实际使用的定时器中断周期TIMER1 ticksCPU ticks 的 1/16底层实现直接读取pwm2_get_module_data()-setupData的三个字段app/modules/pwm2.c。pwm2.get_pin_data()输出指定 GPIO 引脚的内部数据结构同样用于排查频率副作用。isPinSetup, duty, pulseResolutions, divisableFrequency, frequencyDivisor, resolutionCPUTicks, resolutionInterruptCounterMultiplier pwm2.get_pin_data(pin)返回值说明isPinSetupbool引脚是否已配置duty当前分配的占空比pulseResolutions分配的脉冲周期步数divisableFrequency分配的频率值frequencyDivisor分配的频率除数resolutionCPUTicks计算出的单个脉冲周期CPU ticksresolutionInterruptCounterMultiplier构成一个脉冲周期所需的定时器中断次数底层实现逐字段返回setupData.pin[pin]的内容并校验引脚号合法1~GPIO_PIN_NUM即 1~12见 app/modules/pwm2.c。底层实现一览PWM2 的中断处理是典型的计数比较法每个引脚维护currentInterruptCounter当前中断计数、pulseInterruptCcounter脉冲总中断数与offInterruptCounter关断中断数。每次 TIMER1 中断触发timerInterruptHandler()时先为每个启用引脚累加计数再根据“当前计数是否小于关断计数”决定该引脚本轮输出高电平还是低电平最后通过GPIO_REG_WRITE(GPIO_OUT_W1TS/W1TC)一次性批量写 GPIO 输出寄存器app/driver/pwm2.c。pulseInterruptCcounter (pulseResolutions 1) * resolutionInterruptCounterMultiplierapp/driver/pwm2.coffInterruptCounter则依据占空比及边界情况0% 与 100%做getDutyAdjustment()修正app/driver/pwm2.c。这套数据结构定义在 app/include/driver/pwm2.h也是get_timer_data()/get_pin_data()返回值对应的字段来源。使用建议总结先确认固件已通过app/include/user_modules.h的LUA_USE_MODULES_PWM2宏启用 PWM2 模块高频应用如 100kHz 以上务必控制引脚数量与系统负载避免触发看门狗多频率混用前先用get_timer_data()验证公共中断周期避免 GCD 退化为 1 的不可用组合与pwm、pcm、ws2812等 TIMER1 使用者不可并发需按应用场景在两者之间做取舍需要高精度波形或与其他定时器功能并发的场景应改用硬件 PWMpwm模块或专用的硬件外设。赞分享物联网嵌入式【免费下载链接】nodemcu-firmwareLua based interactive firmware for ESP8266, ESP8285 and ESP32项目地址https://gitcode.com/gh_mirrors/no/nodemcu-firmware点击查看免费下载相关推荐Arduino-IRremote发送引脚配置终极指南软件PWM与硬件PWM对比分析Arduino IRremote发送引脚配置终极指南软件PWM与硬件PWM对比分析 Arduino IRremote是一款功能强大的红外遥控库允许Ardui物联网嵌入式智能家居DiffSynth-Studio Offload Training 全解析基于 Hook 机制的逐层 CPU 卸载训练指南DiffSynth Studio Offload Training 全解析基于 Hook 机制的逐层 CPU 卸载训练指南 导读 本文面向需要在有限显存VR物联网嵌入式NodeMCU Firmware pcm 模块实战指南基于 Sigma-Delta 硬件的音频播放与驱动 API 全解析NodeMCU Firmware pcm 模块实战指南基于 Sigma Delta 硬件的音频播放与驱动 API 全解析 导读 NodeMCU Firmwar物联网嵌入式上一篇Flutter-Music-Player插件集成教程flute_music_player深度使用指南下一篇Shogun机器学习工具箱跨平台部署与性能优化实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

F2 环形图(Donut Chart)实战指南:极坐标、中心文本与嵌套环图实现
F2 环形图(Donut Chart)实战指南:极坐标、中心文本与嵌套环图实现

数据可视化前端 【免费下载链接】F2 📱📈An elegant, interactive and flexible charting library for mobile. 项目地址: https://gitcode.com/gh_mirrors/f2/F2 点击查看 免费下载 F2 是一个面向移动端的优雅、交互式且灵活的图表库。本篇… · 2026/9/27 7:58:22

国内本地操作型 Agent 测评对比:用 TaoToken 统一 Key 跑通 OpenClaw 配置链路
国内本地操作型 Agent 测评对比:用 TaoToken 统一 Key 跑通 OpenClaw 配置链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 7:58:16

如何在 VS Code 中配置 Claude Code 扩展并接入 TaoToken 统一 API 通道
如何在 VS Code 中配置 Claude Code 扩展并接入 TaoToken 统一 API 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 7:58:10

使用 Native SDK 构建 React 桌面应用:从 `zig build run` 到开发服务器与打包发布
使用 Native SDK 构建 React 桌面应用:从 `zig build run` 到开发服务器与打包发布

桌面应用跨平台 【免费下载链接】native Toolkit for building native desktop apps 项目地址: https://gitcode.com/gh_mirrors/ze/native 点击查看 免费下载 examples/react 是 Native SDK 仓库中最简洁的「前端 原生壳」参考实现:前端使用 React&am… · 2026/9/27 8:45:59

基于Python的新能源汽车销售数据分析系统(需求文档)
基于Python的新能源汽车销售数据分析系统(需求文档)

论文(设计)基本要求:包括论文(设计)的基本内容、应完成的基本环节及各环节要求、学生应遵循的学术规范等一、基本内容:本系统前端采用现代化的UI框架,实现用户友好的交互界面。用户可通过登录与注册模块安全… · 2026/9/27 8:45:59

gopls 汇编文件支持实战:在 Go *.s 文件中实现定义跳转、引用查找、悬停与高亮
gopls 汇编文件支持实战:在 Go *.s 文件中实现定义跳转、引用查找、悬停与高亮

开发工具静态分析代码质量IDE代码生成 【免费下载链接】tools [mirror] Go Tools 项目地址: https://gitcode.com/gh_mirrors/too/tools 点击查看 免费下载 导读:Go 汇编文件(*.s)长期是语言服务器(LSP)服… · 2026/9/27 8:45:53

Substrate Collective Pallet 深度解析:理事会治理中的多成员投票、提案动议与 Prime 默认投票机制
Substrate Collective Pallet 深度解析:理事会治理中的多成员投票、提案动议与 Prime 默认投票机制

区块链开发框架后端 【免费下载链接】substrate Substrate: The platform for blockchain innovators 项目地址: https://gitcode.com/gh_mirrors/su/substrate 点击查看 免费下载 本文围绕 frame/collective/README.md 展开,系统讲解 Substrate 中 pal… · 2026/9/27 8:45:41

提供秦皇岛网站建设3招告别丑模板,免费工具救急
提供秦皇岛网站建设3招告别丑模板,免费工具救急

提供秦皇岛网站建设3招告别丑模板,免费工具救急 看着手里那份刚做好的官网,你是不是也跟我当时一样,心里直犯嘀咕?这模板网站太丑不够用,发出去客户第一眼就划走,根本留不住人。别急着删,也别急着换更贵的模板,咱们先停下来,用几个 免费工具… · 2026/9/27 8:45:41

Three.js 赛博空间高拟真流体雨滴与地面波纹:基于动态法线贴图与水面着色器
Three.js 赛博空间高拟真流体雨滴与地面波纹:基于动态法线贴图与水面着色器

Three.js 赛博空间高拟真流体雨滴与地面波纹:基于动态法线贴图与水面着色器在构建赛博朋克 3D 虚拟都市、雨夜暗黑展厅或未来全息交互界面时,倾盆大雨与积水地面上的动态雨滴涟漪(Rain Droplets & Ground Ripples) 是渲染电影… · 2026/9/27 8:45:35

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码