19:HAL—-DAC

一:介绍

1:简历

2:简图 

F1,F4,F7的DAC框架图都一样。

触发源:

宏定义补全及解释

#define DAC_TRIGGER_NONE 0x00000000UL /*!< 转换是自动的,一旦DAC1_DHRxxxx寄存器被加载,不由外部触发 */
#define DAC_TRIGGER_T2_TRGO (DAC_CR_TSEL1_2 | DAC_CR_TEN1) /*!< TIM2 TRGO选为DAC通道的外部转换触发 */
#define DAC_TRIGGER_T4_TRGO (DAC_CR_TSEL1_2 | DAC_CR_TSEL1_0 | DAC_CR_TEN1) /*!< TIM4 TRGO选为DAC通道的外部转换触发 */
#define DAC_TRIGGER_T5_TRGO (DAC_CR_TSEL1_1 | DAC_CR_TSEL1_0 | DAC_CR_TEN1) /*!< TIM5 TRGO选为DAC通道的外部转换触发(注意:这里应该是TIM5,而不是TIM3) */
#define DAC_TRIGGER_T6_TRGO (DAC_CR_TEN1) /*!< 转换由软件触发为DAC通道 */
#define DAC_TRIGGER_T7_TRGO (DAC_CR_TSEL1_1 | DAC_CR_TEN1) /*!< TIM7 TRGO选为DAC通道的外部转换触发 */
#define DAC_TRIGGER_T8_TRGO (DAC_CR_TSEL1_0 | DAC_CR_TEN1) /*!< TIM8 TRGO选为DAC通道的外部转换触发 */
#define DAC_TRIGGER_EXT_IT9 (DAC_CR_TSEL1_2 | DAC_CR_TSEL1_1 | DAC_CR_TEN1) /*!< EXTI Line9事件选为DAC通道的外部转换触发 */
#define DAC_TRIGGER_SOFTWARE (DAC_CR_TEN1) /*!< 软件触发DAC转换 */

解释

  • DAC_TRIGGER_NONE:没有外部触发,转换是自动的,一旦DAC的数据寄存器被写入新的数据,就会启动转换。
  • DAC_TRIGGER_T2_TRGO 至 DAC_TRIGGER_T8_TRGO:这些宏定义分别选择TIM2到TIM8的TRGO(触发输出)作为DAC的外部转换触发源。这意味着DAC的转换将由指定定时器的特定事件(如更新事件)来触发。
  • DAC_TRIGGER_EXT_IT9:选择外部中断/事件线9(EXTI Line9)的触发事件作为DAC的外部转换触发源。这允许DAC的转换由外部事件(如按钮按下)触发。
  • DAC_TRIGGER_SOFTWARE:软件触发DAC转换。这意味着可以通过编程方式(即写入一个特定的寄存器值)来启动DAC的转换,而不是依赖于外部事件或定时器。

请注意,对于DAC_TRIGGER_T5_TRGO的注释中提到的TIM3可能是一个错误,因为根据宏定义中的位操作,它实际上对应的是TIM5的TRGO(假设DAC_CR_TSEL1_1DAC_CR_TSEL1_0分别对应于选择触发源的位字段)。此外,DAC_TRIGGER_T6_TRGO实际上并不直接对应于任何定时器的TRGO,而是直接由软件触发(即DAC_CR_TEN1位被设置),这与DAC_TRIGGER_SOFTWARE相同,但通常DAC_TRIGGER_SOFTWARE的命名更直接地表达了其意图。

具体的TRGO可以参考我的:

11:HAL--定时器代码总结-CSDN博客

3:输入/出电压

 可以参考我们写的ADC的:

15:HAL----ADC模数转化器-CSDN博客

4:工作原理

5:电压计算

 

Vref+一般为3.3V

6:配置

 

想要注意的寄存器:

使用DAC1右对齐输出电压的时候,实际就是对于下面寄存器的写入。

使用不同的ADC和不同的对齐方式,它对于的寄存器不同

7:HAL配置

 

二:案列

下面的案列全部使用stm32F407VEt6做的

A:DAC简单输出

#include "stm32f4xx.h"                  // Device header
#include "LED.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
DAC_HandleTypeDef g_dac_handle;

/* DAC初始化函数 */
void dac_init(void)
{
    DAC_ChannelConfTypeDef dac_ch_conf;

    g_dac_handle.Instance = DAC1;
    HAL_DAC_Init(&g_dac_handle);                                        /* 初始化DAC */

    dac_ch_conf.DAC_Trigger = DAC_TRIGGER_NONE;                         /* 不使用触发功能 */
    dac_ch_conf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;            /* DAC输出缓冲关闭 */

    HAL_DAC_ConfigChannel(&g_dac_handle, &dac_ch_conf, DAC_CHANNEL_1);  /* 配置DAC通道1 */
    HAL_DAC_Start(&g_dac_handle, DAC_CHANNEL_1);                        /* 开启DAC通道1 */
	
	
}

/* DAC MSP初始化函数 */
void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac)
{
    if (hdac->Instance == DAC1)
    {
        GPIO_InitTypeDef gpio_init_struct;

        __HAL_RCC_DAC_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();

        gpio_init_struct.Pin = GPIO_PIN_4;
        gpio_init_struct.Mode = GPIO_MODE_ANALOG;  //模拟输入
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
			
    }
}

/* 设置通道输出电压 
vol:想要设置的电压,单位MV
DAC的输出电压=(DORX/4096)*Vref+ ---->Vref+一般为3.3V
DORX=DAC的输出电压/Vref*4096;
*/
void dac_set_voltage(float vol)
{
    float temp = vol;
    temp /= 1000;
    temp = temp * 4096.0 / 3.3;      //temp-->DORX寄存器的值

    if (temp >= 4096)temp = 4095;   /* 如果值大于等于4096, 则取4095 */
		
    HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, temp); /* 12位右对齐数据格式设置DAC值 */

}

#include "stm32f4xx.h"                  // Device header
#include "sys.h"
#include "delay.h"
#include "LED.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
#include "adc.h"
#include "DAC.h"



extern DAC_HandleTypeDef g_dac_handle;
uint16_t  adc_Value;
int main(void)
{		
	
	
    HAL_Init();                                 /* 初始化HAL库 */        
		Clock_HSE_Init(8,336,RCC_PLLP_DIV2,7);      /* 设置时钟,168Mhz */
    delay_init(168);                            /* 延时初始化 */
          
		Uart_Init(115200);
		adc_init();
		dac_init();  

			dac_set_voltage(2200); //设置DAC的电压为2200MV=2.2
    while(1)
    {
			
		
			printf("DORX:%d\r\n",HAL_DAC_GetValue(&g_dac_handle,DAC_CHANNEL_1));
			adc_Value=adc_get_result();
		
			printf("电压:%f %2d\r\n",(float)adc_Value*(3.3/4096),adc_Value);
			delay_ms(1000);
			
				
		}
}

可以直接属于我们的万用表测量电压。

也可以使用我们的ADC测量电压,使用ADC时,注意我们的数据类型。

B:输出三角波

和上面的A实验一样,什么都没有改变,只有增加了一个 dac_triangular_wave()函数。

#include "stm32f4xx.h"                  // Device header
#include "LED.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
#include "delay.h"
DAC_HandleTypeDef g_dac_handle;

/* DAC初始化函数 */
void dac_init(void)
{
    DAC_ChannelConfTypeDef dac_ch_conf;

    g_dac_handle.Instance = DAC1;
    HAL_DAC_Init(&g_dac_handle);                                        /* 初始化DAC */

    dac_ch_conf.DAC_Trigger = DAC_TRIGGER_NONE;                         /* 不使用触发功能 */
    dac_ch_conf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;            /* DAC输出缓冲关闭 */

    HAL_DAC_ConfigChannel(&g_dac_handle, &dac_ch_conf, DAC_CHANNEL_1);  /* 配置DAC通道1 */
    HAL_DAC_Start(&g_dac_handle, DAC_CHANNEL_1);                        /* 开启DAC通道1 */
	
	
}

/* DAC MSP初始化函数 */
void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac)
{
    if (hdac->Instance == DAC1)
    {
        GPIO_InitTypeDef gpio_init_struct;

        __HAL_RCC_DAC_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();

        gpio_init_struct.Pin = GPIO_PIN_4;
        gpio_init_struct.Mode = GPIO_MODE_ANALOG;  //模拟输入
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
			
    }
}

/* 设置通道输出电压 
vol:想要设置的电压,单位MV
DAC的输出电压=(DORX/4096)*Vref+ ---->Vref+一般为3.3V
DORX=DAC的输出电压/Vref*4096;
*/
void dac_set_voltage(float vol)
{
    float temp = vol;
    temp /= 1000;
    temp = temp * 4096.0 / 3.3;      //temp-->DORX寄存器的值

    if (temp >= 4096)temp = 4095;   /* 如果值大于等于4096, 则取4095 */
		
    HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, temp); /* 12位右对齐数据格式设置DAC值 */

}



/**
 * @brief       设置DAC_OUT1输出三角波
 *   @note      输出频率 ≈ 1000 / (dt * samples) Khz, 不过在dt较小的时候,比如小于5us时, 由于delay_us
 *              本身就不准了(调用函数,计算等都需要时间,延时很小的时候,这些时间会影响到延时), 频率会偏小.
 * 
 * @param       maxval : 最大值(0 < maxval < 4096), (maxval + 1)必须大于等于samples/2
 * @param       dt     : 每个采样点的延时时间(单位: us)
 * @param       samples: 采样点的个数, samples必须小于等于(maxval + 1) * 2 , 且maxval不能等于0
 * @param       n      : 输出波形个数,0~65535
 *
 * @retval      无
 */
void dac_triangular_wave(uint16_t maxval, uint16_t dt, uint16_t samples, uint16_t n)
{
    uint16_t i, j;
    float incval;           /* 递增量 */
    float Curval;           /* 当前值 */
    
    if((maxval + 1) <= samples) return ;    /* 数据不合法 */
        
    incval = (maxval + 1) / (samples / 2);  /* 计算递增量 */
    
    for(j = 0; j < n; j++)
    { 
        Curval = 0;
        HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, Curval);    /* 先输出0 */
        for(i = 0; i < (samples / 2); i++)  /* 输出上升沿 */
        {
            Curval  +=  incval;             /* 新的输出值 */
            HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, Curval);
            delay_us(dt);
        } 
        for(i = 0; i < (samples / 2); i++)  /* 输出下降沿 */
        {
            Curval  -=  incval;             /* 新的输出值 */
            HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, Curval);
            delay_us(dt);
        }
    }
}


#include "stm32f4xx.h"                  // Device header
#include "sys.h"
#include "delay.h"
#include "LED.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
#include "adc.h"
#include "DAC.h"



extern DAC_HandleTypeDef g_dac_handle;
uint16_t  adc_Value;
int main(void)
{		
	
	
    HAL_Init();                                 /* 初始化HAL库 */        
		Clock_HSE_Init(8,336,RCC_PLLP_DIV2,7);      /* 设置时钟,168Mhz */
    delay_init(168);                            /* 延时初始化 */
          
		Uart_Init(115200);
		adc_init();
		dac_init();  

			dac_set_voltage(2200); //设置DAC的电压为2200MV=2.2
    while(1)
    {
			
		
				dac_triangular_wave(4095, 5, 2000, 100);    /* 幅值4095, 采样点间隔5us, 2000个采样点, 100个波形 */
			
				
		}
}






//        t++;
//        key = key_scan(0);      /* 按键扫描 */

//        if (key == KEY0_PRES)   /* 高采样率 , 约100Hz波形 */
//        {
//            lcd_show_string(30, 130, 200, 16, 16, "DAC Wave1 ", BLUE);
//            dac_triangular_wave(4095, 5, 2000, 100);    /* 幅值4095, 采样点间隔5us, 2000个采样点, 100个波形 */
//            lcd_show_string(30, 130, 200, 16, 16, "DAC None  ", BLUE);
//        }
//        else if (key == KEY1_PRES)  /* 低采样率 , 约100Hz波形 */
//        {
//            lcd_show_string(30, 130, 200, 16, 16, "DAC Wave2 ", BLUE);
//            dac_triangular_wave(4095, 500, 20, 100);    /* 幅值4095, 采样点间隔500us, 20个采样点, 100个波形 */
//            lcd_show_string(30, 130, 200, 16, 16, "DAC None  ", BLUE);
//        }

//        if (t == 10)        /* 定时时间到了 */
//        {
//            LED0_TOGGLE();  /* LED0闪烁 */
//            t = 0;
//        }

//        delay_ms(10);
//    }




C:正弦波

#include "stm32f4xx.h"                  // Device header
#include "LED.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
#include "delay.h"
#include "math.h"
DAC_HandleTypeDef g_dac_handle;
DMA_HandleTypeDef g_dma_dac_handle;
uint16_t g_dac_sin_buf[4096];            /* 发送数据缓冲区 */
/* DAC初始化函数 */
void dac_init(void)
{
    DAC_ChannelConfTypeDef dac_ch_conf;

    g_dac_handle.Instance = DAC1;
    HAL_DAC_Init(&g_dac_handle);                                        /* 初始化DAC */

    dac_ch_conf.DAC_Trigger = DAC_TRIGGER_T5_TRGO;                         /* TIM5触发功能 */
    dac_ch_conf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;            /* DAC输出缓冲关闭 */

    HAL_DAC_ConfigChannel(&g_dac_handle, &dac_ch_conf, DAC_CHANNEL_1);  /* 配置DAC通道1 */
		HAL_DAC_Start(&g_dac_handle, DAC_CHANNEL_1);                        /* 开启DAC通道1 */


	
}

/* DAC MSP初始化函数 */
void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac)
{
    if (hdac->Instance == DAC1)
    {
        GPIO_InitTypeDef gpio_init_struct;
				__HAL_RCC_DMA2_CLK_ENABLE();
        __HAL_RCC_DAC_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();

        gpio_init_struct.Pin = GPIO_PIN_4;
        gpio_init_struct.Mode = GPIO_MODE_ANALOG;  //模拟输入
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
			
			
				    
    
   
    
				g_dma_dac_handle.Instance =DMA1_Stream5 ;
				g_dma_dac_handle.Init.Direction = DMA_MEMORY_TO_PERIPH;  /*内存--外设*/
				g_dma_dac_handle.Init.PeriphInc = DMA_PINC_DISABLE;       /*外设不自增*/
				g_dma_dac_handle.Init.MemInc = DMA_MINC_ENABLE;						/*内存自增*/
				g_dma_dac_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;   /*外设16为*/
				g_dma_dac_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     /*内存16为*/
				g_dma_dac_handle.Init.Mode = DMA_CIRCULAR;           /*循环模式*/
				g_dma_dac_handle.Init.Priority = DMA_PRIORITY_MEDIUM;
				HAL_DMA_Init(&g_dma_dac_handle);
    
			__HAL_LINKDMA(&g_dac_handle, DMA_Handle1, g_dma_dac_handle);
					/*
					DstAddress这是目标内存缓冲区的地址:
					*/
				HAL_DMA_Start(&g_dma_dac_handle, (uint32_t)g_dac_sin_buf, (uint32_t)&DAC1->DHR12R1, 0);


			
    }
}

/* 设置通道输出电压 
vol:想要设置的电压,单位MV
DAC的输出电压=(DORX/4096)*Vref+ ---->Vref+一般为3.3V
DORX=DAC的输出电压/Vref*4096;
*/
void dac_set_voltage(float vol)
{
    float temp = vol;
    temp /= 1000;
    temp = temp * 4096.0 / 3.3;      //temp-->DORX寄存器的值

    if (temp >= 4096)temp = 4095;   /* 如果值大于等于4096, 则取4095 */
		
    HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, temp); /* 12位右对齐数据格式设置DAC值 */

}




/**
 * @brief       产生正弦波序列函数
 *   @note      需保证: maxval > samples/2
 * @param       maxval : 最大值(0 < maxval < 2048)
 * @param       samples: 采样点的个数
 * @retval      无
 */
void dac_creat_sin_buf(uint16_t maxval, uint16_t samples)
{
    uint8_t i;
    float outdata = 0;                     /* 存放计算后的数字量 */
    float inc = (2 * 3.1415962) / samples; /* 计算相邻两个点的x轴间隔 */

    if(maxval <= (samples / 2))return ;	   /* 数据不合法 */

    for (i = 0; i < samples; i++)
    {
        /* 
         * 正弦波函数解析式:y = Asin(ωx + φ)+ b
         * 计算每个点的y值,将峰值放大maxval倍,并将曲线向上偏移maxval到正数区域
         * 注意:DAC无法输出负电压,所以需要将曲线向上偏移一个峰值的量,让整个曲线都落在正数区域
         */
        outdata = maxval * sin(inc * i) + maxval;
        if (outdata > 4095)
            outdata = 4095; /* 上限限定 */
        //printf("%f\r\n",outdata);
        g_dac_sin_buf[i] = outdata;
    }
}

// * @param       ndtr        : DMA通道单次传输数据量
void General_timx_int_init(uint16_t arr, uint16_t psc,uint16_t cndtr)
{		
		TIM_IC_InitTypeDef TIM_IC_Init={0};
		 TIM_MasterConfigTypeDef tim_mater_config = {0};
		 
    TIM_Handle.Instance =TIM5;
    TIM_Handle.Init.Prescaler = psc;
    TIM_Handle.Init.Period = arr;
		TIM_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;
		TIM_Handle.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
		TIM_Handle.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_IC_Init(&TIM_Handle);
		__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_UPDATE);
	
		TIM_IC_Init.ICPolarity=TIM_ICPOLARITY_BOTHEDGE;
		TIM_IC_Init.ICSelection=TIM_ICSELECTION_DIRECTTI;
		TIM_IC_Init.ICPrescaler=TIM_ICPSC_DIV1;
		TIM_IC_Init.ICFilter=0x08;
		
		HAL_TIM_IC_ConfigChannel(&TIM_Handle,&TIM_IC_Init,TIM_CHANNEL_2);
		
	
		 tim_mater_config.MasterOutputTrigger = TIM_TRGO_UPDATE;  //更新中断做为TRGO
    tim_mater_config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    HAL_TIMEx_MasterConfigSynchronization(&TIM_Handle, &tim_mater_config);
    //CNT==ARR溢出产生的中断
		__HAL_TIM_ENABLE_IT(&TIM_Handle,TIM_IT_UPDATE);
		

		HAL_TIM_IC_Start_IT(&TIM_Handle,TIM_CHANNEL_2);

		
    HAL_DAC_Stop_DMA(&g_dac_handle, DAC_CHANNEL_1);
    HAL_DAC_Start_DMA(&g_dac_handle, DAC_CHANNEL_1, (uint32_t *)g_dac_sin_buf, cndtr, DAC_ALIGN_12B_R);
		
}
#include "stm32f4xx.h"                  // Device header
#include "sys.h"
#include "delay.h"
#include "LED.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
#include "adc.h"
#include "DAC.h"
#include "tim.h"


extern DAC_HandleTypeDef g_dac_handle;
uint16_t  adc_Value;
int main(void)
{		
	
	
    HAL_Init();                                 /* 初始化HAL库 */        
		Clock_HSE_Init(8,336,RCC_PLLP_DIV2,7);      /* 设置时钟,168Mhz */
    delay_init(168);                            /* 延时初始化 */
          
		Uart_Init(115200);
		dac_init();  
		
	
		/*
		T=((ARR+1)*(PSC+1))/主频
		f=主频/((ARR+1)*(PSC+1))=84000 000 /(10*28)=300,000HZ=300KHZ
		定时器的更新中断的频率也是我们正弦波的频率
		*/
    while(1)
    {
			
					General_timx_int_init(10-1,28-1,100);
					dac_creat_sin_buf(2048, 100);
			
				
		}
}

 

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值