DAC工作原理与配置
参考资料
STM32FX开发板
《STM32FX开发指南-HAL库版本》-第X章 DAC实验
STM32FXxx官方资料:
《STM32FX中文参考手册》-第N章 数字模拟转换DAC
笔记基于正点原子官方视频
视频连接https://www.bilibili.com/video/BV1Wx411d7wT?p=71&spm_id_from=333.1007.top_right_bar_window_history.content.click
如有侵权,联系删除
一、 DAC工作原理
1.DAC简介
STM32的DAC模块(数字/模拟转换模块)是12位数字输入,电压输出型的DAC。DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。DAC工作在12位模式时,数据可以设置成左对齐或右对齐。DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压VREF+以获得更精确的转换结果。
2.STM32的DAC模块主要特点
① 2个DAC转换器:每个转换器对应1个输出通道
② 8位或者12位单调输出
③ 12位模式下数据左对齐或者右对齐
④ 同步更新功能
⑤ 噪声波形生成
⑥ 三角波形生成
⑦ 双DAC通道同时或者分别转换
⑧ 每个通道都有DMA功能
3.DAC模块方图
VDDA和VSSA为DAC模块模拟部分的供电。
Vref+则是DAC模块的参考电压。
DAC_OUTx就是DAC的输出通道了(对应PA4或者PA5引脚)。
4.DAC转换原理
5.DAC数据格式
6.DAC触发选择
7.DAC其他
二、DAC相关寄存器
1.DAC相关寄存器
里面内容参见《STM32FX中文参考手册》
2.DAC通道1相关寄存器
-
DAC控制寄存器 DAC_CR
-
DAC软件触发寄存器DAC_SWTRIGR
-
DAC通道1的12位右对齐数据保持寄存器DAC_DHR12R1
-
DAC通道1的12位左对齐数据保持寄存器DAC_DHR12L1
-
DAC通道1的8位右对齐数据保持寄存器DAC_DHR8R1
-
DAC通道1数据输出寄存器DAC_DOR1
3.DAC控制寄存器DAC_CR
4.DAC通道1的12位右对齐数据保持寄存器DAC_DHR12R1
5.DAC通道1的12位左对齐数据保持寄存器DAC_DHR12L1
6.DAC通道1的8位右对齐数据保持寄存器DAC_DHR8R1
7.DAC通道1数据输出寄存器DAC_DOR1
三、DAC硬件连接
四、DAC-HAL库函数配置
1.DAC相关HAL库函数
-
HAL_StatusTypeDef HAL_DAC_Init(DAC_HandleTypeDef* hdac);
-
void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac);
-
HAL_StatusTypeDef HAL_DAC_Start();
-
HAL_StatusTypeDef HAL_DAC_Stop();
-
HAL_StatusTypeDef HAL_DAC_ConfigChannel();
-
HAL_StatusTypeDef HAL_DAC_SetValue();
-
void HAL_DAC_IRQHandler(DAC_HandleTypeDef* hdac);
-
void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef* hdac);
-
void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef* hdac);
-
void HAL_DAC_ErrorCallbackCh1(DAC_HandleTypeDef *hdac);
-
void HAL_DAC_DMAUnderrunCallbackCh1(DAC_HandleTypeDef *hdac);
2.DAC配置步骤:
① 开启DAC和IO口时钟,设置输入引脚为模拟输入:
__HAL_RCC_DAC_CLK_ENABLE(); //使能DAC时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟
② 初始化DAC和通道参数 :
HAL_DAC_Init();
HAL_DAC_ConfigChannel();
③ 使能DAC转换通道:
HAL_DAC_Start();
④ 设置DAC输出值:
HAL_DAC_SetValue();
五、DAC配置实例
实现功能
通过按键控制一个数字变量,按键WK_UP每按一下数字自加200,按键 KEY1每按一下数字自减200
数值通过ADC输出,然后用DAC采集到输出的数字量并转化成模拟量电压(4096->3.3v)
1.引入DAC支持文件
2.开启DAC和IO口时钟,设置输入引脚为模拟输入:
__HAL_RCC_DAC_CLK_ENABLE(); //使能DAC时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟
//DAC底层驱动,时钟配置,引脚 配置
//此函数会被HAL_DAC_Init()调用
//hdac:DAC句柄
void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac)
{
GPIO_InitTypeDef GPIO_Initure; //定义GPIO结构体
__HAL_RCC_DAC_CLK_ENABLE(); //使能DAC时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
GPIO_Initure.Pin=GPIO_PIN_4; //PA4
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟模式
GPIO_Initure.Pull=GPIO_NOPULL; //不带上下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}
3.初始化DAC和通道参数
HAL_DAC_Init();
HAL_DAC_ConfigChannel();
DAC_HandleTypeDef DAC1_Handler;//DAC句柄
//初始化DAC
void DAC1_Init(void)
{
DAC_ChannelConfTypeDef DACCH1_Config;
DAC1_Handler.Instance=DAC;
HAL_DAC_Init(&DAC1_Handler); //初始化DAC
DACCH1_Config.DAC_Trigger=DAC_TRIGGER_NONE; //不使用触发功能
DACCH1_Config.DAC_OutputBuffer=DAC_OUTPUTBUFFER_DISABLE; //DAC1输出缓冲关闭
HAL_DAC_ConfigChannel(&DAC1_Handler,&DACCH1_Config,DAC_CHANNEL_1); //DAC通道1配置
HAL_DAC_Start(&DAC1_Handler,DAC_CHANNEL_1); //开启DAC通道1
}
4.设置DAC输出值:
HAL_DAC_SetValue();
//设置通道1输出电压
//当数值为1000时,DAC输出1V
//vol:0~3300,代表0~3.3V
void DAC1_Set_Vol(u16 vol)
{
double temp=vol;
temp/=1000; //temp=temp/1000;
temp=temp*4096/3.3;
HAL_DAC_SetValue(&DAC1_Handler,DAC_CHANNEL_1,DAC_ALIGN_12B_R,temp);//12位右对齐数据格式设置DAC值
}
到这里dac.c函数编写完毕,dac.c代码如下:
#include "dac.h"
DAC_HandleTypeDef DAC1_Handler;//DAC句柄
//初始化DAC
void DAC1_Init(void)
{
DAC_ChannelConfTypeDef DACCH1_Config;
DAC1_Handler.Instance=DAC;
HAL_DAC_Init(&DAC1_Handler); //初始化DAC
DACCH1_Config.DAC_Trigger=DAC_TRIGGER_NONE; //不使用触发功能
DACCH1_Config.DAC_OutputBuffer=DAC_OUTPUTBUFFER_DISABLE; //DAC1输出缓冲关闭
HAL_DAC_ConfigChannel(&DAC1_Handler,&DACCH1_Config,DAC_CHANNEL_1); //DAC通道1配置
HAL_DAC_Start(&DAC1_Handler,DAC_CHANNEL_1); //开启DAC通道1
}
//DAC底层驱动,时钟配置,引脚 配置
//此函数会被HAL_DAC_Init()调用
//hdac:DAC句柄
void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac)
{
GPIO_InitTypeDef GPIO_Initure; //定义GPIO结构体
__HAL_RCC_DAC_CLK_ENABLE(); //使能DAC时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
GPIO_Initure.Pin=GPIO_PIN_4; //PA4
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟模式
GPIO_Initure.Pull=GPIO_NOPULL; //不带上下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}
//设置通道1输出电压
//当数值为1000时,DAC输出1V
//vol:0~3300,代表0~3.3V
void DAC1_Set_Vol(u16 vol)
{
double temp=vol;
temp/=1000; //temp=temp/1000;
temp=temp*4096/3.3;
HAL_DAC_SetValue(&DAC1_Handler,DAC_CHANNEL_1,DAC_ALIGN_12B_R,temp);//12位右对齐数据格式设置DAC值
}
同时,dac.h代码如下:
#ifndef __DAC_H
#define __DAC_H
#include "sys.h"
extern DAC_HandleTypeDef DAC1_Handler;//DAC句柄
void DAC1_Init(void);
void DAC1_Set_Vol(u16 vol); //当数值为1000时,DAC输出1V
#endif
5.main.c函数编写
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "sdram.h"
#include "usmart.h"
#include "adc.h"
#include "dac.h"
int main(void)
{
u16 adcx;
float temp;
u8 t=0;
u16 dacval=0;
u8 key;
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhz
delay_init(180); //初始化延时函数
uart_init(115200); //初始化USART
usmart_dev.init(90); //初始化USMART
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
SDRAM_Init(); //初始化SDRAM
LCD_Init(); //初始化LCD
MY_ADC_Init(); //初始化ADC1
DAC1_Init(); //初始化DAC1
POINT_COLOR=RED;
LCD_ShowString(30,50,200,16,16,"Apollo STM32F429");
LCD_ShowString(30,70,200,16,16,"DAC TEST");
LCD_ShowString(30,90,200,16,16,"Apollo Control By Wire");
LCD_ShowString(30,110,200,16,16,"2022/4/2");
LCD_ShowString(30,130,200,16,16,"WK_UP:+ KEY1:-");
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(30,150,200,16,16,"DAC VAL:");
LCD_ShowString(30,170,200,16,16,"DAC VOL:0.000V");
LCD_ShowString(30,190,200,16,16,"ADC VOL:0.000V");
HAL_DAC_SetValue(&DAC1_Handler,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0);//初始值为0
while(1)
{
t++;
key=KEY_Scan(0);
if(key==WKUP_PRES)
{
if(dacval<4000)dacval+=200;
HAL_DAC_SetValue(&DAC1_Handler,DAC_CHANNEL_1,DAC_ALIGN_12B_R,dacval);//设置DAC值
}else if(key==2)
{
if(dacval>200)dacval-=200;
else dacval=0;
HAL_DAC_SetValue(&DAC1_Handler,DAC_CHANNEL_1,DAC_ALIGN_12B_R,dacval);//设置DAC值
}
if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了
{
adcx=HAL_DAC_GetValue(&DAC1_Handler,DAC_CHANNEL_1); //读取前面设置DAC的值
LCD_ShowxNum(94,150,adcx,4,16,0); //显示DAC寄存器值
temp=(float)adcx*(3.3/4096); //得到DAC电压值
adcx=temp;
LCD_ShowxNum(94,170,temp,1,16,0); //显示电压值整数部分
temp-=adcx;
temp*=1000;
LCD_ShowxNum(110,170,temp,3,16,0X80); //显示电压值的小数部分
adcx=Get_Adc_Average(ADC_CHANNEL_5,10); //得到ADC转换值
temp=(float)adcx*(3.3/4096); //得到ADC电压值
adcx=temp;
LCD_ShowxNum(94,190,temp,1,16,0); //显示电压值整数部分
temp-=adcx;
temp*=1000;
LCD_ShowxNum(110,190,temp,3,16,0X80); //显示电压值的小数部分
LED0=!LED0;
t=0;
}
delay_ms(10);
}
}