用PWM波在STM32上实现8位DAC的工程实践指南在嵌入式开发中模拟信号输出是一个常见需求但并非所有微控制器都配备足够的DAC资源。对于成本敏感型项目特别是智能家居传感器、小型电机控制等应用利用PWM波配合RC滤波器实现DAC功能是一个极具性价比的解决方案。本文将深入探讨如何通过STM32的定时器PWM功能配合精心设计的RC滤波器实现8位分辨率的模拟输出。1. PWM DAC的核心原理与优势PWM转DAC的核心思想是利用低通滤波器提取PWM信号中的直流分量。当PWM波的占空比变化时其平均电压也随之改变这正是DAC功能的基础实现方式。PWM DAC相比硬件DAC的三大优势成本优势无需额外DAC芯片仅需几个电阻电容资源复用充分利用MCU已有的PWM外设灵活性分辨率可通过软件调整适应不同需求在STM32中PWM波由定时器产生关键参数由ARR自动重装载寄存器和CCRx捕获/比较寄存器决定。当计数器值小于CCRx时输出高电平大于CCRx时输出低电平达到ARR值时复位重新计数。提示8位分辨率需要将ARR值设为2550-255共256个等级这样PWM频率定时器时钟/(ARR1)2. STM32 PWM配置实战以STM32F103系列为例配置定时器3的通道1产生PWM波// PWM初始化代码示例 void PWM_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_InitTypeDef GPIO_InitStructure; // 使能时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 配置GPIO GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; // TIM3_CH1 GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // 定时器基础配置 TIM_TimeBaseStructure.TIM_Period 255; // 8位分辨率 TIM_TimeBaseStructure.TIM_Prescaler 0; TIM_TimeBaseStructure.TIM_ClockDivision 0; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); // PWM模式配置 TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse 0; // 初始占空比 TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM3, TIM_OCInitStructure); TIM_Cmd(TIM3, ENABLE); }关键参数说明参数说明8位DAC典型值TIM_Period自动重装载值255TIM_Prescaler预分频系数根据时钟频率调整TIM_Pulse初始占空比0-2553. RC滤波器设计精要RC低通滤波器的设计是PWM DAC成败的关键。滤波器需要满足两个核心要求足够衰减PWM基频及其谐波保持足够的响应速度一阶与二阶滤波器对比特性一阶滤波器二阶滤波器衰减斜率20dB/十倍频40dB/十倍频元件数量1R1C2R2C设计复杂度简单中等相位延迟较小较大对于8位分辨率我们需要确保基波谐波造成的纹波小于1LSB3.3V/256≈12.9mV。以72MHz时钟、8位分辨率为例关键计算步骤PWM频率 72MHz / 256 281.25kHz基波幅度 (2×3.3V)/π ≈ 2.1V所需衰减 20×log10(2.1V/0.0129V) ≈ 44dB截止频率计算一阶滤波器fc 281.25kHz / 10^(44/20) ≈ 1.77kHz二阶滤波器fc 281.25kHz / 10^(44/40) ≈ 22.34kHz4. 实际电路实现与优化基于上述计算我们给出两种典型电路实现方案方案一一阶RC滤波器PWM输出 → R1 → 输出 → C1 → GND ↓ 负载元件值计算# 一阶滤波器计算示例 fc_desired 1.77e3 # 目标截止频率 C 100e-9 # 选用常见100nF电容 R 1 / (2 * 3.1416 * fc_desired * C) print(f所需电阻值: {R:.1f} Ω)输出所需电阻值: 899.7 Ω可选用900Ω或1kΩ方案二二阶RC滤波器PWM输出 → R1 → R2 → 输出 → C1 → GND ↓ C2 → GND元件值计算Butterworth配置# 二阶滤波器计算示例 fc_desired 22.34e3 C 10e-9 # 选用10nF电容 R 1 / (2 * 3.1416 * fc_desired * C) print(f单电阻值: {R:.1f} Ω)输出单电阻值: 712.8 Ω可选用715Ω或750Ω注意实际应用中应考虑运放缓冲避免负载影响滤波特性。若直接驱动负载建议在输出端添加电压跟随器。5. 性能测试与校准技巧实现PWM DAC后需要进行系统级测试和校准测试步骤输出0%占空比测量实际输出电压应为0V输出100%占空比测量实际输出电压应接近VCC输出50%占空比验证输出电压是否为中间值用示波器观察纹波电压确保1LSB常见问题及解决方案问题现象可能原因解决方法输出非线性滤波器截止频率过高降低fc增大RC时间常数响应速度慢滤波器截止频率过低提高fc减小RC时间常数输出电压不足负载阻抗过低添加运放缓冲纹波过大滤波器衰减不足增加滤波器阶数在实际项目中我发现使用二阶滤波器配合简单的软件校准可以获得优于±2LSB的线性度。一个实用的校准技巧是在代码中建立查找表补偿非线性误差// 非线性补偿表示例 const uint8_t DAC_LUT[256] { 0, 1, 2, 3, ..., // 实测校准值 // ... 253, 254, 255 }; void Set_PWM_DAC(uint8_t value) { TIM3-CCR1 DAC_LUT[value]; }
别再浪费你的STM32定时器了!用PWM波低成本实现8位DAC(附RC滤波器参数计算)
发布时间:2026/5/18 14:44:07
用PWM波在STM32上实现8位DAC的工程实践指南在嵌入式开发中模拟信号输出是一个常见需求但并非所有微控制器都配备足够的DAC资源。对于成本敏感型项目特别是智能家居传感器、小型电机控制等应用利用PWM波配合RC滤波器实现DAC功能是一个极具性价比的解决方案。本文将深入探讨如何通过STM32的定时器PWM功能配合精心设计的RC滤波器实现8位分辨率的模拟输出。1. PWM DAC的核心原理与优势PWM转DAC的核心思想是利用低通滤波器提取PWM信号中的直流分量。当PWM波的占空比变化时其平均电压也随之改变这正是DAC功能的基础实现方式。PWM DAC相比硬件DAC的三大优势成本优势无需额外DAC芯片仅需几个电阻电容资源复用充分利用MCU已有的PWM外设灵活性分辨率可通过软件调整适应不同需求在STM32中PWM波由定时器产生关键参数由ARR自动重装载寄存器和CCRx捕获/比较寄存器决定。当计数器值小于CCRx时输出高电平大于CCRx时输出低电平达到ARR值时复位重新计数。提示8位分辨率需要将ARR值设为2550-255共256个等级这样PWM频率定时器时钟/(ARR1)2. STM32 PWM配置实战以STM32F103系列为例配置定时器3的通道1产生PWM波// PWM初始化代码示例 void PWM_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_InitTypeDef GPIO_InitStructure; // 使能时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 配置GPIO GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; // TIM3_CH1 GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // 定时器基础配置 TIM_TimeBaseStructure.TIM_Period 255; // 8位分辨率 TIM_TimeBaseStructure.TIM_Prescaler 0; TIM_TimeBaseStructure.TIM_ClockDivision 0; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); // PWM模式配置 TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse 0; // 初始占空比 TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM3, TIM_OCInitStructure); TIM_Cmd(TIM3, ENABLE); }关键参数说明参数说明8位DAC典型值TIM_Period自动重装载值255TIM_Prescaler预分频系数根据时钟频率调整TIM_Pulse初始占空比0-2553. RC滤波器设计精要RC低通滤波器的设计是PWM DAC成败的关键。滤波器需要满足两个核心要求足够衰减PWM基频及其谐波保持足够的响应速度一阶与二阶滤波器对比特性一阶滤波器二阶滤波器衰减斜率20dB/十倍频40dB/十倍频元件数量1R1C2R2C设计复杂度简单中等相位延迟较小较大对于8位分辨率我们需要确保基波谐波造成的纹波小于1LSB3.3V/256≈12.9mV。以72MHz时钟、8位分辨率为例关键计算步骤PWM频率 72MHz / 256 281.25kHz基波幅度 (2×3.3V)/π ≈ 2.1V所需衰减 20×log10(2.1V/0.0129V) ≈ 44dB截止频率计算一阶滤波器fc 281.25kHz / 10^(44/20) ≈ 1.77kHz二阶滤波器fc 281.25kHz / 10^(44/40) ≈ 22.34kHz4. 实际电路实现与优化基于上述计算我们给出两种典型电路实现方案方案一一阶RC滤波器PWM输出 → R1 → 输出 → C1 → GND ↓ 负载元件值计算# 一阶滤波器计算示例 fc_desired 1.77e3 # 目标截止频率 C 100e-9 # 选用常见100nF电容 R 1 / (2 * 3.1416 * fc_desired * C) print(f所需电阻值: {R:.1f} Ω)输出所需电阻值: 899.7 Ω可选用900Ω或1kΩ方案二二阶RC滤波器PWM输出 → R1 → R2 → 输出 → C1 → GND ↓ C2 → GND元件值计算Butterworth配置# 二阶滤波器计算示例 fc_desired 22.34e3 C 10e-9 # 选用10nF电容 R 1 / (2 * 3.1416 * fc_desired * C) print(f单电阻值: {R:.1f} Ω)输出单电阻值: 712.8 Ω可选用715Ω或750Ω注意实际应用中应考虑运放缓冲避免负载影响滤波特性。若直接驱动负载建议在输出端添加电压跟随器。5. 性能测试与校准技巧实现PWM DAC后需要进行系统级测试和校准测试步骤输出0%占空比测量实际输出电压应为0V输出100%占空比测量实际输出电压应接近VCC输出50%占空比验证输出电压是否为中间值用示波器观察纹波电压确保1LSB常见问题及解决方案问题现象可能原因解决方法输出非线性滤波器截止频率过高降低fc增大RC时间常数响应速度慢滤波器截止频率过低提高fc减小RC时间常数输出电压不足负载阻抗过低添加运放缓冲纹波过大滤波器衰减不足增加滤波器阶数在实际项目中我发现使用二阶滤波器配合简单的软件校准可以获得优于±2LSB的线性度。一个实用的校准技巧是在代码中建立查找表补偿非线性误差// 非线性补偿表示例 const uint8_t DAC_LUT[256] { 0, 1, 2, 3, ..., // 实测校准值 // ... 253, 254, 255 }; void Set_PWM_DAC(uint8_t value) { TIM3-CCR1 DAC_LUT[value]; }