在使用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配置
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)
{}
}
实现现象
示波器捕获到单片机输出正弦波。