UVW 3 phases Brushless DC motor control

Dependencies:   QEI mbed-rtos mbed

Fork of DCmotor by manabu kosaka

Revision:
13:791e20f1af43
Parent:
12:a4b17bb682eb
--- a/UVWpwm.cpp	Fri Dec 21 22:06:56 2012 +0000
+++ b/UVWpwm.cpp	Sun Mar 03 09:09:34 2013 +0000
@@ -1,44 +1,65 @@
 #include "mbed.h"
 #include "controller.h"
-#include "UVWpwm.h"
+#include "UVWpwm.h"  // PWM発生用UVWpwm.cppの変数や定数の定義
+
+#define DEADTIME_US (unsigned long)(DEADTIME*1000000)  // [us], デッドタイム
 
-#define DEADTIME_US (unsigned long)(DEADTIME*1000000)  // [us], deadtime to be set between plus volt. to/from minus
+Timeout pwm[3];    // タイムアウト関数の宣言(ある時間経過後に関数コールする)
 
-Timeout pwm[3];
-
+// デジタル信号を出力するポートupperとlowerをU, V, W相について設定
 DigitalOut pwm_upper[] = {(U_UPPER_PORT), (V_UPPER_PORT),(W_UPPER_PORT)};
 DigitalOut pwm_lower[] = {(U_LOWER_PORT), (V_LOWER_PORT),(W_LOWER_PORT)};
 
-pwm_parameters     uvw[3]; // UVW pwm の定数、変数
+pwm_parameters     uvw[3]; // UVW相pwm用の定数、変数宣言
+
+// U, V相シャント抵抗の両端の電圧のアナログ入力名の設定, *3.3[V]
+AnalogIn VshuntR_Uplus( R_SHUNT_UP_PORT); // *3.3[V], U相+側アナログ入力
+AnalogIn VshuntR_Uminus(R_SHUNT_UM_PORT); // *3.3[V], U相-側アナログ入力
+AnalogIn VshuntR_Vplus( R_SHUNT_VP_PORT); // *3.3[V], V相+側アナログ入力
+AnalogIn VshuntR_Vminus(R_SHUNT_VM_PORT); // *3.3[V], V相-側アナログ入力
 
 // 関数配列: NG
 //void (*pwmUVWout[])(int) = {pwmout,pwmout,pwmout};
 //  pwmUVWout[i](i);
 
 #if PWM_WAVEFORM==0   // 0: saw tooth wave comparison
-void pwmUout() {    // pwm out using timer
-    unsigned char   i=0;
-    uvw[i].mode += 1;
-    if( uvw[i].mode==1 ){
-        pwm_upper[i] = 1;
-        pwm_lower[i] = 0;
-        uvw[i].upper_us = uvw[i].duty*1000000/PWM_FREQ - DEADTIME_US;   // ON time of Uupper
-        pwm[i].attach_us(&pwmUout, uvw[i].upper_us); // setup pwmU to call pwmUout after t [us]
-        uvw[i].lower_us = 1000000/PWM_FREQ -uvw[i].upper_us - 2*DEADTIME_US; // ON time of Ulower
-    }else if( uvw[i].mode==2 ){
-        pwm[i].attach_us(&pwmUout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
-        pwm_upper[i] = 0;
-        pwm_lower[i] = 0;
-    }else if( uvw[i].mode==3 ){
-        pwm[i].attach_us(&pwmUout, uvw[i].lower_us); // setup pwmU to call pwmUout after t [us]
-        pwm_upper[i] = 0;
-        pwm_lower[i] = 1;
-    }else{// if( u.mode==4 ){
-        pwm[i].attach_us(&pwmUout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
-        pwm_upper[i] = 0;
-        pwm_lower[i] = 0;
-        uvw[i].mode = 0;
-    }
+void pwmUout() {    // タイムアウト関数でU相PWMを発生する関数
+    unsigned char   i=0;  // i=0のときU相
+    uvw[i].mode += 1;   // チョッピングのオンオフを決定するモードを1増やす
+    if( uvw[i].mode==1 ){       // モードが1のとき、Tonの状態をつくる
+        pwm_upper[i] = 1;         // 上アームUuをオン
+        pwm_lower[i] = 0;         // 下アームUdをオフ
+        // モード1の時間幅 T1 = Ton-Tdt を計算
+        uvw[i].upper_us = uvw[i].duty*1000000/PWM_FREQ - DEADTIME_US;
+        // 時間幅が小さいときはTMINにする
+        if( uvw[i].upper_us < TMIN ){  uvw[i].upper_us=TMIN;}
+        // T1[μs]経過してからタイムアウトでこの関数自身をコール
+        pwm[i].attach_us(&pwmUout, uvw[i].upper_us);
+        // モード3の時間幅 T3=Toff-Tdt=Tpwm-(T1+Tdt)-Tdtを計算
+        uvw[i].lower_us = 1000000/PWM_FREQ -uvw[i].upper_us - 2*DEADTIME_US;
+        // 時間幅が小さいときはTMINにする
+        if( uvw[i].lower_us < TMIN ){  uvw[i].lower_us=TMIN;}
+    }else if( uvw[i].mode==2 ){ // モードが2のとき、デッドタイムをつくる
+        // Tdt[μs]経過してからタイムアウトでこの関数自身をコール
+        pwm[i].attach_us(&pwmUout, DEADTIME_US);
+#ifndef SIMULATION
+        // シャント抵抗の両端の電圧を見てモータ電流を検出
+        p.iuvw[0] = (VshuntR_Uplus - VshuntR_Uminus)*3.3 /R_SHUNT; // iu [A]
+#endif
+        pwm_upper[i] = 0;         // 上アームUuをオフ
+        pwm_lower[i] = 0;         // 下アームUdをオフ
+    }else if( uvw[i].mode==3 ){ // モードが3のとき、Toffの状態をつくる
+        // T3[μs]経過してからタイムアウトでこの関数自身をコール
+        pwm[i].attach_us(&pwmUout, uvw[i].lower_us);
+        pwm_upper[i] = 0;         // 上アームUuをオフ
+        pwm_lower[i] = 1;         // 下アームUdをオン
+    }else{                     // モードが4のとき、デッドタイムをつくる
+        // Tdt[μs]経過してからタイムアウトでこの関数自身をコール
+        pwm[i].attach_us(&pwmUout, DEADTIME_US);
+        pwm_upper[i] = 0;         // 上アームUuをオフ
+        pwm_lower[i] = 0;         // 下アームUdをオフ
+        uvw[i].mode = 0;          // チョッピングのオンオフを決定するモードを
+    }                             // 0にする
 }
 
 void pwmVout() {    // pwm out using timer
@@ -48,10 +69,16 @@
         pwm_upper[i] = 1;
         pwm_lower[i] = 0;
         uvw[i].upper_us = uvw[i].duty*1000000/PWM_FREQ - DEADTIME_US;   // ON time of Uupper
+        if( uvw[i].upper_us < TMIN ){  uvw[i].upper_us=TMIN;}
         pwm[i].attach_us(&pwmVout, uvw[i].upper_us); // setup pwmU to call pwmUout after t [us]
         uvw[i].lower_us = 1000000/PWM_FREQ -uvw[i].upper_us - 2*DEADTIME_US; // ON time of Ulower
+        if( uvw[i].lower_us < TMIN ){  uvw[i].lower_us=TMIN;}
     }else if( uvw[i].mode==2 ){
         pwm[i].attach_us(&pwmVout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
+#ifndef SIMULATION
+        // シャント抵抗の両端の電圧を見てモータ電流を検出
+        p.iuvw[1] = (VshuntR_Vplus - VshuntR_Vminus)*3.3 /R_SHUNT; // iv [A]
+#endif
         pwm_upper[i] = 0;
         pwm_lower[i] = 0;
     }else if( uvw[i].mode==3 ){
@@ -73,8 +100,10 @@
         pwm_upper[i] = 1;
         pwm_lower[i] = 0;
         uvw[i].upper_us = uvw[i].duty*1000000/PWM_FREQ - DEADTIME_US;   // ON time of Uupper
+        if( uvw[i].upper_us < TMIN ){  uvw[i].upper_us=TMIN;}
         pwm[i].attach_us(&pwmWout, uvw[i].upper_us); // setup pwmU to call pwmUout after t [us]
         uvw[i].lower_us = 1000000/PWM_FREQ -uvw[i].upper_us - 2*DEADTIME_US; // ON time of Ulower
+        if( uvw[i].lower_us < TMIN ){  uvw[i].lower_us=TMIN;}
     }else if( uvw[i].mode==2 ){
         pwm[i].attach_us(&pwmWout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
         pwm_upper[i] = 0;
@@ -91,34 +120,49 @@
     }
 }
 #elif PWM_WAVEFORM==1   // 1: triangler wave comparison
-void pwmUout() {    // pwm out using timer
-    unsigned char   i=0;
-    uvw[i].mode += 1;
-    if( uvw[i].mode==1 ){
-        uvw[i].upper_us = uvw[i].duty*1000000/PWM_FREQ - DEADTIME_US;   // ON time of Uupper
-        uvw[i].lower_us = 1000000/PWM_FREQ -uvw[i].upper_us - 2*DEADTIME_US; // ON time of Ulower
-        pwm_upper[i] = 0;
-        pwm_lower[i] = 1;
+void pwmUout() {    // タイムアウト関数でU相PWMを発生する関数
+    unsigned char   i=0;  // i=0のときU相
+    uvw[i].mode += 1;   // チョッピングのオンオフを決定するモードを1増やす
+    if( uvw[i].mode==1 ){       // モードが1のとき、Toffの状態をつくる
+        pwm_upper[i] = 0;         // 上アームUuをオフ
+        pwm_lower[i] = 1;         // 下アームUdをオン
+        // モード3の時間幅 T3 = Ton-Tdt を計算
+        uvw[i].upper_us = uvw[i].duty*1000000/PWM_FREQ - DEADTIME_US;
+        // モード1,5の時間幅 T1=(Toff-Tdt)/2=(Tpwm-T3-2Tdt)/2を計算
+        uvw[i].lower_us = 1000000/PWM_FREQ -uvw[i].upper_us - 2*DEADTIME_US;
         uvw[i].lower_us /= 2;
-        pwm[i].attach_us(&pwmUout, uvw[i].lower_us); // setup pwmU to call pwmUout after t [us]
-    }else if( uvw[i].mode==2 ){
-        pwm[i].attach_us(&pwmUout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
-        pwm_upper[i] = 0;
-        pwm_lower[i] = 0;
-    }else if( uvw[i].mode==3 ){
-        pwm[i].attach_us(&pwmUout, uvw[i].upper_us); // setup pwmU to call pwmUout after t [us]
-        pwm_upper[i] = 1;
-        pwm_lower[i] = 0;
-    }else if( uvw[i].mode==4 ){
-        pwm[i].attach_us(&pwmUout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
-        pwm_upper[i] = 0;
-        pwm_lower[i] = 0;
-    }else{// if( uvw[i].mode==5 ){
-        pwm[i].attach_us(&pwmUout, uvw[i].lower_us); // setup pwmU to call pwmUout after t [us]
-        pwm_upper[i] = 0;
-        pwm_lower[i] = 1;
-        uvw[i].mode = 0;
-    }
+        // 時間幅が小さいときはTMINにする
+        if( uvw[i].lower_us < TMIN ){  uvw[i].lower_us=TMIN;}
+        // T1[μs]経過してからタイムアウトでこの関数自身をコール
+        pwm[i].attach_us(&pwmUout, uvw[i].lower_us);
+        // 時間幅が小さいときはTMINにする
+        if( uvw[i].upper_us < TMIN ){  uvw[i].upper_us=TMIN;}
+    }else if( uvw[i].mode==2 ){ // モードが2のとき、デッドタイムをつくる
+        // Tdt[μs]経過してからタイムアウトでこの関数自身をコール
+        pwm[i].attach_us(&pwmUout, DEADTIME_US);
+        pwm_upper[i] = 0;         // 上アームUuをオフ
+        pwm_lower[i] = 0;         // 下アームUdをオフ
+    }else if( uvw[i].mode==3 ){ // モードが3のとき、Tonの状態をつくる
+        // T3[μs]経過してからタイムアウトでこの関数自身をコール
+        pwm[i].attach_us(&pwmUout, uvw[i].upper_us);
+        pwm_upper[i] = 1;         // 上アームUuをオン
+        pwm_lower[i] = 0;         // 下アームUdをオフ
+    }else if( uvw[i].mode==4 ){ // モードが4のとき、デッドタイムをつくる
+        // Tdt[μs]経過してからタイムアウトでこの関数自身をコール
+        pwm[i].attach_us(&pwmUout, DEADTIME_US);
+#ifndef SIMULATION
+        // シャント抵抗の両端の電圧を見てモータ電流を検出
+        p.iuvw[0] = (VshuntR_Uplus - VshuntR_Uminus)*3.3 /R_SHUNT; // iu [A]
+#endif
+        pwm_upper[i] = 0;         // 上アームUuをオフ
+        pwm_lower[i] = 0;         // 下アームUdをオフ
+    }else{                     // モードが5のとき、Toffの状態をつくる
+        // T5(=T1)[μs]経過してからタイムアウトでこの関数自身をコール
+        pwm[i].attach_us(&pwmUout, uvw[i].lower_us);
+        pwm_upper[i] = 0;         // 上アームUuをオフ
+        pwm_lower[i] = 1;         // 下アームUdをオン
+        uvw[i].mode = 0;          // チョッピングのオンオフを決定するモードを
+    }                             // 0にする
 }
 void pwmVout() {    // pwm out using timer
     unsigned char   i=1;
@@ -129,7 +173,9 @@
         pwm_upper[i] = 0;
         pwm_lower[i] = 1;
         uvw[i].lower_us /= 2;
+        if( uvw[i].lower_us < TMIN ){  uvw[i].lower_us=TMIN;}
         pwm[i].attach_us(&pwmVout, uvw[i].lower_us); // setup pwmU to call pwmUout after t [us]
+        if( uvw[i].upper_us < TMIN ){  uvw[i].upper_us=TMIN;}
     }else if( uvw[i].mode==2 ){
         pwm[i].attach_us(&pwmVout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
         pwm_upper[i] = 0;
@@ -140,6 +186,10 @@
         pwm_lower[i] = 0;
     }else if( uvw[i].mode==4 ){
         pwm[i].attach_us(&pwmVout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
+#ifndef SIMULATION
+        // シャント抵抗の両端の電圧を見てモータ電流を検出
+        p.iuvw[1] = (VshuntR_Vplus - VshuntR_Vminus)*3.3 /R_SHUNT; // iv [A]
+#endif
         pwm_upper[i] = 0;
         pwm_lower[i] = 0;
     }else{// if( uvw[i].mode==5 ){
@@ -159,7 +209,9 @@
         pwm_upper[i] = 0;
         pwm_lower[i] = 1;
         uvw[i].lower_us /= 2;
+        if( uvw[i].lower_us < TMIN ){  uvw[i].lower_us=TMIN;}
         pwm[i].attach_us(&pwmWout, uvw[i].lower_us); // setup pwmU to call pwmUout after t [us]
+        if( uvw[i].upper_us < TMIN ){  uvw[i].upper_us=TMIN;}
     }else if( uvw[i].mode==2 ){
         pwm[i].attach_us(&pwmWout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
         pwm_upper[i] = 0;
@@ -185,7 +237,7 @@
 void start_pwm(){
     unsigned char i; 
     for( i=0;i<3;i++ ){
-        uvw[i].duty = 0.5;
+        uvw[i].duty = 0.5;  // 0.5のときにVu=0[V]
         pwm_upper[i] = pwm_lower[i] = 0;
         uvw[i].mode = 0;
     }