ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

PWM转DAC:低成本实现模拟电压输出的硬件技巧与工程实践

PWM转DAC:低成本实现模拟电压输出的硬件技巧与工程实践 1. 从PWM到DAC一个被低估的硬件技巧如果你手头有一个微控制器项目需要输出一个模拟电压信号比如控制LED亮度、驱动一个简单的扬声器或者生成一个缓慢变化的传感器基准电压但你的MCU偏偏没有内置数模转换器DAC你会怎么办是去外挂一个DAC芯片增加成本和PCB面积还是直接换一个带DAC的MCU其实绝大多数工程师在职业生涯的某个阶段都会遇到这个问题而一个经典且高效的解决方案就藏在几乎每个MCU都有的基础外设里脉冲宽度调制也就是PWM。把PWM当DAC用这听起来像是一个“凑合”的土办法但事实上它在精度要求不高、带宽需求低的场景下是一个非常可靠且成本为零的工程选择。我做过不少消费电子和物联网设备在很多对成本极其敏感或者IO口资源紧张的项目里这个技巧帮我省下了宝贵的BOM成本和PCB空间。它的核心思想很简单通过一个低通滤波器将PWM输出的数字方波中的高频开关成分滤掉只留下其直流平均分量这个平均电压值就正比于PWM的占空比。这样一来一个只有高低电平的数字引脚就摇身一变成为了一个可以输出连续可变电压的模拟端口。当然这个方法并非没有局限。它输出的“模拟”信号带宽很窄无法快速变化它的精度和稳定性受到PWM分辨率、滤波器设计以及电源噪声的显著影响。但这恰恰是它的用武之地——对于那些变化缓慢的控制信号、设定点或者指示灯驱动它完美契合。本文将彻底拆解“PWM变DAC”这个技巧从背后的数学原理和电路模型开始一步步带你设计滤波器、在代码中配置PWM并深入探讨如何评估其性能、避开常见的坑最终让你能自信地在下一个项目中应用这个既古老又实用的硬件设计技巧。2. 核心原理方波、平均值与低通滤波要理解PWM如何模拟DAC我们必须先抛开“模拟”和“数字”的刻板印象从信号的角度来看待PWM输出。一个PWM信号本质上是一个周期固定、但高电平时间脉宽可调的方波。2.1 直流平均分量的计算假设PWM信号的周期为T高电平时间为Ton占空比D Ton / T。如果该信号的高电平电压为Vcc例如3.3V低电平为0V。那么在一个周期内该信号的平均电压值Vavg可以通过积分计算Vavg (1/T) * ∫_0^T V(t) dt (1/T) * (Vcc * Ton 0 * (T - Ton)) Vcc * (Ton / T) Vcc * D这个公式揭示了最核心的关系PWM信号在一个周期内的平均电压等于电源电压乘以占空比。例如Vcc3.3V50%占空比时平均电压就是1.65V75%占空比时平均电压是2.475V。如果我们能让负载只对这个“平均电压”产生响应而忽略快速的电压跳变那么从效果上看我们就得到了一个DAC。2.2 低通滤波器的作用与模型然而真实的负载如一个LED、一个运算放大器的输入并不会自动计算平均值。它们会对电压的瞬时变化做出反应。PWM信号中除了我们想要的直流分量即平均电压还包含丰富的高频谐波成分这些谐波是方波形状所固有的。如果我们直接把PWM引脚连接到负载负载感受到的将是高速通断的方波而非平滑的直流电压。这时低通滤波器就登场了。它的作用就像一个“频率门卫”允许低频这里指变化缓慢的直流或低频信号通过而强烈衰减高频成分。一个最简单的一阶RC低通滤波器由一个电阻和一个电容构成其截止频率fc由公式决定fc 1 / (2π * R * C)其中R是电阻值C是电容值。截止频率的含义是频率低于fc的信号大部分能通过频率高于fc的信号则被大幅衰减。我们的设计目标就是让fc远低于PWM的基波频率即1/T从而将PWM方波中的高频开关噪声滤除得足够干净最终在电容两端得到一个纹波很小的、近似直流的电压这个电压值就等于上述计算的平均电压Vavg。注意这里说的“基波频率”就是PWM的频率本身。一个占空比50%的方波其能量主要分布在开关频率及其奇数次谐波上。滤波器必须对这些频率都有足够的衰减。为了更直观地理解不同滤波器参数下的效果我们可以看下面这个对比滤波器类型电路复杂度纹波电压响应速度适用场景一阶RC滤波最简单1电阻1电容较高衰减慢-20dB/十倍频慢建立时间长对纹波不敏感信号变化极慢的场景如LED调光、基准电压二阶RC滤波简单2电阻2电容较低衰减更快-40dB/十倍频更慢需要更低纹波但仍可接受较慢响应的场景有源滤波复杂需运放很低可精确设计可设计通常比无源快需要低阻抗输出、精确截止频率或特定滤波特性的场景对于大多数将PWM用作DAC的应用一阶RC滤波器因其极简和低成本已成为事实上的标准选择。它的设计就是在纹波、响应速度和电路复杂度之间取得一个平衡。3. 硬件设计实战RC滤波器参数计算与选型理论清晰后我们来动手设计。整个硬件部分的核心就是这个一阶RC低通滤波器。设计过程就是根据你的性能需求求解R和C的值。3.1 明确设计约束条件在计算之前必须定义三个关键参数PWM频率这是你将在微控制器代码中设置的PWM开关频率记为f_pwm。允许的电压纹波你希望滤波后输出电压的波动峰值V_ripple有多大这取决于你的负载对噪声的敏感度。例如驱动一个LED100mV纹波可能无关紧要但作为一个精密传感器的参考电压可能要求纹波小于10mV。期望的响应速度当你的PWM占空比改变后滤波器的输出电压需要多长时间才能稳定到新值的某个百分比比如90%这个时间与滤波器的RC时间常数τ R * C直接相关。τ越大响应越慢。这三个参数相互制约。提高PWM频率可以降低纹波但可能会受限于MCU的性能。减小纹波要求更低的截止频率更大的RC乘积但这会降低响应速度。你需要根据具体应用做权衡。3.2 分步计算与元件选择假设我们为一个智能灯饰项目设计MCU的GPIO输出高电平为3.3V我们期望PWM频率f_pwm 1 kHz(周期 T 1ms)可接受的峰峰值纹波V_ripple_pp 50mV负载是一个高输入阻抗的MOSFET栅极几乎不吸取电流。步骤一估算所需截止频率对于一阶RC滤波器当输入为方波时输出纹波电压的近似公式为V_ripple_pp ≈ Vcc * (T / (R*C)) Vcc * (T / τ) 其中 τ R*C。 这个公式在截止频率远低于PWM频率时比较准确。我们可以用它进行初步估算τ R*C ≈ Vcc * T / V_ripple_pp 3.3V * 0.001s / 0.05V 0.066 秒。 那么截止频率fc 1 / (2πτ) ≈ 1 / (2*3.14*0.066) ≈ 2.4 Hz。这意味着为了将1kHz PWM的纹波抑制到50mV以下我们需要一个截止频率大约为2.4Hz的低通滤波器。这是一个非常低的频率。步骤二选择具体的R和C值有了 τ 0.066s我们就可以选择R和C了。理论上有无穷多对组合如 66kΩ 1μF 6.6kΩ 10μF。选择时需考虑电阻R不能太小否则会从MCU的GPIO吸取过大电流。通常MCU GPIO的拉电流能力在20mA左右为了安全留有余量流过R的电流应远小于此值。当输出为高电平3.3V时电流 I Vcc / R。若R10kΩ I0.33mA非常安全。也不能太大否则电路容易受电磁干扰。电容C不能太小否则纹波会太大不能太大否则体积和成本会增加且漏电流可能影响精度。电解电容便宜容量大但精度差、有极性陶瓷电容如X7R X5R精度高、无极性是更好的选择但大容量10μF的陶瓷电容价格较高。一个折中的方案选择 R 10 kΩ 则 C τ / R 0.066s / 10000Ω 6.6 μF。 我们可以取一个标称值C 10 μF。此时实际 τ‘ 10k * 10μF 0.1s 截止频率 fc’ 1.6 Hz 纹波会更小。步骤三电路连接与布局最终的电路极其简单MCU_PWM_GPIO ---[R]------[C]--- GND|VoutVout就是从电容C正极引出的“模拟”电压。这里有几个硬件实操要点电容类型强烈推荐使用多层陶瓷电容MLCC如10μF/10V X5R或X7R材质。它们没有极性ESR低性能稳定。如果使用电解电容务必注意极性反接会损坏。布局电阻和电容应尽可能靠近MCU的PWM输出引脚放置尤其是电容的接地端回路越短越好以减少引入噪声的机会。负载考虑我们的计算假设负载是理想的高阻抗。如果负载会吸取不可忽略的电流例如直接驱动一个LED那么负载电阻会与R形成分压导致输出电压低于计算值。在这种情况下要么确保负载阻抗远大于R至少10倍以上要么在滤波器后增加一个电压跟随器运放构成进行缓冲提供低阻抗输出。4. 软件配置最大化PWM性能的关键硬件滤波器搭建好了但PWM信号的质量是软件赋予的。不恰当的PWM配置会直接导致最终的“模拟”输出精度差、噪声大。4.1 PWM频率与分辨率的权衡这是最重要的一个权衡点。PWM有两个核心参数频率如前所述频率越高经过相同滤波器后纹波越小对滤波器要求越低。但频率受限于MCU定时器的时钟和你的分辨率需求。分辨率指占空比可以调节的精细程度通常用位数表示。例如8位分辨率意味着占空比可以有256级0-25510位则有1024级。矛盾在于在定时器时钟源固定的情况下提高频率必然会降低分辨率。因为频率 f 时钟 / (分频系数 * 自动重载值)。自动重载值决定了计数器的最大值也直接决定了分辨率最大值1就是级数。要提高f就必须减小自动重载值从而减少了可用的计数值分辨率就下降了。如何选择这取决于应用高精度、慢变化信号优先保证分辨率。例如要输出0-3.3V步进小于5mV约需660级10位分辨率。此时可以接受较低的PWM频率如100Hz-1kHz然后通过更严格的滤波器更大的RC来抑制纹波。快速响应、精度要求一般可以适当提高频率以加快响应速度或简化滤波器。例如LED调光人眼对亮度微小变化不敏感8位256级通常足够频率可以设在100Hz以上以避免闪烁。以常见的STM32的通用定时器为例如果系统时钟是72MHz我们希望得到10位分辨率自动重载值ARR1023不分频PSC0那么PWM频率f 72MHz / (10231) ≈ 70.3 kHz。这是一个很高的频率对滤波器非常友好可以用很小的RC值就能滤出平滑电压。4.2 代码实现示例与高级技巧以下是基于STM32 HAL库的一个基础配置示例目标是生成一个1kHz 8位分辨率的PWMTIM_HandleTypeDef htim2; TIM_OC_InitTypeDef sConfigOC {0}; // 定时器基础配置 htim2.Instance TIM2; htim2.Init.Prescaler 71; // 系统时钟72MHz 分频后为1MHz (72/(711)) htim2.Init.CounterMode TIM_COUNTERMODE_UP; htim2.Init.Period 999; // 自动重载值ARR 周期 (ARR1)/定时器时钟 1000/1MHz 1ms - 1kHz htim2.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(htim2); // PWM通道配置 sConfigOC.OCMode TIM_OCMODE_PWM1; sConfigOC.Pulse 500; // 初始占空比 CCR值 500/1000 50% sConfigOC.OCPolarity TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(htim2, sConfigOC, TIM_CHANNEL_1); // 启动PWM HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_1); // 动态改变占空比 __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_1, 750); // 改为75%占空比高级技巧中心对齐模式大多数定时器支持边沿对齐计数器向上计数和中心对齐计数器先上后下。中心对齐模式可以将PWM输出的谐波能量更多地集中在开关频率的倍频上而不是分散在基波和谐波中有时更有利于滤波。死区时间如果用于驱动桥式电路需要设置死区时间但作为DAC使用时通常不需要。DMA传输如果需要输出复杂的模拟波形如正弦波可以预先计算好一个周期的占空比数组然后通过DMA自动、定时地更新PWM的捕获比较寄存器CCR从而解放CPU。这是实现“PWM DAC”播放音频等动态波形的基础。5. 性能评估与常见问题排查电路搭好了代码也跑起来了用万用表一量电压确实随着占空比变化了。但这就够了吗作为一个严谨的工程师我们必须量化它的性能并知道如何解决可能出现的问题。5.1 实测指标纹波、线性度与建立时间不要只相信万用表的直流电压档它测的是平均值会掩盖纹波。你需要一个示波器来真正评估输出质量。测量纹波将示波器探头连接到滤波器的输出端电容两端。设置示波器为交流耦合适当调整垂直灵敏度如20mV/格和时间基准。你应该能看到一个近似三角波或锯齿波的微小波动这就是纹波。测量其峰峰值Vpp。这个值应该与你理论计算或预期的纹波值在同一数量级。如果纹波过大首先检查PWM频率是否稳定然后考虑增大电容C或电阻R以降低截止频率。测试线性度编写一个循环让PWM占空比从最小值如0线性增加到最大值如255。用万用表直流电压档记录下几个关键占空比点如0 64 128 192 255对应的输出电压。理论上电压应与占空比成完美的线性关系Vout Vcc * (Duty / Max_Duty)。实际绘制出的Vout-Duty曲线可能会在两端接近0%和100%出现非线性。这通常是因为GPIO引脚在输出极低或极高占空比时其上升/下降时间、驱动能力不对称导致的。如果线性度要求高应避免使用两端的5%-10%的范围。测量建立时间在示波器上将PWM占空比从一个值如10%阶跃变化到另一个值如90%。使用示波器的单次触发和上升沿/下降沿触发捕捉电压变化的完整过程。测量输出电压从变化开始到达最终值±1%误差带内所需的时间。这就是系统的建立时间。对于一阶RC系统理论上从10%到90%的上升时间约为2.2τ。实测值应与理论值吻合。如果响应太慢就需要减小R或C但这会增大纹波你需要重新权衡。5.2 典型问题与解决方案在实际项目中我遇到过不少坑这里总结几个最常见的问题一输出电压达不到理论值例如100%占空比时不到Vcc可能原因1GPIO负载过重。检查你的电阻R是否太小。如果R1kΩ当输出高电平时GPIO需要提供3.3V/1kΩ3.3mA的电流。虽然很多MCU可以承受但如果同时有其他负载可能导致内部压降使输出高电平低于Vcc。解决方案是增大R比如到10kΩ。可能原因2电容漏电流。特别是使用电解电容时其漏电流可能达到几十甚至上百微安。这个漏电流在电阻R上会产生压降。解决方案是换用漏电流极小的陶瓷电容或适当减小R值但需考虑GPIO驱动能力。可能原因3负载电流过大。如果你的负载如一个LED直接接在Vout上它会从滤波器中吸取电流导致电压下降。解决方案是在滤波器后增加一个电压跟随器进行缓冲。问题二输出噪声大纹波远超计算值可能原因1电源噪声。PWM输出和模拟电路共用同一个嘈杂的数字电源。用示波器查看Vcc引脚上的噪声。解决方案是给模拟部分MCU的模拟电源引脚、滤波电路增加LC滤波或使用低压差线性稳压器LDO单独供电。可能原因2地线噪声。滤波电容的接地端没有接到一个干净、稳定的“模拟地”上而是和数字地的大电流路径混在一起。解决方案是采用星型接地或单点接地将滤波电容的地直接接到MCU的模拟地引脚或一个安静的地平面点。可能原因3PWM频率不稳定。检查代码中定时器配置是否正确是否有其他中断或任务长时间阻塞影响了PWM的稳定性。可以用示波器直接测量PWM引脚本身的频率和占空比是否精准。问题三响应速度太慢无法跟上控制需求根本原因RC时间常数τ太大。这是为提高滤波效果降低纹波而付出的代价。解决方案提高PWM频率这是最有效的方法。频率提高一倍在保持相同纹波水平的前提下截止频率可以提高一倍从而RC乘积可以减半响应速度翻倍。检查你的MCU能否支持更高的PWM频率。使用高阶滤波器如前所述二阶无源或有源滤波器可以在相同的截止频率下提供更陡的衰减从而允许你使用更高的截止频率更小的τ来达到相同的纹波抑制效果进而提升响应速度。但这增加了电路复杂度。接受更大的纹波如果负载对纹波不敏感可以重新评估纹波要求适当放宽从而减小RC值。将PWM用作DAC是一个在成本、性能和复杂度之间寻求优雅平衡的经典工程实践。它绝不仅仅是“凑合能用”而是在明确边界条件低带宽、中低精度下的最优解。理解其背后的信号原理掌握滤波器设计中的权衡艺术在软件上精细配置PWM参数并在调试中善用仪器观察现象、定位问题你就能把这个简单的技巧变成项目工具箱里一件可靠又灵活的工具。下次当你的设计需要多一路模拟输出而资源紧张时不妨先问问自己这里真的需要一个真正的DAC吗也许一个PWM加两个元件的方案正是最合适的那一个。
返回列表