【STM32】DAC基本原理、寄存器、库函数(DAC一般步骤)

发布者:JoyfulSunflower最新更新时间:2019-03-12 来源: eefocus关键字:STM32  DAC  寄存器  库函数 手机看文章 扫描二维码
随时随地手机看文章

STM32F1xx官方资料:


《STM32中文参考手册V10》-第12章  数字模拟转换DAC


DAC的基本介绍

DAC的基本定义

Digital-to-Analog Converter的缩写。指数/模转换器或者数字/模拟转换器。是指将离散的数字信号转换为连续变量的模拟信号的器件。


典型的数字模拟转换器将表示一定比例电压值的数字信号转换为模拟信号。


STM32的DAC模块是12位数字输入,电压输出型的DAC。


DAC的主要特征

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

8位或者12位单调输出;

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

同步更新功能;

噪声波形生成;

三角波形生成;

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

每个通道都有DMA功能;

外部触发转换;

输入参考电压VREF+。

 


DAC的工作原理

DAC的工作框图



DAC模块的框图看起来比较复杂,接下来会一点一点地对它进行分析。


DAC引脚

在框图的四围是DAC的各个引脚,它们的名称、信号类型和作用见下图:



这里需要注意的是:STM32F103ZET6一共只有两个DAC_OUTx引脚,分别为DAC_OUT1(PA4)、DAC_OUT2(PA5)。并且在做DAC功能的时候,引脚GPIO模式应该是模拟输入!!!


为什么要使用模拟输入模式呢?因为一旦使能DACx通道后,相应的GPIO引脚(PA4或者PA5)会自动与DAC的模拟输出相连,设置为输入,是为了额外额外的干扰。



DAC转换

由框图可以看出,DAC受DORx寄存器直接控制的,但是不能直接往DORx寄存器写入数据,而是通过DHRx间接地传给DORx寄存器,实现对DAC的输出控制。


不能直接对寄存器DAC_DORx写入数据,任何输出到DAC通道x的数据都必须写入DAC_DHRx寄存器(数据实际写入DAC_DHR8Rx、DAC_DHR12Lx、DAC_DHR12Rx、DAC_DHR8RD、DAC_DHR12LD、或者DAC_DHR12RD寄存器)。


如果没有选中硬件触发(寄存器DAC_CR1的TENx位置0),存入寄存器DAC_DHRx的数据会在一个APB1时钟周期后自动传至寄存器DAC_DORx;

如果选中硬件触发(寄存器DAC_CR1的TENx位置1),数据传输在触发发生以后3个APB1时钟周期后完成。

一旦数据从DAC_DHRx寄存器装入DAC_DORx寄存器,在经过时间tSETTLING之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化。



DAC数据格式

根据上面可知,数据写入DAC_DHRx寄存器,然而实际上DAC_DHRx一共有6个寄存器!这是为什么呢?这就和DAC数据格式有很大的关系了。


根据选择的配置模式,数据按照下文所述写入指定的寄存器:


单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]位)。

一般采用第三种方式:12位数据右对齐比较多。


根据对DAC_DHRyyyx寄存器的操作,经过相应的移位后,写入的数据被转存到DHRx寄存器中(DHRx是内部的数据保存寄存器x)。随后,DHRx寄存器的内容或被自动地传送到DORx寄存器,或通过软件触发或外部事件触发被传送到DORx寄存器。



双DAC通道,有3种情况:


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触发

在框图的左上方,是指DAC转换可以由某外部事件触发(定时器计数器、外部中断线)。配置控制位TSELx[2:0]可以选择8个触发事件之一触发DAC转换。具体的外部触发的种类如下图所示:



DAC输出电压

当DAC的参考电压位VREF+的时候,数字输入经过DAC被线性地转换为模拟电压输出,其范围为0到VREF+。


任一DAC通道引脚上的输出电压满足下面的关系:


DAC输出 = VREF x (DOR / 4095)。


注意:此时数据格式:应该选择12位数据右对齐。


使能DAC输出缓存

DAC集成了2个输出缓存,可以用来减少输出阻抗,无需外部运放即可直接驱动外部负载。每个DAC通道输出缓存可以通过设置DAC_CR寄存器的BOFFx位来使能或者关闭。


但是,如果STM32的DAC输出缓存使能的话,虽然输出能力强一点,但是输出没有办法减到0,所以一般都不使用这个功能。


DAC相关配置寄存器

DAC控制寄存器(DAC_CR)



作用:配置DAC通道使能、触发使能、输出缓存、噪声输出使能、三角波输出使能。


DAC软件触发寄存器(DAC_SWTRIGR)



作用:配置DAC通道软件触发使能。


DAC通道数据保持寄存器(DAC_DHRxRx)

DAC通道1的12位右对齐数据保持寄存器(DAC_DHR12R1)



DAC通道1的12位左对齐数据保持寄存器(DAC_DHR12L1)



DAC通道1的8位右对齐数据保持寄存器(DAC_DHR8R1)



除了DAC通道1,还有DAC通道2的对应的三个数据保持寄存器。


DAC数据输出寄存器(DAC_DORx)

DAC通道1数据输出寄存器(DAC_DOR1)



除了DAC通道1,还有DAC通道2的对应的数据输出寄存器。


DAC相关配置库函数

1个初始化函数

void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct);

作用:配置外部触发的方式、噪声波生成、三角波生成、输出缓存。


1个使能函数

void DAC_Cmd(uint32_t DAC_Channel, FunctionalState NewState);

作用:配置DAC某个通道使能。


3个输出值函数

void DAC_SetChannel1Data(uint32_t DAC_Align, uint16_t Data);

void DAC_SetChannel2Data(uint32_t DAC_Align, uint16_t Data);

uint16_t DAC_GetDataOutputValue(uint32_t DAC_Channel);

作用:前两个向各自通道以某种对齐方式放入数值,第三个获得某个通道输出的数值。


DAC一般步骤

实验目标:利用按键控制STM32内部DAC的通道1来输出电压,同时通过ADC1的通道1采集DAC的输出电压。


开启输出引脚、DAC时钟,设置为模拟输入。调用函数:RCC_APBxPeriphClockCmd();

初始化DAC,设置DAC的工作模式。调用函数:DAC_Init();

使能DAC转换通道。调用函数:DAC_Cmd();

设置DAC的输出值。调用函数:DAC_SetChannelxData()。

下面按照这个一般步骤来进行一个简单的DAC程序:


//DAC通道1输出初始化

void Dac1_Init(void)

{

  

GPIO_InitTypeDef GPIO_InitStructure;

DAC_InitTypeDef DAC_InitType;

 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );   //使能PORTA通道时钟

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

 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // 端口配置

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

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_SetBits(GPIOA,GPIO_Pin_4) ;//PA.4 输出高


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

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

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

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

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

 

DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1

  

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

 

}

 

//设置通道1输出电压

//vol:0~3300,代表0~3.3V

void Dac1_Set_Vol(u16 vol)

{

float temp=vol;

temp/=1000;

temp=temp*4096/3.3;

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

}

 

 int main(void)

 {  

u16 adcx;

float temp;

  u8 t=0;  

u16 dacval=0;

u8 key;

delay_init();     //延时函数初始化   

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级

uart_init(115200); //串口初始化为115200

KEY_Init();   //初始化按键程序

  LED_Init();      //LED端口初始化

LCD_Init(); //LCD初始化

usmart_dev.init(72); //初始化USMART

  Adc_Init();   //ADC初始化

Dac1_Init(); //DAC初始化

 

POINT_COLOR=RED;//设置字体为红色 

LCD_ShowString(60,50,200,16,16,"WarShip STM32");

LCD_ShowString(60,70,200,16,16,"DAC TEST");

LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");

LCD_ShowString(60,110,200,16,16,"2015/1/15");

LCD_ShowString(60,130,200,16,16,"WK_UP:+  KEY1:-");

//显示提示信息       

POINT_COLOR=BLUE;//设置字体为蓝色

LCD_ShowString(60,150,200,16,16,"DAC VAL:");       

LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");       

LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");


DAC_SetChannel1Data(DAC_Align_12b_R, 0);//初始值为0           

while(1)

{

t++;

key=KEY_Scan(0);   

if(key==WKUP_PRES)

{  

if(dacval<4000)dacval+=200;

DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值

}else if(key==KEY1_PRES)

{

if(dacval>200)dacval-=200;

else dacval=0;

  DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值

}  

if(t==10||key==KEY1_PRES||key==WKUP_PRES) //WKUP/KEY1按下了,或者定时时间到了

{   

adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值

LCD_ShowxNum(124,150,adcx,4,16,0);      //显示DAC寄存器值

temp=(float)adcx*(3.3/4096); //得到DAC电压值

adcx=temp;

  LCD_ShowxNum(124,170,temp,1,16,0);      //显示电压值整数部分

  temp-=adcx;

temp*=1000;

LCD_ShowxNum(140,170,temp,3,16,0X80); //显示电压值的小数部分

  adcx=Get_Adc_Average(ADC_Channel_1,10); //得到ADC转换值   

temp=(float)adcx*(3.3/4096); //得到ADC电压值

adcx=temp;

  LCD_ShowxNum(124,190,temp,1,16,0);      //显示电压值整数部分

  temp-=adcx;

temp*=1000;

LCD_ShowxNum(140,190,temp,3,16,0X80); //显示电压值的小数部分

LED0=!LED0;    

t=0;

}     

delay_ms(10);

 

}

 }


关键字:STM32  DAC  寄存器  库函数 引用地址:【STM32】DAC基本原理、寄存器、库函数(DAC一般步骤)

上一篇:【STM32】PWM DAC基本原理(实验:PWM实现DAC)
下一篇:【STM32】ADC库函数、一般步骤详解 实例:内部温度传感器

推荐阅读最新更新时间:2024-03-16 16:25

STM32之ADC原理
ADC的位数决定了ADC的精度,有8位的,12位的,16位的等。 还有一个很重要的参数就是转换时间。 ST M32f103RBT6有2个ADC 控制器 。128KFlash,20KRAM 每一个ADC控制器都有多个通道,例如ADC1的外部通道有16个,可以理解为有一个 开关 分别连接各个通道。 每个通道的采样间隔和采样时间都可以设置。 三。ADC各通道与IO管脚对应表 一般负参考电压接地,正参考电压接 3.3V 。 模拟输入电压不能超过3.3V,否则输入 引脚 可能被烧毁。 ADC框图 Vref+连接到VDDA,Vref-连接到VSSA。 最多4个通道连接到注入通道,最多16个通道连接到规则通道。 什么
[单片机]
<font color='red'>STM32</font>之ADC原理
STM32外设库文件分析(V3.5)
标准库文件3.5版本 1._htmresc 里面有两个logo,没用,删除。 2.Release_Notes.html 发行版本,可以看到各个版本的发行时间,修改内容。 3.Utilities 里面是一些测试C文件,评估使用。 4.stm32f10x_stdperiph_lib_um.chm 帮助文件。 5.Project 文件夹有个模版和一个例程。以工程模式提供。 6.Libraries 文件夹下面包括两个文件夹: CMSIS Cortex Microcontroller Software Interface Standard CM3 CoreSupport:core_cm3.c core_cm3.h
[单片机]
STM32 定时器时钟配置技巧
众所周知 STM32 的时钟配置比较复杂,而定时器的时钟配置更是 ‘奇葩‘。 如下图(截图自STM32F4编程手册)APB的预分频器分频系数如果不为1,则定时器的时钟就倍频了反而。 配置技巧 下面以STM32F4为例, 这里配置定时器8的计数频率为 10Khz,从时钟树中可知TIM8挂在APB2总线 获取当前 APB2(PLCK2) 的时钟频率 获取 APB2 预分频器的分频值 根据上述参数判断,如果分频值不为1,则定时器时钟 x2 .Prescaler = xxx 这是一个推荐的写法 int hw_timer_init(TIM_HandleTypeDef *htim) { uint32_t FLatency, t8
[单片机]
<font color='red'>STM32</font> 定时器时钟配置技巧
stm32 系统默认时钟问题
今天在看正点原子的程序时,发现程序中没有配置时钟,但是定时器竟然可以用。 刚开始以为是stm32默认时钟选择为72MHz,但是又想到系统时钟是需要代码配置的。 想到可能是在启动文件中系统调用了某些函数,查了一下,果然是这样,在startup_stm32f10x_hd.s文件中,有这么一段 ; Reset handler Reset_Handler PROC EXPORT Reset_Handler IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0
[单片机]
STM32使用FSMC控制NAND flash 例程
近几天开发项目需要用到STM32驱动NAND FLASH,但由于开发板例程以及固件库是用于小页(512B),我要用到的FLASH为1G bit的大页(2K),多走了两天弯路。以下笔记将说明如何将默认固件库修改为大页模式以驱动大容量NAND,并作驱动。 本文硬件:控制器:STM32F103ZET6,存储器:HY27UF081G2A 首先说一下NOR与NAND存储器的区别,此类区别网上有很多,在此仅大致说明: 1、Nor读取速度比NAND稍快 2、Nand写入速度比Nor快很多 3、NAND擦除速度(4ms)远快于Nor(5s) 4、Nor 带有SRAM接口,有足够的地址引脚来寻址,可以很轻松的挂接到CPU地址和数据总线上,对CPU要
[单片机]
STM32单片机学习笔记(4):24C02(模拟IIC)
项目简介 利用CubMX生成基于32单片机的HAl库工程,然后编写程序在proteus上仿真验证。本项目最适合没有开发板的同学学习,零成本利用仿真软件率先入门STM32单片机。这是第四部分针对EEPROM 24C02的一个实例,IIC通信是一种比较典型的串行通信方式,在很多情况下都会有所使用,了解并熟悉IIC通信就显得十分重要。本项目之所以使用模拟IIC,而没有使用STM32单片机内置的硬件IIC,主要由于Half库里IIC的坑太多了,自己一开始也是想通过HAL库来开发,但是始终不成功,也有可能仿真软件也有些坑,如果有能够做出来的大佬,也欢迎评论区或私聊我交流,不过在实物32单片机开发板上网上好像验证过可用,但是手上暂时缺开发板,
[单片机]
<font color='red'>STM32</font>单片机学习笔记(4):24C02(模拟IIC)
STM32 DMA学习
一个简单的例子 transfer a word data buffer from FLASH memory to embedded SRAM memory. 在V3.1.2库的位置 STM32F10x_StdPeriph_Lib_V3.1.2\Project\STM32F10x_StdPeriph_Examples\DMA\FLASH_RAM /* DMA1 channel6 configuration */ DMA_DeInit(DMA1_Channel6); //peripheral base address DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SRC_
[单片机]
<font color='red'>STM32</font> DMA学习
STM32 FSMC操作SRAM的步骤简析
本次操作的SRAM的型号是IS62WV51216,是高速,8M位静态SRAM。它采用ISSI(Intergrated Silicon Solution, Inc)公司的高性能CMOS技术,按照512K个字(16)位进行组织存储单元。其具有高性能、低功耗特点。为方便用户扩展SRAM的存储空间,为用户有提供了两个片选引脚;此外,含有两个字节控制信号UB和LB,可方便用户按字节访问SRAM或按字访问SRAM。IS62WV51216具有45ns/55ns访问速度,因为是全静态操作,因此无需外部时钟和刷新要求。 IS62WV51216功能框图 IS62WV51216有地址译码器、数据IO、控制逻辑和存储阵列四部分构成。地址译码器将1
[单片机]
<font color='red'>STM32</font> FSMC操作SRAM的步骤简析
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved