您的位置:首页 > 编程语言 > MATLAB

利用MATLAB计算SPWM脉冲宽度与并应用STM32输出

2017-09-01 09:19 399 查看
转自 光电科技协会 王诚博
http://blog.csdn.net/wcb425499094/article/details/76703042
先上一张spwm波形生成原理图:



首先利用MATLAB产生三角波与正弦波叠加:

[cpp]
view plain
copy
print?

%% 产生正弦波与三角波叠加  
y1=abs(sawtooth(a*2*pi*m,0.5));%三角波  
y2=0.8*sin(a*pi);%正弦波  
figure(1)  
plot(a,y1,a,y2)  



%% 产生正弦波与三角波叠加
y1=abs(sawtooth(a*2*pi*m,0.5));%三角波
y2=0.8*sin(a*pi);%正弦波
figure(1)
plot(a,y1,a,y2)

如图:



接着取交点,想了两种方法:

1.直接图片上取点,该方法不精确,毕竟只能目测和用鼠标点击。

[cpp]
view plain
copy
print?

[X Y]=ginput(40)%图像中取点(不精确)  
save('kuan','X');  



[X Y]=ginput(40)%图像中取点(不精确)
save('kuan','X');


2.做差,使用阈值。

[cpp]
view plain
copy
print?

for i=1:length(y1)%利用差值取点,设定阈值  
    if(abs(y1(i)-y2(i))<0.01)  
        X(P)=a(i);  
        P=P+1;  
    end  
end  



for i=1:length(y1)%利用差值取点,设定阈值
if(abs(y1(i)-y2(i))<0.01)
X(P)=a(i);
P=P+1;
end
end


阈值设置为0.001只取出20个点,但如上图应该有40个点,所以增大阈值,设为0.01。

取出了200个点,如图:



放大观察:



可知每个交点取出了5个点,40个点刚好200个,所以假设正弦波与三角波交点附近正弦波斜率不变,所以采用平均的方法:

[html]
view plain
copy
print?

for i=0:m*4-1%取平均值  
        x(i+1)=(X((i+1)*5)+X(i*5+1))/2;  
end  



for i=0:m*4-1%取平均值
x(i+1)=(X((i+1)*5)+X(i*5+1))/2;
end


然后就可以画出spwm波形:

[cpp]
view plain
copy
print?

%% 画出SPWM波形  
for n=1:m*2  
       y3(1:floor(x(1)*10000))=0;  
       y3(floor(x(2*n-1)*10000):floor(x(2*n)*10000))=0.8;  
       if(n==20)  
       break  
       end  
       y3(floor(x(2*n)*10000):floor(x(2*(n+1)-1)*10000))=0;  
       y3(floor(x(40)*10000):length(y3))=0;  
end  
figure(4)  
plot(a,y3)  
axis([0 1 0 1])  



%% 画出SPWM波形
for n=1:m*2
y3(1:floor(x(1)*10000))=0;
y3(floor(x(2*n-1)*10000):floor(x(2*n)*10000))=0.8;
if(n==20)
break
end
y3(floor(x(2*n)*10000):floor(x(2*(n+1)-1)*10000))=0;
y3(floor(x(40)*10000):length(y3))=0;
end
figure(4)
plot(a,y3)
axis([0 1 0 1])


如图:



最后,计算正弦波半个周期的spwm的周期和占空比(使用stm32输出比较器输出pwm波):

[cpp]
view plain
copy
print?

%% 计算SPWM的周期,占空比(利用输出比较器)  
for i=1:m  
    tp(i)=(x(2*(i+1)-1)-x(2*i-1))*th;%spwm周期  
    ti(i)=(x(2*i)-x(2*i-1))*th;%脉冲宽度  
end  
tc=[floor(tp./max(tp)*255),fliplr(floor(tp./max(tp)*255))];%单片机定时器从1计到255(最大spwm周期)  
dlmwrite('cycle.c',tc);%写入c文件  
p=ti./tp;%计算spwm占空比  
p1=[p fliplr(p)];%半个正弦波周期spwm的占空比序列  
p1=floor(p1.*tc);%单片机定时器基准脉冲宽度  
dlmwrite('dac_sinWave.c',p1);  



%% 计算SPWM的周期,占空比(利用输出比较器)
for i=1:m
tp(i)=(x(2*(i+1)-1)-x(2*i-1))*th;%spwm周期
ti(i)=(x(2*i)-x(2*i-1))*th;%脉冲宽度
end
tc=[floor(tp./max(tp)*255),fliplr(floor(tp./max(tp)*255))];%单片机定时器从1计到255(最大spwm周期)
dlmwrite('cycle.c',tc);%写入c文件
p=ti./tp;%计算spwm占空比
p1=[p fliplr(p)];%半个正弦波周期spwm的占空比序列
p1=floor(p1.*tc);%单片机定时器基准脉冲宽度
dlmwrite('dac_sinWave.c',p1);


如果使用DAC描点:

[cpp]
view plain
copy
print?

b=floor(linspace(0,1,258)*10000);  
for i=1:256  
y4(i)=floor(y3(b(i+1))*4095);  
end  
dlmwrite('dac_SPWM.c',y4);  



b=floor(linspace(0,1,258)*10000);
for i=1:256
y4(i)=floor(y3(b(i+1))*4095);
end
dlmwrite('dac_SPWM.c',y4);


但该方法速度太慢,而且单片机利用效率太低,所以舍弃。

下面粘上MATLAB源代码:

[cpp]
view plain
copy
print?

%% 变量初始化  
t=0.02;%正弦波周期  
th=t/2;%半波周期  
m=10;%三角波周期数  
a=0:0.0001:1;  
y3=0:0.0001:1;  
P=1;  
x=zeros(1);%分配空间  
tp=zeros(1);  
ti=zeros(1);  
%% 产生正弦波与三角波叠加  
y1=abs(sawtooth(a*2*pi*m,0.5));%三角波  
y2=0.8*sin(a*pi);%正弦波  
figure(1)  
plot(a,y1,a,y2)  
%% 取点  
%[X Y]=ginput(40)%图像中取点(不精确)  
% save('kuan','X');  
for i=1:length(y1)%利用差值取点,设定阈值  
    if(abs(y1(i)-y2(i))<0.01)  
        X(P)=a(i);  
        P=P+1;  
    end  
end  
figure(2)  
plot(a,y1,a,y2,X,1,'*')  
for i=0:m*4-1%取平均值  
        x(i+1)=(X((i+1)*5)+X(i*5+1))/2;  
end  
figure(3)  
plot(a,y1,a,y2,x,1,'*')  
%% 画出SPWM波形  
for n=1:m*2  
       y3(1:floor(x(1)*10000))=0;  
       y3(floor(x(2*n-1)*10000):floor(x(2*n)*10000))=0.8;  
       if(n==20)  
       break  
       end  
       y3(floor(x(2*n)*10000):floor(x(2*(n+1)-1)*10000))=0;  
       y3(floor(x(40)*10000):length(y3))=0;  
end  
figure(4)  
plot(a,y3)  
axis([0 1 0 1])  
%% DAC描点法(速度太慢舍弃)  
% b=floor(linspace(0,1,258)*10000);  
% for i=1:256  
% y4(i)=floor(y3(b(i+1))*4095);  
% end  
% dlmwrite('dac_SPWM.c',y4);  
%% 计算SPWM的周期,占空比(利用输出比较器)  
for i=1:m  
    tp(i)=(x(2*(i+1)-1)-x(2*i-1))*th;%spwm周期  
    ti(i)=(x(2*i)-x(2*i-1))*th;%脉冲宽度  
end  
tc=[floor(tp./max(tp)*255),fliplr(floor(tp./max(tp)*255))];%单片机定时器从1计到255(最大spwm周期)  
dlmwrite('cycle.c',tc);%写入c文件  
p=ti./tp;%计算spwm占空比  
p1=[p fliplr(p)];%半个正弦波周期spwm的占空比序列  
p1=floor(p1.*tc);%单片机定时器基准脉冲宽度  
dlmwrite('dac_sinWave.c',p1);  
   



%% 变量初始化
t=0.02;%正弦波周期
th=t/2;%半波周期
m=10;%三角波周期数
a=0:0.0001:1;
y3=0:0.0001:1;
P=1;
x=zeros(1);%分配空间
tp=zeros(1);
ti=zeros(1);
%% 产生正弦波与三角波叠加 y1=abs(sawtooth(a*2*pi*m,0.5));%三角波 y2=0.8*sin(a*pi);%正弦波 figure(1) plot(a,y1,a,y2)%% 取点
%[X Y]=ginput(40)%图像中取点(不精确)
% save('kuan','X');
for i=1:length(y1)%利用差值取点,设定阈值 if(abs(y1(i)-y2(i))<0.01) X(P)=a(i); P=P+1; end end
figure(2)
plot(a,y1,a,y2,X,1,'*')
for i=0:m*4-1%取平均值 x(i+1)=(X((i+1)*5)+X(i*5+1))/2; end
figure(3)
plot(a,y1,a,y2,x,1,'*')
%% 画出SPWM波形 for n=1:m*2 y3(1:floor(x(1)*10000))=0; y3(floor(x(2*n-1)*10000):floor(x(2*n)*10000))=0.8; if(n==20) break end y3(floor(x(2*n)*10000):floor(x(2*(n+1)-1)*10000))=0; y3(floor(x(40)*10000):length(y3))=0; end figure(4) plot(a,y3) axis([0 1 0 1])
%% DAC描点法(速度太慢舍弃)
% b=floor(linspace(0,1,258)*10000);
% for i=1:256
% y4(i)=floor(y3(b(i+1))*4095);
% end
% dlmwrite('dac_SPWM.c',y4);
%% 计算SPWM的周期,占空比(利用输出比较器) for i=1:m tp(i)=(x(2*(i+1)-1)-x(2*i-1))*th;%spwm周期 ti(i)=(x(2*i)-x(2*i-1))*th;%脉冲宽度 end tc=[floor(tp./max(tp)*255),fliplr(floor(tp./max(tp)*255))];%单片机定时器从1计到255(最大spwm周期) dlmwrite('cycle.c',tc);%写入c文件 p=ti./tp;%计算spwm占空比 p1=[p fliplr(p)];%半个正弦波周期spwm的占空比序列 p1=floor(p1.*tc);%单片机定时器基准脉冲宽度 dlmwrite('dac_sinWave.c',p1);


stm32程序是用野火的例程改的,经过MATLAB计算得出周期与占空比(放入定时器的自动重装载寄存器ARR和比较寄存器CRR):

[cpp]
view plain
copy
print?

uint8_t indexWave[] = {16,47,78,106,132,155,174,188,198,203,203,198,  
188,174,155,132,106,78,47,16};  
uint8_t indexcycle[] = {241,241,242,243,244,246,248,250,252,255,255,  
252,250,248,246,244,243,242,241,241};  



uint8_t indexWave[] = {16,47,78,106,132,155,174,188,198,203,203,198,
188,174,155,132,106,78,47,16};
uint8_t indexcycle[] = {241,241,242,243,244,246,248,250,252,255,255,
252,250,248,246,244,243,242,241,241};


在中断中改变寄存器的值(三路输出):

[cpp]
view plain
copy
print?

TIM3->ARR = indexcycle[pwm_index];     
TIM3->CCR2 = indexWave[pwm_index];     
TIM3->CCR3 = indexWave[pwm_index];        
TIM3->CCR4 = indexWave[pwm_index];     
pwm_index++;                                                  



TIM3->ARR = indexcycle[pwm_index];
TIM3->CCR2 = indexWave[pwm_index];
TIM3->CCR3 = indexWave[pwm_index];
TIM3->CCR4 = indexWave[pwm_index];
pwm_index++;


定时器配置

[cpp]
view plain
copy
print?

/*基本定时器配置*/  



/*基本定时器配置*/


[cpp]
view plain
copy
print?

TIM_TimeBaseStructure.TIM_Period = 255;                                    
TIM_TimeBaseStructure.TIM_Prescaler = 0;                                      
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;              
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;    
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);  



TIM_TimeBaseStructure.TIM_Period = 255;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);


[cpp]
view plain
copy
print?

/*PWM模式配置*/  



/*PWM模式配置*/


[cpp]
view plain
copy
print?

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                         
 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    
 TIM_OCInitStructure.TIM_Pulse = 0;                                                   
 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                                                          <span style="font-family: Arial, Helvetica, sans-serif;">   </span>  



TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;


[cpp]
view plain
copy
print?

TIM_OC2Init(TIM3, &TIM_OCInitStructure);  
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  
    
TIM_OC3Init(TIM3, &TIM_OCInitStructure);      
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  
    
TIM_OC4Init(TIM3, &TIM_OCInitStructure);  
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  
TIM_ARRPreloadConfig(TIM3, ENABLE);  
/* TIM3 enable counter */  
TIM_Cmd(TIM3, ENABLE);    
  
TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE);  
          
NVIC_Config_PWM();  



TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);

TIM_OC4Init(TIM3, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE);

TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE);

NVIC_Config_PWM();


使用示波器观察得到SPWM输出:



看出这是SPWM波形。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐