本文主要是介绍DAC --- 数模转换器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
<一>.DAC简介
<1>.DAC简介
DAC,全称:Digital-to-Analog Converter,指数字/模拟转换器。
ADC和DAC是模拟电路与数字电路之间的桥梁。
<2>.DAC的特性参数
1.分辨率
表示模拟电压的最小增量,常用二进制位数表示,比如:8、12位等。
2.建立时间
表示将一个数字量转换为稳定模拟信号所需的时间。
3.精度
转换器实际特性曲线与理想特性曲线之间的最大误差,误差源:比例系统误差、失调误差、非线性误差。
原因:元件参数误差、基准电压不稳定。运算放大器零漂等。
<3>.STM32各系列DAC的主要特性
<二>.DAC工作原理
1.DAC框图简介(F1/F4/F7)
实际操作DHRyyy:自动、软件、外部事件
DORx:不能直接写入数据
2.参考电压/模拟部分电压
3.DAC数据格式
4.触发源
三种触发转换方式:自动触发、软件触发、外部事件触发;
DHRx数据加载到DORx后,模拟输出电压将经过时间V(SETTLING)-建立时间 后可用。
关闭触发时(TEN=0)的转换时序图
5.DMA请求
6.DAC输出电压
<三>.DAC输出实验
<1>.实验简要
1.功能描述
通过DAC1通道1(PA4)输出预设电压,然后由ADC1通道1(PA1)采集,最后显示ADC转换的数字量及换算后的电压值;
2.关闭通道1触发(即自动)
TEN1位置0;
3.关闭输出缓冲
BUFF1位置1;
4.使用12位右对齐模式
将数字量写入DAC_DHR12R1寄存器。
<2>.DAC寄存器介绍(F1)
输出缓存(BOFF1):可减少阻抗,使输出能力会强一些,但无法输出0
<3>.DAC输出实验配置步骤
- 初始化DAC:HAL_DAC_Init();
- DAC MSP初始化:HAL_DAC_MspInit() --- 配置NVIC、CLOCK、GPIO等;
- 配置DAC相应通道相关参数:HAL_DAC_ConfigChannel();
- 启动D/A转换:HAL_DAC_Start();
- 设置输出数字量:HAL_DAC_SetValue();
- 读取通道输出数字量(可选):HAL_DAC_GetValue()
函数 | 主要寄存器 | 主要功能 |
HAL_DAC_Init() | 无 | 配置DAC工作状态(HAL库内部使用) |
HAL_DAC_MspInit() | 无 | 存放NVIC、CLOCK、GPIO初始化代码 |
HAL_DAC_ConfigChannel() | CR | 配置DAC相应通道的相关参数 |
HAL_DAC_Start() | CR、SWTRIGR | 启动D/A转换 |
HAL_DAC_SetValue() | DHR12Rx | 设置输出数字量 |
HAL_DAC_Getvalue() | DORx | 读取通道输出数字量 |
关键结构体 (F1)
<4>.代码
dac.c
#include "./BSP/DAC/dac.h"
#include "./SYSTEM/delay/delay.h"DAC_HandleTypeDef g_dac_handle; /* DAC句柄 *//*** @brief DAC初始化函数* @note 本函数支持DAC1_OUT1/2通道初始化* DAC的输入时钟来自APB1, 时钟频率=36Mhz=27.8ns* DAC在输出buffer关闭的时候, 输出建立时间: tSETTLING = 4us (F103数据手册有写)* 因此DAC输出的最高速度约为:250Khz, 以10个点为一个周期, 最大能输出25Khz左右的波形** @param outx: 要初始化的通道. 1,通道1; 2,通道2* @retval 无*/
void dac_init(uint8_t outx)
{GPIO_InitTypeDef gpio_init_struct;DAC_ChannelConfTypeDef dac_ch_conf;__HAL_RCC_DAC_CLK_ENABLE(); /* 使能DAC1的时钟 */__HAL_RCC_GPIOA_CLK_ENABLE(); /* 使能DAC OUT1/2的IO口时钟(都在PA口,PA4/PA5) */gpio_init_struct.Pin = (outx==1)? GPIO_PIN_4 : GPIO_PIN_5; /* STM32单片机, 总是PA4=DAC1_OUT1, PA5=DAC1_OUT2 */gpio_init_struct.Mode = GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOA, &gpio_init_struct);g_dac_handle.Instance = DAC;HAL_DAC_Init(&g_dac_handle); /* 初始化DAC */dac_ch_conf.DAC_Trigger = DAC_TRIGGER_NONE; /* 不使用触发功能 */dac_ch_conf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE; /* DAC1输出缓冲关闭 */switch(outx){case 1: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 */break;case 2:HAL_DAC_ConfigChannel(&g_dac_handle, &dac_ch_conf, DAC_CHANNEL_2); /* 配置DAC通道2 */HAL_DAC_Start(&g_dac_handle,DAC_CHANNEL_2); /* 开启DAC通道2 */break;default:break;}}/*** @brief 设置通道1/2输出电压* @param outx: 1,通道1; 2,通道2* @param vol : 0~3300,代表0~3.3V* @retval 无*/
void dac_set_voltage(uint8_t outx, uint16_t vol)
{double temp = vol;temp /= 1000;temp = temp * 4096 / 3.3;if (temp >= 4096)temp = 4095; /* 如果值大于等于4096, 则取4095 */if (outx == 1) /* 通道1 */{HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, temp); /* 12位右对齐数据格式设置DAC值 */}else /* 通道2 */{HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_2, DAC_ALIGN_12B_R, temp); /* 12位右对齐数据格式设置DAC值 */}
}
dac.h
#ifndef __DAC_H
#define __DAC_H#include "./SYSTEM/sys/sys.h"void dac_init(uint8_t outx); /* DAC通道1初始化 */
void dac_set_voltage(uint8_t outx, uint16_t vol); /* 设置通道1/2输出电压 */ #endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/DAC/dac.h"
#include "./BSP/ADC/adc3.h"extern DAC_HandleTypeDef g_dac_handle;int main(void)
{uint16_t adcx;float temp;uint8_t t = 0;uint16_t dacval = 0;uint8_t key;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */usmart_dev.init(72); /* 初始化USMART */led_init(); /* 初始化LED */lcd_init(); /* 初始化LCD */key_init(); /* 初始化按键 */adc3_init(); /* 初始化ADC3 */dac_init(1); /* 初始化DAC1_OUT1通道 */lcd_show_string(30, 50, 200, 16, 16, "STM32F103", RED);lcd_show_string(30, 70, 200, 16, 16, "DAC TEST", RED);lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);lcd_show_string(30, 110, 200, 16, 16, "WK_UP:+ KEY1:-", RED);lcd_show_string(30, 130, 200, 16, 16, "DAC VAL:", BLUE);lcd_show_string(30, 150, 200, 16, 16, "DAC VOL:0.000V", BLUE);lcd_show_string(30, 170, 200, 16, 16, "ADC VOL:0.000V", BLUE);while (1){t++;key = key_scan(0); /* 按键扫描 */if (key == WKUP_PRES){if (dacval < 4000)dacval += 200;HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dacval);/* 输出增大200 */}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 */}if (t == 10 || key == KEY1_PRES || key == WKUP_PRES) /* WKUP/KEY1按下了,或者定时时间到了 */{adcx = HAL_DAC_GetValue(&g_dac_handle, DAC_CHANNEL_1); /* 读取前面设置DAC1_OUT1的值 */lcd_show_xnum(94, 130, adcx, 4, 16, 0, BLUE); /* 显示DAC寄存器值 */temp = (float)adcx * (3.3 / 4096); /* 得到DAC电压值 */adcx = temp;lcd_show_xnum(94, 150, temp, 1, 16, 0, BLUE); /* 显示电压值整数部分 */temp -= adcx;temp *= 1000;lcd_show_xnum(110, 150, temp, 3, 16, 0X80, BLUE); /* 显示电压值的小数部分 */adcx = adc3_get_result_average(ADC3_CHY, 20); /* 得到ADC3通道1的转换结果 */temp = (float)adcx * (3.3 / 4096); /* 得到ADC电压值(adc是16bit的) */adcx = temp;lcd_show_xnum(94, 170, temp, 1, 16, 0, BLUE); /* 显示电压值整数部分 */temp -= adcx;temp *= 1000;lcd_show_xnum(110, 170, temp, 3, 16, 0X80, BLUE); /* 显示电压值的小数部分 */LED0_TOGGLE(); /* LED0闪烁 */t = 0;}delay_ms(10);}
}
<四>.DAC输出三角波实验
<五>.DAC输出正弦波实验
<六>.PWM DAC实验
这篇关于DAC --- 数模转换器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!