完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:alientek 阿波罗 STM32F767 开发板2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子
第二十八章 PWM DAC 实验 上一章,我们介绍了 STM32F767 自带 DAC 模块的使用,但有时候,可能两个 DAC 不 够用,此时,我们可以通过 PWM+RC 滤波来实一个 PWM DAC。本章我们将向大家介绍如 何使用 STM32F767 的 PWM 来设计一个 DAC。我们将使用按键(或 USMART)控制 STM32F767 的 PWM 输出,从而控制 PWM DAC 的输出电压,通过 ADC1 的通道 5 采集 PWM DAC 的输出电压,并在 LCD 模块上面显示 ADC 获取到的电压值以及 PWM DAC 的设定输 出电压值等信息。本章将分为如下几个部分: 28.1 PWM DAC 简介 28.2 硬件设计 28.3 软件设计 28.4 下载验证 28.1 PWM DAC 简介 有时候,STM32F767 自带的 2 路 DAC 可能不够用,需要多路 DAC,外扩 DAC 成本又 会高不少。此时,我们可以利用 STM32F767 的 PWM+简单的 RC 滤波来实现 DAC 输出, 从而节省成本。 在精度要求不是很高的时候,PWM+RC 滤波的 DAC 输出方式,是一种非 常廉价的解决方案。 PWM 本质上其实就是是一种周期一定,而高低电平占空比可调的方波。实际电路的典 型 PWM 波形,如图 28.1.1 所示: 图 28.1.1 实际电路典型 PWM 波形 图 28.1.1 的 PWM 波形可以用分段函数表示为式①: 其中:T 是单片机中计数脉冲的基本周期,也就是 STM32F767 定时器的计数频率的倒 数。N 是 PWM 波一个周期的计数脉冲个数,也就是 STM32F767 的 ARR-1 的值。n 是 PWM 波一个周期中高电平的计数脉冲个数,也就是 STM32F767 的 CCRx 的值。VH 和 VL 分别 是 PWM 波的高低电平电压值,k 为谐波次数,t 为时间。我们将①式展开成傅里叶级数, 得到公式②: 从②式可以看出,式中第 1 个方括弧为直流分量,第 2 项为 1 次谐波分量,第 3 项为大 于 1 次的高次谐波分量。式②中的直流分量与 n 成线性关系,并随着 n 从 0 到 N,直流分量 从 VL 到 VL+VH 之间变化。这正是电压输出的 DAC 所需要的。因此,如果能把式②中除 直流分量外的谐波过滤掉,则可以得到从 PWM 波到电压输出 DAC 的转换,即:PWM 波 可以通过一个低通滤波器进行解调。式②中的第 2 项的幅度和相角与 n 有关,频率为 1/(NT), 其实就是 PWM 的输出频率。该频率是设计低通滤波器的依据。如果能把 1 次谐波很好过滤 掉,则高次谐波就应该基本不存在了。 通过上面的了解,我们可以得到 PWM DAC 的分辨率,计算公式如下: 分辨率=log2(N) 这里假设 n 的最小变化为 1,当 N=256 的时候,分辨率就是 8 位。而 STM32F767 的定 时器大部分都是 16 位的(tiM2 和 TIM5 是 32 位),可以很容易得到更高的分辨率,分辨率 越高,速度就越慢。不过我们在本章要设计的 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 的衰减。 STM32F767 的定时器最快的计数频率是 216Mhz,某些定时器只能到 108M,所以我们 以 108M 频率为例介绍,8 位分辨率的时候,PWM 频率为 108M/256=421.875Khz。如果是 1 阶 RC 滤波,则要求截止频率 2.66Khz,如果为 2 阶 RC 滤波,则要求截止频率为 33.62Khz。 阿波罗 STM32F767 开发板的 PWM DAC 输出采用二阶 RC 滤波,该部分原理图如图 28.1.2 所示: 图 28.1.2 PWM DAC 二阶 RC 滤波原理图 二阶 RC 滤波截止频率计算公式为: f=1/2πRC 以上公式要求 R28*C37=R29*C38=RC。根据这个公式,我们计算出图 28.1.2 的截止频 率为:33.8Khz,和 33.62Khz 非常接近,满足设计要求。 PWM DAC 的原理部分,就为大家介绍到这里。 28.2 硬件设计 本章用到的硬件资源有: 1) 指示灯 DS0 2) KEY_UP 和 KEY1 按键 3) 串口 4) LCD 模块 5) ADC 6) PWM DAC 本章,我们使用 STM32F767 的 TIM9_CH2(PA3)输出 PWM,经过二阶 RC 滤波后,转 换为直流输出,实现 PWM DAC。同上一章一样,我们通过 ADC1 的通道 5(PA5)读取 PWM DAC 的输出,并在 LCD 模块上显示相关数值,通过按键和 USMART 控制 PWM DAC 的输 出值。我们需要用到 ADC 采集 DAC 的输出电压,所以需要在硬件上将 PWM DAC 和 ADC 短接起来,PWM DAC 部分原理图如图 28.2.1 所示: 图 28.2.1 PWM DAC 原理图 从上图可知 PWM_DAC 的连接关系,但是这里有个特别需要注意的地方:因为 PWM_DAC 和 USART2_RX 共用了 PA3 引脚,所以在做本例程的时候,必须拔了 P8 上面 PA3(RX)的跳线帽(左侧跳线帽),否则会影响 PWM 转换结果!!! 在硬件上,我们还需要用跳线帽短接多功能端口的 PDC 和 ADC,如图 28.2.2 所示: 图 28.2.2 硬件连接示意图 28.3 软件设计 打开本章的实验工程可以看到,我们本章并没有增加其他新的库函数文件支持。主要是 使用了 adc 和定时器相关的库函数支持。因为我们是使用定时器产生 PWM 信号作为 PWM DAC 的输入信号经过二阶 RC 滤波从而产生一定幅度模拟信号,所以我们需要添加定时器 相关的库函数支持。在 HARDWARE 分组下,我们新建了 pwmdac.c 源文件和对应的头文件 用来初始化定时器 9 的 PWM。接下来我们看看 pwmdac.c 源文件内容: TIM_HandleTypeDef TIM9_Handler; //定时器 9 PWM 句柄 TIM_OC_InitTypeDef TIM9_CH2Handler; //定时器 9 通道 2 句柄 //PWM DAC 初始化(也就是 TIM9 通道 2 初始化) //PWM 输出初始化 //arr:自动重装值 //psc:时钟预分频数 void TIM9_CH2_PWM_Init(u16 arr,u16 psc) { TIM9_Handler.Instance=TIM9; //定时器 9 TIM9_Handler.Init.Prescaler=psc; //定时器分频系数 TIM9_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式 TIM9_Handler.Init.Period=arr; //自动重装载值 TIM9_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&TIM9_Handler); //初始化 PWM TIM9_CH2Handler.OCMode=TIM_OCMODE_PWM1; //模式选择 PWM1 TIM9_CH2Handler.Pulse=arr/2; //设置比较值用来确定占空比为 50% TIM9_CH2Handler.OCPolarity=TIM_OCPOLARITY_HIGH; //输出比较极性为高 HAL_TIM_PWM_ConfigChannel(&TIM9_Handler,&TIM9_CH2Handler, TIM_CHANNEL_2);//配置 TIM9 通道 2 HAL_TIM_PWM_Start(&TIM9_Handler,TIM_CHANNEL_2);//开启 PWM 通道 2 } //定时器底层驱动,时钟使能,引脚配置 //此函数会被 HAL_TIM_PWM_Init()调用 //htim:定时器句柄 void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_TIM9_CLK_ENABLE(); //使能定时器 9 __HAL_RCC_GPIOA_CLK_ENABLE(); //开启 GPIOA 时钟 GPIO_Initure.Pin=GPIO_PIN_3; //PA3 GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推完输出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速 GPIO_Initure.Alternate= GPIO_AF3_TIM9; //PA3 复用为 TIM9_CH2 HAL_GPIO_Init(GPIOA,&GPIO_Initure); } //设置 TIM 通道 2 的占空比 //TIM_TypeDef:定时器 //compare:比较值 void TIM_SetTIM9Compare2(u32 compare) { TIM9->CCR2=compare; } 该文件有三个函数,和 PWM 输出实验几乎是一模一样的,只不过定时器由 TIM3 换为 了 TIM9,这里就不细说了。 接下来我们看看主函数内容: //设置输出电压 //vol:0~330,代表 0~3.3V void PWM_DAC_Set(u16 vol) { double temp=vol; temp/=100; temp=temp*256/3.3; TIM_SetTIM9Compare2(temp); } int main(void) { u16 adcx; float temp; u8 t=0; u16 pwmval=0; u8 key; Cache_Enable(); //打开 L1-Cache HAL_Init(); //初始化 HAL 库 Stm32_Clock_Init(432,25,2,9); //设置时钟,216Mhz delay_init(216); //延时初始化 uart_init(115200); //串口初始化 usmart_dev.init(108); //初始化 USMART LED_Init(); //初始化 LED KEY_Init(); //初始化按键 SDRAM_Init(); //初始化 SDRAM LCD_Init(); //LCD 初始化 MY_ADC_Init(); //初始化 ADC1 TIM9_CH2_PWM_Init(255,1); /TIM9 PWM 初始化, Fpwm=90M/256=351.562Khz. POINT_COLOR=RED; LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7"); 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,"2016/1/13"); 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_SetTIM9Compare2(pwmval); //初始值为 0 while(1) { t++; key=KEY_Scan(0); if(key==WKUP_PRES) { if(pwmval<250)pwmval+=10; TIM_SetTIM9Compare2(pwmval); //输出 }else if(key==KEY1_PRES) { if(pwmval>10)pwmval-=10; else pwmval=0; TIM_SetTIM9Compare2(pwmval); //输出 } if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1 按下了,或者定时时间到了 { adcx=HAL_TIM_ReadCapturedValue(&TIM9_Handler,TIM_CHANNEL_2); 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); // 得到转换值 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_Toggle; } delay_ms(10); } } 此部分代码,同上一章的基本一样,先对需要用到的模块进行初始化,然后显示一些提 示信息,本章我们通过 KEY_UP 和 KEY1(也就是上下键)来实现对 PWM 脉宽的控制,经 过 RC 滤波,最终实现对 DAC 输出幅值的控制。按下 KEY_UP 增加,按 KEY1 减小。同时 在 LCD 上面显示 TIM4_CCR1 寄存器的值、PWM DAC 设计输出电压以及 ADC 采集到的实 际输出电压。同时 DS0 闪烁,提示程序运行状况。 28.4 下载验证 在代码编译成功之后,我们通过下载代码到 ALIENTEK 阿波罗 STM32 开发板上,可以 看到 LCD 显示如图 28.4.1 所示: 图 28.4.1 PWM DAC 实验测试图 同时伴随 DS0 的不停闪烁,提示程序在运行。此时,我们通过按 KEY_UP 按键,可以 看到输出电压增大,按 KEY1 则变小。特别提醒:此时 PA3 不能接其他任何外设,如果没 有拔了 P8 排针上面 PA3 的跳线帽,那么 PWM DAC 将有很大误差!!!! |
|
相关推荐
|
|
STM32CUBEMX(12)--IIC,12864OLED(0.96寸)移植
418 浏览 0 评论
STM32CUBEMX(5)--自定义红外NEC解码,定时器TIM捕获方式
522 浏览 0 评论
stm32f407vet6+LAN8720A调试以太网遇到软件复位失败问题
908 浏览 0 评论
使用STM32CubeMX对红外波形进行GPIO输出,并LED显示
440 浏览 0 评论
482 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-9-12 18:18 , Processed in 0.714358 second(s), Total 64, Slave 47 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191