STM32 的 DAC 模块(数字/模拟转换模块)是 12 位数字输入,电压输出型的 DAC。 DAC可以配置为 8 位或 12 位模式,也可以与 DMA 控制器配合使用。 DAC 工作在 12 位模式时,数据可以设置成左对齐或右对齐。
DAC 模块有 2 个输出通道,每个通道都有单独的转换器。在双 DAC 模式下, 2 个通道可以独立地进行转换,也可以同时进行转换并同步地更新 2 个通道的输出。
本节实验,我们将利用按键(或 USMART) 控制 STM32 内部 DAC1来输出电压,通过
ADC1的通道1 采集 DAC的输出电压,在 LCD 模块上面显示 ADC 获取到的电压值以及 DAC 的设定输出电压值等信息。
STM32 的 DAC 模块主要特点有:
① 2 个 DAC 转换器:每个转换器对应 1 个输出通道
② 8 位或者 12 位单调输出
③ 12 位模式下数据左对齐或者右对齐
④ 同步更新功能
⑤ 噪声波形生成
⑥ 三角波形生成
⑦ 双 DAC 通道同时或者分别转换
⑧ 每个通道都有 DMA 功能
当 DAC 的参考电压为 Vref+的时候(对 STM32F103RC 来说就是 3.3V), DAC 的输出电压是线性的从 0~Vref+, 12 位模式下 DAC 输出电压与 Vref+以及 DORx 的计算公式如下:
DACx 输出电压=Vref*( DORx/4095)
我的ADC和DAC的理解是:
ADC可以采集电压把电压转换为数字,DAC可以把数字转换为电压的形式并输出
配置步骤:
1)开启
PA 口时钟,设置
PA4 为模拟输入。
STM32F103RCT6 的 DAC 通道 1 在 PA4 上,所以,我们先要使能 PORTA 的时钟,然后设置
PA4 为模拟输入。 DAC 本身是输出,但是为什么端口要设置为模拟输入模式呢?因为一但使能 DACx 通道之后,相应的 GPIO 引脚( PA4 或者 PA5)会自动与 DAC 的模拟输出相连,设置为输入,是为了避免额外的干扰。
2)使能
DAC1 时钟。
3) 初始化
DAC,设置
DAC 的工作模式。
4) 使能
DAC 转换通道
5) 设置
DAC 的输出值。
dac.c
#include "dac.h" void Dac1_Init(void) { GPIO_InitTypeDef GPIO_ist; DAC_InitTypeDef DAC_ist; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );//使能 PA 时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE ); //使能 DAC 时钟 GPIO_ist.GPIO_Pin=GPIO_Pin_4; GPIO_ist.GPIO_Mode=GPIO_Mode_AIN;//模拟输入 GPIO_ist.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_ist); GPIO_SetBits(GPIOA,GPIO_Pin_4);//PA.4 输出高 DAC_ist.DAC_Trigger=DAC_Trigger_None; //不使用触发功能 DAC_ist.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生 DAC_ist.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0; DAC_ist.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;//关DAC1输出缓存 DAC_Init(DAC_Channel_1,&DAC_ist); //初始化 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值 } u16 Dac1_Get_Vol(void) { return DAC_GetDataOutputValue(DAC_Channel_1); }
dac.h
#ifndef _DAC_H #define _DAC_H #include "sys.h" void Dac1_Init(void); u16 Dac1_Get_Vol(void); void Dac1_Set_Vol(u16 vol); #endif
主函数。。通过按键来调节DAC输出电压的强度,WKUP增强,KEY0减弱(也可以通过USMART组件设置)
#include "led.h" #include "delay.h" #include "sys.h" #include "usart.h" #include "lcd.h" #include "adc.h" #include "dac.h" #include "key.h" void init() { delay_init(); //延时函数初始化 uart_init(9600); //串口初始化为9600 LED_Init(); //初始化与LED连接的硬件接口 LCD_Init(); KEY_Init(); Adc_Init(); Dac1_Init(); POINT_COLOR=RED;//设置字体为红色 LCD_ShowString(60,40,200,24,24,"DAC Test ^-^"); LCD_ShowString(60,70,200,16,16,"Bigggg difficulty"); LCD_ShowString(60,90,200,16,16,"2015/1/25"); LCD_ShowString(60,110,200,16,16,"By--Mr yh"); LCD_ShowString(60,130,200,16,16,"WK_UP:+ KEY0:-"); //显示提示信息 POINT_COLOR=BLUE;//设置字体为蓝色 LCD_ShowString(60,150,200,16,16,"DAC VAL:"); LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V"); LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V"); Dac1_Set_Vol(330); } int main(void) { u16 adcnum=0; u16 dacnum=0; float tem; u8 key,t=0; init(); while(1) { t++; key=KEY_Scan(0); if(key==WK_UP_PRES) { if(dacnum<4000)dacnum+=200; DAC_SetChannel1Data(DAC_Align_12b_R,dacnum); } else if(key==KEY0_PRES) { if(dacnum>200)dacnum-=200; else dacnum=0; DAC_SetChannel1Data(DAC_Align_12b_R,dacnum); } if(t==10||key==WK_UP_PRES||key==KEY0_PRES) { adcnum=Dac1_Get_Vol();dacnum=adcnum; LCD_ShowxNum(124,150,adcnum,4,16,0);//显示DAC寄存器值 tem=(float)adcnum*(3.3/4096); //得到DAC电压值 adcnum=tem; LCD_ShowxNum(124,170,tem,1,16,0);//显示电压值整数部分 tem-=adcnum;tem*=1000; LCD_ShowxNum(140,170,tem,3,16,0X80);//显示电压值的小数部分 adcnum=Get_Adc_Average(ADC_Channel_1,10); tem=(float)adcnum*(3.3/4096); adcnum=tem; LCD_ShowxNum(124,190,tem,1,16,0); tem-=adcnum;tem*=1000; LCD_ShowxNum(140,190,tem,3,16,0X80); t=0; LED0=!LED0; } delay_ms(10); } }
最后在通过杜邦线将PA1和PA4连起来就好了。。至于为什么要连这两个口 看图
ADC1 和DAC1 分别挂在了 PA1和PA4上,所以我们想要通过ADC1采集DAC1输出的电压,就要将这两点连起来