STM32-DAC

目录

DAC

功能框图

参考电压

数模转换和输出通道

触发源和DHRx寄存器

DAC初始化结构体

DAC_Trigger

DAC_OutputBuffer

实验环节

DAC配置

测试环节

实现现象


DAC

数字/模拟转换模块,把输入的数字编码转换成对应的模拟电压输出。

在常见的数字信号系统中,大部分传感器信号被转化成电压信号,而ADC把电压模拟信号转换成易于计算机存储、处理的数字编码,由计算机处理完成后再由DAC输出电压模拟信号,该电压模拟信号常常用来驱动某些执行器件,使人类易于感知。如音频信号的采集和还原。

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

功能框图

STM32-DAC_第1张图片

整个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通道引脚需要被配制成模拟输入功能。

触发源和DHRx寄存器

在使用DAC时,不能直接对上述DORx寄存器写入数据,任何输出到DAC通道x的数据都必须写入到DHRx寄存器中(包含DHR8Rx、DHR12Lx等,根据数据对齐方向和分辨率的情况写入到对应的寄存器中)。

数据被写入到DHRx寄存器后,DAC会根据触发配置进行处理,若使用硬件触发,则DHRx中的数据会在3个APB1时钟周期后传输到DORx,DORx随之输出相应的模拟电压到输出通道;若DAC设置为外部事件触发,可以使用定时器(TIMx_TRGO)、EXTI_9信号或软件触发(SWTRIGx)这几种方式控制数据DAC转换的时机,例如使用定时器触发,配合不同时刻的DHRx数据,可实现DAC输出正弦波的功能。

DAC初始化结构体

typedef struct
{
    uint32_t DAC_Trigger;         // DAC触发方式
    uint32_t DAC_OutputBuffer;    // 是否使能输出缓冲器          
} DAC_ChannelConfTypeDef;

DAC_Trigger

配置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_OutputBuffer

使能了DAC的输出缓冲后可以减小输出阻抗,适合直接驱动一些外部负载。

实验环节

DAC配置

STM32-DAC_第2张图片

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)
	{}
}

实现现象

示波器捕获到单片机输出正弦波。

你可能感兴趣的:(#,野火指南者STM32F103,stm32,1024程序员节)