#stm32DAC

DAC 简介

STM32F407 的 DAC 模块(数字/模拟转换模块)是 12 位数字输入,电压输出型的 DAC。DAC 可以配置为 8 位或 12 位模式,也可以与 DMA 控制器配合使用。DAC 工作在 12 位模式时,数据可以设置成左对齐或右对齐。DAC 模块有 2 个输出通道,每个通道都有单独的转换器。在双 DAC 模式下,2 个通道可以独立地进行转换,也可以同时进行转换并同步地更新 2 个通道的输出。DAC 可以通过引脚输入参考电压 Vref+(通 ADC 共用)以获得更精确的转换结果。

框图

在这里插入图片描述
① 2 个 DAC 转换器:每个转换器对应 1 个输出通道
② 8 位或者 12 位单调输出
③ 12 位模式下数据左对齐或者右对齐
④ 同步更新功能
⑤ 噪声波形生成
⑥ 三角波形生成
⑦ 双 DAC 双通道同时或者分别转换
⑧ 每个通道都有 DMA 功能
在这里插入图片描述
从图 34.1.1 可以看出,DAC 输出是受 DORx(x=1/2,下同)寄存器直接控制的,但是我们不能直接往 DORx 寄存器写入数据,而是通过 DHRx 间接的传给 DORx 寄存器,实现对 DAC输出的控制。
前面我们提到,STM32F407 的 DAC 支持 8/12 位模式,8 位模式的时候是固定的右对齐的,而 12 位模式又可以设置左对齐/右对齐。DAC 单通道模式下的数据寄存器对齐方式,总共有 3种情况,如下图所示:
在这里插入图片描述
① 8 位数据右对齐:用户将数据写入 DAC_DHR8Rx[7:0]位(实际存入 DHRx[11:4]位)。
② 12 位数据左对齐:用户将数据写入DAC_DHR12Lx[15:4]位(实际存入DHRx[11:0]位)。
③ 12位数据右对齐:用户将数据写入DAC_DHR12Rx[11:0]位(实际存入DHRx[11:0]位)。
对于 DAC 双通道(可用时),也有三种可能的方式,如下图所示:
在这里插入图片描述
① 8 位数据右对齐:用户将 DAC 通道 1 的数据写入 DAC_DHR8RD[7:0]位(实际存入
DHR1 [11:4]位),将 DAC 通道 2 的数据写入 DAC_DHR8RD[15:8]位(实际存入 DHR2
[11:4]位)。
② 12 位数据左对齐:用户将 DAC 通道 1 的数据写入 DAC_DHR12LD [15:4]位(实际存
入 DHR1[11:0]位),将 DAC 通道 2 的数据写入 DAC_DHR12LD [31:20]位(实际存入
DHR2[11:0]位)。
③ 12 位数据右对齐:用户将 DAC 通道 1 的数据写入 DAC_DHR12RD [11:0]位(实际存
入 DHR1[11:0]位),将 DAC 通道 2 的数据写入 DAC_DHR12RD [27:16]位(实际存入
DHR2[11:0]位)。
DAC 可以通过软件或者硬件触发转换,通过配置 TENx 控制位来决定。
如果没有选中硬件触发(寄存器 DAC_CR1 的 TENx 位置 0),存入寄存器 DAC_DHRx 的数据会在 1 个 APB1 时钟周期后自动传至寄存器 DAC_DORx。如果选中硬件触发(寄存器DAC_CR1 的 TENx 位置 1),数据传输在触发发生以后 3 个 APB1 时钟周期后完成。一旦数据从 DAC_DHRx 寄存器装入 DAC_DORx 寄存器,在经过时间 tSETTLING 之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化。我们可以从《STM32F407ZGT6.pdf》数据手册查到 tSETTLING的典型值为 3us,最大是 6us,所以 DAC 的转换速度最快是 333K 左右。
不使用硬件触发(TEN=0),其转换的时间框图如图 34.1.4 所示:
在这里插入图片描述
当 DAC 的参考电压为 VREF+的时候,DAC 的输出电压是线性的从 0~VREF+,12 位模式下 DAC 输出电压与 VREF +以及 DORx 的计算公式如下:
DACx 输出电压= VREF *(DORx/4096)
如果使用硬件触发(TEN=1),可通过外部事件(定时计数器、外部中断线)触发 DAC 转换。由 TSELx[2:0]控制位来决定选择 8 个触发事件中的一个来触发转换。这 8 个触发事件如下
在这里插入图片描述
每个 DAC 通道都有 DMA 功能,两个 DMA 通道分别用于处理两个 DAC 通道的 DMA 请
求。如果 DMAENx 位置 1 时,如果发生外部触发(而不是软件触发),就会产生一个 DMA 请
求,然后 DAC_DHRx 寄存器的数据被转移到 DAC_NORx 寄存器。

DAC 寄存器

DACx 控制寄存器(DACx_CR)

在这里插入图片描述
EN1 位:用于 DAC 通道 1 的使能,我们需要用到 DAC 通道 1 的输出,该位必须设置为 1。
BOFF1 位:用于 DAC 输出缓存控制,这里 STM32 的 DAC 输出缓存做的有些不好,如果使能的话,虽然输出能力强一点,但是输出没法到 0,这是个很严重的问题。所以该位我们设置为 0。
TEN1 位:用于 DAC 通道 1 的触发使能,我们设置该位为 0,不使用硬件触发。写入 DHR1的值会在 1 个 APB1 周期后传送到 DOR1,然后输出到 PA4 口上。
TSEL1[2:0]位,用于选择 DAC 通道 1 的触发方式,这里我们没有用到外部触发,所以这几位设置为 0 即可。
WAVE1[1:0]位,用于控制 DAC 通道 1 的噪声/波形输出功能,默认设置为 00,不使能噪声/波形输出。
DMAEN1 位,用于控制 DAC 通道 1 的 DMA 使能,本实验不使能,设置该位为 0 即可。
MAMP[3:0]位,用于在噪声生成模式下选择屏蔽位,在三角波生成模式下选择波形值。本章没有用到波形发生器,所以设置为 0 即可。

DACx 通道 1 12 位右对齐数据保持寄存器(DACx_DHR12R1)

在这里插入图片描述
该寄存器用来设置 DAC 输出,通过写入 12 位数据到该寄存器,就可以在 DAC 输出通道
1(PA4)得到我们所要的结果。

代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "stdio.h"
#include "usart.h"
#include "DAC.h"
void SystemClock_Config(void);

const uint8_t TEXT_TO_SEND[]={"stm32 DMA usart1"};
#define SEND_BUF_SIZE (sizeof(TEXT_TO_SEND)+2)*200 /* 发送数据长度, 等于sizeof(TEXT_TO_SEND) + 2的200倍. */
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
	uint8_t key=0;
	uint16_t i=0;
  uint16_t dacval=0;
	uint16_t temp;
  HAL_Init();

  SystemClock_Config();
  MX_GPIO_Init();
	usart_Init();
	key_init();
	dac_init();
	dac_set_voltage(3000);
	printf("demo!!!\r\n");

  while (1)
  {
   key = key_scan(0);
		if(key==KEY0_PRES)
		{
			if(dacval< 4000) dacval+=200;
			HAL_DAC_SetValue(&g_dac_handle,DAC_CHANNEL_1,DAC_ALIGN_12B_R,dacval);
		}
		else if(key==KEY1_PRES)
		{
			if (dacval > 200)dacval -= 200;
            else dacval = 0;
			 HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dacval);   /* 输出减少200 */
		}
		i++;
		HAL_Delay(10);
		if(i==20)
		{
			temp = HAL_DAC_GetValue(&g_dac_handle,DAC_CHANNEL_1);
			printf("the DOR1 value :%d\r\n",temp);
			HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
			i=0;
		}
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    gpio.c
  * @brief   This file provides code for the configuration
  *          of all used GPIO pins.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "DAC.h"
#include "usart.h"
#include "stdio.h"
 DAC_HandleTypeDef g_dac_handle;
 void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac)
 {
	__HAL_RCC_DAC_CLK_ENABLE();
	__HAL_RCC_GPIOA_CLK_ENABLE();
	GPIO_InitTypeDef gpio_init_structer;
	gpio_init_structer.Pin = (1==1)? GPIO_PIN_4:GPIO_PIN_5;
	gpio_init_structer.Mode = GPIO_MODE_ANALOG;
	gpio_init_structer.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOA,&gpio_init_structer);
 }
 static void dac_channal_init(void)
 {
	 DAC_ChannelConfTypeDef dac_ch_conf;
	 dac_ch_conf.DAC_Trigger = DAC_TRIGGER_NONE; //不使用触发。
	 dac_ch_conf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;/* DAC1输出缓冲关闭 */
	 HAL_DAC_ConfigChannel(&g_dac_handle,&dac_ch_conf,DAC1_CHANNEL_1);
	 HAL_DAC_Start(&g_dac_handle,DAC1_CHANNEL_1);
 }
 void dac_init(void)
{
	g_dac_handle.Instance = DAC;
	HAL_DAC_Init(&g_dac_handle);
	dac_channal_init();
}
void dac_set_voltage(uint16_t vol)
{
	double temp =vol;
	temp/=1000;
	temp = temp * 4096/3.3;
	if(temp>=4096) temp = 4095;
	HAL_DAC_SetValue(&g_dac_handle,DAC_CHANNEL_1,DAC_ALIGN_12B_R,temp);
}

流程图

在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值