目录
DAC
功能框图
参考电压
数模转换和输出通道
触发源和DHRx寄存器
DAC初始化结构体
DAC_Trigger
DAC_OutputBuffer
实验环节
DAC配置
测试环节
实现现象
数字/模拟转换模块,把输入的数字编码转换成对应的模拟电压输出。
在常见的数字信号系统中,大部分传感器信号被转化成电压信号,而ADC把电压模拟信号转换成易于计算机存储、处理的数字编码,由计算机处理完成后再由DAC输出电压模拟信号,该电压模拟信号常常用来驱动某些执行器件,使人类易于感知。如音频信号的采集和还原。
STM32具有片上外设DAC,它的分辨率可配置为8/12位的数字输入信号,具有两个DAC输出通道(两通道互不影响,每通道都可以使用DMA功能,都具有出错检测能力,可外部触发)。
整个DAC模块围绕“数字至模拟转换器x”展开。
参考电源引脚为Vdda、Vssa和Vref+,STM32的DAC规定了它的参考电压Vref+输入范围为2.4~3.3V。
“数字至模拟转换器x”输入为DAC的数据输出寄存器的数字编码(DAC_DORx),经过它转换的模拟信号由DAC_OUTx输出。
而DAC_DORx又受控制逻辑支配,可以控制DAC_DORx加入一些伪噪声信号或配置产生三角波信号。
DAC根据触发源信号来进行DAC转换,相当于DAC转换器的开关,可以配置的触发源为外部中断源触发、定时器触发或软件控制触发。
当需要控制正弦波的频率,就需要定时器定时触发DAC进行数据转换。
与ADC外设类似,DAC也使用Vref+硬件作为参考电压。一般Vssa接地,把Vref+和Vdda接3.3V,可得到DAC的输出电压范围为:0~3.3V。
如果想让输出电压范围变宽,可以外部加一个电压调理电路。
以Vref+为参考电源,以DAC的数据输出寄存器DAC_DORx作为输入,经过“数字至模拟转换器x”转换得到的模拟信号由DAC_OUTx通道输出。
在STM32中具有2个DAC部件,每个DAC有1个对应的输出通道连接到特定的引脚,即:PA4-通道1,PA5-通道2,为避免干扰,使用DAC功能时,DAC通道引脚需要被配制成模拟输入功能。
在使用DAC时,不能直接对上述DORx寄存器写入数据,任何输出到DAC通道x的数据都必须写入到DHRx寄存器中(包含DHR8Rx、DHR12Lx等,根据数据对齐方向和分辨率的情况写入到对应的寄存器中)。
数据被写入到DHRx寄存器后,DAC会根据触发配置进行处理,若使用硬件触发,则DHRx中的数据会在3个APB1时钟周期后传输到DORx,DORx随之输出相应的模拟电压到输出通道;若DAC设置为外部事件触发,可以使用定时器(TIMx_TRGO)、EXTI_9信号或软件触发(SWTRIGx)这几种方式控制数据DAC转换的时机,例如使用定时器触发,配合不同时刻的DHRx数据,可实现DAC输出正弦波的功能。
typedef struct
{
uint32_t DAC_Trigger; // DAC触发方式
uint32_t DAC_OutputBuffer; // 是否使能输出缓冲器
} DAC_ChannelConfTypeDef;
配置DAC的触发模式,当DAC产生相应的触发事件时,才会把DHRx寄存器的值转移到DORx寄存器中进行转换。触发模式有:
定时器触发模式(DAC_TRIGGER_T2/4/6/7_TRGO),使用定时器2/4/6/7控制DHRx寄存器的数据按时间转移到DORx寄存器中进行转换,利用这种方式可以输出特定的波形;
DAC_TRIGGER_EXT_IT9,当发生EXTI_9事件时(如GPIO中断事件),触发中断;
软件触发(DAC_TRIGGER_SOFTWARE),向DAC_SWTRIGR寄存器写入配置即可触发信号进行转换。
使能了DAC的输出缓冲后可以减小输出阻抗,适合直接驱动一些外部负载。
DAC_HandleTypeDef hdac;
DMA_HandleTypeDef hdma_dac_ch1;
TIM_HandleTypeDef htim6;
void MX_DAC_Init(void)
{
DAC_ChannelConfTypeDef sConfig = {0};
/** DAC Initialization
*/
hdac.Instance = DAC;
if (HAL_DAC_Init(&hdac) != HAL_OK)
{
Error_Handler();
}
/** DAC channel OUT1 config
*/
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
}
void HAL_DAC_MspInit(DAC_HandleTypeDef *dacHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (dacHandle->Instance == DAC)
{
__HAL_RCC_DAC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**DAC GPIO Configuration
PA4 ------> DAC_OUT1
*/
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* DAC DMA Init */
/* DAC_CH1 Init */
hdma_dac_ch1.Instance = DMA2_Channel3;
hdma_dac_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_dac_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dac_ch1.Init.MemInc = DMA_MINC_ENABLE;
hdma_dac_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_dac_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_dac_ch1.Init.Mode = DMA_CIRCULAR;
hdma_dac_ch1.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&hdma_dac_ch1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(dacHandle, DMA_Handle1, hdma_dac_ch1);
}
}
void HAL_DAC_MspDeInit(DAC_HandleTypeDef *dacHandle)
{
if (dacHandle->Instance == DAC)
{
__HAL_RCC_DAC_CLK_DISABLE();
/**DAC GPIO Configuration
PA4 ------> DAC_OUT1
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4);
/* DAC DMA DeInit */
HAL_DMA_DeInit(dacHandle->DMA_Handle1);
}
}
void MX_TIM6_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim6.Instance = TIM6;
htim6.Init.Prescaler = 71;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 999;
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *tim_baseHandle)
{
if (tim_baseHandle->Instance == TIM6)
{
__HAL_RCC_TIM6_CLK_ENABLE();
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *tim_baseHandle)
{
if (tim_baseHandle->Instance == TIM6)
{
__HAL_RCC_TIM6_CLK_DISABLE();
}
}
/* 波形数据 ---------------------------------------------------------*/
uint16_t Sine12bit[32] =
{
2048 , 2460 , 2856 , 3218 , 3532 , 3786 , 3969 , 4072 ,
4093 , 4031 , 3887 , 3668 , 3382 , 3042 , 2661 , 2255 ,
1841 , 1435 , 1054 , 714 , 428 , 209 , 65 , 3 ,
24 , 127 , 310 , 564 , 878 , 1240 , 1636 , 2048
};
void test(void)
{
初始化
/* 启动定时器 */
HAL_TIM_Base_Start(&htim6);
/* 启动DACx DMA功能 */
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)Sine12bit, 32, DAC_ALIGN_12B_R);
while(1)
{}
}
示波器捕获到单片机输出正弦波。