STM32 基DMA的DAC波形发生器

DAC是STM32系列的一个基本外设,可以将数字信号转化成模拟信号,这次我将使用DAC来输出一个特定波形。

首先确定工作方法,由于我目前在做的简易示波器在输出波形的同时还需要显示输入信号,所以不能占用太多CPU时间,于是就选用了基于DMA的ADC。

使用DMA只需告诉DMA外设它要怎么搬移数据就可以处理其他事。

首先定义一下

#define DAC_DHR12R1    (u32)&(DAC->DHR12R1)   //DAC DATA buff

作为DMA的外设数据地址

首先是初始化输出管脚

DAC1对应PA4

void Wave_GPIO_Config(void)//DAC!-------PA5
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4 ;
    GPIO_SetBits(GPIOA,GPIO_Pin_4)  ;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

需要注意的是,ST官方文档上的说明

一旦使能DACx通道,相应的GPIO引脚(PA4或者PA5)就会自动与DAC的模拟输出相连
(DAC_OUTx)。为了避免寄生的干扰和额外的功耗,引脚PA4或者PA5在之前应当设置成模拟输
入(AIN)。

然后是DAC外设的初始化

void Wave_DAC_Config( void)
{
    DAC_InitTypeDef            DAC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);

    DAC_StructInit(&DAC_InitStructure);
    DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;//不使用波形发生器
    DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
    DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;//TIM2 Trigger
    DAC_Init(DAC_Channel_1, &DAC_InitStructure);
    DAC_Cmd(DAC_Channel_1, ENABLE);
    DAC_DMACmd(DAC_Channel_1, ENABLE);
}

DAC_OutputBuffer,即是否使用输出缓存。输出缓存的功能主要用来减小输出阻抗,是STM32的DAC无需外部运放就可以直接驱动负载。(一般不用,因为不确定要求

使用TIM2来触发一次DAC,DAC的输出缓存有两个,一个是DAC_DORx ,用户不能直接写入,另一个是DAC_DHRx (DAC_DHR8Rx、 DAC_DHR12Lx、 DAC_DHR12Rx、 DAC_DHR8RD、DAC_DHR12LD、或者DAC_DHR12RD寄存器 )如果没有选中硬件触发 ,存入寄存器DAC_DHRx的数据会在
一个APB1时钟周期后自动传至寄存器DAC_DORx。如果选中硬件触发 ,数据传输在触发发生以后3个APB1时钟周期后完成。

下面是TIM初始化,TIM的工作决定了DMA与DAC的工作频率

void Wave_TIM_Config(u32 Wave1_Fre)//TIM2 Init
{
    TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.TIM_Prescaler = 0x0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
    TIM_TimeBaseStructure.TIM_Period = Wave1_Fre;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
}

默认情况下TIM的时钟频率为36Mhz,经过分频为36M/((Prescaler+1)*ClockDivision)。

当计数溢出时就会产生触发事件,TIM_TRG

接着是DMA的初始化
void Wave_DMA_Config(uint16_t* wave)//DMA2
{
    DMA_InitTypeDef            DMA_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);

    DMA_StructInit( &DMA_InitStructure);
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//peripherals  to memory
    DMA_InitStructure.DMA_BufferSize = 512;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R1;
     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)wave;

     DMA_Init(DMA2_Channel3, &DMA_InitStructure);
     DMA_Cmd(DMA2_Channel3, ENABLE);

}

对于DMA要搞清楚要搬的数据的地址在哪,要搬到哪,这里要搬的数据在存储器中,地址为(uint32_t)wave,外设地址为DAC_DHR12R1,是从内存到外设,所以工作模式为

DMA_DIR_PeripheralDST,为双向传输,禁止M2M,存储至存储。触发源为TIM2

最后为总体调用
void Wave_Init(uint16_t* wave)
{
  Wave_GPIO_Config();
  Wave_TIM_Config(3000);            //72000000/3000=24000 points per second
  Wave_DAC_Config();
  Wave_DMA_Config(wave);
  TIM_Cmd(TIM2, ENABLE);
}

总结:多看官方文档,程序分段写函数



原文地址:https://www.cnblogs.com/geek-wireless/p/STM32_DAC.html

时间: 2024-10-07 02:33:28

STM32 基DMA的DAC波形发生器的相关文章

【STM32H7教程】第60章 STM32H7的DAC应用之定时器触发实现DMA方式双通道波形

完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第60章       STM32H7的DAC应用之定时器触发实现DMA方式双通道波形 本章节为大家讲解DAC采用定时器触发方式实现DMA双通道波形输出,实际输出效果也比较好,项目使用价值也比较大. 60.1 初学者重要提示 60.2 H7和F4的DAC输出效果对比 60.3 DAC驱动设计 60.4 DAC驱动移植和使用 60.5 实验例程设计框架 60.6 实验例程

STM32外设DMA使用总结

STM32外设DMA使用总结: 1.根据需要选择DAM模式: (1)循环模式-DMA_Mode =  DMA_Mode_Circular (2)正常模式-DMA_Mode =  DMA_Mode_Normal 2.对于DMA1的Chanel3,对应外设为USART3的RX 试想:如果串口接收中断和DAM中断同时打开,CPU如何相应? (1)中断优先级不同:这好说,支持嵌套中断(NVIC)的Cortex-M3自然优先服务中断优先级高的 (2)中断优先级相同:处理原则,先来先处理:若同时到来,中断号

基于FPGA的DDS任意波形发生器设计

一.简介 DDS技术最初是作为频率合成技术提出的,由于其易于控制,相位连续,输出频率稳定度高,分辨率高, 频率转换速度快等优点,现在被广泛应用于任意波形发生器(AWG).基于DDS技术的任意波形发生器用高速存储器作为查找表,通过高速D/A转换器来合成出存储在存储器内的波形.所以它不仅能产生正弦.余弦.方波.三角波和锯齿波等常见波形,而且还可以利用各种编辑手段,产生传统函数发生器所不能产生的真正意义上的任意波形. 二.原理 根据傅立叶变换定理可知,任何周期信号都可以分解为一系列正弦或余弦信号之和,

STM32之DMA+ADC

借用小甲鱼的经典:各位互联网的广大网友们.大家早上中午晚上好..(打下小广告,因为小甲鱼的视频真的很不错).每次看小甲鱼的视频自学都是比较轻松愉快的..我在想,如果小甲鱼出STM32的视频,我会一集不漏的听的.哈.好了..学习到了STM32的DMA模块..琢磨了一下中文参考手册,官方是这样描述的: 直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输.无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作. 是的,无需CPU干预,可以想

STM32之DMA

一.DMA简介 1.DMA简介 DMA(Direct Memory Access:直接内存存取)是一种可以大大减轻CPU工作量的数据转移方式. CPU有转移数据.计算.控制程序转移等很多功能,但其实转移数据(尤其是转移大量数据)是可以不需要CPU参与.比如希望外设A的数据拷贝到外设B,只要给两种外设提供一条数据通路,再加上一些控制转移的部件就可以完成数据的拷贝. DMA就是基于以上设想设计的,它的作用就是解决大量数据转移过度消耗CPU资源的问题.有了DMA使CPU更专注于更加实用的操作--计算.

数字化仪与任意波形发生器的混合模式选项现已开启

--背负式模块新增16条数字线路 德国汉斯多尔夫,2019年9月18日讯--德国Spectrum仪器今日宣布旗下最新系列的16位数字化仪与任意波形发生器(AWG)均开启可选模块,该模块为模拟数据新增了16条同步数字线.新增的数字线使数字化仪和任意波形发生器卡的4条多功能XIO线得到了充分的扩展.这将意味着高达20条可完全编程的XIO线能够作为数字化仪的同步数字输入和任意波形发生器的同步数字输出,或异步I/O线.状态行(status line)甚至额外的触发器输入. 数字化仪与任意波形发生器的混合

STM32 使用DMA+DAC+TIMER 输出正弦波

之前已经简单论述过,根据我个人菜鸟的了解与认识,对之前的知识进行整理回顾: DMA:我的理解就是一个通道,或者是一座桥梁.在静态内存到静态内存,或者外设到静态内存间的一个通讯的通道.建立这个通道的好处是:可以抛开CPU,不占用CPU的资源,直接使用这块内存的内容,速度也会加快. DAC:STM32F103中有两个DAC,可以同时使用.DAC的作用就是将数字量转化为模拟量(电压),在这就不作太多的讲解. TIMER:定时器.不作讲解. 那么对于使用DMA+DAC+TIMER产生正弦波的原理或过程,

STM32 UART DMA实现未知数据长度接收

串口通信是经常使用到的功能,在STM32中UART具有DMA功能,并且收发都可以使用DMA,使用DMA发送基本上大家不会遇到什么问题,因为发送的时候会告知DMA发送的数据长度,DMA按照发送的长度直接发送就OK了,但是使用DMA接收时候就不同了,因为有时候数据接收并不是每一次都是定长的,但是DMA只在接收数据长度和设定数据长度相同的时候才可以触发中断,告诉MCU数据接收完毕,针对这个问题,解决方法如下,有一点复杂,但是很管用. UART在传输一个字节的时候,首先拉低,传输起始位,然后在是LSB

STM32 ADC DMA 中断模式多通道读取ADC转换值

因为做一个电机控制项目,其中需要用到用PWM触发ADC,读取ADC的转换值. 这里有两个关键问题: 第一,如何使PWM触发ADC转换? 第二,如何在ADC多通道扫描模式下,读取各个channel的adc转换值? 第三,如何使用DMA读取多通道ADC转换值? 第一个问题,首先需要将ADC设置成外部触发转换,第二需要选择触发是发生在Timer的上升沿还是下降沿.程序如下: adc.ADC_Resolution = ADC_Resolution_12b; adc.ADC_ScanConvMode =E