一、简介
DAC
Digital-to-Analog Converter的缩写。数模转换器。又称D/A转换器,简称DAC,是指将离散的数字信号转换为连续变量的模拟信号的器件。
典型的数字模拟转换器将表示一定比例电压值的数字信号转换为模拟信号。
STM32F1中有两个DAC,可以同时使用STM32的DAC模块是12位数字输入,电压输出型的DAC。
DAC 有两个用途:输出波形和输出固定电压
DAC工作原理
DAC工作框图
分成三部分讲解:
"触发方式 " “控制逻辑” "数模转换器"
相关寄存器有
1、触发方式:
是指DAC转换可以由某外部事件触发(定时器计数器、外部中断线)。配置控制位TSELx[2:0]可以选择8个触发事件之一触发DAC转换,任意一种触发源都可以触发DAC转换。
具体的外部触发可看下图:
六个是定时器触发:TIM2,TIM4,TIM5,TIM6,TIM7和TIM8。剩下两个分别是:EXTI线路9(PC9)和软件触发。
每次DAC接口侦测到来自选中的定时器TRGO输出,或者外部中断线9的上升沿,存放在寄 存器DAC_DHRx中的数据会被传送到寄存器DAC_DORx中。在3个APB1时钟周期后,寄存器 DAC_DORx更新为新值。
如果选择软件触发,一旦SWTRIG位置’1’,转换即开始。在数据从DAC_DHRx寄存器传送到 DAC_DORx寄存器后,SWTRIG位由硬件自动清’0’
2、控制逻辑
此部分决定了DAC的波形控制,输出方式,DMA传输,等等,
我们来具体讲解下:
从框图可以看出,DAC受DORx寄存器直接控制的,但是数据并不是直接传入DORx的,需要先传入DHRx 之后在间接地传给DORx寄存器 不能直接往DORx寄存器写入数据
- 如果没有选择硬件触发(TENx=0),在一个APB1周期后传入DORx,
- 如果选择硬件触发(TENx=1),则在3个APB1周期后传入DORx
一旦数据从DAC_DHRx寄存器装入DAC_DORx寄存器,在经过时间Tsetting(大约3us) 之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化
寄存器讲解:
从高到低位为:
DMAENx :控制DAC通道1/2 的DMA使能
MAMP2[3:0]:DAC通道2屏蔽/幅值选择器 位 27:24 由软件设置这些位,用来在噪声生成模式下选择屏蔽位,在三角波生成模式下选择波形的幅值。
WAVE2[1:0]:DAC通道2噪声/三角波生成使能,位23:22:
决定是否产生波形,和产生什么波形。
00:关闭波形发生器;
10:使能噪声波形发生器;
1x:使能三角波发生器。
TSELx[2:0]:可以选择8个触发事件。
TENx:DAC通道x触发使能,用来使能/关闭DAC通道x的触发。
0:关闭DAC通道x触发,写入DAC_DHRx寄存器的数据在1个APB1时钟周期后传入 DAC_DORx寄存器;
1:使能DAC通道x触发,写入DAC_DHRx寄存器的数据在3个APB1时钟周期后传入 DAC_DORx寄存器。
注意:如果选择软件触发,写入寄存器DAC_DHRx的数据只需要1个APB1时钟周期就可以传入 寄存器DAC_DORx。
3、数模转换器
VDDA和VSSA为DAC模块模拟部分的供电。
Vref+则是DAC模块的参考电压。
DAC_OUTx就是DAC的输出通道了(对应PA4或者PA5引脚)
从左边的参考电压Vref+ ---->数模转换器 ---->模拟信号输出引脚
注意:DAC的引脚应该设置成模拟输入(AIN)模式
1.DAC输出电压:
数字输入经过DAC被线性地转换为模拟电压输出
其范围为 0~VREF+
DAC输出 = VREF x (DOR/4095)
2.特殊功能:
噪声波形生成,三角波形生成,外部触发转换,双DAC同时或者分别转换;每个通道都有DMA功能;
参考电压:2.4V~ 3.3V
3.DAC的主要特征
- 2个DAC转换器:
- 每个转换器对应1个输出通道;
- 8位或者12位单调输出;
- 12位模式下数据左对齐或者右对齐;
- 同步更新功能;
- 噪声波形生成;
- 三角波形生成;
- 双DAC通道同时或者分别转换;
- 外部触发转换;
- 输入参考电压VREF+。
DAC原理总括
数字/模拟转换模块(DAC)是12位数字输入,电压输出的数字/模拟转换器。DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。
DAC工作在12位模式时,数据可以设置成左对齐或右对齐。
DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压VREF+ 以获得更精确的转换结果。
二、工程创建
1.RCC设置
2.开启ADC
3.时钟树设置
4.ADC设置(这里我们用STM32的的ADC去检测DAC)
5.串口设置
6.DAC设置
1.OUT1 和 OUT2对应两个输出通道
2.External Trigger 外部中断EXTI9 触发,就是使用外部中断来触发ADC
3.Tigger 选择DAC的触发方式 上方都有讲解
4.Output Buffer 使能DAC输出缓存
DAC集成了2个输出缓存,可以用来减少输出阻抗,无需外部运放即可直接驱动外部负载。每个 DAC通道输出缓存可以通过设置DAC_CR寄存器的BOFFx位来使能或者关闭
这个使能即可。
5.项目文件设置
三、代码讲解
1.串口设置:
#include "stdio.h"
//重定向c库函数printf到串口DEBUG_USART,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口DEBUG_USART */
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
return (ch);
}
//重定向c库函数scanf到串口DEBUG_USART,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
int ch;
HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 1000);
return (ch);
}
2.ADC的设置:
在main.c中加上
/* USER CODE BEGIN 0 */
uint16_t ADC_Value;
/* USER CODE END 0 */
在ADC初始化之后加上AD校准函数
MX_ADC1_Init();
HAL_ADCEx_Calibration_Start(&hadc1); //AD校准
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
while中加上:
HAL_ADC_Start(&hadc1); //启动ADC转换
HAL_ADC_PollForConversion(&hadc1, 50); //等待转换完成,50为最大等待时间,单位为ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
ADC_Value = HAL_ADC_GetValue(&hadc1); //获取AD值
printf("ADC1 Reading : %d \r\n",ADC_Value);
printf("PA1 True Voltage value : %.4f \r\n",ADC_Value*3.3f/4096);
printf("测试\r\n");
}
HAL_Delay(1000);
3.DAC输出电压:
在main()主函数中设置DAC输出的数据为12位右对齐,DAC输出为2048,并使能DAC1输出通道
/* USER CODE BEGIN 2 */
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048);
HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
/* USER CODE END 2 */
DAC输出 = VREF x (DOR/4095)
则实际输出的电压为
2048/4096x3.3V=1.65V。
讲解一下上面用到的函数:
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048);
- 功能:设置DAC的输出值
参数一: DAC结构体名
参数二: 设置DAC通道
参数三: 设置DAC对齐方式
参数四: 设置输出电压值 12位最大位4095
HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
- 功能:开启DAC输出
- 参数一: DAC结构体名
- 参数二: DAC通道
DAC相关库函数:
HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef* hdac, uint32_t Channel); //开启DAC输出
HAL_StatusTypeDef HAL_DAC_Stop(DAC_HandleTypeDef* hdac, uint32_t Channel); //关闭DAC输出
HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t* pData, uint32_t Length, uint32_t Alignment); //需要函数中不断开启 //开启DAC的DMA输出
HAL_StatusTypeDef HAL_DAC_Stop_DMA(DAC_HandleTypeDef* hdac, uint32_t Channel); //关闭DAC的DMA输出
HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data); //设置DAC输出值
uint32_t HAL_DAC_GetValue(DAC_HandleTypeDef* hdac, uint32_t Channel); //获取DAC输出值
三角波配置:
接下来讲解如何输出三角波:
一、打开STM32cubeMX的DAC工程文件重新配置:
1.使能DAC输出通道2。
2.DAC外部触发(Trigger) :定时器2触发。
3.波形生成模式(Wave generation mode) :三角波发生器(Triangle wave generation).
可以选择三角波形,和噪声波形(noise wave generation)
4.最大三角波幅(Maximum Triangle Amplitude) :4095。
设三角波幅值为3.3V,即4095
DAC12位数据存储,最大为4095
0-4095 对应 0V~3.3V
二、打开打开Timers,使能定时器2。
这里讲下三角波的频率
简单的说,首先设置一个DAC最大幅值, 之后设置定时器溢出时间,在每次定时器发生溢出等事件之后,定时器会发送触发信号TRGO到DAC,这是内部的三角波计数器就会累加1 然后于DAC_DHRx寄存器的值相加,写到DAC_DORx计数器中,如果该值小于设定的最大幅值,就会正常输出,当大于最大幅值时就会递减,减到0之后又开始累加,周而复始,就形成了三角波。
三角波频率:
设三角波幅值为3.3V,即4095,所以一个周期计数器计数4096*2=8192次,则三角波频率为“定时器频率/8192”
代码实现:
在main函数中添加以下两行代码,即可输出三角波
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim2);
HAL_DAC_Start(&hdac, DAC_CHANNEL_2);
/* USER CODE END 2 */
分别为开启定时器TIM2 和开启DAC