UVW 3 phases Brushless DC motor control

Dependencies:   QEI mbed-rtos mbed

Fork of DCmotor by manabu kosaka

UVWpwm.cpp

Committer:
kosaka
Date:
2013-06-07
Revision:
14:7f83c4b96d34
Parent:
13:791e20f1af43

File content as of revision 14:7f83c4b96d34:

#include "mbed.h"
#include "controller.h"
#include "UVWpwm.h"  // PWM発生用UVWpwm.cppの変数や定数の定義

#define DEADTIME_US (unsigned long)(DEADTIME*1000000)  // [us], デッドタイム

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用の定数、変数宣言

// 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() {    // タイムアウト関数で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
    unsigned char   i=1;
    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
        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 ){
        pwm[i].attach_us(&pwmVout, 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(&pwmVout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
        pwm_upper[i] = 0;
        pwm_lower[i] = 0;
        uvw[i].mode = 0;
    }
}

void pwmWout() {    // pwm out using timer
    unsigned char   i=2;
    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
        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;
        pwm_lower[i] = 0;
    }else if( uvw[i].mode==3 ){
        pwm[i].attach_us(&pwmWout, 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(&pwmWout, DEADTIME_US); // setup pwmU to call pwmUout after t [us]
        pwm_upper[i] = 0;
        pwm_lower[i] = 0;
        uvw[i].mode = 0;
    }
}
#elif PWM_WAVEFORM==1   // 1: triangler wave comparison
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;
        // 時間幅が小さいときは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;
    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;
        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;
        pwm_lower[i] = 0;
    }else if( uvw[i].mode==3 ){
        pwm[i].attach_us(&pwmVout, 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(&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 ){
        pwm[i].attach_us(&pwmVout, uvw[i].lower_us); // setup pwmU to call pwmUout after t [us]
        pwm_upper[i] = 0;
        pwm_lower[i] = 1;
        uvw[i].mode = 0;
    }
}

void pwmWout() {    // pwm out using timer
    unsigned char   i=2;
    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;
        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;
        pwm_lower[i] = 0;
    }else if( uvw[i].mode==3 ){
        pwm[i].attach_us(&pwmWout, 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(&pwmWout, 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(&pwmWout, uvw[i].lower_us); // setup pwmU to call pwmUout after t [us]
        pwm_upper[i] = 0;
        pwm_lower[i] = 1;
        uvw[i].mode = 0;
    }
}
#endif


void start_pwm(){
    unsigned char i; 
    for( i=0;i<3;i++ ){
        uvw[i].duty = 0.5;  // 0.5のときにVu=0[V]
        pwm_upper[i] = pwm_lower[i] = 0;
        uvw[i].mode = 0;
    }
    pwmUout();
    pwmVout();
    pwmWout();
}

void stop_pwm(){
    unsigned char i; 
    for( i=0;i<3;i++ ){
        pwm_upper[i] = pwm_lower[i] = 0;
        uvw[i].mode = 0;
        pwm[i].detach();
    }
}