完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
电子发烧友论坛|
本帖最后由 蓝e 于 2016-7-12 22:32 编辑
用Verilog通过DDS合成正弦波信号 主要原理: DDS:直接数字合成,正弦波0-2pi周期内,相位到幅度是一一对应的。首先需要的将正弦波查询表存储起来,然后在时钟下,通过相位累加模块和地址查询模块实现正弦波信号。 正弦波查询表:存储的是量化的正弦波在一个周期的幅度信息(幅度的“地址”也蕴含相位)。幅度的地址数目决定了相位量化的误差。而存储每一个幅度的比特数决定了幅度的量化误差。可以通过Quartus II的IP核资源创建。 Verilog编写的DDS模块主要由三部分组成, 一、相位累加器,用于决定输出信号频率的范围和精度; 二、正弦函数功能表(波形存储器),用于存储经量化和离散后的正弦函数的幅值; 三、查表模块,相位累加器的输出地址查表。 两种方法可以改变输出信号的频率: (1)改变查表寻址的时钟频率,可以改变输出波形的频率。 (2)改变寻址的步长来改变输出信号的频率。步长即为对数字波形查表的相位增量。由累加器对相位增量进行累加,累加器的值作为查表地址。 相位累加器是DDS 的核心所在,它由一个加法器和一个位相位寄存器组成,每来一个时钟,相位寄存器以步长K累加,相位寄存器的输出与相位控制字相加,然后输入到正弦查询表地址上。正弦查询表包含一个周期正弦波的数字幅度信息,每个地址对应正弦波中0-2pi范围的一个相位点。查询表把输入的地址相位信息映射成正弦波幅度的数字量信号。相位寄存器每经过2^N/K 个fc 时钟后回到初始状态,相应地正弦查询表经过一个循环回到初始位置,输出一个正弦波。 输出正弦波周期为fo=fc* K/2^N,最小分辨率为f=fc/2^N。(通过fc和K控制正弦波频率精度) 其中,N 为累加器位宽,K 为步长,fc 为时钟频率。计数模(最大值):M=2^N。 一般正弦波表幅度地址位宽与累加的查表地址位宽不同,按前者位宽取后者对应高位的位宽即可。(具体见实例) Verilog程序 1、sine_top.v顶层设计 `timescale 10ns /1ns //时延:时间单位/时间精度 module sine_top(//采用直接数字合成(Direct Digital Synthesis) sine, clk, rst_n ); output[7:0]sine; //输出叠加的正弦波 input rst_n; input clk; wire [15:0] rom_ad; //16bit内部连接线,传递相位增量(频率控制字的整数倍) wire [9:0] address; //10bit wire signed [7:0] sine1; //8位大小的存储器阵列 assign sine=sine1; //M=2^N=2^16=65536(N控制频率分辨率,fc/M),通过相位增量K(频率控制字)控制输出频率。fout=K*fclk/M //通过查表输出正弦波,一个周期内,1024(10位)点 X 8bit(幅度量化精度) //fclk=100MHz(10ns) //10MHz //带参数的模块实例化 adder #(.fcw(6554)) uut0( //10MHz-->6554(频率控制字),实例化adder模块,uut0 .clk(clk), .rst(rst_n), .sum(rom_ad) //rom_ad,16bit大小内部连接线 ); assign address=rom_ad [15:6];//address,10bit取rom_ad高10位作为地址,与表中1024个值一一对应。 rom_sine0 rom0( //IP核 .address(address),//输入10位的地址,查出正弦波表对应的幅度值 .clock(clk), .q(sine1) //输出结果 ); endmodule 2、adder.v文件,累加模块 module adder#(parameter fcw=16'd10000)( //参数为16位大小 默认参数(10000) sum, clk, rst ); output [15:0] sum; //输出地址 input clk; input rst; reg [15:0] sum; //初值 always @(posedge clk)//正沿触发 begin if(!rst) //复位0有效 sum<=16'd0; else sum<=sum+fcw; //求和 end endmodule 3、sine_stimulate.v仿真测试文件 //sine_stimulate.v,my testbench `timescale 1ns/1ns modulesine_stimulate; // reg rst_n; //复位信号 reg clk; //时钟信号 wire signed[7:0]sine; sine_top uut0( .sine(sine), .clk(clk), .rst_n(rst_n) ); initial //过程语句,只执行一次(与always不同) begin clk=0; rst_n=0; #50; //延迟50ns rst_n=1; end always #5 clk=~clk; endmodule Quartus II 13.0 和ModelsimSE 10.1a联合仿真结果 仿真输出的正弦波: 插值后的正弦波图形: 这就是我用Verilog编程,采用DDS合成正弦波的所有流程。 ----------------------------------------------------------------------------------------------------------------- 赶紧动手开始探索你的神奇之旅吧,学习FPGA开发,享受Verilog编程、仿真带来的乐趣!!! 版主刚开始做教程,如有不足,敬请原谅!祝好! 附: 正弦查询表(.mif文件) |
|
相关推荐
92 个讨论
|
|
|
楼主能分享一下mif文件怎么产生的吗
|
|
|
|
|
|
|
|
|
楼主,你的波形拉到示波器上好丑呀!同学说是不是三角波
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
楼主,我用你的方法尝试,也没有显示出正弦波形,插值法怎么显示出来啊?求指导
|
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-1 10:47 , Processed in 1.155258 second(s), Total 75, Slave 67 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
2332