zl程序教程

您现在的位置是:首页 >  Java

当前栏目

(29)STM32——PWM DAC实验笔记

2023-02-18 15:49:44 时间

目录

学习目标

成果展示 

介绍

简介

硬件

代码

总结 


学习目标

        本节内容讲解的是有关PWM转DAC的知识点,其实这种做法我们已经不陌生了,因为在学习51单片机的时候,DA也是通过PWM来实现的。51单片机——AD/DA转换,好了,接下来就让我们开始吧!

成果展示 

https://live.csdn.net/v/embed/233690

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就详细的介绍过,再学一遍就当是复习了。