stm32 - DAC基本输出方式

DAC简介

数模转换器(DAC)是极为常用的电子器件,可以将数字量转换为以参考量为基准的模拟量,以满足应用需求。

电压输出模式

stm32中,D/A转换器包含以下三种输出方式:

  1. 输出电压
  2. 噪声生成
  3. 三角波生成

本文将着重介绍最基本的电压输出方式。

主要特征

DAC的主要特征有:

  1. 2个DAC转换器:1个输出通道对应1个转换器
  2. 8位或者12位单调输出
  3. 12位模式下数据左对齐或者右对齐
  4. 同步更新功能
  5. 噪声波形生成
  6. 三角波形生成
  7. 双DAC通道同时或者分别转换
  8. 每个通道都有DMA功能
  9. 外部触发转换
  10. 输入参考电压V_REF+

数据对齐方式

DAC 输出通道的数据对齐方式包含以下三种:

  1. 8位右对齐
  2. 12位左对齐
  3. 12位右对齐

此外,在单 DAC 通道模式下,数据寄存器的存储方式如下:

dacAlignMode1

在双 DAC 通道模式下,数据寄存器的存储方式则为:

dacAlignMode2

我通常会选择12位右对齐方式,并在单通道模式设置数据时与0x0fff进行"位与"。

DAC转换

dacConvert

用户无法直接对DAC的数据寄存器 DAC_DORx 写入数据,只能通过修改数据保持寄存器 DAC_DHRx 装入数据。

  1. 未选择"硬件触发"时,保持寄存器 DAC_DHRx 的值将在1个APB1周期后自动传入数据寄存器 DAC_DORx;
  2. 已选择"硬件触发"时,保持寄存器 DAC_DHRx 的值将在触发发生后3个APB1后传入数据寄存器 DAC_DORx。
  3. 当数据存入 DAC_DORx 后再经过时间 t_settings(与负载和电源电压有关),输出变为有效。

DAC触发方式

#define DAC_Trigger_None                   ((uint32_t)0x00000000)
/*!< Conversion is automatic once the DAC1_DHRxxxx register
has been loaded, and not by external trigger */

#define DAC_Trigger_T6_TRGO                ((uint32_t)0x00000004)
/*!< TIM6 TRGO selected as external conversion trigger for DAC channel */

#define DAC_Trigger_T8_TRGO                ((uint32_t)0x0000000C)
/*!< TIM8 TRGO selected as external conversion trigger for DAC channel
only in High-density devices*/

#define DAC_Trigger_T3_TRGO                ((uint32_t)0x0000000C)
/*!< TIM8 TRGO selected as external conversion trigger for DAC channel
only in Connectivity line, Medium-density and Low-density Value Line devices */

#define DAC_Trigger_T7_TRGO                ((uint32_t)0x00000014)
/*!< TIM7 TRGO selected as external conversion trigger for DAC channel */

#define DAC_Trigger_T5_TRGO                ((uint32_t)0x0000001C)
/*!< TIM5 TRGO selected as external conversion trigger for DAC channel */

#define DAC_Trigger_T15_TRGO               ((uint32_t)0x0000001C)
/*!< TIM15 TRGO selected as external conversion trigger for DAC channel
only in Medium-density and Low-density Value Line devices*/

#define DAC_Trigger_T2_TRGO                ((uint32_t)0x00000024)
/*!< TIM2 TRGO selected as external conversion trigger for DAC channel */

#define DAC_Trigger_T4_TRGO                ((uint32_t)0x0000002C)
/*!< TIM4 TRGO selected as external conversion trigger for DAC channel */

#define DAC_Trigger_Ext_IT9                ((uint32_t)0x00000034)
/*!< EXTI Line9 event selected as external conversion trigger for DAC channel */

#define DAC_Trigger_Software               ((uint32_t)0x0000003C)
/*!< Conversion started by software trigger for DAC channel */

触发方式 大致可分为四类:

  1. DAC_Trigger_None : 无触发;
  2. DAC_Trigger_Tx_TRGO : 来自片上定时器的TRGO输出
  3. DAC_Trigger_Ext_IT9 : 来自外部中断线9的上升沿
  4. DAC_Trigger_Software : 来自软件控制位 SWTRIG

当 DAC 接口检测到来自定时器 TRGO输出EXTI9 的上升沿时,最近存入 DAC_DHRx 中的数据将被传入 DAC_DORx 中。经3个APB1周期后更新 DAC_DORx 的值。对于 "软件触发",需要在程序中对 SWTRIG 置位完成触发,该触发位将被硬件自动清零。

DAC输出电压

DAC输出 = V_reference × DOR /4095;

式中,V_reference 为参考电压,DOR 为 DAC 输出数据寄存器的值(0255/04095)。

DAC 基本输出方式

DAC 参数设置

stm32f103中包含2个通道的12位D/A转换器,PA4PA5作为两个通道输出接口,在使用时需要配置为模拟输入AIN。当使能 DAC 的输出通道后,相应的 GPIO 管脚将自动与 DAC 的模拟输出接口(DAC_OUTx)相连。

void dacConfig(void)
{
GPIO_InitTypeDef  GPIO_InitStructure;
DAC_InitTypeDef DAC_InitStructure;

/* 开启GPIOA时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
/* 配置DAC输出通道 */
GPIO_Init(GPIOA, &GPIO_InitStructure);


/* 开启DAC时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC,ENABLE);

DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;                  // 无触发
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;    // 无波形生成
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;     // 禁用输出缓存
/* 配置DAC参数 */
DAC_Init(DAC_Channel_1,&DAC_InitStructure);

/* enable dac1 */
DAC_Cmd(DAC_Channel_1,ENABLE);
}

设置 DAC 输出电压

经测试,我所用最小系统板的DA参考电压并非3.3v,而是接近于3.24v,我们可以通过宏定义配置好参考电压。

#define REFERENCE_VOLTAGE 3.24f      // DAC 参考电压

根据公式 data = 4095*(v/v_ref)可以求得电压v对应的12位数。

void setVoltage(double voltage)
{
uint16_t temp;

if(voltage < 0.0 || voltage > REFERENCE_VOLTAGE)
  return;

temp = (uint16_t)(4095*voltage/REFERENCE_VOLTAGE) & 0x0fff;

DAC_SetChannel1Data(DAC_Align_12b_R,temp);     // 电压输出:12位右对齐
}

产生正弦波信号

使用宏定义PI以及采样频率,并添加头文件math.h

#include <math.h>

#define PI  3.14159f
#define FSAMPLE 100                 // 采样频率 (Hz)

使用sin函数和一个static变量即可生成正弦信号。

void createSinWave(double baseAmp, double amp, double frequency, double fSample)
{
static uint32_t time = 0;
double voltage = 0.0;

voltage = amp*sin(2*PI*frequency*time/fSample) + baseAmp;
time++;

setVoltage(voltage);
}

修改main函数,每隔一个采样周期修改一次DA输出电压,完成正弦信号的输出。

int main(void)
{
dacConfig();
while(1)
{
  createSinWave(2,0.5,1,FSAMPLE); // 产生 2±0.5v , 1Hz 的正弦信号
  delayMs(1000.0/FSAMPLE);
}
}

查看波形

使用示波器或NI采集卡即可查看生成的正弦信号。

DacOutput