如何利用FPGA生成SPWM调制信号

2 篇文章 0 订阅
1 篇文章 1 订阅

实验目标

想生成20kHz的正弦波的SPWM信号

稍微说一下原理

SPWM即正弦波宽度脉冲调制

脉冲宽度随着sin函数发生变化。

冲量等效原理

冲量相等而形状不同的窄脉冲加在具有惯性的环节上时,其效果基本相同;冲量即窄脉冲的积分面积,所说的效果基本相同是指环节的输出波形基本相同。如果把各输入波形用傅里叶变换分析,则其低频段非常接近,仅在高频略有差异。
如下图,上下电压的分为14小段,每段的面积积分应是一致的,这样通过惯性环节时就会得到相同的输出:
在这里插入图片描述

双极性的的SPWM信号

本次是通过三角波和正弦波幅值大小进行对比,在下图中:三角波大于正弦波时,SPWM信号为0,反之,为1,产生了不规则占空比的下面的SPWM波形。
注意:
①三角波频率f1和正弦波频率f2的比值N为载波比,N需要大一点
②要保证三角波的峰峰值大于等于正弦波的峰峰值
在这里插入图片描述
原理性的具体可以参考:
[1]https://wenku.baidu.com/view/99d488ea7275a417866fb84ae45c3b3566ecddf8.html?fr=search-4
[2]https://wenku.baidu.com/view/94564f1d24c52cc58bd63186bceb19e8b8f6ecf1.html

具体步骤

1.用matlab生成三角波和正弦波的coe文件

1.创建matlab文件写代码:

clc;
close all;
clear;
%%triangle wave
k=1/50;
t0=0:1:24;
t1=25:1:49;
a0=k*t0;
a1=k*t1;
t2=50:1:99;
a2=1-k*(t2-50);
a=[a1,a2,a0];
t=[t0,t1,t2];
y0=round(a*1024);
 plot (y0)
 hold on
%%sine wave
 t3=0:1:999;
 A=0.25*sin(2*pi*t3/1000)+0.5;
y1=round(A*1024);
plot(y1)
%%
l1=length(t);%三角波的长度
l2=length(t3);%正弦波的序列长度


%%生成文件三角波coe文件
fid1=fopen('triwave.coe','w+');
fprintf(fid1,'memory_initialization_radix = 16;\n');
fprintf(fid1,'memory_initialization_vector =\n');
for i=1:l1-1
fprintf(fid1,'%x',y0(i));
fprintf(fid1,',\n');
end
fprintf(fid1,'%x',y0(l1));
fprintf(fid1,';');
fclose(fid1);

%%生成正弦波coe文件
fid1=fopen('sinwave.coe','w+');
fprintf(fid1,'memory_initialization_radix = 16;\n');
fprintf(fid1,'memory_initialization_vector =\n');
for i=1:l2-1
fprintf(fid1,'%x',y1(i));
fprintf(fid1,',\n');
end
fprintf(fid1,'%x',y1(l2));
fprintf(fid1,';');
fclose(fid1);

生成的数据分别是一个周期的三角波采样和一个周期的正弦波采样,这里我们设置的正弦波的周期是三角波的十倍。
在这里插入图片描述

2.找不到生成的文件,一般是路径的问题。检查你的路径没问题的话,会出现以下文件。
在这里插入图片描述
这些文件作为fpga导入rom ip核的coe文件。
tips:生成的coe文件可以直接拖进matlab的执行框或者vivado里面看一看是否正常。

2.调用ROM的ip读取coe文件

1.vivado新建好工程,一系列不再多说。
2.点击IP Catalog在这里插入图片描述

3.搜索ROM,点击Block Memory Generator
4.根据三角波的coe可以看到,进制是16,共102行,所以去掉前两行声明,共100行数。所以数据宽度width为3个16进制数,1个16进制数4位,共12位;深度depth位100。
在这里插入图片描述

5.根据上面的结论,创建三角波的rom_ip1,修改加亮处
在这里插入图片描述
选择三角波的文件
在这里插入图片描述
6. 点击 ok,点击 Generate 生成 ip 核。
在这里插入图片描述
7.同理,正弦波的也可以这么调用,步骤大致相同,不同的地方:
①正弦波的数据深度为1000
在这里插入图片描述

②调用的文件为正弦波的coe
在这里插入图片描述

3.调用pll的ip核来提供三角波和正弦波的控制时序

IP Catalog搜clock 选择Clocking Wizard
在这里插入图片描述
修改加亮区域
在这里插入图片描述
在这里插入图片描述
输出时钟
在这里插入图片描述
我想输出的是20kHz的正弦波,matlab生成的一个周期的正弦波是1000个点,20乘1000乘1000,所以这里输出的时钟1应该为20MHz,我因为刚入门练手所以生成80MHz,后面多写了一个四分频,其实是一样的。

新建wave_clk.v代码如下,调用了Clocking Wizard的ip
要注意,IP中的reset和设置的iRST_n高低有效是相反的,所以括号里加了~。

module wave_clk(
input iSys_clk,
input iRst_n,
output  oTri_clk,
output  oSin_clk
);
    wire locked;
    wire clk_temp1;
    reg [1:0] cnt1;
   // reg [5:0] cnt2;
    clk_wiz1 clk_generator 
     (
      // Clock out ports
      .clk_out1(clk_temp1),     // output clk_out1
      // Status and control signals
      .reset(~iRst_n), // input reset
      .locked(locked),       // output locked
     // Clock in ports
      .clk_in1(iSys_clk));     
      
      always@(posedge clk_temp1 or negedge iRst_n)
      begin
      if(!iRst_n)
      //begin
      cnt1<=2'b00;
      //cnt2<=6'b00;
      //end
      else if (cnt1==2'b11)
      cnt1<=2'b00;
      //else if (cnt2==6'd39)
      //cnt2<=6'b00;
      else //begin
      cnt1<=cnt1+1;
      //cnt2<=cnt2+1;
      //end
      end
     assign oTri_clk=(cnt1==2'b00) ?1:0;
     assign oSin_clk=(cnt1==2'b00) ?1:0;
//assign oSin_clk=(cnt2==2'b00) ?1:0;
endmodule

4.调用ROM的ip来获取数据,进行比较

新建一个wave_comparator.v,这个文件是用来读取ROM的数据,然后比较得出SPWM的信号为1还是为0;
调用上面两个已经生成ROM IP
代码如下:

module wave_comparator(
input iCLK_tri,
input iCLK_sin,
input iRST_n,//
output oComparator
);
    wire [11:0] Read_tri_data,Read_sin_data;
    reg [7:0]   Read_tri_addr;
    reg [9:0]   Read_sin_addr;
    
    always@(posedge iCLK_tri or negedge iRST_n )
    begin
    if(!iRST_n)
    Read_tri_addr<=0;//addr=0 data=?
    else if(Read_tri_addr==7'd99)//99 or 100?
    Read_tri_addr<=0;
    else
    Read_tri_addr<=Read_tri_addr+1;
    end
    
    always@(posedge iCLK_sin or negedge iRST_n )
    begin
    if(!iRST_n)
    Read_sin_addr<=0;
    else if(Read_sin_addr==10'd999)
    Read_sin_addr<=0;
    else
    Read_sin_addr<=Read_sin_addr+1;
    end
       
    rom_ip1 rom_tri
    (
    .clka(iCLK_tri),
    .addra(Read_tri_addr),
    .douta(Read_tri_data)
    );

    rom_ip2 rom_sin
    (
    .clka(iCLK_sin),
    .addra(Read_sin_addr),
    .douta(Read_sin_data)
    );    
    assign oComparator=(Read_tri_data<Read_sin_data)?1:0;
    
endmodule

5.建立wave.v调用wave_clk和wave_comparator

在这里插入图片描述
在这里插入图片描述
ALI和BLI就是输出的SPWM信号,ALI和BLI反相。

module wave(
input iSys_clk,
input iRst_n,
output ALI,BLI
    );
    wire oTri_clk;
    wire oSin_clk;
    
    wave_clk wave_clk
    (
    . iSys_clk(iSys_clk),
    . iRst_n(iRst_n),
    .  oTri_clk(oTri_clk),
    .  oSin_clk(oSin_clk)
    );
    wave_comparator wave_comparator
    (
    . iCLK_tri(oTri_clk),
    . iCLK_sin(oSin_clk),
    . iRST_n(iRst_n),//
    . oComparator(ALI)
    
    );
   assign BLI=~ALI;
   
   
 /*  ila ILA
   (
   .clk(iSys_clk),
   
   
   .probe0(iSys_clk),
   .probe1(oTri_clk),
   .probe2(oSin_clk),
   .probe3(iRst_n),
   .probe4(ALI)
   

   );
   */
endmodule

7.进行管脚约束

在这里插入图片描述
输入的选择系统时钟管脚,iRst_n用的是摁键开关,输出选择绑定io管脚输出,具体请参考开发板的原理图进行绑定约束
在这里插入图片描述

8.generate bitstream and program device

在这里插入图片描述

9.示波器观察

大概是对的吧,uhhhhh~
在这里插入图片描述

回顾

其实生成方法有很多种,可以一开始在matlab里面就比较完生成0和1的信号在直接导入,也可以用vivado完成大部分工作,每一个步骤其实都有很多替代方案,实现的方法多种多样是很灵活的,我刚刚入门开始学习,我写的方法比较笨和麻烦,本篇作为自己以后忘了复习用。

  • 19
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值