zoukankan      html  css  js  c++  java
  • 【STM32】PWM DAC基本原理(实验:PWM实现DAC)

    虽然STM32F103ZET6具有内部DAC,但是也仅仅只有两条DAC通道,并且STM32还有其他的很多型号是没有DAC的。通常情况下,采用专用的D/A芯片来实现,但是这样就会带来成本的增加。

    不过STM32所有的芯片都有PWM输出,并且PWM输出通道很多,资源丰富。因此,我们可以使用PWM+简单的RC滤波来实现DAC的输出从而节省成本。

    PWM DAC
    PWM DAC的构成原理
    PWM本质上其实就是是一种周期一定,而高低电平占空比可调的方波。实际电路的典型PWM波形,如下图所示:

     

    针对PWM的波形进行以下分析:

    高电平阶段:计数器当前值从0-CCRx阶段(总时间=CCRx*每两个计数之间的间隔时间);
    低电平阶段:计数器当前值从CCRx-ARR-1阶段(总时间=(ARR-1-CCRx)*每两个计数之间的间隔时间)。
    如果PWM内容如果不太懂,可以参考链接:【STM32】通用定时器的PWM输出(实例:PWM输出)。

    根据PWM的波形,可以用分段函数来进行表示:

     

    其中:T是STM32中计数脉冲的基本周期,也就是STM32定时器的计数频率的倒数;N是PWM波一个周期的计数脉冲个数,也就是STM32的ARR-1的值;n是PWM波一个周期中高电平的计数脉冲个数,也就是STM32的CCRx的值;VH和VL分别是PWM波的高低电平电压值;k为谐波次数;t为时间。

    我们将分段函数①式展开成傅里叶级数,得到公式②:

     

    从②式可以看出,式中第1个方括弧为直流分量,第2项为1次谐波分量,第3项为大于1次的高次谐波分量。

    式②中的直流分量与n成线性关系,并随着n从0到N,直流分量从VL到VL+VH之间变化。而STM32的DAC功能也就是电压输出,这正是电压输出的DAC所需要的。

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

    PWM DAC的具体实现
    通过上面的了解,我们可以得到PWM DAC的分辨率,计算公式如下:

    分辨率=log2(N)

    这里假设n的最小变化为1,当N=256的时候,分辨率就是8位。而STM32的定时器都是16位的,可以很容易得到更高的分辨率,分辨率越高,速度就越慢。不过我们在本章要设计的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的衰减。

    STM32的定时器最快的计数频率是72Mhz,8为分辨率的时候,PWM频率为72M/256=281.25Khz。如果是1阶RC滤波,则要求截止频率为1.77Khz,如果为2阶RC滤波,则要求截止频率为22.34Khz。

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

    f=1/2πRC

    以上公式要求R55=R56=R,C63=C64=C(R55*C63=R56*C64=RC)。根据这个公式,我们计算出图25.1.2的截止频率为:33.8Khz超过了22.34Khz,这个和我们前面提到的要求有点出入,原因是该电路我们还需要用作PWM DAC音频输出,而音频信号带宽是22.05Khz,为了让音频信号能够通过该低通滤波,同时为了标准化参数选取,所以确定了这样的参数。实测精度在0.5LSB以内。

    PWM DAC实例
    硬件连接
    单片机:STM32F103ZET6
    硬件资源:指示灯DS0,WK_UP和KEY1按键,ADC,PWM DAC
    具体的硬件连接的图如下所示:

     

    STM32控制程序
    //设置输出电压
    //vol:0~330,代表0~3.3V
    void PWM_DAC_Set(u16 vol)
    {
    float temp=vol;
    temp/=100;
    temp=temp*256/3.3;
    TIM_SetCompare1(TIM1,temp);
    }
    int main(void)
    {     
    u16 adcx;
    float temp;
    u8 t=0;     
    u16 pwmval=0;
    u8 key;
    delay_init();    //延时函数初始化    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(115200);    //串口初始化为115200
    KEY_Init();    //KEY初始化
    LED_Init();    //LED端口初始化
    usmart_dev.init(72);    //初始化USMART    
    LCD_Init();    //LCD初始化
    Adc_Init();    //ADC初始化
    TIM1_PWM_Init(255,0);    //TIM1 PWM初始化, Fpwm=72M/256=281.25Khz.
    TIM_SetCompare1(TIM1,100);//初始值为0    
    
    
    POINT_COLOR=RED;//设置字体为红色 
    LCD_ShowString(60,50,200,16,16,"WarShip STM32");    
    LCD_ShowString(60,70,200,16,16,"PWM DAC TEST");    
    LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
    LCD_ShowString(60,110,200,16,16,"2015/1/15");    
    LCD_ShowString(60,130,200,16,16,"WK_UP:+ KEY1:-");    
    //显示提示信息    
    POINT_COLOR=BLUE;//设置字体为蓝色
    LCD_ShowString(60,150,200,16,16,"PWM VAL:");    
    LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");    
    LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");
    
    TIM_SetCompare1(TIM1,pwmval);//初始值    
    while(1)
    {
    t++;
    key=KEY_Scan(0);    
    if(key==WKUP_PRES)
    {    
    if(pwmval<250)pwmval+=10;
    TIM_SetCompare1(TIM1,pwmval); //输出
    }else if(key==KEY1_PRES)    
    {
    if(pwmval>10)pwmval-=10;
    else pwmval=0;
    TIM_SetCompare1(TIM1,pwmval); //输出
    }     
    if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了
    {    
    adcx=TIM_GetCapture1(TIM1);
    LCD_ShowxNum(124,150,adcx,4,16,0); //显示DAC寄存器值
    temp=(float)adcx*(3.3/256);    //得到DAC电压值
    adcx=temp;
    LCD_ShowxNum(124,170,temp,1,16,0); //显示电压值整数部分
    temp-=adcx;
    temp*=1000;
    LCD_ShowxNum(140,170,temp,3,16,0x80); //显示电压值的小数部分
    adcx=Get_Adc_Average(ADC_Channel_1,20); //得到ADC转换值    
    temp=(float)adcx*(3.3/4096);    //得到ADC电压值
    adcx=temp;
    LCD_ShowxNum(124,190,temp,1,16,0); //显示电压值整数部分
    temp-=adcx;
    temp*=1000;
    LCD_ShowxNum(140,190,temp,3,16,0x80); //显示电压值的小数部分
    t=0;
    LED0=!LED0;    
    }    
    delay_ms(10);    
    
    }

    ---------------------
    作者:Yngz_Miao
    来源:CSDN
    原文:https://blog.csdn.net/qq_38410730/article/details/80113841
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    Codeforces 1485C Floor and Mod (枚举)
    CodeForces 1195D Submarine in the Rybinsk Sea (算贡献)
    CodeForces 1195C Basketball Exercise (线性DP)
    2021年初寒假训练第24场 B. 庆功会(搜索)
    任务分配(dp)
    开发工具的异常现象
    Telink MESH SDK 如何使用PWM
    Telink BLE MESH PWM波的小结
    [LeetCode] 1586. Binary Search Tree Iterator II
    [LeetCode] 1288. Remove Covered Intervals
  • 原文地址:https://www.cnblogs.com/isAndyWu/p/9910998.html
Copyright © 2011-2022 走看看