目录
本节学习的是有关DAC的知识点,主要进行的是数字信号到模拟信号的转换,内容其实和我们之前学51的时候是类似的,在此就不做过多介绍,如果对AD/ DA有不太了解的同学还是建议先去看一下51的AD/DA转换。
DAC
STM32F4 的 DAC 模块(数字/模拟转换模块)是 12 位数字输入,电压输出型的 DAC。DAC 可以配置为 8 位或 12 位模式,也可以与 DMA 控制器配合使用。DAC 工作在 12 位模式时, 数据可以设置成左对齐或右对齐。DAC 模块有 2 个输出通道,每个通道都有单独的转换器。 在双 DAC 模式下,2 个通道可以独立地进行转换,也可以同时进行转换并同步地更新 2 个 通道的输出。DAC 可以通过引脚输入参考电压 Vref+(通 ADC 共用)以获得更精确的转换结果。
- 2 个 DAC 转换器:每个转换器对应 1 个输出通道
- 8 位或者 12 位单调输出
- 12 位模式下数据左对齐或者右对齐
- 同步更新功能
- 噪声波形生成
- 三角波形生成
- 双 DAC 通道同时或者分别转换
- 每个通道都有 DMA 功能
图中 VDDA 和 VSSA 为 DAC 模块模拟部分的供电,而 Vref+则是 DAC 模块的参考电 压。DAC_OUTx 就是 DAC 的输出通道了(对应 PA4 或者 PA5 引脚)。 值得我们注意的是,如果我们想要写入东西到DOR中去,则必须通过DHR寄存器来写入,所以这样会有一个延迟,时间大概是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模块是连接到PA4引脚上的,所以我们到时候需要使能相应的GPIO,还有,本实验同时使用ADC,DAC 模块,所以还需要使用跳线帽连接ADC和DAC模块,让DAC的模拟输出作为ADC的模拟输入。


1、开启 PA 口时钟,设置 PA4 为模拟输入。
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);//初始化2、使能 DAC1 时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//使能 DAC 时钟3、初始化 DAC,设置 DAC 的工作模式。
void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct);4、使能 DAC 转换通道。
DAC_Cmd(DAC_Channel_1, ENABLE); //使能 DAC 通道 15、设置 DAC 的输出值。
DAC_SetChannel1Data(DAC_Align_12b_R, 0); //12 位右对齐数据格式设置 DAC 值
- #include "dac.h"
-
-
- //DAC通道1输出初始化
- void Dac1_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_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
- DAC_InitType.DAC_OutputBuffer = DAC_OutputBuffer_Disable; //DAC1输出缓存关闭
- DAC_InitType.DAC_Trigger = DAC_Trigger_None;//不使用触发功能
- DAC_InitType.DAC_WaveGeneration = DAC_WaveGeneration_None;//不使用波形发生
- 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值
- }
- #include "sys.h"
- #include "delay.h"
- #include "usart.h"
- #include "led.h"
- #include "adc.h"
- #include "dac.h"
- #include "key.h"
-
- int main(void)
- {
- u16 adcx;
- float temp;
- u8 t=0;
- u16 dacval=0;
- u8 key;
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
- delay_init(168); //初始化延时函数
- uart_init(115200); //初始化串口波特率为115200
- LED_Init(); //初始化LED
- Adc_Init(); //adc初始化
- KEY_Init(); //按键初始化
- Dac1_Init(); //DAC通道1初始化
- DAC_SetChannel1Data(DAC_Align_12b_R,dacval);//初始值为0
- while(1)
- {
- t++;
- key=KEY_Scan(1);
- if(key==WKUP_PRES)
- {
- if(dacval<4000)dacval+=200;
- DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值
- }else if(key==KEY1_PRES)
- {
- if(dacval>200)dacval-=200;
- else dacval=0;
- DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值
- }
- if(t==100||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了
- {
- adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
- printf ("DAC VAL:%d",adcx); //显示DAC寄存器值
- printf ("\r\n\r\n");
- temp=(float)adcx*(3.3/4096); //得到DAC电压值
- adcx=temp;
- printf("DAC VOL:%fV",temp); //显示电压值
- printf ("\r\n\r\n");
- adcx=Get_Adc_Average(ADC_Channel_5,10); //得到ADC转换值
- temp=(float)adcx*(3.3/4096); //得到ADC电压值
- adcx=temp;
- printf("ADC VOL:%fV",temp); //显示电压值
- printf ("\r\n\r\n");
- LED0=!LED0;
- t=0;
- }
- delay_ms(10);
- }
- }
本节DAC的基础知识就先介绍到这,后期还会对代码进行修改以及调试,继续探索一下AD/DA的功能,好了,谢谢大家的观看。