UVW 3 phases Brushless DC motor control
Dependencies: QEI mbed-rtos mbed
Fork of BLDCmotor by
UVWpwm.cpp
- Committer:
- kosakaLab
- Date:
- 2013-09-07
- Revision:
- 17:1ac855d69c78
- Parent:
- 15:427f5ae8e957
File content as of revision 17:1ac855d69c78:
#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);
void pwmVout(), pwmWout();
#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;}
pwmVout(); pwmWout();
}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();
#if PWM_WAVEFORM == 1
pwmVout();
pwmWout();
#endif
}
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();
}
}
