DAC简介:

stm32只有2个DAC,每个DAC有1个独立的通道,这和ADC有区别(有3个ADC,每个ADC有16个通道),特征如下:

DAC 功能框图

功能说明:

1 参考电压:

2 数模转换 输出通道:

注意,在使用DAC时,GPIO引脚一定要配置成模拟输入,不然没有输出,中文参考手册的描述:

3 触发源及DHRx寄存器

双DAC 模式:

DAC 的寄存器描述:


1 控制寄存器DAC_CR

2 DAC 软件触发寄存器:

3 输入数据对齐寄存器:

4 双DAC输入数据寄存器

5 输出数据寄存器(由软件写入):

定时器触发设置


1 定时器时基初始化,并配置触发源:


/**

  * @brief  配置TIM

  * @param  无

  * @retval 无

  */

static void DAC_TIM_Config(void)

{

TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;

/* 使能TIM2时钟,TIM2CLK 为72M */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  /* TIM2基本定时器配置 */

 // TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 

  TIM_TimeBaseStructure.TIM_Period = (20-1);        //定时周期 20  

  TIM_TimeBaseStructure.TIM_Prescaler = 0x0;        //预分频,不分频 72M / (0+1) = 72M

  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;    //时钟分频系数

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

 

  /* 配置TIM2触发源 */

  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

 

/* 使能TIM2 */

  TIM_Cmd(TIM2, ENABLE);

}

这里面使用到了TIM_SelectOutputTrigger函数,这个在之前 TIM 定时器章节几乎没有使用,来看一下源码实现:


/**

  * @brief  Selects the TIMx Trigger Output Mode.

  * @param  TIMx: where x can be 1, 2, 3, 4, 5, 6, 7, 8, 9, 12 or 15 to select the TIM peripheral.

  * @param  TIM_TRGOSource: specifies the Trigger Output source.

  *   This paramter can be one of the following values:

  *

  *  - For all TIMx

  *     @arg TIM_TRGOSource_Reset:  The UG bit in the TIM_EGR register is used as the trigger output (TRGO).

  *     @arg TIM_TRGOSource_Enable: The Counter Enable CEN is used as the trigger output (TRGO).

  *     @arg TIM_TRGOSource_Update: The update event is selected as the trigger output (TRGO).

  *

  *  - For all TIMx except TIM6 and TIM7

  *     @arg TIM_TRGOSource_OC1: The trigger output sends a positive pulse when the CC1IF flag

  *                              is to be set, as soon as a capture or compare match occurs (TRGO).

  *     @arg TIM_TRGOSource_OC1Ref: OC1REF signal is used as the trigger output (TRGO).

  *     @arg TIM_TRGOSource_OC2Ref: OC2REF signal is used as the trigger output (TRGO).

  *     @arg TIM_TRGOSource_OC3Ref: OC3REF signal is used as the trigger output (TRGO).

  *     @arg TIM_TRGOSource_OC4Ref: OC4REF signal is used as the trigger output (TRGO).

  *

  * @retval None

  */

void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource)

{

  /* Check the parameters */

  assert_param(IS_TIM_LIST7_PERIPH(TIMx));

  assert_param(IS_TIM_TRGO_SOURCE(TIM_TRGOSource));

  /* Reset the MMS Bits */

  TIMx->CR2 &= (uint16_t)~((uint16_t)TIM_CR2_MMS);

  /* Select the TRGO source */

  TIMx->CR2 |=  TIM_TRGOSource;

}


可以看到,其实就是配置TIMx_CR2寄存器的对应位,寄存器描述如下:

我们希望给定时器一个计数值,当定时器溢出(更新中断)时,产生一个更新事件,正好作为DAC的定时器触发。

DAC配置(产生两路DAC模拟信号)


1 生成正弦波数据


/* 波形数据 ---------------------------------------------------------*/

const uint16_t Sine12bit[POINT_NUM] = {

2048 , 2460 , 2856 , 3218 , 3532 , 3786 , 3969 , 4072 ,

4093 , 4031 , 3887 , 3668 , 3382 , 3042 , 2661 , 2255

1841 , 1435 , 1054 , 714 , 428 , 209 , 65 , 3 ,

24 , 127 , 310 , 564 , 878 , 1240 , 1636 , 2048

};

2 DMA配置:


/**

  * @brief  配置DMA

  * @param  无

  * @retval 无

  */

static void DAC_DMA_Config(void)

{

DMA_InitTypeDef  DMA_InitStructure;

 

/* 使能DMA2时钟 */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);

/* 配置DMA2 */

  DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_ADDRESS; //外设数据地址

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&DualSine12bit ; //内存数据地址 DualSine12bit

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向内存至外设

  DMA_InitStructure.DMA_BufferSize = POINT_NUM; //缓存大小为POINT_NUM字节

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设数据地址固定

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存数据地址自增

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //外设数据以字为单位

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //内存数据以字为单位

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环模式

  DMA_InitStructure.DMA_Priority = DMA_Priority_High; //高DMA通道优先级

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非内存至内存模式

 

  DMA_Init(DMA2_Channel4, &DMA_InitStructure);

  /* 使能DMA2-14通道 */

  DMA_Cmd(DMA2_Channel4, ENABLE);

}

3 GPIO初始化:


/**

  * @brief  使能DAC的时钟,初始化GPIO

  * @param  无

  * @retval 无

  */

static void DAC_Config(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

DAC_InitTypeDef  DAC_InitStructure;

 

  /* 使能GPIOA时钟 */

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

/* 使能DAC时钟 */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);

  /* DAC的GPIO配置,模拟输入 */

  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4 | GPIO_Pin_5;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

 

  /* 配置DAC 通道1 */

  DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO; //使用TIM2作为触发源

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

  DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; //不使用DAC输出缓冲

  DAC_Init(DAC_Channel_1, &DAC_InitStructure);

 

  /* 配置DAC 通道2 */

  DAC_Init(DAC_Channel_2, &DAC_InitStructure);

 

  /* 使能通道1 由PA4输出 */

  DAC_Cmd(DAC_Channel_1, ENABLE);

  /* 使能通道2 由PA5输出 */

  DAC_Cmd(DAC_Channel_2, ENABLE);

 

  /* 使能DAC的DMA请求 */

  DAC_DMACmd(DAC_Channel_2, ENABLE);

}

4 定时器时基初始化和触发配置


/**

  * @brief  配置TIM

  * @param  无

  * @retval 无

  */

static void DAC_TIM_Config(void)

{

TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;

/* 使能TIM2时钟,TIM2CLK 为72M */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  /* TIM2基本定时器配置 */

 // TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 

  TIM_TimeBaseStructure.TIM_Period = (20-1);        //定时周期 20  

  TIM_TimeBaseStructure.TIM_Prescaler = 0x0;        //预分频,不分频 72M / (0+1) = 72M

  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;    /时钟分频系数

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

 

  /* 配置TIM2触发源 */

  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

 

/* 使能TIM2 */

  TIM_Cmd(TIM2, ENABLE);

}

5 生成双DAC数据(频率相同,幅值1/2),然后初始化双DAC:


/**

  * @brief  DAC初始化函数

  * @param  无

  * @retval 无

  */

void DAC_Mode_Init(void)

{

uint32_t Idx = 0;  

 

DAC_Config();

DAC_TIM_Config();

/* 填充正弦波形数据(两路DAC幅值相差1/2),双通道右对齐*/

  for (Idx = 0; Idx < POINT_NUM; Idx++)

  {

    DualSine12bit[Idx] = (Sine12bit[Idx] << 16) + (Sine12bit[Idx] / 2);

  }

DAC_DMA_Config();

}

在主函数中进行测试:


main.c


/**

  * @brief  主函数

  * @param  无

  * @retval 无

  */

int main(void)

{

    *初始化DAC,开始DAC转换*/

    DAC_Mode_Init();

    while(1);  

}


测试效果如图所示,波形生成正确。

关键字:STM32  DAC  参考电压 引用地址:stm32专题三十五:DAC

上一篇:stm32专题三十四:独立看门狗 IWDG
下一篇:stm32专题三十六:MDK编译过程和文件类型(一)

推荐阅读

       半导体产业景气近期虽出现杂音,但硅晶圆的前景展望仍然乐观,预期硅晶圆续供不应求的情况可望持续数年的时间,相关业者营运展望乐观,不过,受到中美贸易战的影响,加上产能扩充等因素引发市场担忧,硅晶圆股价在6月初开始反转直下,如今开始反弹。        涨价题材股中,市场最看好硅晶圆,另外,金属氧化物半导体场效晶体管(MOS...
倍捷连接器珠海工厂新增Amphe-Lite产品线以最新科技解决恶劣环境互联难题 近日,倍捷连接器(PEI-Genesis)得到安费诺最新的授权,在其珠海工厂添加Amphe-Lite系列产品的生产线,为亚洲用户提供更多产品和组装搭配组合。 Amphe-Lite系列具有轻量化、体积小、密度高、可靠性高等特点,且符合D38999第三代军用规格,代表最新的连接技术标准。该系列产品适用...
韩国媒体 Elec 的一份新报告显示,LG 正努力在明年 3 月发布一款具备可滚动式显示屏的设备,该设备代号为 “B Project”。  此外,预计 LG 还将推出其他智能手机产品,包括一个 Velvet 系列后续者的和新款旗舰机型,旗舰新机可能会作为 V60 ThinQ 5G 的继任者推出。  报道指出,“B Project”是 LG 电子 Explorer Proje...
10月31日,据韩媒报道称,10月份内存半导体DRAM价格下跌近10%,显示出第四季度DRAM市场行情"峰值出局"(peak out,景气见顶,下跌)的担忧正在成为现实。据TrendForce数据显示,10月份PC用DRAM通用产品(DDR4 8GB)成交价为3.71美元,环比降价0.39美元,比上一季度下降9.51%。DRAM自今年1月份起一直保持价格上升趋势,此次是全年首次降价。半导体市场调...

史海拾趣

问答坊 | AI 解惑

来这里有几天了!知道这里有很多高手,有事情想请教!!

来这里有几天了!知道这里有很多高手,有事情想请教!!就是用VB控制电动机的流程!!!谢谢!!…

查看全部问答∨

C51易懂单片机基础教程

简要介绍单片的内外部结构以及学习时的软,硬件准备;大量具体实例,分析十分详细 非常实用于初学者入门级教程…

查看全部问答∨

关于网络的AT指令

1.网络初始化的AT命令有哪些 2.关闭网络有哪些AT命令 3.重新注册网络是什么AT命令…

查看全部问答∨

向USB设备传输图像 请大家解决问题

目的是向USB设备传输图像并显示 USB设备已经做好了 驱动正常 而且有测试程序 只要选择一个文件 点发送 最终设备就可以显示图像了 现在我要做的就是在另一个复杂点的程序中也实现这个功能 但是目前总是不成功 因为是第一次接触USB传输的领域 请大 ...…

查看全部问答∨

Wince数据库

wince中,驻留在对象存储库中的数据库,当关机,对象存储库中的数据库还存在么?请解释下 本人,使用CCeDBDatabase创建的数据库,每次重启系统时,都会重新创建,请问,有没其他方法,让数据库只创建一次?…

查看全部问答∨

stlink调试异常

本人用 IAR 夹ST LINK 调试,用了几天都正常,今天突然出故障了,就是程序跑几秒钟之后,会跑到汇编行(Disassembly)的__DebugBreak的地方,找了好久的原因都不知所措,烦请学长指点。 1XH0NNOW2OM%_TLHW9I@P`A.jpg (8.86 KB) ...…

查看全部问答∨

ADC采样不准可能是受什么干扰

ADC输入较大时,输出的数字值正确,但当输入较小时,输出就不对了,越接近零,错误越大。 芯片应该没问题,可能是layout的影响,哪些情况会出现这种干扰呢?…

查看全部问答∨

maple驱动18B20

#define ONEWIRE_DQ 27  //OneWire 引脚int OneWire_Reset(int);int OneWire_ReadByte(int, int);int OneWire_ReadBit(int, int);void OneWire_WriteByte(int, int);void OneWire_WriteBit(int, int);int OneWire_DS18B20_ConvertTemperature( ...…

查看全部问答∨

PIC运行问题

请问一下,为什么同样的代码。有时可以正常运行,有时不能正常运行。比如,LCD的显示,有时可以正常显示,有时连清屏都做不到。这是为什么呢?望高手可以给以解释。…

查看全部问答∨

菜鸟问题——LM3S9B96历程问题

刚刚玩这种板子,为什么9B96的历程在ARM 软件跑的时候都要修改PC,SP指针?不修改就不能正确运行程序 还有就是自己建的工程好像都不能正常运行。 历程里的map文件哪里来的? 有没有高手指点一二,谢谢了~…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

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

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved