实验目标
想生成20kHz的正弦波的SPWM信号
稍微说一下原理
SPWM即正弦波宽度脉冲调制
脉冲宽度随着sin函数发生变化。
冲量等效原理
冲量相等而形状不同的窄脉冲加在具有惯性的环节上时,其效果基本相同;冲量即窄脉冲的积分面积,所说的效果基本相同是指环节的输出波形基本相同。如果把各输入波形用傅里叶变换分析,则其低频段非常接近,仅在高频略有差异。
如下图,上下电压的分为14小段,每段的面积积分应是一致的,这样通过惯性环节时就会得到相同的输出:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818223245168.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
双极性的的SPWM信号
本次是通过三角波和正弦波幅值大小进行对比,在下图中:三角波大于正弦波时,SPWM信号为0,反之,为1,产生了不规则占空比的下面的SPWM波形。
注意:
①三角波频率f1和正弦波频率f2的比值N为载波比,N需要大一点
②要保证三角波的峰峰值大于等于正弦波的峰峰值
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818223557581.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
原理性的具体可以参考:
[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);
生成的数据分别是一个周期的三角波采样和一个周期的正弦波采样,这里我们设置的正弦波的周期是三角波的十倍。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819094423840.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
2.找不到生成的文件,一般是路径的问题。检查你的路径没问题的话,会出现以下文件。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200818224938465.png#pic_center)
这些文件作为fpga导入rom ip核的coe文件。
tips:生成的coe文件可以直接拖进matlab的执行框或者vivado里面看一看是否正常。
2.调用ROM的ip读取coe文件
1.vivado新建好工程,一系列不再多说。
2.点击IP Catalog![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819092655984.png#pic_center)
3.搜索ROM,点击Block Memory Generator![](https://img-blog.csdnimg.cn/2020081909280191.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
4.根据三角波的coe可以看到,进制是16,共102行,所以去掉前两行声明,共100行数。所以数据宽度width为3个16进制数,1个16进制数4位,共12位;深度depth位100。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819093540875.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
5.根据上面的结论,创建三角波的rom_ip1,修改加亮处
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819093407388.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
选择三角波的文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819093927988.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
6. 点击 ok,点击 Generate 生成 ip 核。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819094059354.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
7.同理,正弦波的也可以这么调用,步骤大致相同,不同的地方:
①正弦波的数据深度为1000
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819094310513.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
②调用的文件为正弦波的coe
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819094335774.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
3.调用pll的ip核来提供三角波和正弦波的控制时序
IP Catalog搜clock 选择Clocking Wizard
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020081909572757.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
修改加亮区域
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819100109948.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819100211787.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
输出时钟
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819100045247.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
我想输出的是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
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819101734290.png#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819101819686.png#pic_center)
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.进行管脚约束
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819102159374.png#pic_center)
输入的选择系统时钟管脚,iRst_n用的是摁键开关,输出选择绑定io管脚输出,具体请参考开发板的原理图进行绑定约束
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819102517847.png#pic_center)
8.generate bitstream and program device
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819103019859.png#pic_center)
9.示波器观察
大概是对的吧,uhhhhh~
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200819103223108.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTUyNjQ1Ng==,size_16,color_FFFFFF,t_70#pic_center)
回顾
其实生成方法有很多种,可以一开始在matlab里面就比较完生成0和1的信号在直接导入,也可以用vivado完成大部分工作,每一个步骤其实都有很多替代方案,实现的方法多种多样是很灵活的,我刚刚入门开始学习,我写的方法比较笨和麻烦,本篇作为自己以后忘了复习用。