OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 34211|回复: 34

DAC+DMA(1k-25k)任意正弦波输出

[复制链接]

13

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
130
金钱
130
注册时间
2013-1-28
在线时间
0 小时
发表于 2013-8-14 11:30:51 | 显示全部楼层 |阅读模式

  经过一天不懈的努力,终于搞出来了,本人用TIME4触发DAC实现DMA传输产生正弦波(100点),经测试误差1HZ,主要代码如下:

void DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
 u32 DR_Base;  //做缓冲用,不知道为什么.非要不可
 RCC->AHBENR|=1<<1;//开启DMA2时钟
 __nop();                    //等待 DMA1 时钟稳定
    __nop();                    //经测试最少 2 个 nop
    __nop(); 
 DR_Base=cpar;
 DMA_CHx->CPAR=DR_Base;   //DMA1 外设地址
 DMA_CHx->CMAR=(u32)cmar; //DMA1,存储器地址
 DMA1_MEM_LEN=cndtr;      //保存DMA传输数据量
 DMA_CHx->CNDTR=cndtr;    //DMA1,传输数据量
 DMA_CHx->CCR=0X00000000;//复位
 DMA_CHx->CCR|=1<<4;  //从存储器读
 DMA_CHx->CCR|=1<<5;  //循环模式
 DMA_CHx->CCR|=0<<6;  //外设地址非增量模式
 DMA_CHx->CCR|=1<<7;  //存储器增量模式
 DMA_CHx->CCR|=1<<8;  //外设数据宽度为16位
 DMA_CHx->CCR|=1<<10; //存储器数据宽度16位
 DMA_CHx->CCR|=1<<12; //中等优先级
 DMA_CHx->CCR|=0<<14; //非存储器到存储器模式 
 
 DMA_CHx->CCR|=1<<1;  //允许完成中断
// DMA_CHx->CCR|=1<<2;  //允许半完成中断
 DMA_CHx->CCR|=1<<0;  //开启DMA传输
 
 MY_NVIC_Init(1,3,DMA2_Channel3_IRQChannel,2);
// MYDMA2_Enable(DMA2_Channel3);    
}
//开启一次DMA传输
void DMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
 DMA_CHx->CCR&=~(1<<0);       //关闭DMA传输
 DMA_CHx->CNDTR=DMA1_MEM_LEN; //DMA1,传输数据量
 DMA_CHx->CCR|=1<<0;          //开启DMA传输


void Dac1_Init(void)
{
 RCC->APB2ENR|=1<<2;    //使能PORTA时钟    
 RCC->APB1ENR|=1<<29;   //使能DAC时钟    
     
 GPIOA->CRL&=0XFF00FFFF;
 GPIOA->CRL|=0X00000000;//PA4 PA5模拟输入    

 DAC->CR|=1<<0; //使能DAC1
 DAC->CR|=1<<1; //DAC1输出缓存不使能 BOFF1=1
 DAC->CR|=1<<2; //使用触发功能 TEN1=0
 DAC->CR|=5<<3; //(0101)DAC TIM6 TRGO,不过要TEN1=1才行
 DAC->CR|=0<<6; //不使用波形发生
 DAC->CR|=0<<8; //屏蔽、幅值设置
 DAC->CR|=1<<12; //DAC1 DMA使能

 DAC->DHR12R1=0;
 DAC->DHR12R2=0;
}

void Timerx_Init(u16 arr,u16 psc)
{
 RCC->APB1ENR|=1<<2;//TIM4时钟使能  
 __nop();
 __nop();
  TIM4->ARR=arr;  //设定计数器自动重装值//刚好1ms   
 TIM4->SC=psc;  //预分频器7200,得到10Khz的计数时钟
 //TIM2->CR1=0x8000; //ARPE使能 
 TIM4->CR2|=3<<4;    //比较脉冲 (必须要)
 //TIM2->CR1|=1<<2;         
 TIM4->CR1|=0x01;    //使能定时器2    
}
while(1)

{

        DMA_Config(DMA2_Channel3,(u32)&DAC->DHR12R1,(u32)Sine12bit,100); 
       DMA_Enable(DMA2_Channel3);
     Dac1_Init();
     f = 800; 
     Timerx_Init(720000/f,0);

}

f表示频率,PA4输出

 

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
106
金钱
106
注册时间
2016-1-31
在线时间
23 小时
发表于 2017-2-13 09:02:58 | 显示全部楼层
sweetstandard 发表于 2017-2-8 06:28
这个程序,两个DAC用同一个触发源,频率一定是相同的。我用不同的触发源,比如:DAC1用T6触发,DAC1用T7触 ...

开两个DMA通道试试
回复 支持 1 反对 0

使用道具 举报

13

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
130
金钱
130
注册时间
2013-1-28
在线时间
0 小时
 楼主| 发表于 2013-8-14 11:36:13 | 显示全部楼层
回复【楼主位】浮夸:
---------------------------------
不加while()
回复 支持 反对

使用道具 举报

51

主题

1455

帖子

3

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2613
金钱
2613
注册时间
2011-1-25
在线时间
176 小时
发表于 2013-8-14 12:38:42 | 显示全部楼层
谢谢分享。。
一直努力就很好。
回复 支持 反对

使用道具 举报

71

主题

467

帖子

0

精华

高级会员

Rank: 4

积分
800
金钱
800
注册时间
2011-11-18
在线时间
5 小时
发表于 2013-8-14 14:06:02 | 显示全部楼层
标注给力
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-8-14 16:11:00 | 显示全部楼层
楼主用DMA。如何控制输出波形的频率的?

看代码,楼主的定时器是用来触发一次DMA传输,并不是触发一个点数据的传送。
我觉得这并不能输出任意波形的sin波形才对。
DAC和DMA的速度是固定的,在10Khz和1Khz下,输出正弦波的点速度一样,那么怎么产生不同的正弦波?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

13

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
130
金钱
130
注册时间
2013-1-28
在线时间
0 小时
 楼主| 发表于 2013-8-14 16:53:37 | 显示全部楼层
回复【5楼】正点原子:
---------------------------------
溢出一次就触发一次dac,改变TIM4->ARR的值改变频率,经测试很好用,主要是误差很小很小。

STM32 可调正弦波发生程序(DMA).zip

1.95 MB, 下载次数: 7774

回复 支持 反对

使用道具 举报

13

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
130
金钱
130
注册时间
2013-1-28
在线时间
0 小时
 楼主| 发表于 2013-8-14 17:04:57 | 显示全部楼层
回复【6楼】浮夸:
---------------------------------
貌似是触发一次DAC,DMA只传一个数据,而不是传所写长度的数据。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-8-14 22:05:18 | 显示全部楼层
回复【7楼】浮夸:
---------------------------------
哦,那就对了。
如果触发一次,就完成一次DMA的所有传输,那就肯定不好设置频率的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

4

主题

55

帖子

0

精华

初级会员

Rank: 2

积分
101
金钱
101
注册时间
2013-8-8
在线时间
2 小时
发表于 2013-8-15 17:09:52 | 显示全部楼层
打点计数器啊! 能设置再快点吗?  1ms 输出太慢了吧?
回复 支持 反对

使用道具 举报

13

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
130
金钱
130
注册时间
2013-1-28
在线时间
0 小时
 楼主| 发表于 2013-8-15 19:39:38 | 显示全部楼层
回复【9楼】zxc2769:
---------------------------------
时间间隔是自己设的,你的计数器的值和输出的频率是一个函数关系(程序里面给出来了),理论是可以做到很高很高的频率,不过内部DA速度跟不上,再加上点数(100点),所以最高频率也就25k左右。
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
21
金钱
21
注册时间
2013-9-17
在线时间
0 小时
发表于 2013-9-17 10:55:21 | 显示全部楼层
回复【6楼】浮夸:
---------------------------------
回复【6楼】浮夸:

回复【5楼】正点原子:
---------------------------------
溢出一次就触发一次dac,改变TIM4->ARR的值改变频率,经测试很好用,主要是误差很小很小。

---------------------------------
假如每传一个数据就要重新触发的话,那还用什么DMA呀,直接在定时器中断中更新DAC的值不是更简便....
回复 支持 反对

使用道具 举报

45

主题

248

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
448
金钱
448
注册时间
2013-5-18
在线时间
0 小时
发表于 2014-2-6 21:36:45 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

45

主题

248

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
448
金钱
448
注册时间
2013-5-18
在线时间
0 小时
发表于 2014-2-6 21:38:29 | 显示全部楼层
寄存器,我喜欢
回复 支持 反对

使用道具 举报

11

主题

81

帖子

0

精华

高级会员

Rank: 4

积分
652
金钱
652
注册时间
2012-8-1
在线时间
68 小时
发表于 2014-2-9 13:01:50 | 显示全部楼层
很好的资料,谢谢分享
回复 支持 反对

使用道具 举报

13

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
130
金钱
130
注册时间
2013-1-28
在线时间
0 小时
 楼主| 发表于 2014-4-9 20:32:06 | 显示全部楼层
回复【11楼】verymao:
---------------------------------
定时器产生TRGO时间触发DAC和DMA传输都不需要CPU的干涉,不暂用资源,加快速度
回复 支持 反对

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2013-7-18
在线时间
24 小时
发表于 2014-9-12 14:19:14 | 显示全部楼层
回复【7楼】浮夸:
---------------------------------
程序下载测试过,的却可以!但是从DMA的理解来看,应该是一次DMA传送100个数据,只是DAC转换的速度由定时器决定,难道DAC内部有缓冲,DMA把100个数据送给DAC了,DAC再慢慢根据定时器频率来做转换吗,这里没搞明白!
回复 支持 反对

使用道具 举报

20

主题

102

帖子

0

精华

初级会员

Rank: 2

积分
183
金钱
183
注册时间
2013-7-17
在线时间
30 小时
发表于 2014-9-25 11:45:51 | 显示全部楼层
回复【16楼】fs_ding:
---------------------------------
测试过了?为啥我的测不到波形啊??必须要加上显示屏么?
回复 支持 反对

使用道具 举报

27

主题

259

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
387
金钱
387
注册时间
2014-8-19
在线时间
0 小时
发表于 2014-10-4 21:21:44 | 显示全部楼层
回复【10楼】浮夸:
---------------------------------
能做到25K?失真度怎样?
回复 支持 反对

使用道具 举报

3

主题

11

帖子

0

精华

新手上路

积分
43
金钱
43
注册时间
2014-8-23
在线时间
0 小时
发表于 2014-10-5 11:36:49 | 显示全部楼层
正弦波的话,pwm加个滤波器比较好控制吧
回复 支持 反对

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2013-7-18
在线时间
24 小时
发表于 2014-10-6 17:57:32 | 显示全部楼层
回复【17楼】雨思小米粥:
---------------------------------
跟显示屏没关系吧,需要的话我可以给你发段代码。
回复 支持 反对

使用道具 举报

6

主题

40

帖子

0

精华

初级会员

Rank: 2

积分
101
金钱
101
注册时间
2014-7-18
在线时间
4 小时
发表于 2015-7-6 11:10:04 | 显示全部楼层
回复【20楼】fs_ding:
---------------------------------
发段给我吧 946053464
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2015-12-2
在线时间
1 小时
发表于 2015-12-2 11:56:32 | 显示全部楼层
谢谢楼主的分享
回复 支持 反对

使用道具 举报

2

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
56
金钱
56
注册时间
2015-11-18
在线时间
7 小时
发表于 2015-12-16 21:51:06 | 显示全部楼层
回复【8楼】正点原子:
---------------------------------
原子哥,DMA是一次直接把所有数据给到DMA的缓冲,然后DAC按定时触发频率一个一个读DMA缓冲的数据吗?看了代码,没有对DMA数据传输的寄存器配置,手册上也没说,
回复 支持 反对

使用道具 举报

2

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
56
金钱
56
注册时间
2015-11-18
在线时间
7 小时
发表于 2015-12-16 22:20:19 | 显示全部楼层
。。DMA_InitStructure.DMA_BufferSize=65536
这东西设置了,好像DMA通道就有65536个寄存器暂存缓冲值了?  
回复 支持 反对

使用道具 举报

18

主题

79

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
283
金钱
283
注册时间
2015-11-12
在线时间
54 小时
发表于 2016-5-6 14:37:00 | 显示全部楼层
你产生25K的波形时,定时器的溢出时间是多少?能达到25K么,DAC的转换时间不是限定了它的最高频率么?
回复 支持 反对

使用道具 举报

2

主题

394

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2115
金钱
2115
注册时间
2012-5-8
在线时间
314 小时
发表于 2016-7-6 17:08:00 | 显示全部楼层
谢谢分享!
回复 支持 反对

使用道具 举报

0

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
99
金钱
99
注册时间
2016-2-21
在线时间
20 小时
发表于 2016-7-6 18:41:16 | 显示全部楼层
谢谢分享,很少见到用寄存器写的,我也是用寄存器
回复 支持 反对

使用道具 举报

0

主题

25

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2016-3-6
在线时间
43 小时
发表于 2017-2-8 06:20:25 | 显示全部楼层
浮夸 发表于 2013-8-15 19:39
回复【9楼】zxc2769:
---------------------------------
时间间隔是自己设的,你的计数器的值和输出的频率 ...

应该是 2.5 KHZ 吧?
事在人为,顺势而为。
回复 支持 反对

使用道具 举报

0

主题

25

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2016-3-6
在线时间
43 小时
发表于 2017-2-8 06:21:39 | 显示全部楼层
pthread 发表于 2016-5-6 14:37
你产生25K的波形时,定时器的溢出时间是多少?能达到25K么,DAC的转换时间不是限定了它的最高频率么?

估计他此处有笔误,应该是 2.5 KHZ
事在人为,顺势而为。
回复 支持 反对

使用道具 举报

0

主题

25

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2016-3-6
在线时间
43 小时
发表于 2017-2-8 06:28:24 | 显示全部楼层
这个程序,两个DAC用同一个触发源,频率一定是相同的。我用不同的触发源,比如:DAC1用T6触发,DAC1用T7触发,两个DAC输出的两个SIN波形是都得到了,但频率却不符合预先设计值,我设定的T6频率10KHZ,T7频率20KHZ,输出的结果是,两个DAC频率都是30KHZ。目前还没查出此诡异之理。
事在人为,顺势而为。
回复 支持 反对

使用道具 举报

0

主题

25

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2016-3-6
在线时间
43 小时
发表于 2017-3-22 09:29:36 | 显示全部楼层
本帖最后由 sweetstandard 于 2017-3-22 09:32 编辑

谢谢,问题已经解决。之前是误解了“双DAC"的含义,以为”双DAC“是使用两个独立的DAC呢,其实”双DAC“是同时触发两个DAC。之后,我用了单独两个DAC,问题就解决了。
具体程序如下,希望有朋友能借鉴到。

#include "dac.h"
#include "dma.h"
//-------------------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;                                      // 端口配置 PA-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_T6_TRGO;        //使用触发功能 TEN1=1
        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值
        
       MY_DAC1_DMA_Config();        
        
}
//-------------------DAC 通道 2 输出初始化-------------------------------------
void Dac2_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_5;                                      // 端口配置 PA-5
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                     //模拟输入
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        GPIO_SetBits(GPIOA,GPIO_Pin_5)        ;                     //PA.5 输出高
        
        DAC_InitType.DAC_Trigger=DAC_Trigger_T7_TRGO;        //使用触发功能 TEN1=1
        DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
        DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
        DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //Dac2输出缓存关闭 BOFF1=1

        DAC_Init(DAC_Channel_2,&DAC_InitType);  //初始化DAC通道2
        DAC_Cmd(DAC_Channel_2, ENABLE);         //使能Dac2
        DAC_SetChannel2Data(DAC_Align_12b_R, 0);//12位右对齐数据格式设置DAC值
        
        MY_DAC2_DMA_Config();               
}
事在人为,顺势而为。
回复 支持 反对

使用道具 举报

5

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
70
金钱
70
注册时间
2017-2-15
在线时间
11 小时
发表于 2017-4-9 22:09:05 | 显示全部楼层
void Timerx_Init(u16 arr,u16 psc)
请问定时器溢出周期与正弦波形周期有什么关系啊?定时器溢出周期是DAC输出一个点的时间,还是DAC输出100个点的时间啊?
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2017-9-20
在线时间
8 小时
发表于 2017-12-22 15:11:55 | 显示全部楼层

请问你输出正弦波的频率调整精度是多少,可以每次调整1HZ吗?
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2019-5-29
在线时间
19 小时
发表于 2019-5-29 20:16:55 | 显示全部楼层
好东西
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-18 07:50

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表