正点原子【STM32

您所在的位置:网站首页 stm32输出pwm控制电压的问题 正点原子【STM32

正点原子【STM32

2023-04-20 04:07| 来源: 网络整理| 查看: 265

1)资料下载:点击资料即可下载

2)对正点原子Linux感兴趣的同学可以加群讨论:935446741

3)关注正点原子公众号,获取最新资料更新

上一章,我们介绍了 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);

//设置时钟,168Mhz

delay_init(168);

//初始化延时函数

uart_init(115200);

//初始化 USART

usmart_dev.init(84);

//初始化 USMART

LED_Init();

//初始化 LED

KEY_Init();

//初始化 KEY

LCD_Init();

//初始化 LCD

MY_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);

//初始值为 0

while(1)

{

t++;

key=KEY_Scan(0);

if(key==4)

{

if(pwmval10)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 将有很大误差!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3