电赛准备DDS & AD9910模块数据手册、使用方法详解

   日期:2020-09-23     浏览:355    评论:0    
核心提示:写在前面 --Fraay大家好我又来了,本次带来的是AD9910模块的数据手册、使用方法详解,以及如何根据AD9910的原理进行编程,实现DDS的功能。这次文章可以说是对数据手册的一个整理,也是对我自己这一阶段学习的一个记录。其实网上有现成的例程供各位参考,甚至只需要修改引脚便可使用,但是本着学习的态度,还是很有必要深入了解数据手册,并且对应着数据手册来看别人代码的底层,是如何控制相应寄存器来完成功能的。这也是可编程芯片的魅力所在吧!硬件/软件准备使用的是康威电子的AD9910...

写在前面        --Fraay

大家好我又来了,本次带来的是AD9910模块的数据手册、使用方法详解,以及如何根据AD9910的原理进行编程,实现DDS的功能。这次文章可以说是对数据手册的一个整理,也是对我自己这一阶段学习的一个记录。

其实网上有现成的例程供各位参考,甚至只需要修改引脚便可使用,但是本着学习的态度,还是很有必要深入了解数据手册,并且对应着数据手册来看别人代码的底层,是如何控制相应寄存器来完成功能的。这也是可编程芯片的魅力所在吧!

硬件/软件准备

使用的是康威电子的AD9910模块,淘宝店有卖的,如图

这个板子300+的价格,工艺是十分精良的,有条件的可以入手一块;条件不够可以不买,仅仅来学习也是非常好的一个平台。

(千万不要试图自己用覆铜板做,因为会出现很多pcb布局布线的问题,导致失败。毕竟单独的AD9910芯片价格也在100+)

 

单片机我选择的是STM32ZET6,不过这个并不是必须的,只是因为我开发板恰好是这个型号的,控制这个模块只需要13个(大约)管脚就够了用万能的C8T6也可以实现。

软件我使用的是CUBEMX,我没有工程模板并且很懒CUBEMX有强大的代码自动配置功能,并且十分稳定不会出错,代码系统化,可维护性高,使用十分方便。

硬件介绍

如图

数据手册详述(部分功能)

AD9910的数据手册英文版一共65页,我学习的时候是硬啃的,现在好在有中文翻译版,我就按照中文版进行再次翻译成人话(我认为能被更好的理解的并表达方式)不过大家有时间还是应该多多训练阅读英文数据手册的能力。

总体概述

如图,说白了就是最多400M的模拟输出;串行/并行数据通信;扫频/扫幅等;应用领域:本振产生;雷达的线性调频chrip的生成等。

管脚

先跳过管脚的含义,因为管脚配置跟完成的功能息息相关,100+个管教很多都是可以固定配置死的,而且若详细描述各个管脚篇幅过长,所以在应用中讲配置管脚。

工作模式

重点来了,AD9910的四种工作模式由于篇幅的考虑,这次文章只记录最AD9910模块最实用的单频调制功能。

单频调制

说白了就是我直接通过32给他传数据,规定他的振幅/频率/相位,他按照我给的参数来输出相应的正弦波

原理

那我32把数据传给谁?

答案是8个内部编程寄存器Profile 0-7。

如何选择我要往那个寄存器里面读和写?

答案是利用外部引脚PROFILE[2:0]进行选择(这就是我之前说的在应用中讲管脚)

32在PROFILE输出000那就是选择profile0,001->profile1......

并且在下一个时钟上升沿自动更新profile0-7的数据

AD9910怎么计算输出的振幅/频率/相位?

如图,说白了就是f_sysclk平均分成2^32份,输出频率等于FTW *(f_sysclk / 2^32)

此处需要注意的是,FTW是32位的,但是他最多只能表示0-2^31-1这么多的数,因为奈奎斯特采样频率的限制,最多取1/2的f_sysclk才能还原信号。

如图,幅度和相位跟频率类似,这里的POW就相当于FTW,而ASF表示相对于满量程的比例因子,输出的幅度(14位ADC)即

(ASF/2^14)* 满量程输出的幅度

 

写到这基本单频调制模式的基础已经明了了具体步骤如下

配置管脚信息(32发控制字给dds)使模块为单频调制模式->给确定的profile0-7(任意一个即可,不过要和你FROFILE引脚配置的相符)寄存器写值->发送ioupdate信号更新数据->输出

通信协议

可以看出32必须要与dds通信才可以实现功能,因此就要涉及串行数据的传递(先不考虑并行接口的使用)

这一段话我们知道了通信包含写指令+写数据,指令包括地址+读写位,并且完成同i性能之后要更新ioupdate

上图是指令的具体格式

上图是相关的通信管脚

说白了就是先要复位ioreset,拉低cs,然后32模拟一个时钟,MSB/LSB传输,每当输出完成之后要ioupdate

这样看起来一点都不直观,那就说一点人话,贴底层发送代码

//======================八位发送程序================================
void txd_8bit(uchar txdat)
{
	uchar i,sbt;
	sbt=0x80;
	SCLK=0;
	for (i=0;i<8;i++)
	{
		if ((txdat & sbt)==0) 
			AD9910_SDIO=0; 
		else 
			AD9910_SDIO=1;
		SCLK=1;
		sbt=sbt>>1;
		SCLK=0;
	}
}  

代码+时序图可以看到:首先sclk=0(空闲),0x80=1000_0000。8个循环内,把发送数组跟sbt相与看是否最高位是0(其他位肯定都为0)是的话就操作SDIO=0,否则SDIO=1,然后sclk拉高,数据成功发送,紧接着把sbt右移一位变成0100_0000判断tsdat第二位,进行发送。以此类推完成8位数组的发送,可见完全符合上图的通信协议

 

给谁通信?

搞明白传数据的流程之后,下面就要涉及到给谁传数据?

下面介绍一系列需要通信的寄存器

3个CRF寄存器

上图三张位于PDF的第50页,有兴趣的话可以看看

CRF我自己的理解就是先对AD9910进行一个模式的配置,不给参数,主要是决定他的初始化设置,具体每一位怎么配置,有什么功能,都在PDF的55页。这个表格太长了而且很详细,就不描述了.

但是我们通过这个表格可以知道,我要往0x00/01/02这三个地址依次写数据,回答了给谁通信的问题。

还是贴底层代码来看通信过程

//======================ad9910发送cfr控制字=======================
//crf1/2/3的值所代表的含义,在PDF55页有详细描述,根据配置需求来
//我这里用的值适应于单频调制功能
//uchar cfr1[]={0x00,0x40,0x00,0x00};       //cfr1
//uchar cfr2[]={0x01,0x00,0x00,0x00};       //cfr2
//const uchar cfr3[]={0x05,0x0F,0x41,0x32};       //cfr3 40M 输入时钟 25倍频  VC0=101               
                                                  //ICP=001;
void Txcfr(void)
{
	uchar m,k;

	CS=0;
	txd_8bit(0x00);    //cfr1地址
	for (m=0;m<4;m++)
		txd_8bit(cfr1[m]); 
	CS=1;  
	for (k=0;k<10;k++);
	
	CS=0;
	txd_8bit(0x01);    //cfr2地址
	for (m=0;m<4;m++)
		txd_8bit(cfr2[m]); 
	CS=1;  
	for (k=0;k<10;k++);

	CS=0;
	txd_8bit(0x02);    //cfr3地址
	for (m=0;m<4;m++)
		txd_8bit(cfr3[m]); 
	CS=1;
	for (k=0;k<10;k++);

	UP_DAT=1;
	for(k=0;k<10;k++);
	UP_DAT=0;
	delay_ms(1);
}         

上图根据前面的内容不难理解,分别经历了片选cs,写命令,写数据,ioupdate操作。

 

Profile 0寄存器

把CRF配置好了之后,AD9910初始化也就成功了,已经进入单频调制功能了

接下来由于总体程序里面写了PROFILE1/2/3=0,即选中了profile0这个寄存器,所以就要往这个寄存器里面写数据

上图位profile0的描述,可以看到地址是0x0E,一共64个位,不同的位代表不同的意思,这个就是单频调制的参数选择,然后AD9910就会自动按照这个参数产生正弦波。

同样,贴底层

//===================设置频率===================//
void Freq_convert(ulong Freq)
{
	ulong Temp;
	if(Freq > 400000000)
		Freq = 400000000;
	Temp=(ulong)Freq*4.294967296; //  4.294967296=(2^32)/1000000000 
                                  //  把1G的内部时钟分为2^32份
	profile0[7]=(uchar)Temp;     //可以看到profile0在频率控制字一共有4个字节
	profile0[6]=(uchar)(Temp>>8);//所以分四次发送
	profile0[5]=(uchar)(Temp>>16);
	profile0[4]=(uchar)(Temp>>24);
	Txprofile();
}

//===================ad9910·发送profile0控制字======================
void Txprofile(void)
{
	uchar m,k;

	CS=0;
	txd_8bit(0x0e);    //profile0地址
	for (m=0;m<8;m++)
		txd_8bit(profile0[m]); //分8次把所有的profile0数据全发送出去
	CS=1;
	for(k=0;k<10;k++);//等待

	UP_DAT=1;
	for(k=0;k<10;k++);//等待
	UP_DAT=0;
	delay_ms(1);
}   

上图只是写了设置频率的部分,设置幅度和相位同理。

把这些部分完成之后,AD9910就会以单频调制的模式输出固定参数的正弦波,也就达到了dds的基本功能,后面再接混频电路或者其他的设计都可以。

 

总结一下,单频调制的步骤发送cfr1/2/3->发送profile0

结尾

以上内容介绍了单频调制如何实现,并且讲解了底层最重要的代码的原理,希望大家看了之后会对代码完成的工作有个具体的认识。后面的RAM、DRG等功能可以参考数据手册的相关章节。放出我自己的单频调制程序+数据手册,如果无法上传的话,,需要的可以留言,我挨个发。

最后希望能给小丁同学带来帮助,脚踏实地的学习。

2020.9.20于湖北工业大学

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服