DAC简介

DAC 为数字/模拟转换模块,故名思议,它的作用就是把输入的数字编码,转换成对应的模拟电压输出,它的功能与 ADC 相反。在常见的数字信号系统中,大部分传感器信号被化成电压信号,而 ADC 把电压模拟信号转换成易于计算机存储、处理的数字编码,由计算机处理完成后,再由DAC 输出电压模拟信号,该电压模拟信号常常用来驱动某些执行器件,使人类易于感知。如音频信号的采集及还原就是这样一个过程。

STM32 具有片上 DAC 外设,它的分辨率可配置为 8 位或 12 位的数字输入信号,具有两个 DAC输出通道,这两个通道互不影响,每个通道都可以使用 DMA 功能,都具有出错检测能力,可外部触发。

DAC 功能框图剖析

整个 DAC 模块围绕框图下方的“数字至模拟转换器 x”展开。

  • 左边引脚:VDDA、VSSA 及 Vref+,其中 STM32 的 DAC 规定了它的参考电压:math:V_{ref +} 输入范围为 2.4~3.3V。
  • “数字至模拟转换器 x”:为 DAC 的数据寄存器“DORx”的数字编码,经过它转换得的模拟信号由图中右侧的“DAC_OUTx”输出
  • 数据寄存器“DORx”:又受“控制逻辑”支配,它可以控制数据寄存器加入一些伪噪声信号或配置产生三角波信号。
  • 左上角为 DAC 的触发源:为外部中断源触发、定时器触发或软件控制触发。

参考电压

与 ADC 外设类似,DAC 也使用 VREF+ 引脚作为参考电压,在设计原理图的时候一般把 VSSA 接地,把 VREF+ 和 VDDA 接 3.3V,可得到 DAC 的输出电压范围为:0~3.3V。

如果想让输出的电压范围变宽,可以在外部加一个电压调理电路,把 0~3.3V 的 DAC 输出抬升到特定的范围即可。

数模转换及输出通道

框图中的“数字至模拟转换器 x”是核心部件,整个 DAC 外设都围绕它而展开。它以左边的 VREF+作为参考电源,以 DAC 的数据寄存器“DORx”的数字编码作为输入,经过它转换得的模拟信号由右侧的“DAC_OUTx”通道输出。

其中各个部件中的“x”是指设备的标号,在 STM32 中具有 2 个这样的 DAC 部件,每个 DAC 有 1 个对应的输出通道连接到特定的引脚,即:PA4-通道 1,PA5-通道 2,为避免干扰,使用 DAC 功能时,DAC 通道引脚需要被配置成模拟输入功能(AIN)

DAC初始化结构体详解

1
2
3
4
5
6
7
8
9
10
typedef struct {
/*DAC 触发方式 */
uint32_t DAC_Trigger;
/* 是否自动输出噪声或三角波 */
uint32_t DAC_WaveGeneration;
/* 选择噪声生成器的低通滤波或三角波的幅值(若上面输出噪声或者三角波没有用到,则这项也配置没有用到) */
uint32_t DAC_LFSRUnmask_TriangleAmplitude;
/* 选择是否使能输出缓冲器 */
uint32_t DAC_OutputBuffer;
} DAC_InitTypeDef;

DAC输出❤实验

硬件设计

STM32 的 DAC 外设有固定的输出通道,分别为PA4 和 PA5,不过,指南者开发板已经在板载SPI-FLASH 芯片中使用了这两个引脚,所以用作 DAC 通道输出电压时会受到干扰,影响实验。

PA5 引脚连接到 FLASH 芯片的 CLK 引脚中,这可能会干扰 DAC 实验输出的电压信号,导致得不到正确的波形。最好是用于输出DAC的输出线是干净的,没有其他干扰的。

编程要点

  1. 计算获取爱心数据表;
  2. 根据爱心数据表的周期内点数和周期计算定时器触发间隔;
  3. 初始化 DAC 输出通道,初始化 DAC 工作模式;
  4. 配置触发 DAC 用的定时器;
  5. 配置 DMA 自动转运爱心数据表。
  6. 配置完成后,即可在 PA4、PA5 引脚中检测到信号输出。

代码分析

生成爱心数据表

而由于模拟信号连续而数字信号是离散的,所以使用 DAC 爱心时,只能按一定时间间隔输出曲线上的点,在该时间段内输出相同的电压值,若缩短时间间隔,提高单个周期内的输出点数,可以得到逼近连续爱心波的图形,见图DAC按点输出爱心波数据 ,若在外部电路加上适当的电容滤波,可得到更完美的图形。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
clear;          %清空工作区变量
clc; %清空命令窗口

%%画心
x = -2:1/50:2;
y = abs(x.^(2/3))+(0.99*(pi-x.^2).^(1/2)).*sin(13.14520*pi*x);

%%线性比例放大
Calculation = (y+1.7)* 952.3810;
OutData = int16(Calculation);
csvwrite('CH1.c',OutData); %输出这个数组

%%测试验证
plot(x,OutData,'r');

值得注意的是,只需要将范围跳到0~4096即可

DAC配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static void DAC_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
DAC_InitTypeDef DAC_InitStructure;
/* 使能 GPIOA 时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* 使能 DAC 时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
/* DAC 的 GPIO 配置,模拟输入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置 DAC 通道 1 */
//使用 TIM2 作为触发源
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;
//不使用波形发生器
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
//不使用 DAC 输出缓冲
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);

/* 使能通道 1 由 PA4 输出 */
DAC_Cmd(DAC_Channel_1, ENABLE);
}

定时器2配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void DAC_TIM_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* 使能 TIM2 时钟,TIM2CLK 为 72M */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* TIM2 基本定时器配置 */
//定时周期 1ms
TIM_TimeBaseStructure.TIM_Period = (1000-1);
//预分频,不分频 72M / (0+1) = 72M
TIM_TimeBaseStructure.TIM_Prescaler = (72-1);
//时钟分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
//向上计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

/* 配置 TIM2 触发源 */
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
/* 使能 TIM2 */
TIM_Cmd(TIM2, ENABLE);
}

DMA配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
static void DAC_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* 使能 DMA2 时钟 */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
/* 配置 DMA2 */
//外设数据地址
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_ADDRESS;//也就是外设DAC_DHR12RD地址:0x40007420
//内存数据地址 DualSine12bit
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&DAC_Sin ;
//数据传输方向内存至外设
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
//缓存大小为 POINT_NUM 字节
DMA_InitStructure.DMA_BufferSize = POINT_NUM;
//外设数据地址固定
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//内存数据地址自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//外设数据以字为单位
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
//内存数据以字为单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
//循环模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//高 DMA 通道优先级
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
//非内存至内存模式
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA2_Channel4, &DMA_InitStructure);

/* 使能 DMA2-14 通道 */
DMA_Cmd(DMA2_Channel4, ENABLE);

DAC_DMACmd(DAC_Channel_1, ENABLE);
}

DAC初始化

1
2
3
4
5
6
7
8
9
10
11
12
void User_DAC_Init(void)
{
uint16_t i;
DAC_Config();
DAC_TIM_Config();
DAC_DMA_Config();

for(i=0; i<256; i++)
{
DAC_Sin[i] = CH_1[i];
}
}

这里有两个数组,DAC_Sin是用于DMA输出的,CH_1就是用来存放我们要输出的波形的数组的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
uint32_t DAC_Sin[128];
uint16_t CH_1[] = {
3089,3089,3089,3089,3089,3089,3089,3089,
3089,3089,3089,3089,3089,3089,3089,3089,
3089,3089,3089,3089,3089,3089,3089,3089,
3089,3089,3089,3089,3089,3089,3089,3089,
3089,3089,3089,3089,3089,3089,3089,2873,
2606,2556,2826,3267,3567,3475,2995,2409,
2107,2316,2930,3557,3766,3382,2618,1955,
1833,2352,3191,3800,3761,3066,2140,1578,
1752,2565,3496,3929,3560,2600,1655,1334,
1853,2885,3759,3894,3179,2055,1239,1258,
2106,3237,3912,3676,2660,1506,950,1354,
2458,3545,3902,3279,2060,1021,826,1601,
2843,3742,3704,2735,1446,657,873,1950,
3187,3773,3316,2094,881,450,1072,2336,
3418,3605,2761,1414,419,405,1369,2677,
3469,3217,2065,736,65,461,1619,2918,
396,2794,1526,431,232,1075,2430,3440,
3471,2518,1213,409,635,1755,3058,3716,
3321,2143,956,533,1153,2423,3533,3781,
3024,1766,829,821,1751,3022,3827,3661,
2651,1461,867,1251,2366,3498,3929,3401,
2273,1285,1076,1777,2934,3808,3853,3062,
1964,1274,1434,2333,3390,3934,3637,2717,
1781,1436,1894,2848,3684,3883,3343,2441,
1769,1753,2386,3247,3789,3689,3049,2307,
1946,2177,2826,3462,3693,3413,2849,2390,
2320,2642,3104,3395,3366,3121,2926,3089,
3089,3089,3089,3089,3089,3089,3089,3089,
3089,3089,3089,3089,3089,3089,3089,3089,
3089,3089,3089,3089,3089,3089,3089,3089,
3089,3089,3089,3089,3089,3089,3089,3089,
3089,3089,3089,3089,3089,3089,3089,3089
};

最终输出成果

【图片】