PS:上一讲我们讲到了ADC(模数转换),这一讲中,我们介绍一下DAC(数模转换),简而言之,数模转换所完成的工作和模数转换正好相反——数字量转化成模拟量
ADC的时候,我们的stm32是引脚是负责接收一个模拟量,并且把它转化成数字量,而DAC的时候,我们的引脚是负责处理内部的数字指令,将其转化成模拟量进行输出,此时的引脚作为一个输出使用~
这是德州仪器的一篇英文DAC的知识简介:
http://e2e.ti.com/blogs_/b/analogwire/archive/2013/02/25/dac-essentials-a-new-blog-series
wiki的介绍:
https://zh.wikipedia.org/wiki/%E6%95%B8%E4%BD%8D%E9%A1%9E%E6%AF%94%E8%BD%89%E6%8F%9B%E5%99%A8
OK,接下来开始介绍关于stm32内部的DAC特性
说实话,和stm32对ADC的支持相比较,DAC的支持显得可能会稍稍薄弱(误差大概高了0.03V),不过,这并不影响我们使用它。
特点
· 和ADC不同,在stm32中,ADC的结果存储在一个16位的寄存器中,但是,DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用,当配置为12位模式时,也需要考虑左对齐或者右对齐。
· DAC模块有2个输出通道(PA4,PA5),每个通道都有单独的转换器。
· 在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出
DAC的主要模块:
1. 2个DAC转换器:每个转换器对应1个输出通道
2. 八位或十二位的单调输出
3. 噪声波形生成
4. 三角波生成
5. 双DAC同时转换,亦可分别转换
6. 每个通道都有DMA功能
DAC的框图
PS:我么可以看到,DAC可以被通用定时器触发,也可以被外部中断9触发,但是,我们考虑到初学,先不用管这些组合的问题,先简单了解下DAC的库函数配置~
DAC输出电压的范围理论上是在0~Vref,但是,实际上stm32f103的芯片会比理论值大了0.03V。
VDAC=Vref*(DOR/4095),4095是十二位寄存器的最大值-_-.
DAC的库函数配置(以DAC1为例):
因为在使能DACx之后,相应的GPIO引脚会自动与DAC的模拟输出引脚相连,设置为输入,为例避开干扰RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); //使能PORTA通道时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_4) ;//PA.4 输出高
2. 使能DAC1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE ); //使能DAC通道时钟
3. 初始化DAC并且设置工作模式
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
4. 使能DAC的转换通道
DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC1
设置DAC的输出值
DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
配置过程一览
void Dac1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
DAC_InitTypeDef DAC_InitType;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); //使能PORTA通道时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE ); //使能DAC通道时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_4) ;//PA.4 输出高
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); //使能DAC1
DAC_SetChannel1Data(DAC_Align_12b_R, 0); //12位右对齐数据格式设置DAC值
}
//设置通道1输出电压
//vol:0~3300,代表0~3.3V
void Dac1_Set_Vol(u16 vol)
{
float temp=vol;
temp/=1000;
temp=temp*4096/3.3;
DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
}