目录
学习目标
本节内容讲解的是有关PWM转DAC的知识点,其实这种做法我们已经不陌生了,因为在学习51单片机的时候,DA也是通过PWM来实现的。51单片机——AD/DA转换,好了,接下来就让我们开始吧!
成果展示
PWM DAC
介绍
简介
PWM 本质上其实就是是一种周期一定,而高低电平占空比可调的方波。
有时候,STM32F4 自带的 2 路 DAC 可能不够用,需要多路 DAC,外扩 DAC 成本又会高不少。此时,我们可以利用 STM32F4 的 PWM+简单的 RC 滤波(低通滤波,在51的时候介绍过)来实现 DAC 输出,从而节省成本。 在精度要求不是很高的时候,PWM+RC 滤波的 DAC 输出方式,是一种非常廉价的解决方案。
视频中介绍时讲了许多的东西,包括傅里叶级数以及二阶滤波等知识点,这些东西我觉得靠这一个笔记不能完全讲透,就简单的概括一下。、
首先是傅里叶级数,我们在大学一年级就学过高等数学,在级数那一章节就有提到傅里叶级数,我们可以将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是一样的,只不过改变了一下通道和使用的定时器。
#include "pwmdac.h"
#include "led.h"
#include "usart.h"
void TIM9_CH2_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9,ENABLE); //TIM9时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //GPIOA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA3
GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_TIM9); //GPIOA3复用位定时器9 AF3
TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM9,&TIM_TimeBaseStructure);//初始化定时器9
//初始化TIM14 Channel1 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OCInitStructure.TIM_Pulse=0;
TIM_OC2Init(TIM9, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM9 OC2
TIM_OC2PreloadConfig(TIM9, TIM_OCPreload_Enable); //使能TIM9在CCR2上的预装载寄存器
TIM_ARRPreloadConfig(TIM9,ENABLE);//ARPE使能
TIM_Cmd(TIM9, ENABLE); //使能TIM9
}
include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "adc.h"
#include "key.h"
#include "pwmdac.h"
int main(void)
{
u16 adcx;
float temp;
u8 t=0;
u16 pwmval=0;
u8 key;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
LED_Init(); //初始化LED
Adc_Init(); //adc初始化
KEY_Init(); //按键初始化
TIM9_CH2_PWM_Init(255,0); //TIM4 PWM初始化, Fpwm=168M/256=656.25Khz.
TIM_SetCompare2(TIM9,pwmval); //初始值
while(1)
{
t++;
key=KEY_Scan(0);
if(key==KEY0_PRES)
{
if(pwmval<250)pwmval+=10;
TIM_SetCompare2(TIM9,pwmval); //输出
}else if(key==KEY1_PRES)
{
if(pwmval>10)pwmval-=10;
else pwmval=0;
TIM_SetCompare2(TIM9,pwmval); //输出
}
if(t==100||key==KEY0_PRES||key==KEY1_PRES) //WKUP/KEY1按下了,或者定时时间到了
{
adcx=TIM_GetCapture2(TIM9);;
printf ("DAC VAL:%d",adcx); //显示DAC寄存器值
printf ("\r\n\r\n");
temp=(float)adcx*(3.3/256);; //得到DAC电压值
adcx=temp;
printf("DAC VOL:%fV",temp); //显示电压值
printf ("\r\n\r\n");
adcx=Get_Adc_Average(ADC_Channel_5,20); //得到ADC转换值
temp=(float)adcx*(3.3/4096); //得到ADC电压值
adcx=temp;
printf("ADC VOL:%fV",temp); //显示电压值
printf ("\r\n\r\n");
t=0;
LED0=!LED0;
}
delay_ms(10);
}
}
总结
其实这一章的知识在之前的51就详细的介绍过,再学一遍就当是复习了。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/82360.html