1. PWM-DAC实验概述
在嵌入式开发领域,PWM(脉冲宽度调制)转DAC(数模转换)是一项极具实用价值的技术。这个实验的核心在于利用STM32F1xx系列芯片的定时器PWM功能,通过简单的RC滤波电路,实现低成本、高精度的模拟信号输出。相比专用DAC芯片,这种方案在成本敏感型应用中优势明显。
我在工业控制项目中多次采用这种方案,例如需要生成0-10V控制信号的场合。通过合理配置PWM参数和滤波电路,完全能够满足大多数场景的精度要求。下面我将从硬件设计到软件实现,详细拆解这个实验的关键技术点。
2. 硬件设计要点
2.1 PWM输出电路设计
STM32F1xx的定时器可以输出最高72MHz的PWM信号。实验中使用的是定时器通道输出的PWM波,经过二阶RC低通滤波后得到平滑的模拟电压。典型电路参数如下:
| 元件 | 参数值 | 选择依据 |
|---|---|---|
| R1 | 1kΩ | 限流电阻,防止IO过载 |
| R2 | 10kΩ | 与C1构成截止频率约16Hz |
| C1 | 1μF | 陶瓷电容,低ESR特性 |
| C2 | 0.1μF | 高频噪声抑制 |
实际调试中发现,使用X7R或X5R材质的陶瓷电容效果优于电解电容,因为它们的等效串联电阻(ESR)更低。
2.2 精度影响因素分析
PWM-DAC的精度主要受三个因素制约:
- PWM分辨率:STM32F1的定时器支持16位计数器,理论上可实现16位分辨率
- RC滤波特性:截止频率需至少低于PWM频率的1/10
- 电源噪声:LDO电源比开关电源更有利于提高信噪比
实测数据表明,在PWM频率为10kHz,使用12位分辨率时,系统整体精度可达0.1%FSR(满量程范围)。
3. 软件实现详解
3.1 定时器配置
使用标准库配置定时器的关键步骤如下:
c复制// 定时器时基初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 4095; // 12位分辨率
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 72MHz/(71+1)=1MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// PWM输出配置
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 2048; // 50%占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInit(TIM3, &TIM_OCInitStructure, TIM_Channel_2);
3.2 动态调整输出
通过修改CCR寄存器值实现输出电压调整:
c复制void Set_PWM_DAC_Value(uint16_t value)
{
if(value > 4095) value = 4095; // 防止溢出
TIM_SetCompare2(TIM3, value);
}
在电机控制项目中,我通常会添加软件滤波算法,避免输出突变导致机械冲击。例如采用S曲线渐变算法:
c复制void Smooth_Set_PWM(uint16_t target, uint16_t steps)
{
uint16_t current = TIM_GetCapture2(TIM3);
float delta = (float)(target - current)/steps;
for(int i=0; i<steps; i++){
current += (uint16_t)delta;
TIM_SetCompare2(TIM3, current);
Delay_ms(1);
}
}
4. 性能优化技巧
4.1 提高分辨率的方法
虽然硬件定时器支持16位分辨率,但实际应用中会受到PWM频率限制。通过软件方式可以实现更高分辨率:
- PWM+抖动算法:在多个周期内调整占空比,实现等效更高分辨率
- 双PWM合成:使用两个相位相反的PWM信号,通过差分放大提高分辨率
4.2 降低纹波的措施
实测纹波主要来自三个方面:
- PWM开关噪声
- 电源噪声
- 数字信号串扰
对应的解决方案:
- 在PCB布局时,PWM走线要远离模拟信号线
- 在滤波电容旁并联100nF+10μF组合电容
- 在IO口串联22Ω电阻可有效抑制高频振铃
5. 典型应用场景
5.1 工业控制信号生成
在PLC扩展模块中,我常用PWM-DAC生成以下信号:
- 0-10V电机调速信号
- 4-20mA变送器输入(需加V/I转换电路)
- 温度控制系统的设定值输出
5.2 音频信号合成
通过提高PWM频率(建议≥100kHz)和采用Σ-Δ调制技术,可以实现简单的音频合成。一个实用的技巧是使用DMA自动更新PWM占空比,配合预先计算的波形表。
c复制// 生成正弦波表示例
#define WAVE_TABLE_SIZE 256
uint16_t sin_wave[WAVE_TABLE_SIZE];
void Generate_SineWave(void)
{
for(int i=0; i<WAVE_TABLE_SIZE; i++){
float angle = 2 * 3.1415926 * i / WAVE_TABLE_SIZE;
sin_wave[i] = 2048 + (uint16_t)(2047 * sin(angle));
}
}
6. 调试与问题排查
6.1 常见问题速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 输出幅度不足 | 滤波截止频率过高 | 增大RC时间常数 |
| 输出有台阶状纹波 | PWM分辨率不足 | 提高计数器周期值 |
| 输出不稳定 | 电源噪声大 | 增加LC滤波,改用LDO供电 |
| 响应速度慢 | 滤波截止频率过低 | 减小电容值,提高PWM频率 |
6.2 示波器调试技巧
调试PWM-DAC时,建议同时观察三处信号:
- PWM原始输出(确认占空比正确)
- 滤波后信号(检查纹波情况)
- 最终输出(确认负载效应)
一个实用的方法是使用示波器的FFT功能分析输出频谱,可以清晰看到:
- 基波频率(即PWM频率)
- 谐波成分
- 噪声分布
7. 进阶应用:闭环控制
将PWM-DAC与ADC结合,可以实现闭环控制。例如在恒压源设计中:
c复制#define TARGET_VOLTAGE 2500 // 2.5V
void Voltage_Control_Loop(void)
{
uint16_t adc_val = ADC_Read();
int error = TARGET_VOLTAGE - adc_val;
// 简单PI控制
static int integral = 0;
integral += error / 10;
uint16_t pwm_val = 2048 + error / 8 + integral / 20;
TIM_SetCompare2(TIM3, pwm_val);
}
在实际项目中,这种方案的静态误差可以控制在±5mV以内,完全满足大多数检测设备的需求。关键是要合理选择PI参数,避免振荡。我的经验是从较小的比例系数开始,逐步增加直到出现轻微超调,然后加入适当的积分项消除静差。