EDA课程设计任务书-基于DDS的数字移相信号发生器

来源:m.fanwen118.com时间:2022.10.14

基于DDS的数字移相信号发生器

一、课程设计目的

1、进一步熟悉Quartus Ⅱ的软件使用方法;

2、熟悉利用VHDL设计数字系统并学习LPM ROM的使用方法;

3、学习FPGA硬件资源的使用和控制方法;

4、掌握DDS基本原理,学习利用此原理进行信号发生器的设计。

二、设计任务

1、完成8位输出数据宽度的频率可调的移相正弦信号发生器。

2、完成8位输出数据宽度的频率可调的移相三角波、方波信号发生器。

3、以上三种波形使用一个按键依次切换。

4、波形发生器实现幅度可调。

5、信号发生器的原始数据存储在外部存储器里,由FPGA进行读取,经过D/A转换输出,由示波器观察最终结果。

6、完成两路相位相差90度的频率幅度可调的移相信号发生器。结果通过嵌入式分析仪观察两路正交信号。(包括正弦波、方波、三角波)

注意:以上前5点为基本要求,第6点为提高要求。

三、基本原理

直接数字频率合成器(DDS)是通信系统中常用到的部件,利用DDS可以制成很有用的信号源。与模拟式的频率锁相环PLL相比,它有许多优点,突出为(1)频率的切换迅速;(2)频率稳定度高。

一个直接数字频率合成器由相位累加器、波形ROM、D/A转换器和低通滤波器构成。DDS的原理框图如下所示:

图 1 直接数字频率合成器原理图

其中K为频率控制字, fc为时钟频率,N为相位累加器的字长,D为ROM数据位及D/A转换器的字长。相位累加器在时钟 fc的控制下以步长K作为累加,输出N位二进制码作为波形ROM的地址,对波形ROM进行寻址,波形ROM输出的幅码S(n)经D/A转换器变成梯形波S(t),

EDA课程设计任务书基于DDS的数字移相信号发生器

再经低通滤波器平滑后就可 1

以得到合成的信号波形了。合成的信号波形形状取决于波形ROM中存放的幅码,因此用DDS可以产生任意波形。本设计中直接利用D/A转换器得到输出波形,省略了低通滤波器这一环节。

1、频率预置与调节电路

不变量K被称为相位增量,也叫频率控制字。DDS方程为:f0= fc K/2n,f0为输出频率,fc为时钟频率。当K=1时,DDS输出最低频率(也既频率分辩率)为fc /2n

DDS的最大输出频率由 Nyguist 采样定理决定,即fc /2,也就是说K的最大值为2n-1.因此,只要N足够大,DDS可以得到很细的频率间隔。要改变DDS的输出频率,只要改变频率控制字K即可。

2、累加器

相位累加器的原理图如下图

图 2 相位累加器原理图

相位累加器由N为加法器与N位寄存器级联构成。每来一个时钟脉冲fc,加法器将频率控制字与寄存器输出的累加相位数据相加,再把相加后的结果送至寄存器的数据输入端,寄存器将加法器在上一个时钟作用后所产生的下数据反馈到加法器的输入端;以使加法器在下一个时钟作用下继续频率控制字进行相加。这样,相位累加器在时钟的作用下,进行相位累加,当相位累加器累加满量时,就产生一次溢出,完成一个周期性的动作,这个周期应为 uk= 2n / GCD(2N ;k),其中GCD表示最大公约数。

3、波形存储器

用相位累加器输出的数据作为波形存储器的取样地址进行波形的相位——幅值转换,即可在给定的时间上确定输出的波形的抽样幅值。N位的寻址ROM相当于把00--- 3600 的正弦信号离散成具有2n 样值的序列,若波形ROM有D位数据位,则2n个样值的幅值以D位二进制数值固化在ROM 中,按照地址的不同可以输出相宜相位的正弦信号的幅值。相位----幅值变换原理图如下所示。

EDA课程设计任务书基于DDS的数字移相信号发生器

2

图 3 相位-幅度变换原理图

4、D/A转换器

D/A转换器的作用是把已经合成的正弦波的数字量转换成模拟量,正弦幅度量化序列S(n)经D/A转换后变成了包络为正弦波的阶梯波S(t),S(t)的周期为T=uk*Tc.。需要注意的是,频率合成器对D/A转换器的分辨率有一定的要求,D/A转换器的分辨率越高,合成的正弦波S(t)台阶数就越多,输出 波形的精度也就越高。

四、整体系统设计

1、根据以上的原理介绍,按照设计任务要求,利用VHDL进行DDS信号发生器系统的程序设计,通过QuartusⅡ进行编辑、编译、综合、适配、仿真测试。

2、自行设计锁定管脚,重新综合。

3、利用EDA最小系统板或者EDA6000实验设备实现设计。

五、设计报告要求

1.说明数字DDS的工作原理 。

2.画出数字DDS的逻辑电路图。

3. 记录结果波形,进行数据分析(理论值与实际测试值的误差分析)。

4.记录所设计的信号发生器的指标范围(包括产生的信号的频率范围、频率步进、幅度可调范围、幅度步进)。

5.总结设计中遇到的问题,问题出现的原因及解决问题的方法。

六、实验设备

EDA最小系统板一块或EDA6000实验箱一台、PC机一台、示波器一台 3


第二篇:EDA(FPGA)DDS信号发生器课程设计实验报告 11900字

《电子系统实验报告》课程设计

总 结 报 告

题目: DDS信号发生器 设计人员:学号:

同组人员: 班级:

指导老师:

日期:

DDS信号发生器

一 主要功能要求:

本课程系统DDS信号发生器设计我们组利用FPGA生成DDS函数信号发生器内核和利用89S52单片机最小系统实现频率字输出和波形选择。 DDS模块与单片机的通信采用SPI串口协议。系统的16位频率字输出采用单片机的SPI串口协议输出,在DDS模块内部采用16位移位寄存器和16位锁存器进行串行数据到并行数据的转换。从而实现单片机到DDS模块的通信。

DDS模块由频率累加器、相位累加器、波形查找表、D/A模块组成。且系统时钟频率工作于75MHZ。频率和相位累加器采用32位累加器。波形查找表由三个ROM表组成,分别存储正弦波、方波、三角波的量化数据。再用一个三选一选择器作为波形输出的控制器件,控制信号由单片机输出。

二进制振幅键控的数字基带信号由VHDL语言生成M序列的二进制信号。正弦波信号由正弦波表输出。二者再进过一个乘法器,再到D/A模块。由此完成2ASK模块的设计。

二进制振幅键控的数字基带信号由VHDL语言生成M序列的二进制信号。进过二选一模块选择移位全零或者全一,查ROM表,选择移位180度或者0度, 再到D/A。由此完成2PSK模块设计。

(注:

正弦波进行1024次量化采用公式512+511*sin(6.18/1024*k) ------k值为1到1024

对方波进行1024次量化采用前512位量化数值全为1023 后512位量化数值全为0

三角波进行1024次量化采用1.3.5.7…..1023.1021.1019………7.5.3.1的方式进行量化

二 整体设计框图及整机概述

三系统实现的功能

(1)可显示信号发生器输出波形与频率。

(2)正弦波、方波、三角波输出频率范围为 35HZ ~ 1.17MHZ。

(3)具有频率设置功能。

(4)输出信号频率稳定度优于0.1。

(5)输出电压幅值:在5K负载电阻上的电压峰峰值Vopp>=1V。 (6)输出信号能够移2种相位。 (7)用数字示波器观察时比较好。

EDAFPGADDS信号发生器课程设计实验报告

四、DDS模块各部分原理图

EDAFPGADDS信号发生器课程设计实验报告

单片机与DDS模块通信接口部分

EDAFPGADDS信号发生器课程设计实验报告

锁相环模块

EDAFPGADDS信号发生器课程设计实验报告

频率字处理模块

EDAFPGADDS信号发生器课程设计实验报告

波形存储表及3选1选择器

EDAFPGADDS信号发生器课程设计实验报告

2ASK

EDAFPGADDS信号发生器课程设计实验报告

EDAFPGADDS信号发生器课程设计实验报告

相位调制(2PSK)和2ASK和2PSK选择模块

五、 系统软件流程图及流程说明

标志00

EDAFPGADDS信号发生器课程设计实验报告

六 . 程序 #ifndef _spi_h_ #define _spi_h_

#define uchar unsigned char #define uint unsigned int sbit cs = P2^0; sbit sck = P2^1; sbit d_out = P2^2; uint bdata date;

sbit send_bit = date^7; uchar get1=0,get2=0; void delayus(uchar n) {

uchar x,y;

for(x=n;x>0;x--) for(y=2;y>0;y--); }

void send(uint send_date) 信号的器件 { uchar num=0; date = send_date; cs = 1; sck = 1; delayus(20); cs = 0; delayus(20); for(;num<16;num++) { sck = 0; delayus(5); d_out = send_bit; delayus(20); sck = 1; delayus(20); date = date<<1; } cs = 1; delayus(5); }

void send1(uint send_date)

//用于发送

//用于发送

信号的器件 { uchar num=0; date = send_date; cs = 1; sck = 1; delayus(20); cs = 0; delayus(20); for(;num<16;num++) { sck = 0; delayus(5); d_out = send_bit; delayus(20); sck = 1; delayus(20); date = date<<1; } cs = 1; delayus(5); }

void get_spi() interrupt 0 //用于接收信号的器件 { uchar num=0; EX0 = 0; // EA = 0; while (sck == 0); for (;num<8;num++) { get1 = get1<<1; while (sck == 1); while (sck == 0); // if (d_out == 1) get1 = get1 | 0x01; else get1 = get1 | 0x00;

}

while (sck == 0);

for (num=0;num<8;num++) { get2 = get2<<1; while (sck == 1); while (sck == 0); //

if (d_out == 1)

get2 = get2 | 0x01;

#ifndef __KEY_H__ #define __KEY_H__

#define uint unsigned int #define uchar unsigned char

uchar code table[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

/******************************************************************** * 名称 : Delay_1ms() * 功能 : 延时子程序,延时时间为 1ms * x * 输入 : x (延时一毫秒的个数) * 输出 : 无

***********************************************************************/ void Delay_1ms(uint i) { uchar x,j; for(j=0;j<i;j++) for(x=0;x<=148;x++); }

/******************************************************************** * 名称 : Keyscan()

* 功能 : 实现按键的读取。下面这个子程序是按处理 矩阵键盘 的基本方法处理的。

else get2 = get2 | 0x00;

} //EA = 1; IE0 = 0; EX0 = 1; }

#endif

* 输入 : 无

* 输出 : 按键值

***********************************************************************/ uchar Keyscan(void) { uchar i,j, temp, Buffer[4] = {0xfe,0xfd,0xfb,0xf7}; for(j=0; j<4; j++) { P1 = Buffer[j]; /*以下三个_nop_();作用为让 P1 口的状态稳定*/ // _nop_(); // _nop_(); // _nop_(); temp = 0x10; for(i=0; i<4; i++) { if(!(P1 & temp)) { return (i+j*4); //返回取得的按键值 } temp <<= 1; } } }

#endif

#ifndef __LCD1602_H__ #define __LCD1602_H__

#define uchar unsigned char #define uint unsigned int

//这三个引脚参考资料 sbit E=P2^7; //1602使能引脚 sbit RW=P2^6; //1602读写引脚 sbit RS=P2^5; //1602数据/命令选择引脚

/******************************************************************** * 名称 : delay()

* 功能 : 延时,延时时间大概为140US。 * 输入 : 无 * 输出 : 无

***********************************************************************/ void delay() { int i,j; for(i=0; i<=10; i++) for(j=0; j<=2; j++); }

/******************************************************************** * 名称 : Convert(uchar In_Date) * 功能 : 因为电路设计时,P0.0--P0.7接法刚好了资料中的相反,所以设计该函数。 * 输入 : 1602资料上的值 * 输出 : 送到1602的值

***********************************************************************/ uchar Convert(uchar In_Date) {

uchar i, Out_Date = 0, temp = 0;

for(i=0; i<8; i++) {

temp = (In_Date >> i) & 0x01; Out_Date |= (temp << (7 - i));

}

return Out_Date; }

/******************************************************************** * 名称 : enable(uchar del) * 功能 : 1602命令函数 * 输入 : 输入的命令值 * 输出 : 无

***********************************************************************/ void enable(uchar del) { P0 = Convert(del); RS = 0; RW = 0; E = 0; delay(); E = 1; delay(); }

/******************************************************************** * 名称 : write(uchar del) * 功能 : 1602写数据函数

* 输入 : 需要写入1602的数据 * 输出 : 无

***********************************************************************/

void write(uchar del) { P0 = Convert(del); RS = 1; RW = 0;

E = 0; delay(); E = 1; delay(); }

/******************************************************************** * 名称 : L1602_init()

* 功能 : 1602初始化,请参考1602的资料 * 输入 : 无 * 输出 : 无

***********************************************************************/ void L1602_init(void) { enable(0x01); enable(0x38); enable(0x0c); enable(0x06); enable(0xd0); }

/********************************************************************

* 名称 : L1602_char(uchar hang,uchar lie,char sign)

* 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如下 L1602_char(1,5,'b')

* 输入 : 行,列,需要输入1602的数据 * 输出 : 无

***********************************************************************/ void L1602_char(uchar hang,uchar lie,char sign) { 主程序

include<reg52.h> #include<spi.h> #include<Key44.h> #include<lcd1602.h>

uchar a; if(hang == 1) a = 0x80; if(hang == 2) a = 0xc0; a = a + lie - 1; enable(a); write(sign); }

/********************************************************************

* 名称 : L1602_string(uchar hang,uchar lie,uchar *p)

* 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下 L1602_string(1,5,"ab cd ef;") * 输入 : 行,列,需要输入1602的数据 * 输出 : 无

***********************************************************************/ void L1602_string(uchar hang,uchar lie,uchar *p) { uchar a; char q=0; if(hang == 1) a = 0x80; if(hang == 2) a = 0xc0; a = a + lie - 1; enable(a); while(1) { if(*(p+q)=='\0') break; write(*(p+q)); q++; } }

#endif

#define uint unsigned int #define uchar unsigned char #define ulong unsigned long int sbit d1 = P2^3; sbit d0 = P2^4;

ulong s_data; ulong m,n,c;

uchar Key_Value,Key_Value1;

/***********************************************************/ void display(unsigned long int t) { ulong t1,t2,t3,t4,t5,t6,t7; // t8=t%100000000; t7=t%10000000; t6=t%1000000; t5=t%100000; t4=t%10000; t3=t%1000; t2=t%100; t1=t%10;

// L1602_char(1,7,t8/10000000+48); L1602_char(1,8,t7/1000000+48); L1602_char(1,9,t6/100000+48); L1602_char(1,10,t5/10000+48); L1602_char(1,11,t4/1000+48); L1602_char(1,12,t3/100+48); L1602_char(1,13,t2/10+48); L1602_char(1,14,t1+48); }

void display1(uchar t) { int t1; t1=t%10;

L1602_char(2,4,t1+48); }

void display2(uchar t) { int t1; t1=t%10;

L1602_char(2,9,t1+48); }

void main() {

s_data=0x0001; send(s_data); L1602_init();

L1602_string(1,1,"fout="); L1602_string(1,15,"Hz");

L1602_string(2,1,"d1="); L1602_string(2,6,"d0="); L1602_string(2,12,"fbo"); display(35); display1(d1); display2(d0); while(1) { P1 = 0xf0; if(P1 != 0xf0) { Delay_1ms(15); //按键消抖 if(P1 != 0xf0) { Key_Value = Keyscan()%10; Key_Value1 = Keyscan()/10;

if(Key_Value==0&&Key_Value1==0)//20 de jia { s_data=s_data +0x0001; if(s_data==65535) { s_data=0x0001; } send(s_data); n=(s_data+1)*18; display(n); Delay_1ms(100); }

if(Key_Value==1&&Key_Value1==0) //100 de jia { s_data=s_data +0x0006; if(s_data==65535) { s_data=0x0001; } send(s_data); n=(s_data+1)*18; display(n); Delay_1ms(100);

}

if(Key_Value==2&&Key_Value1==0) // 1k display(n);

Delay_1ms(100); }

de jia { s_data=s_data +0x0040; if(s_data==65535) { s_data=0x0001; } send(s_data); n=(s_data+1)*18; display(n); Delay_1ms(100); }

if(Key_Value==3&&Key_Value1==0) //10k de jia { s_data=s_data +0x0280; if(s_data==65535) { s_data=0x0001; } send(s_data); n=(s_data+1)*18; display(n); Delay_1ms(100); }

if(Key_Value==4&&Key_Value1==0) // 100k de jia { s_data=s_data +0x1900; if(s_data==65535) { s_data=0x0001; } send(s_data); n=(s_data+1)*18;

/****************************************************************************************/

if(Key_Value==5&&Key_Value1==0) // 20 de jian { s_data=s_data -0x0001; if(s_data==0) { s_data=0x0001; } send(s_data); n=(s_data+1)*18; display(n); Delay_1ms(100); }

if(Key_Value==6&&Key_Value1==0) //100 de jian { s_data=s_data -0x0006; if(s_data==0) { s_data=0x0001; } send(s_data); n=(s_data+1)*18; display(n); Delay_1ms(100); }

if(Key_Value==7&&Key_Value1==0) // 1k de jian { s_data=s_data -0x0040; if(s_data==0) { s_data=0x0001; }

send(s_data); n=(s_data+1)*18; display(n); Delay_1ms(100); }

if(Key_Value==8&&Key_Value1==0) //10k de jian { s_data=s_data -0x0280; if(s_data==0) { s_data=0x0001; } send(s_data); n=(s_data+1)*18; display(n); Delay_1ms(100); } if(Key_Value==9&&Key_Value1==0) // 100k de jian { s_data=s_data -0x1900; if(s_data==0) { s_data=0x0001; } send(s_data); n=(s_data+1)*18; display(n); Delay_1ms(100); }

/*********************************************************************************/

/*********************************************************************************/ if(Key_Value==0&&Key_Value1==1) // d0 { d0=~d0;

display2(d0);

if(d1==0) { if(d0==0) { L1602_string(2,12,"sin"); } if(d0==1) { L1602_string(2,12,"saj"); } } Delay_1ms(100); }

if(Key_Value==1&&Key_Value1==1) // d1 { d1=~d1; display1(d1); if(d1==1) { L1602_string(2,12,"fbo");

}

if(d1==0) { if(d0==0) { L1602_string(2,12,"sin"); } if(d0==1) { L1602_string(2,12,"saj"); } } Delay_1ms(100); } } } } }

七. 总结设计及体会

总结:

(1)刚开始选择系统设计方案时,我们组进行了激烈的讨论,最终决用我们已经

做好的单片机模块及4*4矩阵键盘。而单片机与DDS模块通信采用SPI协议。

三种波形采用三个ROM表来存。

(2)在确定了基本思路后,我们就开始分工,做单片机程序,DDS模块的设计,

做三种波形的量化数据处理,及单个模块的波形仿真。

(3)当将单片机模块与DDS模块进行联调时,问题出现了单片机与DDS模块能

通信,但是只能通信8位数据。与我原来想的通信16位有区别。导致只能控制

信号4k到1.17M的信号。跟老师沟通情况后,认真考虑清楚情况,认定原因原

来是单片机的SPI模块出现问题。经过调试程序终于可以用了。

(4)在基本功能都调通时,在原来讨论的基础上加了调相(2PSK)与2ASK模

体会:

(1)

(2)

(3)

(4) 做事情前先确认目标。分析可行的方案。 做事情要从小做起,简单做起,起点不要高,但是终点可以高 遇到问题要虚心请教,团队,同学,老师都是我们的资源。 通过此次的设计使我更加了解了FPGA的硬件特性与软件开发工具

QuartusII的使用并且掌握了DDS函数信号发生器的原理。

(5) 感谢金恩老师和耀国老师的悉心教导。

参考资料:

EDA技术实用教程 科学出版社 潘松 黄继业 编

更多类似范文
┣ 更多函数信号发生器课程设计报告
┗ 搜索类似范文