利用MATLAB計算SPWM脈衝寬度與並應用STM32輸出
阿新 • • 發佈:2019-01-24
轉自 光電科技協會 王誠博
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波):
- %% 計算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波形。