STM32F4_PWM DAC

目录

1. 为什么需要使用PWM DAC

2. PWM DAC简介

3. 硬件设计

4. 软件设计

4.1 main.c

4.2 PWMDAC.c

4.3 PWMDAC.h


1. 为什么需要使用PWM DAC

        虽然STM32F4自带DAC模块,但是在有些时候,可能出现两个DAC不够用的情况(STM32F4只有两个DAC),更有甚者,STM32的某些型号是没有板载DAC模块的;这里可能会有很多学习过51单片机的读者发问,为什么不像51一样采用专用的 D/A芯片 来实现,其实这样是可以的,但是会带来成本的增加。

        STM32的所有芯片都有PWM输出功能,并且STM32F4有19个PWM输出通道,16个通用通道,资源丰富。因此,我们可以使用 PWM+RC滤波来实现一个PWM DAC

2. PWM DAC简介

        有时候,STM32F4自带的 2 路DAC可能不够用,需要多路DAC,外扩DAC的成本又比较高。此时,我们可以利用STM32F4的 PWM+简单的RC滤波来实现DAC输出 ,从而节省成本。在精度要求不是很高的时候,PWM+RC滤波的DAC输出方式,是一种非常廉价的解决方案。

PWM称作脉冲宽度调制。其本质就是一种周期一定,而高低电平占空比可调的方波。

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

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

        n是PWM波一个周期中高电平的计数脉冲个数,也就是STM32F4的CCRx的值。

        V_{H}V_{L}分别是PWM波的高低电平电压值,k为谐波次数,t为时间。

将分段函数展开为傅里叶级数得到:

从②式可以看出,式中第1个方括弧为直流分量,第2项为1次谐波分量,第3项为大于1次的高次谐波分量如果我们希望只要直流分量,不要1次谐波分量和多次谐波分量的话,需要借助滤波器滤掉谐波。

式②中的直流分量与 n 成线性关系,并随着n从0到N,直流分量从VL到VL+VH之间变化。这正是电压输出的DAC所需要的。因此,如果能把式②中除直流分量外的谐波过滤掉,则可以得到从PWM波到电压输出DAC的转换,即:PWM波可以通过一个低通滤波器进行解调。式②中的第2项的幅度和相角与n有关,频率为1/(NT),其实就是PWM的输出频率。该频率是设计低通滤波器的依据。如果能把1次谐波很好过滤掉,则高次谐波就应该基本不存在了。 

低通滤波器 是容许低于截止频率的信号通过,但高于截止频率的信号不能通过的电子滤波装置。换句话说,他将信号的频谱分离为将要通过的频率分量和将被阻塞的频率分量,且这部分被阻塞的频率分量是高频分量。而这个通过和阻塞的临界值被称为截止频率。

截止频率 从频域响应的角度讲,当保持输入信号的幅度不变,改变频率使输出信号降至最大值的0.707倍,即用频响特性来表述即为-3dB点处即为截止频率,它是用来说明频率特性指标的一个特殊频率。

通过对上面公式的分析,可以得到PWM DAC的分辨率为:

        分辨率=log2(N)

假设n的最小变化为1,当N=256的时候,分辨率就是8位。STM32F4的定时器大部分都是16位的(TIM2和TIM5是32位的),可以很容易得到更高的分辨率,分辨率越高,速度就越慢。

在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。

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

f=1/2π RC

公式要求R20*C34=R21*C35=RC。

根据计算得截止频率为33.8Khz,超过了26.14Khz,和二阶RC滤波的截止频率有出入的原因是该电路我们还需要用作PWM DAC音频输出,音频信号带宽是22.05Khz,为了让音频信号能够通过该低通滤波,同时为了标准化参数选取,所以确定了这样的参数。实测精度在0.5LSB左右

3. 硬件设计

本次实验,我们使用STM32F4的TIM9_CH2(PA3)输出PWM,经过二阶RC滤波后,转换为直流输出,实现PWM DAC。

 注意:

        本次实验需要用 ADC 采集 DAC 产生的模拟信号,也就是输出电压值,所以在硬件上需要将 PWM DAC 和 ADC 短接。

特别的:

        上图中功能 PWM DAC 和 USART2_RX 共用 PA3 引脚,所以在本实验中,必须拔了 P9 上面 PA3(RX)跳线帽,否则会影响转换结果。

4. 软件设计

        本次实验通过ADC通道5(PA5)读取PWM DAC输出,并在LCD模块上显示相关数值,通过按键控制PWM DAC的输出值。

4.1 main.c

#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"
#include "LED.h"
#include "lcd.h"
#include "usmart.h"
#include "ADC.h"
#include "KEY.h"
#include "DAC.h"
#include "PWMDAC.h"

//LCD状态设置函数
void led_set(u8 sta)//只要工程目录下有usmart调试函数,主函数就必须调用这两个函数
{
	LED1=sta;
}
//函数参数调用测试函数
void test_fun(void(*ledset)(u8),u8 sta)
{
	led_set(sta);
}
int main(void)
{
	u16 adcx,pwmval=0;
	float temp;
	u8 t=0,key;
	delay_init(168);
	uart_init(115200);
	LED_Init();
	LCD_Init();
	Adc_Init();
	Key_Init();
	TIM9_CH2_PWM_Init(255,0);//TIM9 PWM初始化  Fpwm=168M/256=656.25Khz
	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,"2023/20/23");
	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_SetCompare2(TIM9,pwmval);  //初始值
	while(1)
	{
		t++;
		key=KEY_Scan(0);
		if(key==4)// 表示KEY_UP按键按下
		{
			if(pwmval<250)  //pwmval介于0~250之间
				pwmval=pwmval+10;
			TIM_SetCompare2(TIM9,pwmval);  //输出
		}
		else if(key==2)  //表示KEY1按下
		{
			if(pwmval>10)
				pwmval=pwmval-10;
			else
				pwmval=0;
			TIM_SetCompare2(TIM9,pwmval);  //输出
		}
		if(t==10||key==2||key==4)  //有按键按下或者定时时间到了
		{
			adcx=TIM_GetCapture2(TIM9);  //获取DAC寄存器的数值
			LCD_ShowxNum(30+8*8,150,adcx,3,16,0);   //显示DAC寄存器值
			temp=(float)adcx*(3.3/256);  //通过公式转化得到DAC电压值
			adcx=temp; //电压值一定是介于0~3.3V,adcx设置的为整型,所以将temp赋值给adcx,adcx得到temp的整数部分
			LCD_ShowxNum(30+8*8,170,temp,1,16,0);//显示整数部分
			temp=temp-adcx;
			temp=temp*1000;
			LCD_ShowxNum(30+8*10,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(30+8*8,190,temp,1,16,0);  //显示电压值整数部分
			temp=temp-adcx;
			temp=temp*1000;
			LCD_ShowxNum(30+8*10,190,temp,3,16,0x80);  //显示电压值的小数部分
			t=0;
			LED0=!LED0;
		}
		delay_ms(10);
	}
}

4.2 PWMDAC.c

#include "stm32f4xx.h"              
#include "PWMDAC.h"
#include "Timer.h"

//arr:自动重装载值  psc:预分频值
void TIM9_CH2_PWM_Init(u16 arr,u16 psc)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9,ENABLE);// TIM9时钟使能 PA3引脚复用功能TIM9_CH2
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);  //使能GPIOA时钟,因为要用到PA3引脚
	 
	//初始化GPIOA PA3
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//因为PA3引脚复用了很多功能,所以规定每次只能使用引脚的一个功能,所以GPIO模式为复用时,需要调用引脚复用函数
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_TIM9);//将PA3引脚复用为定时器9
	
	//初始化定时器9
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
	TIM_TimeBaseInitStructure.TIM_Period=arr;
	TIM_TimeBaseInitStructure.TIM_Prescaler=psc;
	TIM_TimeBaseInit(TIM9,&TIM_TimeBaseInitStructure);
	
	//初始化TIM9 Channel2 PWM模式 
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出比较使能
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出极性高
	TIM_OCInitStructure.TIM_Pulse=0;
	TIM_OC2Init(TIM9,&TIM_OCInitStructure);  //初始化外设TIM9 OC2
	
	TIM_OC2PreloadConfig(TIM9,TIM_OCPreload_Enable); //使能预装载寄存器
	TIM_ARRPreloadConfig(TIM9,ENABLE);  //ARPE使能
	TIM_Cmd(TIM9,ENABLE);//使能TIM9
}

4.3 PWMDAC.h

#ifndef _PWMDAC__H_
#define _PWMDAC__H_


void TIM9_CH2_PWM_Init(u16 arr,u16 psc);
	
#endif

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值