精华内容
下载资源
问答
  • 基于FPGA数字信号发生器的设计.pdf
  • 基于FPGA信号发生器 能实现 三角波 正弦波 方波 锯齿波
  • 基于FPGA数字信号发生器的设计与实现.pdf
  • 本设计是信号发生器系统的设计和制作过程,介绍了一种基于直接频率合成(DDS)技术,利用FPGA+DAC的硬件平台,设计并实现了一种输出频率和幅度可调的信号发生器。该信号发生器通过单片机与FPGA进行通信,实现频率和...
  • 基于FPGA的DDS型数字信号发生器设计.pdf
  • FPGA实现DDS(正弦波、三角波),经过实际使用,100%可用;
  • 基于FPGA数字信号合成发生器,能够产生正弦波,方波,三角波等。
  • 基于FPGA数字电视信号发生器的设计、电子技术,开发板制作交流
  • 基于FPGA的DDS型数字信号发生器设计 (1).pdf
  • 摘要:本文设计了一种基于FPGA数字电视信号友生器,该信号发生器以一种单芯片多配置的方案,针对系统各部分功能特性和性能进行选片没计,并利用FPGA内部存储资源来生成各种测试信号的图像。  电视信号的数字化...
  • 1.Matlab与FPGA数字信号处理系列——DDS信号发生器——Quartus ii 原理图法利用 ROM 存储波形实现DDS(1) 2.FPGA仿真必备(1)——Matlab生成.mif文件——JPG图片转.mif文件——Matlab生成.txt文件 3.MATLAB与FPGA...

    相关文章
    1.Matlab与FPGA数字信号处理系列——DDS信号发生器——Quartus ii 原理图法利用 ROM 存储波形实现DDS(1)

    2.FPGA仿真必备(1)——Matlab生成.mif文件——JPG图片转.mif文件——Matlab生成.txt文件

    3.MATLAB与FPGA数字信号处理(数字滤波器设计)、无线通信、图像处理、信道编码系列

    1.系统参数及框图

    ROM 存储一个正弦波完整波形,存256个点,每个点进行 8 bit 量化,使用 Matlab 产生 .coe 存储器文件,加载到 ROM 中。

    在这里插入图片描述

    2.Matlab制作.coe文件

    Fs_N = 256;                     % 抽样点数
    Bit_Width = 2^8;               % 量化位宽
     
    t=0:2*pi/Fs_N:2*pi;
    y=0.5*sin(t)+0.5; % (-0.5~0.5)+0.5 ->(0~1),转成无符号数
    % r=ceil(y*(Bit_Width-1));      % 量化,向上取整
    % r=floor(y*(Bit_Width-1));     % 量化,向下取整
    r=round(y*(Bit_Width-1));       % 量化,四舍五入
     
    fid = fopen('sin.coe','w');  % 写入 'sin.coe' 文件
    fprintf(fid,'MEMORY_INITIALIZATION_RADIX=10;\n');   % 固定写法,表示写入的数据是 10进制 表示
    fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n');     % 固定写法,下面开始写入数据
    for i = 1:1:Fs_N
        fprintf(fid,'%d',r(i));
        if i==Fs_N
            fprintf(fid,';\n');   % 最后一个数据用 ;
        else
            fprintf(fid,',\n');    % 其他数据用 ,
        end
    end
    fclose(fid);                     % 写完了,关闭文件
    

    写入后,文件内容如下图所示,第三行开始是波形量化后的数据,在第62-72行全部被量化为255(8-bit量化的最大值),可以想象,输出的波形在顶峰时会有一个较平的地方,是量化精度不够造成的。
    在这里插入图片描述

    下图中Matlab的绘图也证明了这一点,最大值处量化成了同样的数据,波形略有失真,原因在于Matlab使用的是 ceil() 函数向上取整,改成 floor() 向下取整,最小值量化成了同样的数据,波形略有失真。
    向上取整

    向上取整

    向下取整

    向下取整

    四舍五入量化

    四舍五入量化

    3.Vivado中ROM调用.coe文件

    (1)新建工程,调用ROM IP

    选择“Block Memory Generator”。
    在这里插入图片描述

    (2)配置ROM

    1处选择“Stand Alone”,2处选择“Single Port ROM”单口ROM,其中2处的可选项有:单口RAM,简化的双口RAM(一端读一端写),真双口RAM(两端都可读写),单口ROM(1个ROM),双口ROM(相当于2个ROM)。
    在这里插入图片描述

    1处配置数据的量化位宽,2处是ROM的深度(存储的点数),3处设置一直使能工作,能够节省一个使能引脚。
    在这里插入图片描述

    1处勾选加载.coe文件,2处找到.coe文件的路径,点击加载。
    在这里插入图片描述

    配置完成,地址8位,代表深度256,数据8位。
    在这里插入图片描述

    (3)配置计数器

    在这里插入图片描述

    1处配置成8位计数器,输出计数值位宽为8位,2处设置每次计数变化1,3处设置位向上计数,2处和3处配合实现每次加1。
    在这里插入图片描述

    (4)连接引脚

    在这里插入图片描述

    4.仿真测试

    编写TestBench仿真文件,只需要给定时钟信号即可。
    假设给定时钟 125 MHz,即时钟周期为 8 us,每输出一个采样点需要 8 us,输出256个正弦波的采样点需要 256×8 us,即正弦波的周期为 256×8 us,即频率为 125MHz / 256 = 0.488 MHz 左右。

    在这里插入图片描述

    欢迎关注:FPGA探索者

    回复 “DDS256” 获取工程源码。

    在这里插入图片描述

    展开全文
  • 基于FPGA三角波周期随机变化数字信号发生器的设计.pdf
  • 实现一个简易数字信号发生器,更全面地掌握FPGA的开发设计流程,加深对VHDL语言的理解和运用.
  • 基于FPGA数字调制信号发生器设计.pdf
  • 要介绍了直接数字频率合成(DDS)的组成及其工作原理,给出了基于Ahera公司的FPGA实现多波形信号发生器的设计过程和电路结构。设计在Quartusl!软件中完成,并给出了仿真波形。该设计用FPGA实现,因此有许多优点。比如...
  • 基于FPGA的全数字高速跳频信号发生器设计
  • 摘要:本文设计了一种基于FPGA数字电视信号友生器,该信号发生器以一种单芯片多配置的方案,针对系统各部分功能特性和性能进行选片没计,并利用FPGA内部存储资源来生成各种测试信号的图像。  电视信号的数字化...
  • 基于 FPGA Vivado 信号发生器设计(附源工程)

    千次阅读 热门讨论 2020-06-15 10:03:00
    今天给大侠带来基于 FPGA Vivado 信号发生器设计,开发板实现使用的是Digilent basys 3,如有想要入手basys3开发板的,可以联系牛总:18511371833。话不多说,上货。 本篇掌握基于 FPGA Vivado 信号发生器设计...

    今天给大侠带来基于 FPGA Vivado 信号发生器设计,开发板实现使用的是Digilent basys 3,如有想要入手 basys 3 开发板的,可以联系牛总:18511371833。话不多说,上货。

     

    本篇掌握基于 FPGA Vivado 信号发生器设计(附源工程),掌握基于添加文件和IP的Vivado工程设计流程,掌握基于Tcl的Vivado工程设计流程,学习信号发生器的基本组成结构。获取本篇相关源工程代码,可在公众号内回复“信号发生器设计源工程”。

     

    设计原理

     

    信号发生器能够产生频率波形可调的信号输出,目前仅限于1Hz~4999Hz频率范围,波形可选择三角波,方波,锯齿波,以及正弦波。本系统在Basys3上构建了一个简易信号发生器,简化框图如下:

     

    原理:首先,通过按键设置波形的频率,并通过拨码开关设置波形的种类(一共有正弦波、三角波、方波、锯齿波四种)。频率值可以通过数码管显示。片上的输出时钟计算模块能够根据设置好的频率值,计算波形查找表的输出时钟,以及生成查找表的地址。查找表根据波形选择模块,决定输出何种波形数据,并在输出时钟的驱使下,输出波形数据。最后,片上的DA模块将波形数据发送给外部DA。本设计通过Basys3外接Pmod-DA1模块,进行DA输出。

     

    操作步骤

     

    基于添加文件和IP

    1. 新建工程项目

    1) 双击桌面图标打开Vivado 2017.2,或者选择开始>所有程序>Xilinx Design Tools> Vivado 2017.2>Vivado 2017.2;

    2) 点击‘Create Project’,或者单击File>New Project创建工程文件;

    3) 将新的工程项目命名为‘lab5’,选择工程保存路径,勾选‘Create project subdirectory’,创建一个新的工程文件夹,点击Next继续;

    4) 选择新建一个RTL工程,勾选Do not specify sources at this time(不指定添加源文件),先不添加源文件。点击 Next继续;

    5) 选择目标FPGA器件:xc7a35tcpg236-1或Basys3;

    6) 最后在新工程总结中,检查工程创建是否有误。没有问题,则点击Finish,完成新工程的创建。

     

    2. 添加已经设计好的IP和HDL文件

    工程建立完毕,我们将所需的IP文件夹(IP_Catalog)和实验需要使用的HDL文件复制到已经创建的工程文件夹根目录下:

    源文件位于Basys3_workshop\sources\lab5\Src\HDL_source

    复制完成后,如下图所示:

     

    1) 在Vivado界面左侧Flow Navigator中展开PROJECT MANAGER,选择‘Settings’;

     

    2) 弹出窗口中,在左侧Project Settings中展开IP一项,选择‘Repository’,点击右侧的添加IP;

     

    3) 选择复制到工程文件夹根目录下的IP文件夹;

     

    4) 点击OK完成添加;

    5) 添加IP至工程。

    5.1 在Flow Navigator中展开PROJECT MANAGER,选择IP Catalog;

     

    5.2 在右侧IP Catalog窗口的搜索框中搜索‘clocking’,双击‘Clocking Wizard’开始配置IP;

     

    5.3 配置IP。

    5.3.1 将IP的名字由‘clk_wiz_0’修改为‘clock’;

    5.3.2 选择‘Output Clocks’,设置2路输出时钟(100MHz和50MHz);

    5.3.3 在Enable Optional I/O for MMCM/PLL一项中取消勾选‘reset’和‘locked’选项;

     

    5.3.4 Vivado会创建新的文件夹保存配置完成的IP,点击OK继续;

     

    5.3.5 弹出Generate Output Products窗口,在Synthesis Options中选择‘Global’,点击‘Generate’继续。

     

     

    5.4 同样的,在IP Catalog窗口中添加Divider Generator,配置如下图如下图所示:

     

    5.5 同样的,依次在IP Catalog窗口中添加debounce和seg7decimal这两个IP,使用默认IP设置,无需另外配置,并且Generate Output Products,完成后Sources窗格中如下图所示:

     

    6) 添加HDL文件至工程

    6.1 在Flow Navigator中展开PROJECT MANAGER,选择Add Sources;

     

    6.2 在导向窗口中选择‘Add or create design sources’,点击Next继续;

     

    6.3 在Add or Create Design Sources页面中选择‘Add Files’;

     

    6.4 找到lab5根目录,选中添加下图所示的2个HDL文件;

     

    6.5 勾选‘Copy sources into project’,点击Finish完成添加;

     

    6.6 完成后Sources窗格中如下图所示:

     

    7) 添加物理约束(XDC)文件

    7.1 在Flow Navigator中展开PROJECT MANAGER,选择Add Sources;

    7.2 在导向窗口中选择‘Add or create constraints’,点击Next继续;

     

    7.3 在Add or Create Design Sources页面中选择‘Add Files’;

    7.4 找到约束文件路径Basys3_workshop\sources\lab5\Src\Constraint,选中并添加‘signal_gen.xdc’文件;

     

    7.5 勾选‘Copy sources into project’,点击Finish完成添加。

     

    3. 综合、实现、生成比特流文件

    1) 在左侧Flow Navigator中依次点击‘Run Synthesis’、‘Run Implementation’和‘Generate Bitstream’执行综合、实现和生成比特流文件操作。或者,可以直接点击‘Generate Bitstream’,Vivado工具会提示没有已经实现的结果,点击‘Yes’,Vivado工具会依次执行综合、实现和生成比特流文件。

     

    2) 完成后,选择‘Open Hardware Manager’打开硬件管理器。

     

    3) 连接Basys3开发板,点击‘Open target’,选择‘Auto connect’。

     

    4) 连接完成后,点击‘Program device’。

     

    5) 检查弹出框中所选中的bit文件,然后点击Program进行下载。

     

    设计验证

     

    1. 基于Analog Discovery2

    按照下图连接方式,首先将Pmod-DA1模块插入在JC口上方,同时将Analog Discovery2的示波器CH1的输出引线1+(橙色)和1-(橙白色)分别与Pmod-DA1模块的A1和GND相连接。

     

    1) 打开WaveForms软件,连接Analog Discovery2设备

    2) 在左侧的功能选择栏选择‘Scope’,使用示波器

    3) 打开示波器,点击左上角‘Run’按钮,波形输出如下图所示:

     

    2. 基于OpenScope

    按照下图连接方式,首先将Pmod-DA1模块插入在JC口上方,同时将OpenScope的示波器CH1的输出引线1+(橙色)和1-(橙白色)分别与Pmod-DA1模块的A1和GND相连接。

    1) 打开Digilent Agent;

    2) 在Windows工具栏右侧,右键Digilent Agent图标,选择‘Launch WaveForms Live’,在浏览器中打开WaveForms Live;

    3) 选择在实验二中已经添加的设备,点击连接该设备;

     

    4) 在界面右侧将Time设置为2ms,找到并展开Osc Ch1(示波器Ch1),保持默认参数设置,点击右上角开关按钮,打开示波器。

     

    5) 点击界面右上角的‘RUN’按钮,开始运行。在左侧的示波器中观察输出波形结果。

     

    通过DIGILENT Basys3开发板右侧的上下左右键进行频率调节,以及利用低两位的开关来选择输出波形。

     

     

    END

     

    后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。

    大侠们,江湖偌大,继续闯荡,愿一切安好,有缘再见!

     

    往期推荐

    展开全文
  • FPGA实现DDS信号发生器

    2012-12-05 22:10:24
    基于FPGA的DDS信号发生器 基于FPGA数字频率计
  • 基于FPGA信号发生器

    千次阅读 多人点赞 2019-07-01 22:51:15
    上面图片中第一排是FPGA输出到DA的数字信号,第二排是用AD采集到DA输出的数据。可调幅调频调波形,现在的波形只有正弦波,三角波,方波,可以在添加其他波形。调幅,是用硬件滑动变阻器调节。调频,是利用时...

    闭关半年,学习FPGA,其中学到了很多东西。使用的Verilog,学过VHDL,但是不熟悉。接下来的几篇文章都是关于FPGA的。转眼就到大四了。以后准备找FPGA的工作。开始正题,先看效果:在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    上面图片中第一排是FPGA输出到DA的数字信号,第二排是用AD采集到DA输出的数据。可调幅调频调波形,现在的波形只有正弦波,三角波,方波,可以在添加其他波形。调幅,是用硬件滑动变阻器调节。调频,是利用时钟分频,但是不能称作DDS,因为不能调到已知频率(因为我们按键每次分频系数加一),但可以自己计算分频系数,调到已知频率,频率按键控制。调波形,用的三个ROM存储各种波形的数据,按键来控制切换。

    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
        FREQ_ADJ <= 8'd0;
        cnt <= 2'd0;
        end
        else 
        case(key)
        4'b0001:
                if(cnt < 2'd2)
                cnt <= cnt + 1'b1;
                else
                cnt <= 2'd0;
        4'b0011:
                if(FREQ_ADJ < 8'd255)
                FREQ_ADJ <= FREQ_ADJ + 1'b1;
                else 
                FREQ_ADJ <= FREQ_ADJ;
        4'b0100:
                if(FREQ_ADJ > 8'd0)
                FREQ_ADJ <= FREQ_ADJ - 1'b1;
                else 
                FREQ_ADJ <= FREQ_ADJ;
        default: FREQ_ADJ <= FREQ_ADJ;
        endcase
    end 
    

    上述代码用来判断按键的值。

    //频率调节计数器
    always @(posedge clk or negedge rst_n) begin
        if(rst_n == 1'b0)
            freq_cnt <= 8'd0;
        else if(freq_cnt == FREQ_ADJ)    
            freq_cnt <= 8'd0;
        else         
            freq_cnt <= freq_cnt + 8'd1;
    end
    

    上述代码是用来分频的。

    always @(posedge clk or negedge rst_n) begin
        if(rst_n == 1'b0)
            begin
            address_sin <= 8'd0;
            address_square <= 8'd0;
            address_triangle <= 8'd0;
            end 
        else begin
            case(cnt)
            2'd0:
                 if(freq_cnt == FREQ_ADJ)
                 begin
                 address_sin <=  address_sin + 1'b1;
                 rd_data <= data_sin;
                 end
                 else
                 begin
                 address_sin <=  address_sin;
                 rd_data <= data_sin;
                 end
            2'd1:
                if(freq_cnt == FREQ_ADJ)
                 begin
                 address_square <=  address_square + 1'b1;
                 rd_data <= data_square;
                 end
                 else
                 begin
                 address_square <=  address_square;
                 rd_data <= data_square;
                 end
            2'd2:
                if(freq_cnt == FREQ_ADJ)
                 begin
                 address_triangle <=  address_triangle + 1'b1;
                 rd_data <= data_triangle;
                 end
                 else
                 begin
                 address_triangle <=  address_triangle;
                 rd_data <= data_triangle;
                 end
            endcase   
        end            
    end
    

    上述是用来调节波形。
    原理我就不细讲了,很简单,不懂的找我。后面一定要做一个DDS来玩,这个东西比较理想,可能只能用于毕设或者自己玩。我使用的AD9708。我买的正点原子的AD/DA高速模块,我还做了一个数字示波器,刚好把这个模块功能榨干了。下一篇介绍。源码,今天上传不了,后面会留在评论区。可以私聊我,免费。QQ:1757334763

    展开全文
  • 为了提高数字调制信号发生器的频率准确度和稳定度,并使其相关技术参数灵活可调,提出了基于FPGA和DDS技术的数字调制信号发生器设计方法。利用Matlab/Simulink、DSP Builder、QuartusⅡ 3个工具软件,进行基本DDS...
  • FPGA内部的地址累加作为相位数据,以查表方式得到幅度数据,通过高速D/A转换和高速运放得到所需输出信号波形。输出信号的幅度调节则由模拟开关控制电阻网路实现。系统采用串行键盘进行参数设置,由LCD实时显示...
  • FPGA基础之数字信号发生器(DDS)

    千次阅读 2019-10-27 19:32:41
    波形存储器的作用是存储不同相位对应地址的波形值,相位累加器根据不同的相位产生对应的地址,用于选择不同的波形值,频率发生器根据输入频率产生频率控制字,其大小决定了相位累加器地址累加的速度,不同的累加速度...

    一、DDS原理

    最近在复习至芯培训课程的DDS部分,DDS的核心主要包括频率发生器、相位累加器和波形存储器三部分。波形存储器的作用是存储不同相位对应地址的波形值,相位累加器根据不同的相位产生对应的地址,用于选择不同的波形值,频率发生器根据输入频率产生频率控制字,其大小决定了相位累加器地址累加的速度,不同的累加速度决定了输出不同的频率大小。

    二、本工程的相关说明

    实现的功能如下:输入有四个按键,分别对应波形选择、幅度调节、频率加和频率减;输出有蜂鸣器、6个动态数码管和输出波形d_wave。当四个按键有任意一个按下时,蜂鸣器响,数码管显示波形、幅度和频率对应的值,d_dds模块输出对应波形。

    1、顶层设计

    顶层dds模块包括以下几个部分:按键处理模块(key_ctrl)、脉冲处理模块(flag_ctrl)、信号发生器核心部分(d_dds)、蜂鸣器模块(beep)和6个动态数码管显示模块。顶层RTL视图如下。
    在这里插入图片描述dds顶层代码如下:

    module dds(
    
    	input		wire					clk,
    	input		wire					rst_n,
    	
    	input		wire					key_sel,
    	input		wire					key_amp,
    	input		wire					key_fadd,
    	input		wire					key_fsub,
    
    	output	wire					beep,
    	output	wire	[9:0]			d_wave,
    	output	wire	[2:0]			sel,
    	output	wire	[7:0]			seg
    );
    
    	wire					flag_s;
    	wire					flag_a;
    	wire					flag_fa;
    	wire					flag_fs;
    	
    	wire		[1:0]		wave_sel;
    	wire		[1:0]		wave_a;
    	wire		[19:0]	wave_freq;
     
    	key_ctrl key_ctrl_inst(
    
    		.clk					(clk		),
    		.rst_n				(rst_n	),
    		                   
    		.key_sel				(key_sel	),
    		.key_amp				(key_amp	),
    		.key_fadd			(key_fadd),
    		.key_fsub			(key_fsub),
                             
    		.flag_s				(flag_s	),
    		.flag_a				(flag_a	),
    		.flag_fa				(flag_fa	),
    		.flag_fs				(flag_fs	)
    	);
    
    	flag_ctrl flag_ctrl_inst(
    
    		.clk					(clk			),
    		.rst_n				(rst_n		),
    		                   
    		.flag_s				(flag_s		),
    		.flag_a				(flag_a		),
    		.flag_fa				(flag_fa		),
    		.flag_fs				(flag_fs		),
    		                   
    		.wave_sel			(wave_sel	),
    		.wave_a				(wave_a		),
    		.wave_freq			(wave_freq	)
    	);
    
    	d_dds d_dds_inst(
    
    		.clk					(clk			),
    		.rst_n				(rst_n		),
    		                   
    		.wave_sel			(wave_sel	),
    		.wave_a				(wave_a		),
    		.wave_freq			(wave_freq	),
    		                   
    		.d_wave				(d_wave		)
    	);	
    	
    	beep beep_inst(
    
    		.clk					(clk			),
    		.rst_n				(rst_n		),
    		                   
    		.flag_s				(flag_s		),
    		.flag_a				(flag_a		),
    		.flag_fa				(flag_fa		),
    		.flag_fs				(flag_fs		),
                             
    		.beep					(beep			)
    	);	
    	
    	show_data show_data_inst(
    
    		.clk					(clk			),
    		.rst_n				(rst_n		),
    		                   
    		.wave_sel			(wave_sel	),
    		.wave_a				(wave_a		),
    		.wave_freq			(wave_freq	),
    		                   
    		.sel					(sel			),
    		.seg					(seg			)
    	);	
    	
    endmodule 
    

    2、各模块相关说明

    (1)按键处理模块(key_ctrl)

    按键处理包括两个步骤,消抖和边缘检测,需要注意的点是需要对每一个按键进行这两步操作,生成对应的四个脉冲信号:波形选择、幅度调节、频率加和减。顶层代码如下:

    module key_ctrl(
    
    	input		wire					clk,
    	input		wire					rst_n,
    	
    	input		wire					key_sel,
    	input		wire					key_amp,
    	input		wire					key_fadd,
    	input		wire					key_fsub,
    
    	output	wire					flag_s,
    	output	wire					flag_a,
    	output	wire					flag_fa,
    	output	wire					flag_fs
    );
    
    	wire					key_wave1;
    	wire					key_wave2;
    	wire					key_wave3;
    	wire					key_wave4;
    	
    	key_filter key_filter_inst1(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    		
    		.key					(key_sel),
    
    		.key_wave			(key_wave1)
    	);
    
    	edge_check edge_check_inst1(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    
    		.key					(key_wave1),
    		
    		.flag_neg			(flag_s),
    		.flag_pos			()
    	);
    
    	key_filter key_filter_inst2(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    		
    		.key					(key_amp),
    
    		.key_wave			(key_wave2)
    	);
    
    	edge_check edge_check_inst2(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    
    		.key					(key_wave2),
    		
    		.flag_neg			(flag_a),
    		.flag_pos			()
    	);
    
    	key_filter key_filter_inst3(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    		
    		.key					(key_fadd),
    
    		.key_wave			(key_wave3)
    	);
    
    	edge_check edge_check_inst3(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    
    		.key					(key_wave3),
    		
    		.flag_neg			(flag_fa),
    		.flag_pos			()
    	);
    
    	key_filter key_filter_inst4(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    		
    		.key					(key_fsub),
    
    		.key_wave			(key_wave4)
    	);
    
    	edge_check edge_check_inst4(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    
    		.key					(key_wave4),
    		
    		.flag_neg			(flag_fs),
    		.flag_pos			()
    	);
    
    endmodule 
    
    

    (2)脉冲处理模块(flag_ctrl)

    本模块根据四个按键产生的脉冲信号,输出波形选择、幅度和频率的控制信号。需要注意的点是幅度和频率变化只能在选中某一波形的前提条件下进行变化,当切换成其他波形时,要保持上一个波形的设定值不变,初始频率设为50k,按键对应频率加减对应为100Hz。代码如下:

    module flag_ctrl(
    
    	input		wire					clk,
    	input		wire					rst_n,
    	
    	input		wire					flag_s,
    	input		wire					flag_a,
    	input		wire					flag_fa,
    	input		wire					flag_fs,
    	
    	output	reg	[1:0]			wave_sel,
    	output	reg	[1:0]			wave_a,
    	output	reg	[19:0]		wave_freq
    );
    
    	parameter		FREQ = 50_000;
    
    	reg		[1:0]			amp_1;
    	reg		[1:0]			amp_2;
    	reg		[1:0]			amp_3;	
    	reg		[1:0]			amp_4;
    	
    	reg		[19:0]		freq1;
    	reg		[19:0]		freq2;
    	reg		[19:0]		freq3;
    	reg		[19:0]		freq4;	
    	
    	
    	
    	always @ (posedge clk, negedge rst_n)
    		begin
    			if (!rst_n)
    				wave_sel <= 0;
    			else
    				if (flag_s == 1)
    					wave_sel <= wave_sel + 1'b1;
    				else
    					wave_sel <= wave_sel;
    		end
    		
    //===================== according to wave_sel, adjust amplitude ===========================
    		
    	always @ (posedge clk, negedge rst_n)
    		begin
    			if (!rst_n)
    				amp_1 <= 0;
    			else
    				if (wave_sel == 2'b00 && flag_a == 1)
    					amp_1 <= amp_1 + 1'b1;
    				else
    					amp_1 <= amp_1;
    		end
    
    	always @ (posedge clk, negedge rst_n)
    		begin
    			if (!rst_n)
    				amp_2 <= 0;
    			else
    				if (wave_sel == 2'b01 && flag_a == 1)
    					amp_2 <= amp_2 + 1'b1;
    				else
    					amp_2 <= amp_2;
    		end
    
    	always @ (posedge clk, negedge rst_n)
    		begin
    			if (!rst_n)
    				amp_3 <= 0;
    			else
    				if (wave_sel == 2'b10 && flag_a == 1)
    					amp_3 <= amp_3 + 1'b1;
    				else
    					amp_3 <= amp_3;
    		end
    
    	always @ (posedge clk, negedge rst_n)
    		begin
    			if (!rst_n)
    				amp_4 <= 0;
    			else
    				if (wave_sel == 2'b11 && flag_a == 1)
    					amp_4 <= amp_4 + 1'b1;
    				else
    					amp_1 <= amp_1;
    		end
    
    //============== according to wave_sel, adjust frequency ==================================
    
    	always @ (posedge clk, negedge rst_n)
    		begin
    			if (!rst_n)
    				freq1 <= FREQ;
    			else
    				if (wave_sel == 2'b00 && flag_fa == 1)
    					freq1 <= freq1 + 20'd100;
    				else
    					if (wave_sel == 2'b00 && flag_fs == 1)
    						freq1 <= freq1 - 20'd100;
    					else
    						freq1 <= freq1;
    		end
    
    	always @ (posedge clk, negedge rst_n)
    		begin
    			if (!rst_n)
    				freq2 <= FREQ;
    			else
    				if (wave_sel == 2'b01 && flag_fa == 1)
    					freq2 <= freq2 + 20'd100;
    				else
    					if (wave_sel == 2'b01 && flag_fs == 1)
    						freq2 <= freq2 - 20'd100;
    					else
    						freq2 <= freq2;
    		end
    
    	always @ (posedge clk, negedge rst_n)
    		begin
    			if (!rst_n)
    				freq3 <= FREQ;
    			else
    				if (wave_sel == 2'b10 && flag_fa == 1)
    					freq3 <= freq3 + 20'd100;
    				else
    					if (wave_sel == 2'b10 && flag_fs == 1)
    						freq3 <= freq3 - 20'd100;
    					else
    						freq3 <= freq3;
    		end
    
    	always @ (posedge clk, negedge rst_n)
    		begin
    			if (!rst_n)
    				freq4 <= FREQ;
    			else
    				if (wave_sel == 2'b11 && flag_fa == 1)
    					freq4 <= freq4 + 20'd100;
    				else
    					if (wave_sel == 2'b11 && flag_fs == 1)
    						freq4 <= freq4 - 20'd100;
    					else
    						freq4 <= freq4;
    		end
    		
    //=================== according wave_sel, output frequency and amplitude ==========================
    
    	always @ (*)
    		case (wave_sel)
    			2'b00			:	begin wave_freq = freq1; wave_a = amp_1; end
    			2'b01			:	begin wave_freq = freq2; wave_a = amp_2; end
    			2'b10			:	begin wave_freq = freq3; wave_a = amp_3; end
    			2'b11			:	begin wave_freq = freq4; wave_a = amp_4; end
    		endcase
    
    endmodule 
    

    (3)DDS核心模块

    本模块包括四个部分,频率发生器、相位累加器、波形存储器和幅度调节器。需要注意的点:频率发生器的控制字word的位宽为什么要是64位,相位累加器的基地址和偏移地址的处理,波形存储器模块在rom中写入.mif文件时特别注意文件路径,应放在工程文件夹目录下,幅度调节器部分应注意对所成的幅值进行+1处理。顶层代码如下:

    module d_dds(
    
    	input		wire					clk,
    	input		wire					rst_n,
    	
    	input		wire	[1:0]			wave_sel,
    	input		wire	[1:0]			wave_a,
    	input		wire	[19:0]		wave_freq,
    	
    	output	wire	[9:0]			d_wave
    );
    
    	wire		[31:0]		f_word;
    	wire		[9:0]			addr_rom1024x8;
    	wire		[7:0]			wave;
    
    	freq_ctrl freq_ctrl_inst(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    
    		.wave_freq			(wave_freq),
    
    		.f_word				(f_word)
    	);
    
    	addr_ctrl addr_ctrl_inst(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    		
    		.wave_sel			(wave_sel),
    		.f_word				(f_word),
    
    		.addr					(addr_rom1024x8)
    	);
    
    	rom1024x8	rom1024x8_inst (
    	
    		.address					(addr_rom1024x8),
    		.clock					(clk),
    		.q							(wave)
    	);
    
    	a_ctrl a_ctrl_inst(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    
    		.wave_a				(wave_a),
    		.wave					(wave),
    
    		.d_wave				(d_wave)
    	);
    
    endmodule 
    

    (4)蜂鸣器模块

    此模块需要明确的是给什么样的信号蜂鸣器才能发声,本设计使用的蜂鸣器是无源蜂鸣器,给连续高低变化的信号就能发生,当然信号频率有一个范围。需要注意的是按键脉冲信号到来,100ms计数器的启动控制信号的条件是什么,代码如下:
    module beep(

    input		wire					clk,
    input		wire					rst_n,
    
    input		wire					flag_s,
    input		wire					flag_a,
    input		wire					flag_fa,
    input		wire					flag_fs,
    
    output	reg					beep
    

    );

    parameter		T		= 10_000;
    parameter		MAX	= 5_000_000;
    
    reg		[15:0]		cnt_10k;
    reg						wave_10k;
    reg		[22:0]		cnt_100ms;
    
    wire						wave_100ms;
    wire						flag_or;
    
    assign flag_or = (flag_s == 1 || flag_a == 1 || flag_fa == 1 || flag_fs == 1) ? 1'b1 : 1'b0;
    

    //=================== generate 10k wave ===========================================================

    always @ (posedge clk, negedge rst_n)
    	begin
    		if (!rst_n)
    			cnt_10k <= 0;
    		else
    			if (cnt_10k < T - 1)
    				cnt_10k <= cnt_10k + 1'b1;
    			else
    				cnt_10k <= 0;
    	end
    
    always @ (posedge clk, negedge rst_n)
    	begin
    		if (!rst_n)
    			wave_10k <= 0;
    		else
    			if (cnt_10k < T / 2)
    				wave_10k <= 1'b1;
    			else
    				wave_10k <= 1'b0;
    	end
    

    //================== generate wave_100ms ==========================================================

    always @ (posedge clk, negedge rst_n)
    	begin
    		if (!rst_n)
    			cnt_100ms <= MAX - 1;
    		else
    			if ((cnt_100ms == MAX - 1) && flag_or == 1)
    				cnt_100ms <= 0;
    			else
    				if (cnt_100ms < MAX - 1)
    					cnt_100ms <= cnt_100ms + 1'b1;
    				else
    					cnt_100ms <= cnt_100ms;
    	end
    	
    assign wave_100ms = (cnt_100ms != MAX - 1) ? 1'b1 : 1'b0;					
    

    //================= generate beep ===============================================================

    always @ (posedge clk, negedge rst_n)
    	begin
    		if (!rst_n)
    			beep <= 1;
    		else
    			beep <= ~ (wave_10k && wave_100ms);
    	end
    

    endmodule

    (5)6个动态数码管显示模块

    前两个数码管分别显示波形选择和幅度,后四个显示频率值。特别需要注意的是波形选择和幅度信号的位宽,以及频率对应需要bin2bcd模块。代码如下:

    module show_data(
    
    	input		wire					clk,
    	input		wire					rst_n,
    	
    	input		wire	[1:0]			wave_sel,
    	input		wire	[1:0]			wave_a,
    	input		wire	[19:0]		wave_freq,
    	
    	output	wire	[2:0]			sel,
    	output	wire	[7:0]			seg
    );
    
    	wire		[3:0]			b_wave_sel;
    	wire		[3:0]			b_wave_a;
    	wire		[27:0]		bcd;
    	wire		[23:0]		show_data;
    	
    	assign b_wave_sel = wave_sel + 1'b1;
    	assign b_wave_a = wave_a + 1'b1;	
    	assign show_data = {b_wave_sel, b_wave_a, bcd[23:8]};
    	
    	bin2bcd # (.WIDTH_BIN(20), .WIDTH_BCD(28)) bin2bcd_inst(
    
    		.bin					(wave_freq),
    
    		.bcd					(bcd)
    	);
    
    	seven_tube_drive seven_tube_drive_inst(
    
    		.clk					(clk),
    		.rst_n				(rst_n),
    		
    		.show_data			(show_data),
    		
    		.seven_tube_seg	(seg),
    		.seven_tube_sel	(sel)
    	);
    	
    endmodule 
    

    3、测试文件tb

    这个工程不建议对所有模块进行仿真,因为子模块太多,提供一个简单的,不足之处请谅解。代码如下:

    `timescale 1ns/1ps
    
    module dds_tb;
    
    	reg					clk;
    	reg					rst_n;
    
    	reg					key_sel;
    	reg					key_amp;
    	reg					key_fadd;
    	reg					key_fsub;
    
    	wire					beep;
    	wire	[9:0]			d_wave;
    	wire	[2:0]			sel;
    	wire	[7:0]			seg;
    	
    	wire		[7:0]		addr = dds_inst.d_dds_inst.addr_ctrl_inst.p_addr;
    
    	defparam		dds_inst.key_ctrl_inst.key_filter_inst1.T_5ms = 10;
    	defparam		dds_inst.key_ctrl_inst.key_filter_inst2.T_5ms = 10;
    	defparam		dds_inst.key_ctrl_inst.key_filter_inst3.T_5ms = 10;	
    	defparam		dds_inst.key_ctrl_inst.key_filter_inst4.T_5ms = 10;
    
    	defparam		dds_inst.beep_inst.T = 10;
    	defparam		dds_inst.beep_inst.MAX = 50;		
    	
    	dds dds_inst(
    
    		.clk						(clk			),
    		.rst_n					(rst_n		),
    		                      
    		.key_sel					(key_sel		),
    		.key_amp					(key_amp		),
    		.key_fadd				(key_fadd	),
    		.key_fsub				(key_fsub	),
                                
    		.beep						(beep			),
    		.d_wave					(d_wave		),
    		.sel						(sel			),
    		.seg						(seg			)
    	);
    
    	initial clk = 1;
    	always #10 clk = ~ clk;
    	
    	initial 
    		begin
    			rst_n = 0;
    			key_sel = 1;
    			key_amp = 1;
    			key_fadd = 1;
    			key_fsub = 1;
    			# 201
    			
    			rst_n = 1;
    			task_stop;
    		
    			key_sel = 0;
    			task_stop;
    			
    			key_amp = 0;
    			task_stop;
    			
    			key_fadd = 0;			
    			task_stop;
    						
    			key_fsub = 0;
    			task_stop;
    			
    			$stop;
    		end
    	
    	task task_stop;
    		begin
    			repeat (10)
    				begin
    					while (addr != 255) @ (posedge clk);
    					while (addr != 0)	@ (posedge clk);
    				end
    		end
    	endtask			
    	
    endmodule 
    

    三、个人总结

    本人做得还较为顺利,希望给初学者提供一个参考,详细代码见附件。

    展开全文
  • DDS数字移相信号发生器的原理及FPGA实现
  • 基于FPGA的DDS信号发生器系统框图如下图所示,采取查表法。 (1)对一个完整周期的波形进行采样,将采样点存在ROM中; (2)依次给出ROM的访问地址,即可输出一个完整的波形; (3)通过设置不同的频率控制字可以让...
  • FPGA数字信号处理之乘法system generator仿真乘法IP核有符号定点数乘法 system generator仿真 乘法IP核 有符号定点数乘法
  •  而数字电视信号发生器能提供可视的测试图像信号,直观、快捷的测试方法,因此,数字电视信号发生器成为目前电子设计的热门研究课题,他在数字电视节目制作播出、科研、生产以及售后服务过程中起着不可或缺的作用。...
  • 目前数字相机逐步取代模拟相机应用在光电测量设备中,因此图像处理器也逐渐转化为接收数字视频的接口,对数字图像处理器检测的信号发生器的研制也变得十分迫切。本文介绍了一种基于FPGA的两种数字视频格式输出的视频...
  • 基于FPGA的正弦信号发生器设计

    千次阅读 2019-12-07 13:23:06
    FPGA做正弦信号发生器是我上大学期间在实验室里做的,主要用的ROM-IP和DA数模转化芯片,将数字信号转为模拟信号后,通过示波器进行显示。 我记得当时用FPGA做了正弦、三角波、方波信号,然后通过DA输出在示波器上...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,360
精华内容 1,744
关键字:

fpga数字信号发生器