3 phase induction motor Variable Speed Controller using Mega 2560 board - Solved

Hi guys,
I found and a bit modified a 3 phase induction motor Variable Speed Controller sketch which supposed to generate gating signals of 6 IGBTs based on the constant V/F ratio. At the compiling and updating stages there is no error and the board starts to run. The problem is, when I connect 6 LEDs to pins 6,5,9 and 10,11,3 using 220 ohm resistors, the only outputs appear on pins 9,10, 11 and other pins keep off state without blinking (3,5,6). May you please have look on the attached code and help me to find there is problem!

Many thanks,
Mas

1.ino (8.01 KB)

Any idea?!

Firstly style/readability: auto-indent your code, its all over the place and unreadable.

Secondly use whitespace! Push those one line comments to the right so the code is readable without
the comments confusing it. You don't need comments for anything that is clearly indicated by the
code itself - comment the things that are not immediately apparent from reading the code itself.

Some of the variables in your ISR are not declared volatile - fix this.

You are not setting up the timer registers correctly, you are just OR-ing in some bits over the
top of them.

Set the whole register values explicitly, you don't want to be dependent on their previous state.
The code should look like:

  TCCR1A = ..... | .... | .... ;
  TCCR1B = .... | .... ;

or even just:

  TCCR1A = 0b......... ;   // comment about which settings you've used, refering to the section of datasheet...

Anyway I think the OR-ing is why some of your pins are in the wrong mode.

Also I'd switch back to using setup(), not main(), the Arduino runtime may do some important
initialization in its main() that you aren't aware of.

Since the code only runs on a Mega, use pre-processor directives to force the compilation
to fail if compiled for the wrong board, ie #ifndef / #error

Hello,

Would the pinning used on the board be correct?

Because the pinout of the Atmega2560 is not the same as the Arduino 2560.

Please compare the datasheet of the Atmega2560 with the Arduino 2560 diagram.

Does it work?

void io_init()
{
  pinMode(13, OUTPUT); // OC0A Arduino Mega2560 pin 13
  pinMode(4, OUTPUT); // OC0B Arduino Mega2560 pin 4
  pinMode(11, OUTPUT); // OC1A Arduino Mega2560 pin 11
  pinMode(12, OUTPUT); // OC1B Arduino Mega2560 pin 12
  pinMode(10, OUTPUT); // OC2A Arduino Mega2560 pin 10
  pinMode(9, OUTPUT); // OC2B Arduino Mega2560 pin 9
  pinMode(14, INPUT_PULLUP); // up Arduino Mega2560 14
  pinMode(15, INPUT_PULLUP); // dn Arduino Mega2560 15
  pinMode(16, OUTPUT); // Arduino Mega2560 16
}
digitalWrite(16, HIGH); // lighting the diode
up = digitalRead(14); // read: if you press the button, increase the frequency
#define UN (400.0) // motor rated voltage
#define FN (50.0) // motor nominal frequency
#define P (UN/FN) // associate Determining the ratio of voltage to nominal frequency
#define T_PWM (0.000255) // PWM signal period - set by the prescaler in the counters
#define T_MAX (4.0) // Specify the maximum output voltage period
#define T_MIN (0.02) // minimum output voltage
#define K_MAX floor (T_MAX/T_PWM) // number of period values for T_MAX
#define K_MIN ceil (T_MIN/T_PWM) // number of period values for T_MIN
volatile static unsigned int length_tab_sin; // variable containing the number of values in the full // period of the output voltage
static unsigned int i = 0; // auxiliary variable
volatile static unsigned int main_counter = 0; // variable in the interrupt
// ^ every T_PWM period increasing its value by 1
static unsigned int next_value_sin = 0; // variable which value sin should be calculated
static double t_param = 50; // parameter specifying the period of the output voltage
static float t = T_PWM; // T_PWM
static float omega_t; // pulsation of the output voltage multiplied by T_PWM
static float t_out; // output voltage period
static float U_o_param; // parameter specifying the size of the output voltage
// ^ calculated on the basis of t_out and U_in
static unsigned int ocr0a, ocr0b, ocr1a; // auxiliary variables to store obl. fillings
static unsigned int ocr1b, ocr2a, ocr2b; // ^
static double sin_in; // variable containing the parameter of the function sin
static double error = 1; // variable used to stop generating voltage when overloaded
static unsigned int analog = 0; // variable containing the measured value
static double U_in = 0; // variable holding the voltage measurement of the intermediate system
static double U_rms_max; // maximum currently possible to generate the effective voltage value
static bool a = 0; // logical variable for the implementation of two alternating measurements

//void setup()
//{
//  Serial.begin(57600);
//}

int main()
{
  io_init(); // initiate entry and exit
  timers_init(); // initialization of PWM meters
  adc_init(); // initialization of the ADC transducer
  while (1) // infinite loop with the main program
  {
    if (i == 185) // condition specifying the entry to the change function
    { // parameter of the discharge voltage, calling approx. 100ms
      chang_para(); // function to change the parameters of the output voltage
      i = 0;
    }
    next_value_sin = main_counter % length_tab_sin; // the next sine value to be calculated
    sin_in = omega_t*next_value_sin;
    // calculating the value to registers specifying the completion of the output signal /
    ocr0a = round(error * (U_o_param * (sin(sin_in) + 1) * 254 / 2) + 1); // pin
    ocr0b = ocr0a - 1;
    ocr1a = round (error * (U_o_param * (sin(sin_in - 2.09) + 1) * 254 / 2) + 1); // pin
    ocr1b = ocr1a - 1;
    ocr2a = round(error * (U_o_param * (sin(sin_in + 2.09) + 1) * 254 / 2) + 1); // pin
    ocr2b = ocr2a - 1;
    // updating values in registers /
    cli(); // prohibition on obsloge interruptions in case if
    // an interrupt occurred during the upgrade
    OCR0A = ocr0a; // pin
    OCR0B = ocr0b; // pin
    OCR1AL = ocr1a; // pin
    OCR1BL = ocr1b; // pin
    OCR2A = ocr2a; // pin
    OCR2B = ocr2b; // pin
    sei(); // allow for interruption obsloge
    i++;
  }
}
void adc_init()
{
  ADCSRA |= _BV(ADEN); // start the transmitter
  ADCSRA |= _BV(ADPS2); // setting the prescaler
  ADCSRA |= _BV(ADPS1); // ^
  ADCSRA |= _BV(ADPS0); // ^
  ADMUX |= _BV(REFS0); // reference voltage set as power supply
  ADMUX |= ADMUX &= 0b11110000; // choose the ADC0 input for measurement
}
void timers_init()
{
  cli(); // interrupt handler is forbidden
  // timer0 init
  TCCR0A |= _BV(COM0A1) | _BV(COM0B0) | _BV(COM0B1) | _BV(WGM00);
  TCCR0B |= _BV(CS01); // preskaler 8  | _BV(WGM02)
  TIMSK0 |= _BV (TOIE0); // flag from value 0 enabled //
  // timer1 init
  TCCR1A |= _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(WGM10);
  TCCR1B |= _BV (CS11); // preskaler 8 //  | _BV(WGM02)
  // timer2 init
  TCCR2A |= _BV(COM2A1) | _BV(COM2B0) | _BV(COM2B1) | _BV(WGM20);
  TCCR2B |= _BV(CS21); // preskaler 8  | _BV(WGM02)
  // resetting counter values
  TCNT0 = 0;
  TCNT1L = 0;
  TCNT2 = 0; /* the counter counts in g3re to 255, then in d3 ณ: / \ / \ / \
            at the value of 255 there is an interruption at which it occurs
            voltage and current measurements
*/
  sei(); // allow for interruption obsloge
}
void io_init()
{
  pinMode(13, OUTPUT); // OC0A Arduino Mega2560 pin 13
  pinMode(4, OUTPUT); // OC0B Arduino Mega2560 pin 4
  pinMode(11, OUTPUT); // OC1A Arduino Mega2560 pin 11
  pinMode(12, OUTPUT); // OC1B Arduino Mega2560 pin 12
  pinMode(10, OUTPUT); // OC2A Arduino Mega2560 pin 10
  pinMode(9, OUTPUT); // OC2B Arduino Mega2560 pin 9
  pinMode(14, INPUT_PULLUP); // up Arduino Mega2560 14
  pinMode(15, INPUT_PULLUP); // dn Arduino Mega2560 15
  pinMode(16, OUTPUT); // Arduino Mega2560 16
}
ISR(TIMER0_OVF_vect) // interrupt at 0 counter 0
{
  analog = ADC;
  if (a)
  {
    U_in = 0.0709 * analog;
    ADMUX |= _BV(MUX0); // choose the ADC1 input to measure the current
  }
  else
  {
    ADMUX |= ADMUX &= 0b11110000; // select the ADC0 input to measure the voltage
    if (analog > 579)
    {
      error = 0; // if the overload turn off the voltage generation
      digitalWrite(16, HIGH); // lighting the diode
    }
  }
  ADCSRA |= _BV(ADSC); // start reading the measurement
  a = a ^ 1; // the XOR gate negates the logical value a
  main_counter++;
  if (main_counter >= length_tab_sin) main_counter = 0;
}
void chang_para()
{
  t_param = map(analogRead(3), 0, 102, 0, 100);
  U_rms_max = U_in * 0.62; // value 0.62 experimentally limited
  bool up; // logical variable, informs you that the button has been pressed to increase the frequency
  bool down; // logical variable, informs you that the button has been pressed to decrease the frequency
  up = digitalRead(14); // read: if you press the button, increase the frequency
  down = digitalRead(15); // read: if you press the button you will decrease the frequency
  if (!up) t_param--; // if you press the button to increase the frequency then you will decrease the period
  if (!down) t_param ++; // if the button you press decreases the frequency, it will increase the period
  if (t_param < 0) t_param = 0; // protection of exceeding the extreme values
  if (t_param > 100) t_param = 100; // ^
  length_tab_sin = ceil((K_MAX - K_MIN) * t_param / 500 + K_MIN); // amount of values filled in one period
  t_out = T_PWM * length_tab_sin; // calculate the period of the output voltage
  omega_t = t * 2 * PI / t_out; // calculate the output voltage pulsation
  U_o_param = (P / t_out) / U_rms_max; // calculate the parameter determining the value of the output voltage
  if (t_out > 1) U_o_param = 0.5 * (18.5 / U_rms_max); // voltage at the output at low frequencies of 10v
  if (U_o_param > 1) U_o_param = 1; //protection of exceeding the extreme values
  error = 1; //if the overload turn off the voltage generation
  //digitalWrite(13, HIGH); //diode lighting
  //if the overload turn off the voltage generation
  digitalWrite(16, LOW); //diode lighting
  //              Serial.println(t_param);
}

Warning: Note that I have inverted the button logic!

MarkT:
Firstly style/readability: auto-indent your code, its all over the place and unreadable.

Secondly use whitespace! Push those one line comments to the right so the code is readable without
the comments confusing it. You don't need comments for anything that is clearly indicated by the
code itself - comment the things that are not immediately apparent from reading the code itself.

Some of the variables in your ISR are not declared volatile - fix this.

You are not setting up the timer registers correctly, you are just OR-ing in some bits over the
top of them.

Set the whole register values explicitly, you don't want to be dependent on their previous state.
The code should look like:

  TCCR1A = ..... | .... | .... ;

TCCR1B = .... | .... ;



or even just:


TCCR1A = 0b......... ;  // comment about which settings you've used, refering to the section of datasheet...




Anyway I think the OR-ing is why some of your pins are in the wrong mode.

Also I'd switch back to using setup(), not main(), the Arduino runtime may do some important
initialization in its main() that you aren't aware of.

Since the code only runs on a Mega, use pre-processor directives to force the compilation
to fail if compiled for the wrong board, ie #ifndef / #error

Thank you Mark for the points, Actually I got some problem and went out of the home for few days. So I will follow your comments as soon as I come back.
By the way, yesterday I also tested your written code in #24 (for UNO) on the arduino mega 2560 to see its response, but the similar problem happens, only one blinking LED and other 2 are off! May be my problem is the board model?

rtek1000:
Does it work?

void io_init()

{
 pinMode(13, OUTPUT); // OC0A Arduino Mega2560 pin 13
 pinMode(4, OUTPUT); // OC0B Arduino Mega2560 pin 4
 pinMode(11, OUTPUT); // OC1A Arduino Mega2560 pin 11
 pinMode(12, OUTPUT); // OC1B Arduino Mega2560 pin 12
 pinMode(10, OUTPUT); // OC2A Arduino Mega2560 pin 10
 pinMode(9, OUTPUT); // OC2B Arduino Mega2560 pin 9
 pinMode(14, INPUT_PULLUP); // up Arduino Mega2560 14
 pinMode(15, INPUT_PULLUP); // dn Arduino Mega2560 15
 pinMode(16, OUTPUT); // Arduino Mega2560 16
}






digitalWrite(16, HIGH); // lighting the diode






up = digitalRead(14); // read: if you press the button, increase the frequency






#define UN (400.0) // motor rated voltage
#define FN (50.0) // motor nominal frequency
#define P (UN/FN) // associate Determining the ratio of voltage to nominal frequency
#define T_PWM (0.000255) // PWM signal period - set by the prescaler in the counters
#define T_MAX (4.0) // Specify the maximum output voltage period
#define T_MIN (0.02) // minimum output voltage
#define K_MAX floor (T_MAX/T_PWM) // number of period values for T_MAX
#define K_MIN ceil (T_MIN/T_PWM) // number of period values for T_MIN
volatile static unsigned int length_tab_sin; // variable containing the number of values in the full // period of the output voltage
static unsigned int i = 0; // auxiliary variable
volatile static unsigned int main_counter = 0; // variable in the interrupt
// ^ every T_PWM period increasing its value by 1
static unsigned int next_value_sin = 0; // variable which value sin should be calculated
static double t_param = 50; // parameter specifying the period of the output voltage
static float t = T_PWM; // T_PWM
static float omega_t; // pulsation of the output voltage multiplied by T_PWM
static float t_out; // output voltage period
static float U_o_param; // parameter specifying the size of the output voltage
// ^ calculated on the basis of t_out and U_in
static unsigned int ocr0a, ocr0b, ocr1a; // auxiliary variables to store obl. fillings
static unsigned int ocr1b, ocr2a, ocr2b; // ^
static double sin_in; // variable containing the parameter of the function sin
static double error = 1; // variable used to stop generating voltage when overloaded
static unsigned int analog = 0; // variable containing the measured value
static double U_in = 0; // variable holding the voltage measurement of the intermediate system
static double U_rms_max; // maximum currently possible to generate the effective voltage value
static bool a = 0; // logical variable for the implementation of two alternating measurements

//void setup()
//{
//  Serial.begin(57600);
//}

int main()
{
 io_init(); // initiate entry and exit
 timers_init(); // initialization of PWM meters
 adc_init(); // initialization of the ADC transducer
 while (1) // infinite loop with the main program
 {
   if (i == 185) // condition specifying the entry to the change function
   { // parameter of the discharge voltage, calling approx. 100ms
     chang_para(); // function to change the parameters of the output voltage
     i = 0;
   }
   next_value_sin = main_counter % length_tab_sin; // the next sine value to be calculated
   sin_in = omega_tnext_value_sin;
   // calculating the value to registers specifying the completion of the output signal /
   ocr0a = round(error * (U_o_param * (sin(sin_in) + 1) * 254 / 2) + 1); // pin
   ocr0b = ocr0a - 1;
   ocr1a = round (error * (U_o_param * (sin(sin_in - 2.09) + 1) * 254 / 2) + 1); // pin
   ocr1b = ocr1a - 1;
   ocr2a = round(error * (U_o_param * (sin(sin_in + 2.09) + 1) * 254 / 2) + 1); // pin
   ocr2b = ocr2a - 1;
   // updating values in registers /
   cli(); // prohibition on obsloge interruptions in case if
   // an interrupt occurred during the upgrade
   OCR0A = ocr0a; // pin
   OCR0B = ocr0b; // pin
   OCR1AL = ocr1a; // pin
   OCR1BL = ocr1b; // pin
   OCR2A = ocr2a; // pin
   OCR2B = ocr2b; // pin
   sei(); // allow for interruption obsloge
   i++;
 }
}
void adc_init()
{
 ADCSRA |= _BV(ADEN); // start the transmitter
 ADCSRA |= _BV(ADPS2); // setting the prescaler
 ADCSRA |= _BV(ADPS1); // ^
 ADCSRA |= _BV(ADPS0); // ^
 ADMUX |= _BV(REFS0); // reference voltage set as power supply
 ADMUX |= ADMUX &= 0b11110000; // choose the ADC0 input for measurement
}
void timers_init()
{
 cli(); // interrupt handler is forbidden
 // timer0 init
 TCCR0A |= _BV(COM0A1) | _BV(COM0B0) | _BV(COM0B1) | _BV(WGM00);
 TCCR0B |= _BV(CS01); // preskaler 8  | _BV(WGM02)
 TIMSK0 |= _BV (TOIE0); // flag from value 0 enabled //
 // timer1 init
 TCCR1A |= _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(WGM10);
 TCCR1B |= _BV (CS11); // preskaler 8 //  | _BV(WGM02)
 // timer2 init
 TCCR2A |= _BV(COM2A1) | _BV(COM2B0) | _BV(COM2B1) | _BV(WGM20);
 TCCR2B |= _BV(CS21); // preskaler 8  | _BV(WGM02)
 // resetting counter values
 TCNT0 = 0;
 TCNT1L = 0;
 TCNT2 = 0; /
the counter counts in g3re to 255, then in d3 ณ: / \ / \ /
           at the value of 255 there is an interruption at which it occurs
           voltage and current measurements
*/
 sei(); // allow for interruption obsloge
}
void io_init()
{
 pinMode(13, OUTPUT); // OC0A Arduino Mega2560 pin 13
 pinMode(4, OUTPUT); // OC0B Arduino Mega2560 pin 4
 pinMode(11, OUTPUT); // OC1A Arduino Mega2560 pin 11
 pinMode(12, OUTPUT); // OC1B Arduino Mega2560 pin 12
 pinMode(10, OUTPUT); // OC2A Arduino Mega2560 pin 10
 pinMode(9, OUTPUT); // OC2B Arduino Mega2560 pin 9
 pinMode(14, INPUT_PULLUP); // up Arduino Mega2560 14
 pinMode(15, INPUT_PULLUP); // dn Arduino Mega2560 15
 pinMode(16, OUTPUT); // Arduino Mega2560 16
}
ISR(TIMER0_OVF_vect) // interrupt at 0 counter 0
{
 analog = ADC;
 if (a)
 {
   U_in = 0.0709 * analog;
   ADMUX |= _BV(MUX0); // choose the ADC1 input to measure the current
 }
 else
 {
   ADMUX |= ADMUX &= 0b11110000; // select the ADC0 input to measure the voltage
   if (analog > 579)
   {
     error = 0; // if the overload turn off the voltage generation
     digitalWrite(16, HIGH); // lighting the diode
   }
 }
 ADCSRA |= _BV(ADSC); // start reading the measurement
 a = a ^ 1; // the XOR gate negates the logical value a
 main_counter++;
 if (main_counter >= length_tab_sin) main_counter = 0;
}
void chang_para()
{
 t_param = map(analogRead(3), 0, 102, 0, 100);
 U_rms_max = U_in * 0.62; // value 0.62 experimentally limited
 bool up; // logical variable, informs you that the button has been pressed to increase the frequency
 bool down; // logical variable, informs you that the button has been pressed to decrease the frequency
 up = digitalRead(14); // read: if you press the button, increase the frequency
 down = digitalRead(15); // read: if you press the button you will decrease the frequency
 if (!up) t_param--; // if you press the button to increase the frequency then you will decrease the period
 if (!down) t_param ++; // if the button you press decreases the frequency, it will increase the period
 if (t_param < 0) t_param = 0; // protection of exceeding the extreme values
 if (t_param > 100) t_param = 100; // ^
 length_tab_sin = ceil((K_MAX - K_MIN) * t_param / 500 + K_MIN); // amount of values filled in one period
 t_out = T_PWM * length_tab_sin; // calculate the period of the output voltage
 omega_t = t * 2 * PI / t_out; // calculate the output voltage pulsation
 U_o_param = (P / t_out) / U_rms_max; // calculate the parameter determining the value of the output voltage
 if (t_out > 1) U_o_param = 0.5 * (18.5 / U_rms_max); // voltage at the output at low frequencies of 10v
 if (U_o_param > 1) U_o_param = 1; //protection of exceeding the extreme values
 error = 1; //if the overload turn off the voltage generation
 //digitalWrite(13, HIGH); //diode lighting
 //if the overload turn off the voltage generation
 digitalWrite(16, LOW); //diode lighting
 //              Serial.println(t_param);
}

Thank you for your kind modifications, my board is Arduino mega 2560. I am out for few days and will test your codes on Arduino mega 2560 ASP and report you back the results.

[/quote]

rtek1000:
Does it work?

Thank you very much. Rtek, YOU MADE MY DAY.

Maslord:
Thank you very much. Rtek, YOU MADE MY DAY.

Thanks for your feedback!

[Solved]

If it is possible, please add the word solved at the beginning of the title, to serve as an example to those who are looking for a solution to this topic, and to prevent people who are willing to help, open an already resolved topic.

Have fun!

rtek1000:
Thanks for your feedback!

If it is possible, please add the word solved at the beginning of the title, to serve as an example to those who are looking for a solution to this topic, and to prevent people who are willing to help, open an already resolved topic.

Have fun!

Done

Hi Rtek, you've solved de big part of my problem.
If is possible I've two questions to you about your code:
In my project I have an induction motor to drive at variable speed, my intention is to use 2 Arduino boards, one main that does all the other stuff and one only to drive the motor. I want to use the serial between the two boards to make them comunicate (if is possible else I'll use analog read from the other board).

My question is: in your code were can I place my desired frequency? I've understood that is inside the function chang_para. And then how can I reverse the motor (I think I should do in the software the inversion of two phases but how)

Hope you see

Reversing is easy, use a negative frequency.