OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 12312|回复: 12

【ALIENTEK 战舰STM32开发板例程系列连载+教学】第二十五章 PWM DAC实验

[复制链接]

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-3-13 20:47:32 | 显示全部楼层 |阅读模式

第二十五章 PWM DAC实验     

上一章,我们介绍了STM32自带DAC模块的使用,但不是每个STM32都有DAC模块的,对于那些没有DAC模块的芯片,我们可以通过PWM+RC滤波来实一个PWM DAC。本章我们将向大家介绍如何使用STM32PWM来设计一个DAC。我们将使用按键(或USMART)控制STM32PWM输出,从而控制PWM DAC的输出电压,通过ADC1的通道1采集PWM DAC的输出电压,并在LCD模块上面显示ADC获取到的电压值以及PWM DAC的设定输出电压值等信息。本章将分为如下几个部分:

25.1 PWM DAC简介

25.2 硬件设计

25.3 软件设计

25.4 下载验证

25.1 PWM DAC简介

虽然大容量的STM32F103具有内部DAC,但是更多的型号是没有DAC的,不过STM32所有的芯片都有PWM输出,因此,我们可以用PWM+简单的RC滤波来实现DAC输出,从而节省成本。

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


25.1.1 实际电路典型PWM波形

       25.1.1PWM波形可以用分段函数表示为式①:

       其中:T是单片机中计数脉冲的基本周期,也就是STM32定时器的计数频率的倒数。NPWM波一个周期的计数脉冲个数,也就是STM32ARR-1的值。nPWM波一个周期中高电平的计数脉冲个数,也就是STM32CCRx的值。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位。而STM32的定时器都是16位的,可以很容易得到更高的分辨率,分辨率越高,速度就越慢。不过我们在本章要设计的DAC分辨率为8位。

       8位分辨条件下,我们一般要求1次谐波对输出电压的影响不要超过1个位的精度,也就是3.3/256=0.01289V。假设VH3.3VVL0V,那么一次谐波的最大值是2*3.3/π=2.1V,这就要求我们的RC滤波电路提供至少-20lg(2.1/0.01289)=-44dB的衰减。

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

战舰STM32开发板的PWM DAC输出采用二阶RC滤波,该部分原理图如图25.1.2所示:

25.1.2 PWM DAC二阶RC滤波原理图

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

f=1/2πRC

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

       PWM DAC的原理部分,就为大家介绍到这里。

 

25.2硬件设计

本章用到的硬件资源有:

1)  指示灯DS0

2)  WK_UPKEY1按键

3)  串口

4)  TFTLCD模块

5)  ADC

6)  PWM DAC

本章,我们使用STM32TIM4_CH1(PB6)输出PWM,经过二阶RC滤波后,转换为直流输出,实现PWM DAC。同上一章一样,我们通过ADC1的通道1PA1)读取PWM DAC的输出,并在LCD模块上显示相关数值,通过按键和USMART控制PWM DAC的输出值。我们需要用到ADC采集DAC的输出电压,所以需要在硬件上将PWM DACADC短接起来,PWM DAC部分原理图如图25.2.1所示:

25.2.1 PWM DAC原理图

       在硬件上,我们还需要用跳线帽短接多功能端口的PDCADC,如图25.2.2所示:

25.2.2 硬件连接示意图 

25.3 软件设计

找到上一章的工程,然后打开USER文件夹下的工程,打开之前的timer.c文件,在最后添加一个新的函数:TIM4_PWM_Init,该函数代码如下:

//TIM4 CH1 PWM输出设置

//PWM输出初始化

//arr:自动重装值

//psc:时钟预分频数

void TIM4_PWM_Init(u16 arr,u16 psc)

{                                               

       RCC->APB1ENR|=1<<2;           //TIM4时钟使能   

       RCC->APB2ENR|=1<<3;         //使能PORTB时钟      

       GPIOB->CRL&=0X00FFFFFF;   //PB6输出

       GPIOB->CRL|=0X4B000000;      //复用功能输出

       TIM4->ARR=arr;                        //设定计数器自动重装值

       TIM4->SC=psc;                        //预分频器分频设置

       TIM4->CCMR1|=7<<4;              //CH1 PWM2模式       

       TIM4->CCMR1|=1<<3;             //CH1 预装载使能             

TIM4->CCER|=1<<1;               //OC1 低电平有效

       TIM4->CCER|=1<<0;               //OC1输出使能      

       TIM4->CR1=0x0080;                //ARPE使能

       TIM4->CR1|=0x01;                  //使能定时器3                                                 

}

该函数用来初始化TIM4_CH1PWM输出(PB6),其原理同之前介绍的PWM输出一模一样,只是换过一个定时器而已。这里就不细说了。

同时在timer.h里面,修改代码如下:

#ifndef __TIMER_H

#define __TIMER_H

#include "sys.h"

//通过改变TIM3->CCR2的值来改变占空比,从而控制LED0的亮度

#define LED0_PWM_VAL TIM3->CCR2   

//TIM4 CH1作为PWM DAC的输出通道

#define PWM_DAC_VAL  TIM4->CCR1

void TIM3_Int_Init(u16 arr,u16 psc);

void TIM3_PWM_Init(u16 arr,u16 psc);

void TIM5_Cap_Init(u16 arr,u16 psc);

void TIM4_PWM_Init(u16 arr,u16 psc);

#endif

该部分代码在原有基础上添加了TIM4_PWM_Init函数的声明,并添加PWM_DAC_VAL宏定义,用于改变TIM4_CH1PWM占空比,从而控制PWM DAC的输出。

接下来我们在test.c里面,修改代码如下:

//设置输出电压

//vol:0~330,代表0~3.3V

void PWM_DAC_Set(u16 vol)

{

       float temp=vol;

       temp/=100;

       temp=temp*256/3.3;

       PWM_DAC_VAL=temp;         

}

int main(void)

{    

       u16 adcx; u8 key;

       float temp; u8 t=0; u16 pwmval=0;            

      Stm32_Clock_Init(9);    //系统时钟设置

       uart_init(72,9600);      //串口初始化为9600

       delay_init(72);                  //延时初始化

       LED_Init();                //初始化与LED连接的硬件接口

       LCD_Init();                  //初始化LCD

       usmart_dev.init(72);      //初始化USMART       

       KEY_Init();                  //按键初始化             

      Adc_Init();                  //ADC初始化

       TIM4_PWM_Init(255,0);//TIM4 PWM初始化, Fpwm=72M/256=281.25Khz.          

      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,"2012/9/8");      

       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");             

       PWM_DAC_VAL=pwmval;//初始值为0                      

       while(1)

       {

              t++;

              key=KEY_Scan(0);                      

              if(key==4)

              {           

                     if(pwmval<250)pwmval+=10;

                     PWM_DAC_VAL=pwmval;         //输出    

              }else if(key==2)    

              {

                     if(pwmval>10)pwmval-=10;

                     else pwmval=0;

                     PWM_DAC_VAL=pwmval;        //输出

              }    

              if(t==10||key==2||key==4)          //WK_UP/KEY1按下了,或者定时时间到了

              {      

                    adcx=PWM_DAC_VAL;

                     LCD_ShowxNum(124,150,adcx,3,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_CH1,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);

       }

}

此部分代码,同上一章的基本一样,先对需要用到的模块进行初始化,然后显示一些提示信息,本章我们通过WK_UPKEY1(也就是上下键)来实现对PWM脉宽的控制,经过RC滤波,最终实现对DAC输出幅值的控制。按下WK_UP增加,按KEY1减小。同时在LCD上面显示TIM4_CCR1寄存器的值、PWM DAC设计输出电压以及ADC采集到的实际输出电压。同时DS0闪烁,提示程序运行状况。

不过此部分代码还有一个PWM_DAC_Set函数,用于USMART调用,从而通过串口控制PWM DAC的输出,所以还需要将PWM_DAC_Set函数加入USMART控制,方法前面已经有详细的介绍了,大家这里自行添加,或者直接查看我们光盘的源码。

25.4 下载验证

在代码编译成功之后,我们通过下载代码到ALIENTEK战舰STM32开发板上,可以看到LCD显示如图25.4.1所示:

25.4.1 PWM DAC实验测试图

同时伴随DS0的不停闪烁,提示程序在运行。此时,我们通过按WK_UP按键,可以看到输出电压增大,按KEY1则变小。

大家可以试试在USMART调用PWM_DAC_Set函数,来设置PWM DAC的输出电压,如图25.4.2所示:

25.4.2 通过usmart设置PWM DAC的电压输出

 

实验20 PWM DAC实验.rar

111.18 KB, 下载次数: 1290

《STM32开发指南》第二十五章 PWM DAC实验.rar

660.48 KB, 下载次数: 1546

我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

50

主题

201

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
423
金钱
423
注册时间
2013-4-9
在线时间
1 小时
发表于 2013-7-9 12:32:09 | 显示全部楼层
回复【楼主位】正点原子:
---------------------------------
前面的傅里叶堪称天书- -
回复 支持 反对

使用道具 举报

13

主题

53

帖子

0

精华

初级会员

Rank: 2

积分
82
金钱
82
注册时间
2015-6-8
在线时间
2 小时
发表于 2015-8-2 20:19:45 | 显示全部楼层
原子哥,你觉得用这种方法能产生1M的正弦波吗?因为DAC貌似不能产生1M的正弦波。想用PWM模拟,你觉得可行吗?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
 楼主| 发表于 2015-8-2 22:31:22 | 显示全部楼层
回复【3楼】yzl:
---------------------------------
不能。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

13

主题

53

帖子

0

精华

初级会员

Rank: 2

积分
82
金钱
82
注册时间
2015-6-8
在线时间
2 小时
发表于 2015-8-5 14:45:03 | 显示全部楼层
回复【4楼】正点原子:
---------------------------------
谢谢
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
21
金钱
21
注册时间
2015-8-12
在线时间
0 小时
发表于 2015-8-12 22:58:44 | 显示全部楼层
原子哥,我想把3.3v的电压变成5v电压模拟,请问可以吗?是弄一个三极管放大吗?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
 楼主| 发表于 2015-8-13 22:25:16 | 显示全部楼层
回复【6楼】goodboy:
---------------------------------
怎么个变法?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

1

主题

2

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2014-1-3
在线时间
1 小时
发表于 2016-5-25 19:27:05 | 显示全部楼层
大神们,请教个问题,为什么该代码 无法选择STlink 下载,在Debug选项卡里选择ST-link Debugger调试后,一点击其后面的Settings KEIL 软件就挂掉了,不知道是什么原因。我用的是keil 4 。
请大神们支个招
回复 支持 反对

使用道具 举报

13

主题

46

帖子

0

精华

初级会员

Rank: 2

积分
120
金钱
120
注册时间
2014-2-22
在线时间
2 小时
发表于 2016-6-3 11:53:10 | 显示全部楼层
正点原子 发表于 2015-8-13 22:25
回复【6楼】goodboy:
---------------------------------
怎么个变法?

原子哥,我想通过三极管放大把3.3V变成5V,后面加上二阶RC滤波最后输出8位DAC输出,那RC值该怎么选合适??项目上很急,希望原子哥能给予解答,谢谢了
绝望的下一秒就是机遇和希望!
回复 支持 反对

使用道具 举报

38

主题

165

帖子

0

精华

高级会员

Rank: 4

积分
646
金钱
646
注册时间
2014-3-5
在线时间
67 小时
发表于 2016-6-13 22:17:24 | 显示全部楼层
原子哥,这个用5V的参考电压好像不行,我用的STM8,供电电压5V
Hard work!
回复 支持 反对

使用道具 举报

2

主题

171

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3792
金钱
3792
注册时间
2016-6-26
在线时间
276 小时
发表于 2016-7-1 07:30:51 | 显示全部楼层
非常不错,谢谢分享。
回复 支持 反对

使用道具 举报

13

主题

87

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
421
金钱
421
注册时间
2015-12-3
在线时间
46 小时
发表于 2016-7-30 20:14:43 | 显示全部楼层
为什么库函数里边给的是TIM1啊,而这里是4而且还接B口,
我看开发板原理图也是1,最后4竟然行,是弄错了吗
这让我很无语啊
学到老,活到老
回复 支持 反对

使用道具 举报

13

主题

87

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
421
金钱
421
注册时间
2015-12-3
在线时间
46 小时
发表于 2016-7-30 20:15:50 | 显示全部楼层
视频上讲的竟然行,到底怎么jie?
学到老,活到老
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-12 09:12

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表