【Z-turn Board试用体验】+基于FPGA和DDS技术的三相正弦波的发生器设计 - 问答 - 电子技术论坛 - 最好最受欢迎电子论坛!

【Z-turn Board试用体验】+基于FPGA和DDS技术的三相正弦波的发生器设计

何立立 ( 楼主 ) 2015-5-30 10:50:36  显示全部楼层
本帖最后由 何立立 于 2015-5-30 11:12 编辑

  简介:根据现代电子系统对信号源的频率稳定度、准确度及分辨率越来越高的要求,结合直接数字式频率合成器(DDS)的优点,利用FPGA芯片的可编程性和实现方案易改动的特点,提出了一种基于FPGA和DDS技术的任意波形发生器设计方案。目前任意波形发生器的设计还在进行中。
  本文只给出实验阶段的三相正弦波的产生代码和仿真波形,产生的并不是任意波形了。
  DDS设计要求:频率分辨率<=0.001;输出正弦波40Hz-65Hz;输出三路正弦波;用RAM实现ROM查找表;RAM数据位宽16bit;
                三路正弦波的一周期最少输出1024点;
  基本原理:频率分辨率:ΔF=Fclk/(2^N);
            输出波形频率:Fout=K *Fclk/(2^N);
                 ( 其它原理以及怎么计算不再详细介绍,网上都可以直接查找到;)


  实现框图:
            QQ截图20150530094110.png
  根据上述公式可以计算得到(这里直接给出计算结果):累加器字长N=37,DDS频率Fclk=96KHz,ROM表深度4096,频率调制字长K为17位。
实现过程:
  查找表是一个rom。所以这里用ISE自带的rom的ip核。既然用到了rom,那么就要对rom里面的值要写入我们需要的值。这里就用ise的rom的ip核的固定初始化文件coe文件。
          Coe文件格式是:
          第一行是: MEMORY_INItiALIZATION_RADIX=10; 后面的10表示数据是以什么进制表示,这里是10进制,所以是10.如果是16就是16进制表示。
          第二行是:MEMORY_INITIALIZATION_VECTOR= 这个是固定的。
          接下来第三行就是数据,数据以逗号相隔,最后一个数据以分号结束。
           这里我们是要产生三路正弦波,所以需要三个rom。
           那就要对三相正弦波分别生成rom初始化文件coe。用matlab来生成。
           这里要注意,由于da只能转换正数值,所以要将sin的负值部分要处理一下,使之数据范围在0到1之间。
   生成正弦波matlab代码:
   0度:
  1. t=0:2*pi/2^12:2*pi;
  2. y=0.5*sin(t)+0.5;
  3. r=ceil(y*(2^16-1));%将小数(0,1)转变为整数,并就将数值扩大,ceil()像上取整%
  4. fid=fopen('sin_0du.coe','w');%写到sin.coe文件里,用来初始化sin_rom%
  5. fprintf(fid,'memory_initialization_radix=10;n');
  6. fprintf(fid,'memory_initialization_vector=n');
  7. for i=1:1:2^12
  8.     fprintf(fid,'%d',r(i));
  9.     if i==2^12
  10.         fprintf(fid,';');
  11.     else
  12.         fprintf(fid,',n');
  13.     end

  14. end
  15. fclose(fid);
复制代码

  120度:
  1. t=(2/3)*pi:2*pi/2^12:(8/3)*pi;
  2. y=0.5*sin(t)+0.5 ;
  3. r=ceil(y*(2^16-1));%将小数(0,1)转变为整数,并就将数值扩大,ceil()像上取整%
  4. fid=fopen('sin_120du.coe','w');%写到sin.coe文件里,用来初始化sin_rom%
  5. fprintf(fid,'memory_initialization_radix=10;n');
  6. fprintf(fid,'memory_initialization_vector=n');
  7. for i=1:1:2^12;
  8.     fprintf(fid,'%d',r(i));
  9.     if i==2^12
  10.         fprintf(fid,';');
  11.     else
  12.         fprintf(fid,',n');
  13.     end

  14. end
  15. fclose(fid);
复制代码

  -120度:
  1. t=(4/3)*pi:2*pi/2^12:(10/3)*pi;
  2. y=0.5*sin(t)+0.5 ;
  3. r=ceil(y*(2^16-1));%将小数(0,1)转变为整数,并就将数值扩大,ceil()像上取整%
  4. fid=fopen('sin_fu120du.coe','w');%写到sin.coe文件里,用来初始化sin_rom%
  5. fprintf(fid,'memory_initialization_radix=10;n');
  6. fprintf(fid,'memory_initialization_vector=n');
  7. for i=1:1:2^12;
  8.     fprintf(fid,'%d',r(i));
  9.     if i==2^12
  10.         fprintf(fid,';');
  11.     else
  12.         fprintf(fid,',n');
  13.     end

  14. end
  15. fclose(fid);
复制代码


FPGA中实现:
  系统时钟分频实现96Khz的DDS时钟:
  1. module dds_clk_ger(
  2.         rst_n,clk_24_576M,clk_96K
  3.     );
  4.         input rst_n;
  5.         input clk_24_576M;
  6.         output clk_96K;
  7.        
  8.         reg clk_96K;
  9.        
  10.         reg [6:0] cnt;//7位计数器
  11.        
  12.         always @(posedge clk_24_576M or negedge rst_n ) //采用异步复位
  13.                 begin
  14.                         if(!rst_n)
  15.                                 begin
  16.                                         cnt<=0;
  17.                                         clk_96K<=0;
  18.                                 end
  19.                         else
  20.                                 if(cnt==7'b1111111)//在第128个脉冲到来时进行频率翻转
  21.                                         begin
  22.                                                 cnt<=0;
  23.                                                 clk_96K<=!clk_96K;
  24.                                         end
  25.                         else
  26.                                 begin
  27.                                         cnt<=cnt+1'b1;//这里的1一定要表明位宽 1'b1,不然会出现位宽不统一
  28.                                         clk_96K<=clk_96K;
  29.                                 end
  30.                 end

  31. endmodule
复制代码


频率调制模块:
  1. module frequency_tiaozhi(
  2.     rst_n,k,clk_96K,       //DDS系统频率为80K
  3.          result
  4.          );
  5.          input rst_n;
  6.          input k;
  7.          input clk_96K;
  8.          output result;
  9.          
  10.          wire [16:0] k;//频率控制字长k为17位
  11.          reg [26:0] result;//相位寄存器的输出结果,寄存器位数27位
  12.          
  13.          wire [26:0] sum;//相加后的值,累加器的字长N=27
  14.          assign sum=k+result;
  15.        
  16.         always@(posedge clk_96K or negedge rst_n)
  17.                 begin
  18.                         if(!rst_n)
  19.                                 result<=0;
  20.                         else
  21.                                 begin
  22.                                         result<=sum;
  23.                                        
  24.                                 end
  25.                 end
  26.        

  27. endmodule
复制代码

顶层模块:将前面几个模块接起来就好了:
其中U3,U4,U5是0读正弦波,120度,-120度正弦波例化ROM核。
111.png
121212.png

添加测试文件:
  1. module dds_top_tb;

  2.         // Inputs
  3.         reg clk_24_576M;
  4.         reg rst_n;
  5.         reg [16:0] k;

  6.         // Outputs
  7.         wire [15:0] dds_data_sin_0du;
  8.         wire [15:0] dds_data_sin_120du;
  9.         wire [15:0] dds_data_sin_fu120du;

  10.         // Instantiate the Unit Under Test (UUT)
  11.         dds_top uut (
  12.                 .clk_24_576M(clk_24_576M),
  13.                 .rst_n(rst_n),
  14.                 .k(k),
  15.                 .dds_data_sin_0du(dds_data_sin_0du),
  16.                 .dds_data_sin_120du(dds_data_sin_120du),
  17.                 .dds_data_sin_fu120du(dds_data_sin_fu120du)
  18.         );

  19.         initial begin
  20.                 // Initialize Inputs
  21.                 clk_24_576M = 0;
  22.                 rst_n = 0;
  23.                 k = 0;

  24.                 // Wait 100 ns for global reset to finish
  25.                 #100;
  26.        rst_n=1;
  27.                  k=90877;
  28.                 // Add stimulus here
  29.        
  30.         end
  31.       always #20.345 clk_24_576M=!clk_24_576M;
  32. endmodule
复制代码
仿真波形:
  K=55924时波形频率应该为40Hz
22222.png

[size=14.3999996185303px]  K=90877时波形频率应该为65Hz
4444444.png

这样就完成了一个简单的DDS波形发生器的实验了。

接下来是通过ARM向FPGA内RAM写波形数据,给频率控制字来实现任意波形的产生。



8个回复

HelloWii 发表于 2015-5-31 10:57:55
学习一下。。。
回复 1

举报 使用道具

blackroot 发表于 2015-5-31 21:21:08
楼主,使用PL部分的时候,PL部分的时钟是怎样输入进来的?
blackroot 发表于 2015-5-31 21:24:41
比如PL部分的时钟管脚分配是在那个管脚上啊?
东东 发表于 2015-10-30 10:30:35
楼主好厉害,学习了----------
吴津庆 发表于 2017-7-3 13:40:54
很不错的资料,但是你的96KHz那一块好像有点问题
xingzai2013 发表于 2017-12-29 16:33:41
学习了,学习了
贺明辉 发表于 2018-1-4 11:18:59
不错资料,感谢分享
小白 发表于 2018-5-15 13:55:15
不错的介绍,思路清晰,非常好。
您需要登录后才可以回帖 登录 | 注册

本版积分规则


关闭

站长推荐上一条 /6 下一条

小黑屋|手机版|Archiver|电子发烧友 ( 湘ICP备2023018690号 )

GMT+8, 2024-4-17 07:31 , Processed in 0.551486 second(s), Total 64, Slave 45 queries .

Powered by 电子发烧友网

© 2015 bbs.elecfans.com

微信扫描
快速回复 返回顶部 返回列表