历史上的今天
返回首页

历史上的今天

今天是:2024年11月01日(星期五)

正在发生

2021年11月01日 | stm32专题三十五:DAC

2021-11-01 来源:eefocus

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);  

}


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

推荐阅读

史海拾趣

B+B SmartWorx公司的发展小趣事

B+B SmartWorx的前身是B&B Electronics,一个在1981年成立的公司,起初主要为无线和有线网络提供设备连接解决方案。随着技术的快速发展,物联网和M2M连接的需求日益增长,B&B Electronics意识到必须进行创新以应对市场的变化。于是,公司开始致力于开发“边缘智能”技术,使网络连接设备更加智能、自主和响应迅速。这一创新转型使得公司在物联网行业中崭露头角,并在2015年决定将公司名称更改为B+B SmartWorx,以更好地反映其业务重心和技术方向。

Erocore Enterprise Co Ltd公司的发展小趣事

Erocore Enterprise Co Ltd公司自XXXX年在电子行业中创立之初,就专注于电子元件的研发和生产。公司创始人深知技术是企业发展的核心,因此投入大量资源用于技术研究和人才引进。在初创期,Erocore通过不断的技术创新,积累了一定的技术储备和行业经验,为其在后续的市场竞争中奠定了坚实的基础。

GSI Technology公司的发展小趣事

面对电子行业日益激烈的市场竞争和快速变化的市场需求,GSI Technology不断调整战略方向,积极应对挑战。公司加大在研发方面的投入,不断优化产品结构和生产工艺,提高产品质量和竞争力。同时,GSI还积极推动企业转型升级,向更加智能化、绿色化的方向发展。通过一系列的努力,GSI成功克服了行业内的诸多挑战,保持了持续稳定的发展态势。

Freeport Resources Enterprises Corp公司的发展小趣事

在21世纪初,Freeport Resources作为一家历史悠久的矿业公司,开始意识到电子材料市场的巨大潜力。公司决定利用其丰富的矿产资源和勘探经验,转向对电子级金属材料的探索与开发。通过深入研究和市场调研,Freeport Resources成功定位了高纯度铜、钴等金属在半导体、电路板等电子领域的应用,并逐步建立了从矿产开采到电子材料加工的完整产业链。这一转型不仅为公司带来了新的增长点,也使其在电子行业中崭露头角。

Electric Imp Inc.公司的发展小趣事

为了进一步提升品牌影响力和市场份额,Electric Imp Inc.公司开始实施国际化战略。公司先后在北美、欧洲、亚洲等地设立了研发中心和分支机构,以便更好地了解当地市场需求和技术趋势。同时,公司还积极参加国际展览、研讨会等活动,与全球同行交流经验、分享技术。这些努力使得公司的国际化水平不断提高。

ebm-papst公司的发展小趣事

在巩固欧洲市场的基础上,ebm-papst不断拓展全球市场,特别是亚洲市场。近年来,公司在亚洲市场的营收增长率一直保持在较高水平。为了进一步拓展亚洲市场,ebm-papst加大了在中国的产能建设,陆续在上海、西安等地进行扩建和新建产能。这些措施使得ebm-papst能够更好地满足亚洲市场的需求,并为其在全球市场的进一步发展奠定了坚实基础。

问答坊 | AI 解惑

创建Windows CE操作系统(二)

之前介绍过如何创建一个基本的Windows CE的平台,现在咱就上一次没有提到的部分进行一下补充定制并build OS。 首先,在VS2005 IDE中的View -> Other Windows -> Catalog Items中,添加或者删除相应的模块来完成OS定制,选项如下: 然后配置buil ...…

查看全部问答>

模拟乘法器(checked)

本帖最后由 辛昕 于 2018-4-8 22:59 编辑 关于这个东西,我后来其实从来没捡起过。 但是,也就没有必要惦记着了。 当然了,每次说到这个东西,都会想起,故人已去~ 在做运放的过程中,知道了一个叫做模拟乘法器的东西。 但是想上网看看这个东 ...…

查看全部问答>

dsPIC30F 在无传感器BLDC 控制中的应用

dsPIC30F 在无传感器BLDC 控制中的应用…

查看全部问答>

STC单片机PWM的实现方法与原理

昨晚给师弟讲课的内容,利用stc的一款单片机提供的pwm实现变频输出。程序将变频pwm输出到led上作测试。 #include sfr   CCON   = 0xD8; sfr   CMOD   = 0xD9; sfr   CL   &nb ...…

查看全部问答>

S3c2410 LCD nand flash 裸机 程序怎么写?

大家好 我也是刚接触Arm9 这几天在学S3c2410裸机程序 现在遇到一个问题:    从ADS1.2下借鉴过来的代码,通过arm-linux- 工具编译,然后通过Jflash-s3c2410 下载到nand flash ,但运行起来 LCD 始终不是希望的效果。 我把我的 ...…

查看全部问答>

谁要能整理下中九的BIN供大家下载,真是感激不尽啊!

谁要能整理下中九的BIN供大家下载,真是感激不尽啊!…

查看全部问答>

有人用过IXP2350做开发吗?帮忙看看呀~~~~

小弟最近要在ixp2350上做开发,板子是个叫ADI Engineering的公司的,无奈我按照说明书上将串口线和网线连号,接上电源,然后用minicom和hyper terminal 都试过,就是没反应…… 说明书上也没有说要别的什么设置啊~~ 有朋友做过这方面的东东没?? ...…

查看全部问答>

calibrate_delay 的头文件是什么

嵌入式开发,Linux系统,是可以在驱动里面调用calibrate_delay 这个函数的吧 不知道需要包含什么头文件…

查看全部问答>

我的移动硬盘使用时,怎么显示:"本地磁盘"啊?

求救:     我的移动硬盘使用时,怎么显示:\"本地磁盘\"啊?     而且打不开! 谁知道 怎么解决? 谢谢!!!…

查看全部问答>