原创 用TIMER+DMA+DAC写的一个简单DDS,能输出幅值频率可变的正弦波、三角波和锯齿波

2015-10-26 00:36 2242 19 19 分类: MCU/ 嵌入式
代码如下,小伙伴们也可以增加波形的类型,使其输出更多的波形
以下是代码片段:
#include "dac.h"
#include <math.h>

#define MAXWAVECNT 200
#define WAVECNT 100          //波形的阶数,阶数越大波形拟真度越高,频率会越低
u16  wavedatatab[MAXWAVECNT] = {0};	  //存储任意的波形数据
/*自定义波形数据生成
Amp为幅值 0~3.3V
offset为偏置  值0~3.3V
wavetype为波形类型:
                    0为正弦波
                    1为三角波
                    2为锯齿波
                   
*/
void GEN_WAVE(float Amp,float offset,u8 wavetype)
{
	u16 tempAmp = Amp*4096/3.3;	
	u16 tempoffset = offset*4096/3.3;
	u8 i;
	u16 step;
	switch(wavetype)
	{
		case 0:		for(i=0 ;i<WAVECNT;i++)
							{
							wavedatatab = (u16)( tempAmp*sin(2*3.14*i/WAVECNT)+tempoffset); 
							}
							break;
		case 1:	   step = tempAmp/(WAVECNT/2);
         			for(i=0 ;i<WAVECNT;i++)	
							{
								if(i<(WAVECNT/2))	wavedatatab= i*step+tempoffset;
								else wavedatatab = (WAVECNT-i)*step+tempoffset;
							}	
							break;
    case 2:		step = tempAmp/WAVECNT;		
              	for(i=0 ;i<WAVECNT;i++)	
							{
								wavedatatab= i*step+tempoffset;
							}		
              break;							
		default:break;		
		}
}	
										
void TIM2_Int_Init(u16 arr,u16 psc)
{
	RCC->APB1ENR|=1<<0;	//TIM2时钟使能    
 	TIM2->ARR=arr;  	//设定计数器自动重装值 
	TIM2->PSC=psc;  	//预分频器	  
	TIM2->CR1|=1<<7;   	//ARPE使能 
        TIM2->CR2 |=0x2<<4;    //TIMER更新做为TRGO源	
	TIM2->CR1 |=TIM_CR1_CEN;    //使能定时器2
}
void DAC_DMA_init(void)
{
	RCC->AHB1ENR|=1<<21;//DMA1时钟使能 
	DMA1_Stream5->PAR=(u32)&(DAC->DHR12R1);		//DMA外设地址
	DMA1_Stream5->M0AR=(u32)wavedatatab;		//DMA 存储器0地址
	DMA1_Stream5->NDTR=WAVECNT;		        //DMA 传输数量
	DMA1_Stream5->CR=0;			//先全部复位CR寄存器值 
	
	DMA1_Stream5->CR|=1<<6;		//存储器到外设模式
	DMA1_Stream5->CR|=1<<8;		//循环模式
	DMA1_Stream5->CR|=0<<9;		//外设非增量模式
	DMA1_Stream5->CR|=1<<10;		//存储器增量模式
	DMA1_Stream5->CR|=1<<11;		//外设数据长度:16位
	DMA1_Stream5->CR|=1<<13;		//存储器数据长度:16位
	DMA1_Stream5->CR|=1<<16;		//中等优先级
	DMA1_Stream5->CR|=0<<21;		//外设突发单次传输
	DMA1_Stream5->CR|=0<<23;		//存储器突发单次传输
	DMA1_Stream5->CR|= 0x7<<25;//通道选择
	DMA1_Stream5->CR|= 1<< 0;//开DMA
}

//DDS初始化
void Dac1_Init(void)
{  	
	RCC->APB1ENR|=1<<29;   	//使能DAC时钟	   
	RCC->AHB1ENR|=1<<0;  	//使能PORTA时钟	  
	GPIO_Set(GPIOA,PIN4,GPIO_MODE_AIN,0,0,GPIO_PUPD_PU);//PA4,模拟输入,下拉   

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

void SET_DAC_FRQ(u16 frq)
{
	TIM2->CR1 &=~TIM_CR1_CEN;
 	TIM2->ARR = frq;
	TIM2->CR1 |=TIM_CR1_CEN;
}

void DDS_Output_Wave(float Amp,float offset,u8 wavetype,u16 frq)
{
	DMA1_Stream5->CR&= ~(1<< 0);//关DMA
	GEN_WAVE(Amp,offset,wavetype);
	SET_DAC_FRQ(frq);
	DMA1_Stream5->CR|= (1<< 0);//关DMA
}
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
19
关闭 站长推荐上一条 /3 下一条