DAC 简介
Stm32f4内嵌的DAC是12位数字输入,电压输出的数模转换器。DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。DAC工作在12位模式时,数据可以设置成左对齐或右对齐。DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压VREF+以获得更精确的转换结果。 主要特点: 2个DAC转换器:每个转换器对应1个输出通道 8位或者12位单调输出 12位模式下数据左对齐或者右对齐 同步更新功能 噪声波形生成 三角波形生成 双DAC通道同时或者分别转换 每个通道都有DMA功能 外部触发转换 输入参考电压VREF+
DAC框图
VDDA:模拟电源输入 VSSAL:模拟电源接地输入 Vref+:正模拟参考电压输入 DORx:输入数字寄存器 DAC_OUT:模拟输出通道 DAC_OUT1 ->PA4 DAC_OUT2 ->PA5
寄存器
### 过程 软件将数据加载到DAC_DHRx寄存器 写入的数据将移位并存储到相应的 DHRx(数据保 持寄存器 x,即内部非存储器映射寄存器) 根据是否选择硬件触发,DHRx 寄存器将被自动加载,或者通过软件或外部事件触发加载到 DORx 寄存器的数据在 t SETTLING 时间后给模拟输出电压
时序:
如果未选择硬件触发: (DAC_CR 寄存器中的 TENx 位复位) 经过一个 APB1 时钟周期后, DAC_DHRx寄存器中存储的数据将自动转移到 DAC_DORx 寄存器。 如果选择硬件触发 (置位 DAC_CR 寄存器中的 TENx位)且触发条件到来 将在三个 APB1 时钟 周期后进行转移。 当 DAC_DORx 加载了 DAC_DHRx内容时,模拟输出电压将在一段时间 t SETTLING 后可用,具体时间取决于电源电压和模拟输出负载。
数据保持寄存器
对于 DAC 单通道 x,有三种可能的方式:
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 输出电压 经过线性转换后,数字输入会转换为 0 到 VREF+ 之间的输出电压。 各 DAC 通道引脚的模拟输出电压通过以下公式确定:
代码配置
设置步骤: 设置相关GPIO(PA4、5)。 若时钟源为TIMx更新事件,则设置TIMx。 使能DAC时钟 设置触发源,开启相关触发通道,如果用DMA,是否允许数据错误中断。 如果用DMA。配置相关DMA数据流。
#include"stm32f4xx.h"
#include"sys.h"
#include<stdio.h>
static GPIO_InitTypeDef GPIO_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;
static USART_InitTypeDef USART_InitStructure;
static ADC_InitTypeDef ADC_InitStructure;
static ADC_CommonInitTypeDef ADC_CommonInitStructure;
static DAC_InitTypeDef DAC_InitStructure;
void delay_ms(uint32_t n)
{
while(n--)
{
SysTick->CTRL = 0;
SysTick->LOAD = (168000)-1;
SysTick->VAL = 0;
SysTick->CTRL = 5;
while ((SysTick->CTRL & 0x10000)==0);
}
SysTick->CTRL = 0;
}
void delay_us(uint32_t n)
{
while(n--)
{
SysTick->CTRL = 0;
SysTick->LOAD = (168)-1;
SysTick->VAL = 0;
SysTick->CTRL = 5;
while ((SysTick->CTRL & 0x10000)==0);
}
SysTick->CTRL = 0;
}
void usart1_init(uint32_t baud)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF ;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
USART_InitStructure.USART_BaudRate = baud;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void dac_init()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC,ENABLE);
DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
DAC_Cmd(DAC_Channel_1, ENABLE);
}
void adc_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA,&GPIO_InitStructure);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1,&ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_56Cycles);
ADC_Cmd(ADC1,ENABLE);
}
struct __FILE{int handle;};
FILE __stdout;
FILE __stdin;
int fputc(int ch,FILE *f)
{
USART_SendData(USART1,ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
return ch;
}
int main(void)
{
uint16_t adc_val,adc_v;
usart1_init(115200);
printf("ADC test\r\n");
adc_Init();
dac_init();
DAC_SetChannel1Data(DAC_Align_12b_R,1650*4095/3300);
ADC_SoftwareStartConv(ADC1);
delay_ms(1000);
while(1)
{
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
ADC_ClearFlag(ADC1,ADC_FLAG_EOC);
adc_val=ADC_GetConversionValue(ADC1);
adc_v=adc_val*3300/4095;
printf("电压为:%dmv\r\n",adc_v);
printf("剩余点亮%d%% \r\n",adc_v/33);
delay_ms(1000);
}
}
void USART1_IRQHandler(void)
{
uint8_t d=0;
if(USART_GetFlagStatus(USART1,USART_IT_RXNE)==SET)
{
d=USART_ReceiveData(USART1);
if(d==0x01)PFout(10)=0;
if(d==0xf1)PFout(10)=1;
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}
|