Go Down

Topic: void loop cannot execute and returns values on Arduino Mega 2560 (Read 745 times) previous topic - next topic

jremington

There are lots of problems with that code.

It is slow because of the extensive use of floating point operations (trigonometric functions are very slow), you are printing unnecessarily; it may not work because variables are used in interrupt routines that are not declared "volatile" and there appear to be typos in some values. You should NOT do floating point operations in interrupt routines, in fact you should just set a global flag that the interrupt occurred, and exit.

Examples of potential problems:

Code: [Select]
Serial.println("sensor"); //why print this?

Code: [Select]
ISR(TIMER1_OVF_vect) // interrupt at 0 counter 0
{
  analog = ADC;
  if (a)  //not volatile
  {
    U_in = 0.0709 * analog; //slow


Code: [Select]
t_param = map(analogRead(0),0,1230,0,100);  //1023?



Maslord

There are lots of problems with that code.

It is slow because of the extensive use of floating point operations (trigonometric functions are very slow), you are printing unnecessarily; it may not work because variables are used in interrupt routines that are not declared "volatile" and there appear to be typos in some values. You should NOT do floating point operations in interrupt routines, in fact you should just set a global flag that the interrupt occurred, and exit.

Examples of potential problems:

Code: [Select]
Serial.println("sensor"); //why print this?

Code: [Select]
ISR(TIMER1_OVF_vect) // interrupt at 0 counter 0
{
  analog = ADC;
  if (a)  //not volatile
  {
    U_in = 0.0709 * analog; //slow


Code: [Select]
t_param = map(analogRead(0),0,1230,0,100);  //1023?



Thank you Jremington for the points.

Actually I used Serial.println just for debugging, and the value"1230" was a typo.
I red about necessity of "volatile" for intrups, but I do not know how to do it, as "a" is a logical variable! Should I simply use "volatile int a;" at the beginning of the code?

Before adding the following section the code was running very fast, but the problem starts after adding it to the "void loop ()" body.

 
Code: [Select]

//////////////////////////////////////////////
    sensor = 0;
  Ff = 0;
  state = 0;
  prevState = 0;
  counter = 0;
  startTime = millis();
  sample_time = 10;        //Loop for sample duration of sec
  magnet_number = 4;       //is number of magnets per revulotion
  rpm = 0;
  samp=0;
 
  //enable sensor and turn on LED when touched.
  digitalWrite(A5, HIGH);

//  Loop for sample duration of 10 sec
  while((millis() - startTime) < sample_time)
  {
    sensor =  analogRead(A3);
    samp=millis();

    if (sensor > sensore_output_voltage)  //sensore output voltage
    state = 1;
   
    else
    state = 0;
     digitalWrite(A7,state); // Blinking LED when sensor Activated
   
    //On change of state increment counter.
    //A change in state twice represents one revolution
    if(state != prevState)
    {
      counter++;
      prevState = state;
      Serial.println("sensor");
    }
  }
 
///////////////////////////////////////////////////


The problem got worst when I increase the "sample_time" value. I think the while loop and millis function slow down the implementation of the code. Is it possible to execute two action in parallel in loop?


jremington

Quote
use "volatile int a;" at the beginning of the code
Yes.

Quote
Is it possible to execute two action in parallel in loop?
No. But two sequential actions can be carried out so quickly that you might not notice a delay.

Post ALL the code that you are having problems with, and explain as clearly as possible what the problem is. Snippets are useless.

Slumpert

Code: [Select]

sample_time = 10;        //Loop for sample duration of sec

//  Loop for sample duration of 10 sec
  while((millis() - startTime) < sample_time)
  {


The fact that your "sample time" is actually only .01 seconds might be a issue.

Maslord

Yes.
No. But two sequential actions can be carried out so quickly that you might not notice a delay.

Post ALL the code that you are having problems with, and explain as clearly as possible what the problem is. Snippets are useless.

Ok, lets start from the beginning. I had 2 codes, one for three phase PMW drive (code1), the other one for tachometer (code2). Both codes work totally well separately.

The problem started from the pint of combining both codes in one code. Code1 is based on modified "int main()" function and code2 is based on "void loop()" function. So to combine, as MarkT suggested, I moved the code at the start of the main() of code1 into setup() of code1, then renamed "int main ()" to "void loop ()". So in the next step I added the  constants, void setup () and void loop () of code2 in the code1, which became code3 that I posted at #14.

I connected LEDs to PWM outputs so see the blinking status. Now the main problems:

1- When I keep connecting pin A5 to A3, the counter start to count random values which should not. Seems noisy but A3 is connected to ground using 10k resistor.

2- When set "t_param" to a specific value using pot, the blinking speed is much much slower in
comparison with the same value in code1. seems loop () very slow down the speed or change the frequency of PWM.

3- Every time that the counter starts to count, LEDs stop blinking, seems PWM pauses.

Any suggestion?

 

Maslord

Code: [Select]

sample_time = 10;        //Loop for sample duration of sec

//  Loop for sample duration of 10 sec
  while((millis() - startTime) < sample_time)
  {


The fact that your "sample time" is actually only .01 seconds might be a issue.
Yes, but if I increase the sample time the respond times dramatically decreases and PWM is not working.

MarkT

While loops block, you should not have any, let loop() be the only loop....
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Maslord

While loops block, you should not have any, let loop() be the only loop....
No diffrence. Commenting while loop did not help!

Slumpert

I don't even know what code your talking about anymore.

Much less what the actual project is, or how it's wired, or what platform it's running on.

Your last update post, did it include the actual code your still having a problem with?

MarkT

Yes, perhaps repost the code as it is now and a description of what it is doing and a description of what you
want it to be doing.  This will be easier to figure out.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Maslord

Yes, perhaps repost the code as it is now and a description of what it is doing and a description of what you
want it to be doing.  This will be easier to figure out.
I did many many changes on several source codes but all of them was unsuccessful except YOUR code Mark. So I tried to mix your PWM code with my tachometer code and seems it is working now, so many thanks! The final code is as follows:

Code: [Select]

// For the UNO et al.
#define PERIOD 250   // 250 cycles = 15.625us for each half of waveform, 32kHz
#define HALF 125     // half the period is the default PWM threshold - gives square wave.
#define MAXAMP 31



void setup_timers ()
{
  TCCR1A = 0xF2 ;  // phase correct (mode 1010, ICR1 controls period)
  TCCR1B = 0x11 ;  // prescale by 1, change to 0x12 for prescale by 8
  TIMSK1 = 0x01 ;  // overflow interrupt
  TCCR2A = 0x31 ;  // phase correct (mode 101, OCR2A controls period)
  TCCR2B = 0x09 ; // prescale by 1, change to 0x0A for prescale by 8
 
  ICR1  = PERIOD ;    // 31.25us cycle time, 32kHz PWM but 64kHz drive pulses (differential)
  OCR2A = PERIOD ;
 
  OCR1A = HALF-100 ;    // example U drive
  OCR1B = HALF ;
  OCR2B = HALF+100 ;    // example W drive
 
  GTCCR = 0x83 ; // clear and halt prescalers
  TCNT1 = 0xFFFF ;  // synchronize counters exactly.
  TCNT2 = 0 ;
  GTCCR = 0x00 ; // allow prescalers to fly
}


void setup ()
{
  Serial.begin(57600);
  setup_cosines () ;
  setup_timers () ;

  pinMode (9, OUTPUT) ; // OC1A pin = U drive
  pinMode (12, OUTPUT) ; // OC1B pin = V drive
  pinMode (11, OUTPUT) ; // OC2B pin = W drive
  pinMode (0, INPUT) ; // pot pin
  pinMode(A7, OUTPUT); //LED out pin
  pinMode(A5,OUTPUT); //Sensor VCC pin
  pinMode(A3,INPUT); //Sensor Input pin
}

volatile byte u = HALF ;
volatile byte v = HALF ;
volatile byte w = HALF ;


ISR (TIMER1_OVF_vect)   // overflow triggers at BOTTOM, update all the compare regs, which are sampled at TOP
{
  OCR1A = u ;
  OCR1B = v ;
  OCR2B = w ;
}

#define  DEG_360  0x200
#define  DEG_120  0x0AB

char cosine_tab [DEG_360+1] ;  // fails to work if less than 0x202.

void setup_cosines ()
{
  for (int i = 0 ; i < 0x202 ; i++)
  {
    float a = i * 6.283185 / 0x200 ;
    if (i <= DEG_360)
      cosine_tab [i] = round (127.0 * cos (a)) ;
  }
}

/////////////////////////////////////////////////
unsigned int phase = 0 ;
int freq ;        ////0
int amplitude = MAXAMP ;
/////////////////////////////////////////////////
long startTime = 0;
int state, prevState = 0;
int sensor = 0;
long counter = 0;
double Ff = 0;
long sample_time;
int magnet_number;       
int sensore_output_voltage = 1000;
int prim_rpm = 0;
long sec_rpm = 0;
float  pot_co = 0;
/////////////////////////////////////////////////

int my_cosine (int ph)
{
  ph &= DEG_360-1 ;
  int res = cosine_tab [ph] ;
  res *= amplitude ;
  return (res + 0x0F) >> 5 ;
}

void loop ()
{

sensor = 0;
  Ff = 0;
  state = 0;
  prevState = 0;
  counter = 0;
  startTime = millis();
  sample_time = 5000;                                  //5000 for 5 sec Loop for sample duration of sec
  magnet_number = 1;                                   //is number of magnets per revulotion
//  rpm = 0;
//  samp=0;
 
  //enable sensor and turn on LED when touched.
  digitalWrite(A5, HIGH);

  //Loop for sample duration of 10 sec
  while((millis() - startTime) < sample_time)
  {
    sensor =  analogRead(A3);

    if (sensor > sensore_output_voltage)  //sensore output voltage
    {
    state = 1;
           
    }
    else
    state = 0;
     digitalWrite(A7,state); // Blinking LED when sensor Activated

    //On change of state increment counter.
    //A change in state twice represents one revolution
    if(state != prevState)
    {
      counter++;
      prevState = state;
     
    }

//    freq = map(analogRead(A0),0,1023,0,100);
    pot_co = map(analogRead(A0),0,1023,2500,50);
    pot_co = pot_co / 50.0;
    sec_rpm = prim_rpm / pot_co;
    freq = map(sec_rpm, 10, 1500, 0, 100);
   
  phase += freq ;
 
  int newu = my_cosine (phase) ;
  int newv = my_cosine (phase - DEG_120) ;
  int neww = - newu - newv ;
  newu += HALF ;
  newv += HALF ;
  neww += HALF ;
  u = newu ;  // no masking of interrupts needed as u,v,w variables are single byte each.
  v = newv ;
  w = neww ;

  delayMicroseconds (2600) ;     
 
  }
   digitalWrite(A7,LOW);
  digitalWrite(A5, LOW);
 
  counter = counter / 2;

   
  prim_rpm = counter / magnet_number * 50;
}


The idea of this code is that tachometer will read speed of a shaft (not coupled to the motor) and force the motor to rotate with the speed of 0 to 100% (using pot on pin A0) of the shaft speed using PWM.

So, now I have 3 question:

1- For such speed control using above code, do I need PI control to add to the above code or not? (there is not any speed feedback from motor, we only have speed of a shaft which is not mechanically coupled with motor).

2- Mark set the Microseconds delay to 1000, I set it to 2600 to get approximately 50 Hz, how to accurately calculate the delay for 50Hz?

 3- To drive 6-pulse IGBT, I want to use three IR2110 drivers, but as I found in its datasheet I need a H and L input for each phase to fire H and L output from the driver for each IGBT pairs. But on the code output I only have three output for 3 phase. So how to produce H and L signal for each phase?

Many thanks for your helps.
 


MarkT

I did many many changes on several source codes but all of them was unsuccessful except YOUR code Mark. So I tried to mix your PWM code with my tachometer code and seems it is working now, so many thanks!

....

The idea of this code is that tachometer will read speed of a shaft (not coupled to the motor) and force the motor to rotate with the speed of 0 to 100% (using pot on pin A0) of the shaft speed using PWM.

So, now I have 3 question:

1- For such speed control using above code, do I need PI control to add to the above code or not? (there is not any speed feedback from motor, we only have speed of a shaft which is not mechanically coupled with motor).
Without feedback you cannot close a control loop, the best you can do is feed-forwards to compensate for known factors.
Quote
2- Mark set the Microseconds delay to 1000, I set it to 2600 to get approximately 50 Hz, how to accurately calculate the delay for 50Hz?
delayMicroseconds() isn't the thing to use for accuracy, code waiting for micros() to reach a target time and increment the target time each time round,
then you compensate for time spent running code.  Timing can only be as accurate as the system clock,
if thats not a quartz crystal or oscillator you have to expect a percent or so variation.
Quote
3- To drive 6-pulse IGBT, I want to use three IR2110 drivers, but as I found in its datasheet I need a H and L input for each phase to fire H and L output from the driver for each IGBT pairs. But on the code output I only have three output for 3 phase. So how to produce H and L signal for each phase?

Many thanks for your helps.
 
You'll need a high-low MOSFET driver with single input and automatic dead-time to drive from 3 signals.
Most let you determine the deadtime in software as this is the most flexible way.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Maslord

Regardless of the feedback, I tried do use a not gate (2n3904) to generate Linput for driver IC in addition to isolation using 4n35 optocoupler. The schematic digaram of the circuit is attached for one phase. Note that pin5 4n35 is connected to 5vdc through a 1k resistor. Is it ok or has problem?

Regards.

Maslord

I built the circuit and it is working fine when I apply a square wave and its inverted signal using simple low-high command with 500us dead-time on pin 11 and 12 for one phase circuit. But the problem is the generated sine wave and its inverted signal using following modified code. When I apply it to the circuit through 2 optocouplers, they burn IR2110. The reason is that the sine wave has cross its invert in some points at each period which cause short on high and low mosfets. So how to solve the problem? Should I convert sine waves to square wave or what and how?

Code: [Select]

// For the UNO et al.
#define PERIOD 250   // 250 cycles = 15.625us for each half of waveform, 32kHz
#define HALF 125     // half the period is the default PWM threshold - gives square wave.
#define MAXAMP 31

static unsigned int ocr3a, ocr3b, ocr1a; // auxiliary variables to store obl. fillings
static unsigned int ocr1b, ocr2a, ocr2b; // ^

void setup_timers ()
{

cli();
  TCCR1A |= _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(WGM10);
  TCCR1B |= _BV(CS11); // preskaler 8  | _BV(WGM02)
  TIMSK1 |= _BV (TOIE1);                                                                   
 
  TCCR2A |= _BV(COM2A1) | _BV(COM2B0) | _BV(COM2B1) | _BV(WGM20);
  TCCR2B |= _BV (CS21); // preskaler 8 //  | _BV(WGM02)
 
  TCCR3A |= _BV(COM3A1) | _BV(COM3B0) | _BV(COM3B1) | _BV(WGM30);
  TCCR3B |= _BV(CS31); // preskaler 8  | _BV(WGM02)
 
  TCNT1L = 0;
  TCNT2 = 0;
  TCNT3L = 0;
 sei();
}


void setup ()
{
  Serial.begin(57600);
  setup_cosines () ;
  setup_timers () ;


 pinMode(2, OUTPUT); // OC0A Arduino Mega2560 pin 13
  pinMode(5, OUTPUT); // OC0B Arduino Mega2560 pin 4
  pinMode(11, OUTPUT); // OC1A Arduino Mega2560 pin 11 u
  pinMode(12, OUTPUT); // OC1B Arduino Mega2560 pin 12 uu
  pinMode(10, OUTPUT); // OC2A Arduino Mega2560 pin 10
  pinMode(9, OUTPUT); // OC2B Arduino Mega2560 pin 9
 
  pinMode (0, INPUT) ; // pot pin
  pinMode(A7, OUTPUT); //LED out pin
  pinMode(A5,OUTPUT); //Sensor VCC pin
  pinMode(A3,INPUT); //Sensor Input pin
  pinMode(A9,INPUT); //Sensor Input pin
  pinMode(A10,INPUT); //Sensor Input pin
}

volatile byte u = HALF ;
volatile byte v = HALF ;
volatile byte w = HALF ;
volatile byte uu = 0 ;
volatile byte vv = 0 ;
volatile byte ww = 0 ;


ISR (TIMER1_OVF_vect)   // overflow triggers at BOTTOM, update all the compare regs, which are sampled at TOP
{

    OCR1AL = u; // pin 11
    OCR1BL = uu ; // pin 12
    OCR2A = v; // pin 10
    OCR2B = vv ; // pin 9
    OCR3AL = w; // pin 5
    OCR3BL = ww ; // pin 2

}

#define  DEG_360  0x200             //512
#define  DEG_120  0x0AB             //171

char cosine_tab [DEG_360+1] ;  // fails to work if less than 0x202.

void setup_cosines ()
{
  for (int i = 0 ; i < 0x202 ; i++)   //514
  {
    float a = i * 6.283185 / 0x200 ;

    if (i <= DEG_360)
      cosine_tab [i] = round (127.0 * cos (a)) ;
     
  }
}

/////////////////////////////////////////////////
unsigned int phase = 0 ;
int pp = 0;
int freq ;        ////0
int amplitude = MAXAMP ;
float P = 0;        //V/F constant corrector coefficient
/////////////////////////////////////////////////
long startTime = 0;
int state, prevState = 0;
int sensor = 0;
long counter = 0;
double Ff = 0;
long sample_time;
int magnet_number;       
int sensore_output_voltage = 1000;
int prim_rpm = 0;
long sec_rpm = 0;
float  pot_co = 0;
int u1;
int u2;
long samp = 0;
/////////////////////////////////////////////////

int my_cosine (int ph)
{
  ph &= DEG_360-1 ;
  int res = cosine_tab [ph] ;
//  amplitude = P * amplitude;             //8=V/F constant for V=400v and F=50Hz
  res *= amplitude ;
  return (res + 0x0F) >> 5 ;

}

void loop ()
{

sensor = 0;
  Ff = 0;
  state = 0;
  prevState = 0;
  counter = 0;
  startTime = millis();
  sample_time = 10;        //5000 for 5 sec Loop for sample duration of sec
  magnet_number = 1;       //is number of magnets per revulotion
 
  //enable sensor and turn on LED when touched.
  digitalWrite(A5, HIGH);
//   Serial.println("Measuring...");

  //Loop for sample duration of 10 sec
  while((millis() - startTime) < sample_time)
  {
    sensor =  analogRead(A3);
    samp=millis();
   
//    Serial.print("sensor = "); Serial.println(sensor);
    if (sensor > sensore_output_voltage)  //sensore output voltage
    {
    state = 1;
           
    }
    else
    state = 0;
     digitalWrite(A7,state); // Blinking LED when sensor Activated
//
    //On change of state increment counter.
    //A change in state twice represents one revolution
    if(state != prevState)
    {
      counter++;
      prevState = state;

    }


    pot_co = map(analogRead(A0),0,1023,2500,50);
    pot_co = pot_co / 50.0;
    sec_rpm = prim_rpm / pot_co;
    freq = map(sec_rpm, 10, 1500, 0, 100);
    freq = 1    ;
   
   
  phase += freq ;

  int newu =  my_cosine (phase) ;
  int newv = my_cosine (phase - DEG_120) ;
  int neww = - newu - newv ;
 
  newu += HALF;
  newv += HALF;
  neww += HALF;

noInterrupts () ;  // interrupt-safe updating of u,v,w
 
 
  u = newu + 1 ;  // no masking of interrupts needed as u,v,w variables are single byte each.
  v = newv + 1 ;
  w = neww + 1 ;

  uu = newu - 1;
  vv = newv - 1;
  ww = neww - 1;

interrupts () ;

  delayMicroseconds (2000) ;   
 
  }
   digitalWrite(A7,LOW);
  digitalWrite(A5, LOW);
 
  counter = counter / 2; // 12*5sec=60sec
   
  prim_rpm = counter / magnet_number ;
//  prim_rpm = 1500;
//   

}

Go Up