描述
STM32F4的DAC模块(数字/模拟转换模块)是12位数字输入,电压输出型的DAC。DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。DAC工作在12位模式时,数据可以设置成左对齐或右对齐。DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压Vref+(通ADC共用)以获得更精确的转换结果。
STM32F4的DAC模块主要特点有:
① 2个DAC转换器:每个转换器对应1个输出通道
② 8位或者12位单调输出
③ 12位模式下数据左对齐或者右对齐
④ 同步更新功能
⑤ 噪声波形生成
⑥ 三角波形生成
⑦ 双DAC通道同时或者分别转换
⑧ 每个通道都有DMA功能
单个DAC通道的框图如图所示:
图中VDDA和VSSA为DAC模块模拟部分的供电,而Vref+则是DAC模块的参考电压。DAC_OUTx就是DAC的输出通道了(对应PA4或者PA5引脚)。
从图可以看出,DAC输出是受DORx寄存器直接控制的,但是我们不能直接往DORx寄存器写入数据,而是通过DHRx间接的传给DORx寄存器,实现对DAC输出的控制。前面我们提到,STM32F4的DAC支持8/12位模式,8位模式的时候是固定的右对齐的,而12位模式又可以设置左对齐/右对齐。单DAC通道x,总共有3种情况:
① 8位数据右对齐:用户将数据写入DAC_DHR8Rx[7:0]位(实际存入DHRx[11:4]位 )。
② 12位数据左对齐:用户将数据写入DAC_DHR12Lx[15:4]位(实际存入DHRx[11:0]
位 )。
③ 12位数据右对齐:用户将数据写入DAC_DHR12Rx[11:0]位(实际存入DHRx[11:0]
位 )。
我们本章使用的就是单DAC通道1,采用12位右对齐格式,所以采用第③种情况。
如果没有选中硬件触发(寄存器DAC_CR1的TENx位置’0’),存入寄存器DAC_DHRx的数据会在一个APB1时钟周期后自动传至寄存器DAC_DORx。如果选中硬件触发(寄存器DAC_CR1的TENx位置’1’),数据传输在触发发生以后3个APB1时钟周期后完成。 一旦数据从DAC_DHRx寄存器装入DAC_DORx寄存器,在经过时间 tsetting之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化。我们可以从STM32F407ZGT6的数据手册查到 的典型值为3us,最大是6us。所以DAC的转换速度最快是333K左右。本章我们将不使用硬件触发(TEN=0),其转换的时间框图如图所示
当DAC的参考电压为Vref+的时候,DAC的输出电压是线性的从0~Vref+,12位模式下DAC输出电压与Vref+以及DORx的计算公式如下:
DACx输出电压=Vref*(DORx/4095)
接下来,我们介绍一下要实现DAC的通道1输出,需要用到的一些寄存器。首先是DAC控制寄存器DAC_CR,该寄存器的各位描述如图所示:
DAC_CR的低16位用于控制通道1,而高16位用于控制通道2,我们这里仅列出比较重要的最低8位的详细描述,如图所示:
首先,我们来看DAC通道1使能位(EN1),该位用来控制DAC通道1使能的,本章我们就是用的DAC通道1,所以该位设置为1。
再看关闭DAC通道1输出缓存控制位(BOFF1),这里STM32F4的DAC输出缓存做的有些不好,如果使能的话,虽然输出能力强一点,但是输出没法到0,这是个很严重的问题。所以本章我们不使用输出缓存。即设置该位为1。
DAC通道1触发使能位(TEN1),该位用来控制是否使用触发,里我们不使用触发,所以设置该位为0。
DAC通道1触发选择位(TSEL1[2:0]),这里我们没用到外部触发,所以设置这几个位为0就行了。
DAC通道1噪声/三角波生成使能位(WAVE1[1:0]),这里我们同样没用到波形发生器,故也设置为0即可。
DAC通道1屏蔽/复制选择器(MAMP[3:0]),这些位仅在使用了波形发生器的时候有用,本章没有用到波形发生器,故设置为0就可以了。
最后是DAC通道1 DMA使能位(DMAEN1),本章我们没有用到DMA功能,故还是设置为0。
通道2的情况和通道1一模一样,这里就不不细说了。在DAC_CR设置好之后,DAC就可以正常工作了,我们仅需要再设置DAC的数据保持寄存器的值,就可以在DAC输出通道得到你想要的电压了(对应IO口设置为模拟输入)。本章,我们用的是DAC通道1的12位右对齐数据保持寄存器:DAC_DHR12R1,该寄存器各位描述如图所示:
该寄存器用来设置DAC输出,通过写入12位数据到该寄存器,就可以在DAC输出通道1(PA4)得到我们所要的结果。
二.编程步骤
这里我们用到的库函数以及相关定义分布在文件stm32f4xx_dac.c以及头文件stm32f4xx_dac.h中
1)开启PA口时钟,设置PA4为模拟输入。
STM32F407ZGT6的DAC通道1是接在PA4上的,所以,我们先要使能GPIOA的时钟,然后设置PA4为模拟输入。
这里需要特别说明一下,虽然DAC引脚设置为输入,但是STM32F4内部会连接在DAC模拟输出上,这在我们引脚复用映射章节有讲解。
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能GPIOA时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AN;//模拟输入
GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_DOWN;//下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
对于DAC通道与引脚对应关系,这在STM32F4的数据手册引脚表上有列出,如下图:
2)使能DAC1时钟。同其他外设一样,要想使用,必须先开启相应的时钟。STM32F4的DAC模块时钟是由APB1提供的,所以我们先要在通过调用函数RCC_APB1PeriphClockCmd来使能DAC1时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC,ENABLE);//使能DAC时钟
3)初始化DAC,设置DAC的工作模式。
该部分设置全部通过DAC_CR设置实现,包括:DAC通道1使能、DAC通道1输出缓存关闭、不使用触发、不使用波形发生器等设置。这里DAC初始化是通过函数DAC_Init完成的:
void DAC_Init(uint32_t DAC_Channel,DAC_InitTypeDef* DAC_InitStruct);
跟前面一样,首先我们来看看参数设置结构体类型DAC_InitTypeDef的定义:
typedef struct
{
uint32_t DAC_Trigger;
uint32_t DAC_WaveGeneration;
uint32_t DAC_LFSRUnmask_TriangleAmplitude;
uint32_t DAC_OutputBuffer;
}DAC_InitTypeDef;
这个结构体的定义还是比较简单的,只有四个成员变量,下面我们一一讲解。
第一个参数DAC_Trigger用来设置是否使用触发功能,前面已经讲解过这个的含义,这里
我们不是用触发功能,所以值为DAC_Trigger_None。
第二个参数DAC_WaveGeneratio用来设置是否使用波形发生,这里我们前面同样讲解过不
使用。所以值为DAC_WaveGeneration_None。
第三个参数DAC_LFSRUnmask_TriangleAmplitude用来设置屏蔽/幅值选择器,这个变量只
在使用波形发生器的时候才有用,这里我们设置为0即可,值为DAC_LFSRUnmask_Bit0。
第四个参数DAC_OutputBuffer是用来设置输出缓存控制位,前面讲解过,我们不使用输出
缓存,所以值为DAC_OutputBuffer_Disable。到此四个参数设置完毕。看看我们的实例代码:
DAC_InitTypeDef DAC_InitType;
DAC_InitType.DAC_Trigger=DAC_Trigger_None; //不使用触发功能 TEN1=0
DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;
DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable; //DAC1输出缓存关闭
DAC_Init(DAC_Channel_1,&DAC_InitType); //初始化DAC通道1
4)使能DAC转换通道
初始化DAC之后,理所当然要使能DAC转换通道,库函数方法是:DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC通道1
5)设置DAC的输出值。
通过前面4个步骤的设置,DAC就可以开始工作了,我们使用12位右对齐数据格式,所以我们通过设置DHR12R1,就可以在DAC输出引脚(PA4)得到不同的电压值了。设置DHR12R1的库函数是:
DAC_SetChannel1Data(DAC_Align_12b_R, 0);//12位右对齐数据格式设置DAC值
第一个参数设置对齐方式,可以为12位右对齐DAC_Align_12b_R,12位左对齐DAC_Align_12b_L以及8位右对齐DAC_Align_8b_R方式。
第二个参数就是DAC的输入值了,这个很好理解,初始化设置为0。
这里,还可以读出DAC对应通道最后一次转换的数值,函数是:
DAC_GetDataOutputValue(DAC_Channel_1);
三.源码实验
此为设置好PA4,一点点增加值,输出到PA4,然后量PA4的波形
Dac.h
#ifndef_DAC_H_H_H
#define_DAC_H_H_H
#include"stm32f4xx_gpio.h"
#include"stm32f4xx_rcc.h"
#include"stm32f4xx_dac.h"
voidDac1_Init(void); //DAC通道1初始化
voidDac1_Set_Vol(u16 vol); //设置通道1输出电压
#endif
Dac.c
#include"dac.h"
//DAC通道1输出初始化
voidDac1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
DAC_InitTypeDef DAC_InitType;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能GPIOA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC,ENABLE);//使能DAC时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AN;//模拟输入
GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_DOWN;//下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
DAC_InitType.DAC_Trigger=DAC_Trigger_None; //不使用触发功能 TEN1=0
DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable; //DAC1输出缓存关闭BOFF1=1
DAC_Init(DAC_Channel_1,&DAC_InitType); //初始化DAC通道1
DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC通道1
DAC_SetChannel1Data(DAC_Align_12b_R, 0); //12位右对齐数据格式设置DAC值
}
//设置通道1输出电压
//vol:0~3300,代表0~3.3V
voidDac1_Set_Vol(u16 vol)
{
double temp=vol;
temp/=1000;
temp=temp*4096/3.3;
DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
}
Main.c
#include"led.h"
#include"key.h"
#include"delay.h"
#include"uart.h"
#include"exit.h"
#include"iwdog.h"
#include"pwm.h"
voidUser_Delay(__IO uint32_t nCount)
{
while(nCount--)
{
}
}
staticint count = 0;
intmain(void)
{
u16 adcx;
u16 dacval1 = 0;
float temp;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
My_USART2_Init();
delay_init(168);
printf("main test start\n");
Adc_Init();
Dac1_Init();
EXTIX_Init();
while(1)
{
dacval1 += 100;
if(dacval1 >= 4000)
{
dacval1 = 0;
}
DAC_SetChannel1Data(DAC_Align_12b_R,dacval1);
adcx=Get_Adc_Average(ADC_Channel_5,20);
temp=(float)adcx*(3.3/4096);
printf("adc value:(%d)\n",adcx);
delay_ms(1);
}
}
执行结果如下图:
上一篇:【stm32f407】I2C实验
下一篇:【stm32f407】ADC实验
推荐阅读最新更新时间:2024-03-16 16:23
设计资源 培训 开发板 精华推荐
- 三星 Exynos 2600 芯片前景堪忧:良率挑战严峻,有被取消量产风险
- 苹果搁置反垄断报告的请求遭印度监管机构拒绝,案件将继续推进
- 2024年Automechanika Shanghai海量同期活动刷新历届记录,汇聚行业智慧,共谋未来发展
- 企业文化分享 如何培养稀缺的硅IP专业人员?SmartDV开启的个人成长与团队协作之旅
- 恩智浦发布首个超宽带无线电池管理系统解决方案
- 北交大本科生探秘泰克先进半导体开放实验室,亲历前沿高科技魅力
- 新帅上任:杜德森博士(Dr. Torsten Derr)将于2025年1月1日出任肖特集团首席执行官
- 边缘 AI 如何提升日常体验
- 苹果要首发!台积电宣布2nm已准备就绪
- AMD有望用上全新芯片堆叠技术:延迟大幅减少、性能显著提升
- 【求助】急!求助如何用按键来控制LED数码管的亮度
- 【工程源码】基于FPGA的Altera SOC更改Qsys后重新生成hps_0.h文件
- 请教一个关于wince里面一个关于网络的问题,可能是无线网卡驱动的问题
- 大家对能效管理系统有什么建议。
- css8与IEC60730_msp430g2553_example项目的冲突 ,时钟方面
- 设计更智能的天窗
- LM1117-3.3资料
- #Micropython大作战#第三弹:抢楼!大家一起来整理micropython资料
- AN1827 ST7FLITE05/09 SIGMA -- DELTA ADC的实现
- 如何解决excluded from build问题??