龙空技术网

探索者 STM32F407 开发板资料连载第二十七章 PWM DAC 实验

正点原子日常 135

前言:

现在小伙伴们对“stm32 dac输出电压精度”都比较关切,姐妹们都需要分析一些“stm32 dac输出电压精度”的相关资讯。那么小编也在网上网罗了一些有关“stm32 dac输出电压精度””的相关资讯,希望大家能喜欢,咱们快快来学习一下吧!

1)实验平台:alientek 阿波罗 STM32F767 开发板

2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子

第二十七章 PWM DAC 实验

上一章,我们介绍了 STM32F4 自带 DAC 模块的使用,但有时候,可能两个 DAC 不够

用,此时,我们可以通过 PWM+RC 滤波来实一个 PWM DAC。本章我们将向大家介绍如何

使用 STM32F4 的 PWM 来设计一个 DAC。我们将使用按键(或 USMART)控制 STM32F4

的 PWM 输出,从而控制 PWM DAC 的输出电压,通过 ADC1 的通道 5 采集 PWM DAC 的

输出电压,并在 LCD 模块上面显示 ADC 获取到的电压值以及 PWM DAC 的设定输出电压

值等信息。本章将分为如下几个部分:

27.1 PWM DAC 简介

27.2 硬件设计

27.3 软件设计

27.4 下载验证

27.1 PWM DAC 简介

有时候,STM32F4 自带的 2 路 DAC 可能不够用,需要多路 DAC,外扩 DAC 成本又会

高不少。此时,我们可以利用 STM32F4 的 PWM+简单的 RC 滤波来实现 DAC 输出,从而

节省成本。 在精度要求不是很高的时候,PWM+RC 滤波的 DAC 输出方式,是一种非常廉

价的解决方案。

PWM 本质上其实就是是一种周期一定,而高低电平占空比可调的方波。实际电路的典

型 PWM 波形,如图 27.1.1 所示:

图 27.1.1 实际电路典型 PWM 波形

图 27.1.1 的 PWM 波形可以用分段函数表示为式①:

其中:T 是单片机中计数脉冲的基本周期,也就是 STM32F4 定时器的计数频率的倒数。

N 是 PWM 波一个周期的计数脉冲个数,也就是 STM32F4 的 ARR-1 的值。n 是 PWM 波一

个周期中高电平的计数脉冲个数,也就是 STM32F4 的 CCRx 的值。VH 和 VL 分别是 PWM

波的高低电平电压值,k 为谐波次数,t 为时间。我们将①式展开成傅里叶级数,得到公式

②:

从②式可以看出,式中第 1 个方括弧为直流分量,第 2 项为 1 次谐波分量,第 3 项为大

于 1 次的高次谐波分量。式②中的直流分量与 n 成线性关系,并随着 n 从 0 到 N,直流分量

从 VL 到 VL+VH 之间变化。这正是电压输出的 DAC 所需要的。因此,如果能把式②中除

直流分量外的谐波过滤掉,则可以得到从 PWM 波到电压输出 DAC 的转换,即:PWM 波

可以通过一个低通滤波器进行解调。式②中的第 2 项的幅度和相角与 n 有关,频率为 1/(NT),

其实就是 PWM 的输出频率。该频率是设计低通滤波器的依据。如果能把 1 次谐波很好过滤

掉,则高次谐波就应该基本不存在了。

通过上面的了解,我们可以得到 PWM DAC 的分辨率,计算公式如下:

分辨率=log2(N)

这里假设 n 的最小变化为 1,当 N=256 的时候,分辨率就是 8 位。而 STM32F4 的定时

器大部分都是 16 位的(TIM2 和 TIM5 是 32 位),可以很容易得到更高的分辨率,分辨率越

高,速度就越慢。不过我们在本章要设计的 DAC 分辨率为 8 位。

在 8 位分辨条件下,我们一般要求 1 次谐波对输出电压的影响不要超过 1 个位的精度,

也就是 3.3/256=0.01289V。假设 VH 为 3.3V,VL 为 0V,那么一次谐波的最大值是 2*3.3/

π=2.1V,这就要求我们的 RC 滤波电路提供至少-20lg(2.1/0.01289)=-44dB 的衰减。

STM32F4 的定时器最快的计数频率是 168Mhz,某些定时器只能到 84M,所以我们以

84M 频率为例介绍,8 为分辨率的时候,PWM 频率为 84M/256=328.125Khz。如果是 1 阶

RC 滤波,则要求截止频率 2.07Khz,如果为 2 阶 RC 滤波,则要求截止频率为 26.14Khz。

探索者 STM32F4 开发板的 PWM DAC 输出采用二阶 RC 滤波,该部分原理图如图 27.1.2

所示:

图 27.1.2 PWM DAC 二阶 RC 滤波原理图

二阶 RC 滤波截止频率计算公式为:

f=1/2πRC

以上公式要求 R28*C37=R29*C38=RC。根据这个公式,我们计算出图 27.1.2 的截止频

率为:33.8Khz 超过了 26.14Khz,这个和我们前面提到的要求有点出入,原因是该电路我们

还需要用作 PWM DAC 音频输出,而音频信号带宽是 22.05Khz,为了让音频信号能够通过

该低通滤波,同时为了标准化参数选取,所以确定了这样的参数。实测精度在 0.5LSB 左右。

PWM DAC 的原理部分,就为大家介绍到这里。

27.2 硬件设计

本章用到的硬件资源有:

1) 指示灯 DS0

2) KEY_UP 和 KEY1 按键

3) 串口

4) TFTLCD 模块

5) ADC

6) PWM DAC

本章,我们使用 STM32F4 的 TIM9_CH2(PA3)输出 PWM,经过二阶 RC 滤波后,转换

为直流输出,实现 PWM DAC。同上一章一样,我们通过 ADC1 的通道 5(PA5)读取 PWM

DAC 的输出,并在 LCD 模块上显示相关数值,通过按键和 USMART 控制 PWM DAC 的输

出值。我们需要用到 ADC 采集 DAC 的输出电压,所以需要在硬件上将 PWM DAC 和 ADC

短接起来,PWM DAC 部分原理图如图 27.2.1 所示:

图 27.2.1 PWM DAC 原理图

从上图可知 PWM_DAC 的连接关系,但是这里有个特别需要注意的地方:因为

PWM_DAC 和 USART2_RX 共用了 PA3 引脚,所以在做本例程的时候,必须拔了 P9 上面

PA3(RX)的跳线帽(左侧跳线帽),否则会影响 PWM 转换结果!!!

在硬件上,我们还需要用跳线帽短接多功能端口的 PDC 和 ADC,如图 27.2.2 所示:

图 27.2.2 硬件连接示意图

27.3 软件设计

打开本章的实验工程可以看到,我们本章并没有增加其他新的库函数文件支持。主要是

使用了 adc 和定时器相关的库函数支持。因为我们是使用定时器产生 PWM 信号作为 PWM

DAC 的输入信号经过二阶 RC 滤波从而产生一定幅度模拟信号,所以我们需要添加定时器

相关的库函数支持。在 HARDWARE 分组下,我们新建了 pwmdac.c 源文件和对应的头文件

用来初始化定时器 9 的 PWM。接下来我们看看 pwmdac.c 源文件内容:

void TIM9_CH2_PWM_Init(u16 arr,u16 psc){ TIM9_Handler.Instance=TIM9; //定时器 9 TIM9_Handler.Init.Prescaler=psc; //定时器分频 TIM9_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式 TIM9_Handler.Init.Period=arr; //自动重装载值 TIM9_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&TIM9_Handler); //初始化 PWM TIM9_CH2Handler.OCMode=TIM_OCMODE_PWM1; //模式选择 PWM1 TIM9_CH2Handler.Pulse=arr/2;//设置比较值,此值用来确定占空比,//默认比较值为自动重装载值的一半,即占空比为 50% TIM9_CH2Handler.OCPolarity=TIM_OCPOLARITY_HIGH; //输出比较极性为高 HAL_TIM_PWM_ConfigChannel(&TIM9_Handler,&TIM9_CH2Handler,TIM_CHANNEL_2);//配置 TIM9 通道 2 HAL_TIM_PWM_Start(&TIM9_Handler,TIM_CHANNEL_2);//开启 PWM 通道 2}该函数用来初始化 TIM9_CH2 的 PWM 输出(PA3),其原理同之前介绍的 PWM 输出一模一样,只是换过一个定时器而已。这里就不细说了。pwmdac.h 头文件内容主要是函数申明,这里不做过多讲解。接下来我们看看主函数内容:int main(void){u16 adcx;float temp;u8 t=0;u16 pwmval=0;u8 key; HAL_Init();//初始化 HAL 库Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhzdelay_init(168);//初始化延时函数uart_init(115200);//初始化 USARTusmart_dev.init(84);//初始化 USMARTLED_Init();//初始化 LEDKEY_Init();//初始化 KEYLCD_Init();//初始化 LCDMY_ADC_Init(); //初始化 ADC1 TIM9_CH2_PWM_Init(255,1); //TIM9 PWM 初始化, Fpwm=84M/256=328.125Khz.POINT_COLOR=RED;LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");LCD_ShowString(30,70,200,16,16,"PWM DAC TEST");LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");LCD_ShowString(30,110,200,16,16,"2017/4/13");LCD_ShowString(30,130,200,16,16,"WK_UP:+ KEY1:-");POINT_COLOR=BLUE;//设置字体为蓝色LCD_ShowString(30,150,200,16,16,"DAC VAL:");LCD_ShowString(30,170,200,16,16,"DAC VOL:0.000V");LCD_ShowString(30,190,200,16,16,"ADC VOL:0.000V");TIM_SetTIM9Compare2(pwmval);//初始值为 0while(1){t++;key=KEY_Scan(0);if(key==4){if(pwmval<250)pwmval+=10;TIM_SetCompare2(TIM9,pwmval);//输出}else if(key==2){if(pwmval>10)pwmval-=10;else pwmval=0;TIM_SetCompare2(TIM9,pwmval);//输出}if(t==10||key==2||key==4)//WKUP/KEY1 按下了,或者定时时间到了{adcx=TIM_GetCapture2(TIM9);;LCD_ShowxNum(94,150,adcx,3,16,0); //显示 DAC 寄存器值temp=(float)adcx*(3.3/256);;//得到 DAC 电压值adcx=temp;LCD_ShowxNum(94,170,temp,1,16,0); //显示电压值整数部分temp-=adcx; temp*=1000;LCD_ShowxNum(110,170,temp,3,16,0x80);//显示电压值的小数部分adcx=Get_Adc_Average(ADC_Channel_5,20); //得到 ADC 转换值temp=(float)adcx*(3.3/4096); //得到 ADC 电压值adcx=temp;LCD_ShowxNum(94,190,temp,1,16,0);//显示电压值整数部分temp-=adcx; temp*=1000;LCD_ShowxNum(110,190,temp,3,16,0x80);//显示电压值的小数部分t=0; LED0=!LED0;}delay_ms(10);}}

此部分代码,同上一章的基本一样,先对需要用到的模块进行初始化,然后显示一些提

示信息,本章我们通过 KEY_UP 和 KEY1(也就是上下键)来实现对 PWM 脉宽的控制,经

过 RC 滤波,最终实现对 DAC 输出幅值的控制。按下 KEY_UP 增加,按 KEY1 减小。同时

在 LCD 上面显示 TIM4_CCR1 寄存器的值、PWM DAC 设计输出电压以及 ADC 采集到的实

际输出电压。同时 DS0 闪烁,提示程序运行状况。

27.4 下载验证

在代码编译成功之后,我们通过下载代码到 ALIENTEK 探索者 STM32F4 开发板上,

可以看到 LCD 显示如图 27.4.1 所示:

图 27.4.1 PWM DAC 实验测试图

同时伴随 DS0 的不停闪烁,提示程序在运行。此时,我们通过按 KEY_UP 按键,可以

看到输出电压增大,按 KEY1 则变小。特别提醒:此时 PA3 不能接其他任何外设,如果没

有拔了 P9 排针上面 PA3 的跳线帽,那么 PWM DAC 将有很大误差!

标签: #stm32 dac输出电压精度