【正点原子探索者STM32F407开发板例程连载+教学】第27章 PWM DAC实验

2019-07-21 03:59发布

第二十七章 PWM DAC实验

[mw_shl_code=c,true]1.硬件平台:正点原子探索者STM32F407开发板 2.软件平台:MDK5.1 3.固件库版本:V1.4.0 [/mw_shl_code]
      
上一章,我们介绍了STM32F4自带DAC模块的使用,但有时候,可能两个DAC不够用,此时,我们可以通过PWM+RC滤波来实一个PWM DAC。本章我们将向大家介绍如何使用STM32F4PWM来设计一个DAC。我们将使用按键(或USMART)控制STM32F4PWM输出,从而控制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自带的2DAC可能不够用,需要多路DAC,外扩DAC成本又会高不少。此时,我们可以利用STM32F4PWM+简单的RC滤波来实现DAC输出,从而节省成本。 在精度要求不是很高的时候,PWM+RC滤波的DAC输出方式,是一种非常廉价的解决方案。 PWM本质上其实就是是一种周期一定,而高低电平占空比可调的方波。实际电路的典型PWM波形,如图27.1.1所示:
27.1.1 实际电路典型PWM波形        27.1.1PWM波形可以用分段函数表示为式①:

       其中:T是单片机中计数脉冲的基本周期,也就是STM32F4定时器的计数频率的倒数。NPWM波一个周期的计数脉冲个数,也就是STM32F4ARR-1的值。nPWM波一个周期中高电平的计数脉冲个数,也就是STM32F4CCRx的值。VHVL分别是PWM波的高低电平电压值,k为谐波次数,t为时间。我们将①式展开成傅里叶级数,得到公式②:  从②式可以看出,式中第1个方括弧为直流分量,第2项为1次谐波分量,第3项为大于1次的高次谐波分量。式②中的直流分量与n成线性关系,并随着n0N,直流分量从VLVL+VH之间变化。这正是电压输出的DAC所需要的。因此,如果能把式②中除直流分量外的谐波过滤掉,则可以得到从PWM波到电压输出DAC的转换,即:PWM波可以通过一个低通滤波器进行解调。式②中的第2项的幅度和相角与n有关,频率为1/NT),其实就是PWM的输出频率。该频率是设计低通滤波器的依据。如果能把1次谐波很好过滤 掉,则高次谐波就应该基本不存在了。        通过上面的了解,我们可以得到PWM DAC的分辨率,计算公式如下: 分辨率=log2N        这里假设n的最小变化为1,当N=256的时候,分辨率就是8位。而STM32F4的定时器大部分都是16位的(TIM2TIM532位),可以很容易得到更高的分辨率,分辨率越高,速度就越慢。不过我们在本章要设计的DAC分辨率为8位。        8位分辨条件下,我们一般要求1次谐波对输出电压的影响不要超过1个位的精度,也就是3.3/256=0.01289V。假设VH3.3VVL0V,那么一次谐波的最大值是2*3.3/π=2.1V,这就要求我们的RC滤波电路提供至少-20lg(2.1/0.01289)=-44dB的衰减。        STM32F4的定时器最快的计数频率是168Mhz,某些定时器只能到84M,所以我们以84M频率为例介绍,8为分辨率的时候,PWM频率为84M/256=328.125Khz。如果是1RC滤波,则要求截止频率2.07Khz,如果为2RC滤波,则要求截止频率为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_UPKEY1按键 3)  串口 4)  TFTLCD模块 5)  ADC 6)  PWM DAC 本章,我们使用STM32F4TIM9_CH2(PA3)输出PWM,经过二阶RC滤波后,转换为直流输出,实现PWM DAC。同上一章一样,我们通过ADC1的通道5PA5)读取PWM DAC的输出,并在LCD模块上显示相关数值,通过按键和USMART控制PWM DAC的输出值。我们需要用到ADC采集DAC的输出电压,所以需要在硬件上将PWM DACADC短接起来,PWM DAC部分原理图如图27.2.1所示:  27.2.1 PWM DAC原理图        从上图可知PWM_DAC的连接关系,但是这里有个特别需要注意的地方:因为PWM_DACUSART2_RX共用了PA3引脚,所以在做本例程的时候,必须拔了P9上面PA3(RX)的跳线帽(左侧跳线帽),否则会影响PWM转换结果!!!        在硬件上,我们还需要用跳线帽短接多功能端口的PDCADC,如图27.2.2所示:  27.2.2 硬件连接示意图

27.3 软件设计

打开本章的实验工程可以看到,我们本章并没有增加其他新的库函数文件支持。主要是使用了adc和定时器相关的库函数支持。因为我们是使用定时器产生PWM信号作为PWM DAC的输入信号经过二阶RC滤波从而产生一定幅度模拟信号,所以我们需要添加定时器相关的库函数支持。在HARDWARE分组下,我们新建了pwmdac.c源文件和对应的头文件用来初始化定时器9PWM。接下来我们看看pwmdac.c源文件内容: 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); //使能PA时钟        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);  //PA3复用位定时器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_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 } 该函数用来初始化TIM9_CH2PWM输出(PA3),其原理同之前介绍的PWM输出一模一样,只是换过一个定时器而已。这里就不细说了。 pwmdac.h头文件内容主要是函数申明,这里不做过多讲解。 接下来我们看看主函数内容: int main(void) {        u16 adcx, pwmval=0;        float temp;  u8 t=0,key;            NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2        delay_init(168);   //初始化延时函数        uart_init(115200);  //初始化串口波特率为115200        LED_Init();                                //初始化LED       LCD_Init();                                //LCD初始化        Adc_Init();                         //adc初始化        KEY_Init();                        //按键初始化        TIM9_CH2_PWM_Init(255,0);//TIM4 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,"2014/5/6");              LCD_ShowString(30,130,200,16,16,"WK_UP:+  KEY1:-");           POINT_COLOR=BLUE;//设置字体为蓝 {MOD}                    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)               {                                 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_UPKEY1(也就是上下键)来实现对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将有很大误差!

 实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm  正点原子探索者STM32F407开发板购买地址http://item.taobao.com/item.htm?id=41855882779
  

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。