STM32学习和实践笔记(36):DAC数模转换实验

1.STM32F1 DAC简介

  DAC(Digital to analog converter)即数字模拟转换器,它可以将数字信号转换为模拟信号。它的功能与ADC相反。在常见的数字信号系统中,大部分传感器信号被转化成电压信号,而 ADC 把电压模拟信号转换成易于计算机存储、处理的数字编码,由计算机处理完成后,再由 DAC 输出电压模拟信号,该电压模拟信号常常用来驱动某些执行器件,使人类易于感知。如音频信号的采集及还原就是这样一个过程。 

STM32F1 DAC模块是 12 位电压输出数模转换器,它可以配置为 8 位或 12 位模式,也可以与DMA 控制器配合使用。DAC工作在 12 位模式下,数据可以采用左对齐或右对齐。DAC工作在8位模式下,数据只有右对齐方式。

DAC 有两个输出通道,每个通道各有一个转换器。 DAC 双通道模式下,每个通道可以单独进行转换;当两个通道组合在一起同步执行更新操作时,也可以同时进行转换。DAC可通过一个输入参考电压引脚 VREF+ (与ADC 共享)来提高转换后的数据精度。         

STM32F1 DAC主要特性

2个DAC转换器:每个转换器对应1个输出通道

8位或者12位单调输出

12位模式下数据左对齐或者右对齐

同步更新功能

● 噪声波形生成

● 三角波形生成

双DAC通道同时或者分别转换

每个通道都有DMA功能

外部触发转换

输入参考电压VREF+       

1.2 STM32F1 DAC结构框图

  STM32F1 DAC拥有这么多功能,是由DAC内部结构决定。要更好的理解STM32F1的DAC,就需要了解它内部的结构。如图所示:(大家也可以查看《STM32F10x中文参考手册》-12数模转换器(DAC)-12.3章节内容)。    

  

1)标号1:电源和参考电压引脚

  同ADC一样,VDDA与VSSA是DAC模块的供电引脚,而VREF+是DAC模块的参考电压,开发板上已经将VREF+连接到VDDA,所以参考电压范围是0-3.3V。

2)标号2:DAC转换

  DAC 输出是受 DORx 寄存器直接控制的,但是我们不能直接往DORx 寄存器写入数据,而是通过 DHRx 间接的传给 DORx 寄存器,实现对 DAC 输出的控制。

如果未选择硬件触发,也就是软件触发时DAC_CR 寄存器中的 TENx 位复位),那么经过一个 APB1 时钟周期后,DAC_DHRx 寄存器中存储的数据将自动转移到 DAC_DORx 寄存器。

如果选择硬件触发(置位DAC_CR 寄存器中的 TENx 位)且触发条件到来,将在三个 APB1 时钟周期后进行转移。

DAC_DORx 加载了 DAC_DHRx 内容时,模拟输出电压将在一段时间 tSETTLING 后可用,具体时间取决于电源电压和模拟输出负载。我们可以从STM32F103ZET6 的数据手册查到的典型值为 3us,最大是 4us。所以 DAC 的转换速度最快是 250K 左右。

软件触发,即不使用硬件触发时(TENx=0),其转换时序图如图

  DHRx内装载着我们要输出的数据,前面我们提到,STM32F1 的 DAC 支持 8/12 位模式,8 位模式的时候数据是固定的右对齐的,而 12 位模式数据可以设置左对齐/右对齐。对于DAC单通道 x,总共有 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 通道都具有 DMA 功能。两个 DMA 通道用于处理 DAC 通道的 DMA 请求。当 DMAENx 位置 1 时,如果发生外部触发(而不是软件触发),则将产生 DAC DMA 请求DAC_DHRx 寄存器的值随后转移到 DAC_DORx 寄存器。在双通道模式下,如果两个 DMAENx 位均置 1,则将产生两个 DMA 请求。如果只需要一个DMA 请求,应仅将相应 DMAENx 位置 1。这样,应用程序可以在双通道模式下通过一个DMA 请求和一个特定 DMA 通道来管理两个 DAC 通道。由于DAC DMA 请求没有缓冲队列。这样,如果第二个外部触发到达时尚未收到第一个外部触发的确认,将不会发出新的请求,并且 DAC_SR 寄存器中的 DAM 通道下溢标志 DMAUDRx将置 1,以报告这一错误状况。 DMA 数据传输随即禁止,并且不再处理其他 DMA 请求。DAC 通道仍将继续转换旧有数据。这时软件应通过写入“ 1”来将 DMAUDRx 标志清零,将所用 DMA 数据流的 DMAEN 位清零,并重新初始化 DMA 和 DAC 通道,以便正确地重新开始 DMA 传输。软件应修改 DAC 触发 转换频率或减轻 DMA 工作负载,以避免再次发生 DMA 下溢。最后,可通过使能 DMA 数据 传输和转换触发来继续完成 DAC 转换。对于各 DAC 通道,如果使能 DAC_CR 寄存器中相应的 DMAUDRIEx位,还将产生中断

3)标号3:DAC触发选择

  如果 TENx 控制位置 1,可通过外部事件(定时计数器、外部中断线)触发转换。TSELx[2:0]控制位将决定通过 8 个可能事件中的哪一个来触发转换,外部触发源如下图

 如果选择软件触发,一旦 SWTRIG 位置 1, 转换即会开始。DAC_DHRx 寄存器的内容只需一个 APB1 时钟周期即可转移到DAC_DORx 寄存器,加载完成后,SWTRIG 即由硬件复位。

4)标号4:DAC输出

  DAC_OUTx 就是 DAC 的输出通道,DAC1_OUT对应 PA4引脚,DAC2_OUT对应 PA5引脚。

要让DAC通道正常输出,需将 DAC_CR 寄存器中的相应 ENx 位置 1,这样就可接通对应 DAC 通道。经过一段启动时间tWAKEUP 后,DAC 通道被真正使能。使能 DAC 通道 x 后,相应 GPIO 引脚( PA4 或 PA5)将自动连接到模拟转换器输出(DAC_OUTx)。为了避免寄生电流消耗,应首先将 PA4 或 PA5 引脚配置为模拟输入模式 (AIN)。

当 DAC 的参考电压为 Vref+的时候,DAC 的输出电压是线性的从 0~Vref+, 12 位模式下 DAC 输出电压与 Vref+以及 DORx 的计算公式

如下

其中,DOR是送过来的要转换的二进制数据,4096是2的12次方也就是12位寄存器全部为1时的值。

2.STM32F1 DAC配置步骤

  接下来我们介绍下如何使用库函数对DAC进行配置。这个也是在编写程序中必须要了解的。具体步骤如下:(DAC相关库函数在stm32f10x_dac.c和stm32f10x_dac.h文件中)

(1)使能端口及DAC时钟,设置引脚为模拟输入

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入

(2)初始化DAC,设置DAC工作模式

void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct);

typedef struct

{

  uint32_t DAC_Trigger;                      //DAC触发选择

  uint32_t DAC_WaveGeneration;               //DAC波形发生

  uint32_t DAC_LFSRUnmask_TriangleAmplitude; //屏蔽/幅值选择器

  uint32_t DAC_OutputBuffer;                 //DAC输出缓存

}DAC_InitTypeDef;

以下对这个结构成体员的详细描述:

  DAC_Trigger:设置是否使用触发功能以及选定触发源。前面介绍框图时已经说了DAC具有多个触发源,有定时器触发,外部中断线9触发,软件触发和不使用触发,如下所示:    

   

  DAC_WaveGeneration:设置是否使用波形发生,有以下四个选项:

  DAC_LFSRUnmask_TriangleAmplitude:设置屏蔽/幅值选择器。这个变量只在使用波形发生器的时候才有用,通常我们设置为 0 即可,值为DAC_LFSRUnmask_Bit0。 

   DAC_OutputBuffer:设置输出缓存控制位。通常我们不使用输出缓存功能,所以配置参数为DAC_OutputBuffer_Disable。y为什么通常不使用这个功能?因为使用这个功能虽然可以提高驱动能力,但是使用了它之后,DAC的输出不能为0!这会引起功能性的问题,所以不使用它。如果要提高驱动能力,可以DAC输出后加外围驱动电路。

DAC_InitTypeDef DAC_InitStructure;

DAC_InitStructure.DAC_Trigger=DAC_Trigger_None;  //不使用触发功能 TEN1=0

DAC_InitStructure.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生

DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置

DAC_InitStructure.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;  //DAC1输出缓存关闭 BOFF1=1

DAC_Init(DAC_Channel_1,&DAC_InitStructure);  //初始化DAC通道1

(3)使能DAC的输出通道

void DAC_Cmd(uint32_t DAC_Channel, FunctionalState NewState);

DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC通道1

(4)设置DAC的输出值

  通过前面 4 个步骤的设置, DAC 就可以开始工作了,如果我们使用12 位右对齐数据格式,我们通过设置 DHR12R1,就可以在 DAC 输出引脚(PA4)得到不同的电压值了。设置DHR12R1 的库函数是

  DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值

库函数中,还提供一个读取 DAC 对应通道最后一次转换的数值,函数是:uint16_t DAC_GetDataOutputValue(uint32_t DAC_Channel);

3.硬件电路

  本实验使用到硬件资源如下

1)D1指示灯

2)K_UP和K_DOWN按键

3)串口1

4)DAC的通道1

DAC的通道1它属于STM32F1芯片内部的资源,对应芯片的PA4引脚。DAC模块电路如图

PA4输出到PWM0,PA5输出到PWM1.

U16的供电DA_VCC是5V供电(需要注意连好),用来放大DAC的驱动能力。

  D1指示灯用来提示系统运行状态,K_UP按键用来增加DAC输入值,K_DOWN按键用来减小DAC输入值,输入值的改变将控制DAC1_OUT电压输出。通过串口1将DAC1_OUT输出的电压值打印出来         

4.编写DAC控制程序

  本实验所要实现的功能是:通过K_UP与K_DOWN按键控制STM32F1 DAC1输出电压,通过串口将DAC1输出的电压值打印显示,D1指示灯闪烁提示系统运行。程序框架如下:

(1)初始化DAC通道1相关参数

(2)编写主函数

main.c

#include "system.h"
#include "led.h"
#include "SysTick.h"
#include "usart.h"
#include "dac.h"
#include "key.h"




int main()
{
	u8 i=0;
	u8 key=0;
	int Dac_Val=0;
	u16 Dac_OutputValue=0;
	float voltage;


	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
	LED_Init();
	USART1_Init(9600);
	key_Init();
	DAC1_Init();


		while(1)
	{
		key = KEY_Scan(0);
		
		if(key == KEY_UP)
		{
			Dac_Val+=400;//400这个值表示每次按下按键,DAC里的D增加多少,在这里可以任意自定,值越大变化越明显
			if(Dac_Val>=4000) Dac_Val = 4095;		//12位的D最大值为4096
			DAC_SetChannel1Data(DAC_Align_12b_R, Dac_Val);
		}
		else if(key == KEY_DOWN)
		{
			Dac_Val-=400;//
			if(Dac_Val<=0)	Dac_Val = 0;	//
			DAC_SetChannel1Data(DAC_Align_12b_R, Dac_Val);
		}		
		
		i++;
		if(i%20 ==0)
			{
				led1=!led1;//LED1闪,用来指示主程序循环是否运行
			}
			
		if(i%50==0)
			{
					Dac_OutputValue=DAC_GetDataOutputValue(DAC_Channel_1);
					voltage=(float)Dac_OutputValue*(3.3/4096);//转换成电压显示
					printf("DAC输出电压值为:%.2fV\r\n",voltage);				
			}
		delay_ms(10);
		
	}
		
}


dac.c

#include "dac.h"
#include "SysTick.h"

void DAC1_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure; 
	DAC_InitTypeDef DAC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能DAC输入引脚(PA4,PA5)的时钟

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//使能DAC时钟

	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4; //配置GPIO,PA4
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//先配置PA4的模式为模拟输入以减少没有输出时的寄生电流
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;	//
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	DAC_InitStructure.DAC_Trigger=DAC_Trigger_None;//不使用外部触发功能 TEN1=0
	DAC_InitStructure.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
	DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
	DAC_InitStructure.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;//DAC1输出缓存关闭 BOFF1=1
	DAC_Init(DAC_Channel_1,&DAC_InitStructure);//初始化DAC通道1
	
	DAC_SetChannel1Data(DAC_Align_12b_R, 0);//12位右对齐数据格式,设置DAC初始值为0
	DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC通道1
	
}



    程序烧写到开发上板,最开始显示是输出电压值为0V,之后按动上键和下键,输出电压值对应发生如下变化,这说明程序运行正常,实验是成功的。                           

                             

                  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/720133.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

哈尔滨等保测评流程

哈尔滨的等保测评程序是一项严格的、系统化的检测程序&#xff0c;其目的在于保证信息系统的安全、稳定。下面详细介绍了这个过程&#xff1a; 一、引言 随着信息技术的飞速发展&#xff0c;信息系统在各行各业中的应用越来越广泛&#xff0c;信息安全问题也日益凸显。为了保障…

【方法】如何隐藏和保护Excel表格中的敏感数据?

在工作中&#xff0c;很多人经常需要处理包含敏感信息的Excel表格。 为了确保这些数据的安全性&#xff0c;我们可以通过隐藏单元格、行和列&#xff0c;以及设置密码保护工作表的方法&#xff0c;来保护数据&#xff0c;下面一起来看看吧&#xff01; 一、隐藏数据&#xff1…

idea2020版本下载及注册

一。准备idea2020和BetterIntelliJ插件和补丁key 二、开始安装。 idea就正常安装&#xff0c;然后打开&#xff0c;选择试用30天打开即可&#xff0c;然后File - settings - plugins 点击 Install Plugin from Disk 然后选择BetterIntelliJ这个&#xff0c;这个后期不可变名称…

【数据分析】线性及逻辑回归模型和Python实现

各位大佬好 &#xff0c;这里是阿川的博客&#xff0c;祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 Python 初阶 Python–语言基础与由来介绍 Python–…

聆思CSK6大模型+AI交互多模态开源SDK介绍

视觉语音大模型 AI 开发套件( CSK6-MIX )是围绕 CSK6011A 芯片设计的具备丰富语音图像功能与硬件外设的开发板&#xff0c;采用具备丰富组件生态的 Zephyr RTOS作为操作系统&#xff0c;官方提供了十几种开源SDK&#xff0c;包含大模型语音交互、大模型拍照识图、文生图、人脸识…

冒泡排序、选择排序

冒泡排序 按照冒泡排序的思想&#xff0c;我们要把相邻的元素两两比较&#xff0c;当一个元素大于右侧相元素时&#xff0c;交换它们的位置&#xff1b;当一个元素小于或等于右侧相邻元素时&#xff0c;位置不变 大的往右丢&#xff08;往下沉&#xff09;&#xff0c;小的往…

动手学深度学习(Pytorch版)代码实践 -深度学习基础-09过拟合与欠拟合

09过拟合与欠拟合 #通过多项式拟合来探索过拟合和欠拟合 #欠拟合是指模型无法继续减少训练误差。 #过拟合是指训练误差远小于验证误差。 import math import numpy as np import torch from torch import nn from d2l import torch as d2l import liliPytorch as lp#生成数据集…

数据驱动决策:工单统计工具如何赋能企业精准运营

在当今这个数字化飞速发展的时代&#xff0c;企业对于内部运营效率的追求已经达到了前所未有的高度。你是否曾为了繁杂的工单统计管理而头疼不已&#xff1f;是否曾因为无法准确进行工单统计数据而错失商机&#xff1f;今天&#xff0c;我将向你展示一款革命性的工单统计工具&a…

AI从云端到边缘:人员入侵检测算法的技术原理和视频监控方案应用

在当今数字化、智能化的时代&#xff0c;安全已成为社会发展的重要基石。特别是在一些关键领域&#xff0c;如公共安全、智能化监管以及智慧园区/社区管理等&#xff0c;确保安全无虞至关重要。而人员入侵检测AI算法作为一种先进的安全技术&#xff0c;正逐渐在这些领域发挥着不…

MySQl基础入门⑯【操作视图】完结

上一边文章内容 表准备 CREATE TABLE Students (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100),email VARCHAR(255),major VARCHAR(100),score int,phone_number VARCHAR(20),entry_year INT,salary DECIMAL(10, 2) );数据准备 INSERT INTO Students (id, name, ema…

DolphinScheduler日志乱码、worker日志太多磁盘报警、版本更新导致不兼容怎么办?

作者 | 刘宇星 本文作者总结了在使用Apache DolphinScheduler过程中遇见过的常见问题及其解决方案&#xff0c;包括日志出现乱码、worker日志太多磁盘报警、版本更新导致不兼容问题等&#xff0c;快来看看有没有困扰你想要的答案吧&#xff01; DolphinScheduler集群环境有多…

AI大模型的策略布局:通用广度与垂直深度的融合之道

1. 设计理念&#xff1a; 通用大模型&#xff08;GeneralPurpose Large Models&#xff09;&#xff1a;旨在处理多种类型的任务&#xff0c;不特定于某个领域或应用。它们通常具有广泛的知识和能力&#xff0c;能够理解和生成自然语言、进行图像识别、解决数学问题等。 1. 广…

FileZilla证书过期,导致FileZilla Client联不上,或者老断开的处理

1、先到服务器上去重新生成一下证书&#xff0c;并且覆盖掉老的证书。edit--settings 输入信息&#xff0c;并且确认生成新的证书&#xff1a; 2、Client连接的时候&#xff0c;弹出证书信任&#xff0c;点击确认。 这样第一次连接&#xff0c;然后访问目录全都是好的&#xff…

如何开发盲盒小程序APP——入门指南

一、前言 随着盲盒经济的兴起&#xff0c;越来越多的开发者开始关注如何开发盲盒小程序APP。盲盒小程序不仅能为用户提供新颖的购物体验&#xff0c;还能为商家带来可观的利润。本文将为大家介绍如何入门开发盲盒小程序APP。 二、需求分析 目标用户&#xff1a;明确你的目标…

视频太大了怎么缩小内存

我们在分享视频的时候&#xff0c;有时候会遇到过视频文件太大&#xff0c;无法发送或者上传的情况&#xff0c;别担心&#xff0c;今天我就来给大家分享一个简单有效的方法&#xff0c;让你的视频变得更小&#xff0c;更方便分享&#xff01; 打开 “51视频处理官网 的网站。上…

如何使用CST软件敏感度分析 sensitivity analysis --- 天线F-ROM求解器

我们介绍一个自带案例&#xff0c;与直接使用参数配合频域ROM算法不同&#xff0c;这回我们演示constraint参数配合频域通用算法。以自带T分器为例&#xff1a; 其中有一个参数控制了金属柱的半径&#xff0c;初始值为1&#xff1a; 这个参数是个constraint&#xff0c;添加方法…

PowerBi 获取指定时间间隔的日期的方法

获取指定时间间隔的日期&#xff0c;比如我们想得到2024年5月31日后的第三天。 网络上的教程一般是使用DATEADD()函数。 但是这个函数返回的是表。假如我们的需求是不做汇总等计算&#xff0c;只是把它作为一个计算列&#xff0c;或者度量值&#xff0c;那么我更推荐用DATE(&…

迷你小风扇哪个品牌好?迷你小风扇前十名公开揭晓!

随着夏日的炎热袭来&#xff0c;迷你小风扇成为了许多人随身携带的清凉利器。无论是在办公室、户外活动&#xff0c;还是在旅行途中&#xff0c;迷你小风扇都以其小巧便携、强劲风力和持久续航的优势&#xff0c;迅速俘获了大批用户的喜爱。然而&#xff0c;市面上迷你小风扇品…

对yoloV8进行标签过滤来实现行人检测

前言 上一章我们介绍的通过迁移学习&#xff0c;在新的行人数据集上使用已经学习到的特征和权重&#xff0c;从而更快地实现行人检测任务。模型就会调整其参数以适应新的数据集&#xff0c;以提高对行人的识别性能。接下来介绍一种更快更便捷的方法&#xff0c;依旧是基于yolo…

【windows|002】WEB服务和域名介绍

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…