Go Down

Topic: While loop not accurate??? (Read 139 times) previous topic - next topic

Sdlyons

Hi all,

I have a program that executes a while loop when the expression (capture < frames) is true. It works fine if the variable frames is greater than four, but for anything less is always captures 4 frames. Here is my code.  I may have put something in there that is causing this error, but I can not find the issue. Any help or suggestions are much appreciated.

Code: [Select]
//while loop to implement equivalent time sampling at user defined parameters
while(capture < frames)
{
//if statement to capture first image at 0 EST
  if(sample == 0)
  {
    //initializes time at current mS of program
currentMillis = millis();
previousMillis = currentMillis;

 //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < offTime)
   {
    currentMillis = millis();
   }

   //while loop that turns on DUTsig and triggers camera with equivalent time delay (sample)
   while (currentMillis - previousMillis >= offTime)
   {
//turns on DUT and camera sync to capture first image
 previousMillis = currentMillis;        //resets previousMillis to currentMillis
PORTB = B00000011;
_delay_us(1);
PORTB &= ~(1 << syncIn);
++capture;
sample += EST;                         //increments sample by the equivalent sampling time each cycle
   }
    //while loop to keep currentMillis synced with millis
    while (currentMillis - previousMillis < onTime)
   {
     currentMillis = millis();
   }

   //while loop to turn DUTsig off when on time is timed out
   while (currentMillis - previousMillis >= onTime)
   {
    
    previousMillis = currentMillis;       //resets previousMillis to currentMillis
    PORTB &= ~(1 << DUTsig);
   }
  }
  
//if statement for accurate 1 microsecond delay
   if(sample == 1)
 {
  
   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < offTime)
   {
    currentMillis = millis();
   }

   //while loop that turns on DUTsig and triggers camera with equivalent time delay (sample)
   while (currentMillis - previousMillis >= offTime)
   {
    previousMillis = currentMillis;        //resets previousMillis to currentMillis
    PORTB |= (1 << DUTsig);           //writes DUTsig high
    _delay_us(.82);                         //delays syncIn by an additional 1 to create an accurate equivalent time delay
    PORTB |= (1 << syncIn);            //writes syncIn high
    _delay_us(1);                          //holds syncIn high for 1 microsecond
    PORTB &= ~(1 << syncIn);             //writes syncIn low
    ++capture;                             //increments capture to show number of frames that have been taken
   sample += EST;
   }
  
   //while loop to keep currentMillis synced with millis
    while (currentMillis - previousMillis < onTime)
   {
     currentMillis = millis();
   }

   //while loop to turn DUTsig off when on time is timed out
    while (currentMillis - previousMillis >= onTime)
   {
    
    previousMillis = currentMillis;       //resets previousMillis to currentMillis
    PORTB &= ~(1 << DUTsig);
   }
 }

//if statement for accurate 2 microsecond delays
   if(sample == 2)
 {
  
   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < offTime)
   {
    currentMillis = millis();
   }

   //while loop that turns on DUTsig and triggers camera with equivalent time delay (sample)
   while (currentMillis - previousMillis >= offTime)
   {
    previousMillis = currentMillis;        //resets previousMillis to currentMillis
    PORTB |= (1 << DUTsig);           //writes DUTsig high
    _delay_us(1.82);                         //delays syncIn by an additional 2 to create an accurate equivalent time delay
    PORTB |= (1 << syncIn);            //writes syncIn high
    _delay_us(1);                          //holds syncIn high for 1 microsecond
    PORTB &= ~(1 << syncIn);             //writes syncIn low
    ++capture;                             //increments capture to show number of frames that have been taken
   sample += EST;
   }
  
   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < onTime)
   {
     currentMillis = millis();
   }

   //while loop to turn DUTsig off when on time is timed out
   while (currentMillis - previousMillis >= onTime)
   {
    
    previousMillis = currentMillis;       //resets previousMillis to currentMillis
    PORTB &= ~(1 << DUTsig);
   }
 }

//if statement for delays in microseconds up to 16000
   if(sample >= 3 && sample <= 15999)
 {
  
   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < offTime)
   {
    currentMillis = millis();
   }

   //while loop that turns on DUTsig and triggers camera with equivalent time delay (sample)
   while (currentMillis - previousMillis >= offTime)
   {
    previousMillis = currentMillis;        //resets previousMillis to currentMillis
    PORTB |= (1 << DUTsig);                //writes DUTsig high                      
    _delay_us(.37);                        //correction delay
    delayMicroseconds(sample);             //delays by residual amount of uS after millisecond delay
    PORTB |= (1 << syncIn);                //writes syncIn high
    _delay_us(1);                          //holds syncIn high for 1 microsecond
    PORTB &= ~(1 << syncIn);               //writes syncIn low
    ++capture;                             //increments capture to show number of frames that have been taken
     sample += EST;
   }
  
   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < onTime)
   {
     currentMillis = millis();
   }

   //while loop to turn DUTsig off when on time is timed out
   while (currentMillis - previousMillis >= onTime)
   {
    
    previousMillis = currentMillis;       //resets previousMillis to currentMillis
    PORTB &= ~(1 << DUTsig);
   }
 }
}
}

sterretje

That's not quite how you use millis(). You could just as well have used delay().
Quote
Code: [Select]
      //while loop to keep currentMillis synced with millis
      while (currentMillis - previousMillis < offTime)
      {
        currentMillis = millis();
      }

This will run only once
Quote
Code: [Select]
      //while loop that turns on DUTsig and triggers camera with equivalent time delay (sample)
      while (currentMillis - previousMillis >= offTime)
      {
        //turns on DUT and camera sync to capture first image
        previousMillis = currentMillis;        //resets previousMillis to currentMillis
        PORTB = B00000011;
        _delay_us(1);
        PORTB &= ~(1 << syncIn);
        ++capture;
        sample += EST;                         //increments sample by the equivalent sampling time each cycle
      }

Just two things that caught my eye. Possibly not the cause of your problems.

Please post your full program.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

Sdlyons

#2
Nov 08, 2019, 04:48 pm Last Edit: Nov 08, 2019, 04:50 pm by Sdlyons
What do you mean by that is not how you use millis? I essentially used the blinkwithoutdelay program, but fit it to my needs. That particular line is just to keep my variable currentMillis updated to millis(). I may have used it wrong, but that part is working as far as I can tell. Also my full code is too long to post here. It gave an error of too many characters. What I posted is the bulk of my program. I do have some more while loops and if statements to continue delaying at the variable sample. I have included those below. the first code and this code makes up my loop.

Code: [Select]
//if statement for delays over 16000 uS
   if(sample >= 16000)
 {
 
  // if statement to delay in milliseconds
   if(sample - uSdelay == 0)
  {
     
   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < offTime)
   {
    currentMillis = millis();
   }

   //while loop that turns on DUTsig and triggers camera with equivalent time delay (sample)
   while (currentMillis - previousMillis >= offTime)
   {
    previousMillis = currentMillis;        //resets previousMillis to currentMillis
    PORTB |= (1 << DUTsig);                //writes DUTsig high
    delay(mSdelay);                        //delays the mS amount for each whole millisecond
    PORTB |= (1 << syncIn);                //writes syncIn high
    _delay_us(1);                          //holds syncIn high for 1 microsecond
    PORTB &= ~(1 << syncIn);               //writes syncIn low
    ++capture;                             //increments capture to show number of frames that have been taken
    sample += EST;
    }
   
    //while loop to keep currentMillis synced with millis
    while (currentMillis - previousMillis < onTime)
    {
     currentMillis = millis();
    }

    //while loop to turn DUTsig off when on time is timed out
    while (currentMillis - previousMillis >= onTime)
    {
   
    previousMillis = currentMillis;       //resets previousMillis to currentMillis
    PORTB &= ~(1 << DUTsig);
    }
 }
 
 //if statement for accurate 1 microsecond delays
   if(sample - uSdelay == 1)
 {
 
   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < offTime)
   {
    currentMillis = millis();
   }

   //while loop that turns on DUTsig and triggers camera with equivalent time delay (sample)
   while (currentMillis - previousMillis >= offTime)
   {
    previousMillis = currentMillis;        //resets previousMillis to currentMillis
    PORTB |= (1 << DUTsig);           //writes DUTsig high
     delay(mSdelay);                       //delays by whole milliseconds
     _delay_us(.82);                         //delays syncIn by an additional 1 to create an accurate equivalent time delay
    PORTB |= (1 << syncIn);            //writes syncIn high
    _delay_us(1);                          //holds syncIn high for 1 microsecond
    PORTB &= ~(1 << syncIn);             //writes syncIn low
    ++capture;                             //increments capture to show number of frames that have been taken
     sample += EST;
   }
   
    //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < onTime)
   {
     currentMillis = millis();
   }

   //while loop to turn DUTsig off when on time is timed out
   while (currentMillis - previousMillis >= onTime)
   {
   
    previousMillis = currentMillis;       //resets previousMillis to currentMillis
    PORTB &= ~(1 << DUTsig);
   }
 }

//if statement for accurate 2 microsecond delays
   if(sample - uSdelay == 2)
 {
 
   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < offTime)
   {
    currentMillis = millis();
   }

   //while loop that turns on DUTsig and triggers camera with equivalent time delay (sample)
   while (currentMillis - previousMillis >= offTime)
   {
    previousMillis = currentMillis;        //resets previousMillis to currentMillis
    PORTB |= (1 << DUTsig);           //writes DUTsig high
     delay(mSdelay);                       //delays by whole milliseconds
     _delay_us(1.82);                         //delays syncIn by an additional 1 to create an accurate equivalent time delay
    PORTB |= (1 << syncIn);            //writes syncIn high
    _delay_us(1);                          //holds syncIn high for 1 microsecond
    PORTB &= ~(1 << syncIn);             //writes syncIn low
    ++capture;                             //increments capture to show number of frames that have been taken
     sample += EST;
   }

   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < onTime)
   {
     currentMillis = millis();
   }

   //while loop to turn DUTsig off when on time is timed out
   while (currentMillis - previousMillis >= onTime)
   {
   
    previousMillis = currentMillis;       //resets previousMillis to currentMillis
    PORTB &= ~(1 << DUTsig);
   }
 }
 
 
//if statement for delays with both milliseconds and microseconds
   if(sample >= accdelay)
 {
   
   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < offTime)
   {
    currentMillis = millis();
   }

   //while loop that turns on DUTsig and triggers camera with equivalent time delay (sample)
   while (currentMillis - previousMillis >= offTime)
   {
    previousMillis = currentMillis;        //resets previousMillis to currentMillis
    PORTB |= (1 << DUTsig);           //writes DUTsig high
    delay(mSdelay);                       //delays by whole milliseconds
    delayMicroseconds(sample-uSdelay);    //delays by residual amount of uS after millisecond delay
    PORTB |= (1 << syncIn);            //writes syncIn high
    _delay_us(1);                          //holds syncIn high for 1 microsecond
    PORTB &= ~(1 << syncIn);             //writes syncIn low
    ++capture;                             //increments capture to show number of frames that have been taken
     sample += EST;
   }

   //while loop to keep currentMillis synced with millis
   while (currentMillis - previousMillis < onTime)
   {
     currentMillis = millis();
   }

   //while loop to turn DUTsig off when on time is timed out
   while (currentMillis - previousMillis >= onTime)
   {
   
    previousMillis = currentMillis;       //resets previousMillis to currentMillis
    PORTB &= ~(1 << DUTsig);
   }
 }
}

jremington

Quote
What do you mean by that is not how you use millis?
Your use of it is blocking. The computer does nothing until the loop ends.

The point of using millis() is to write non blocking code.

MorganS

That while loop sterretje quoted IS a delay. It is not without-delay.

This is not a while. You cou3kd replace it with if....
Quote
Code: [Select]
while (currentMillis - previousMillis >= offTime)
   {
    previousMillis = currentMillis;        

Read those two lines slowly. If it's greater than offTime then instantly change it so it isn't. The content of the while runs only once.

It seems you repeated that pattern in many places.
"The problem is in the code you didn't post."

Sdlyons

Yes, I want it to run only once. Isn't that how blinkwithoutdelay works?

Sdlyons

I guess an if statement would be more appropriate. I will check to see if that fixes my problem.

jremington

#7
Nov 08, 2019, 06:16 pm Last Edit: Nov 08, 2019, 06:18 pm by jremington
Quote
Yes, I want it to run only once.
Then there is no need for the while or an if construction. Just use the functional statements as is.

If this runs once:
Code: [Select]
     while (currentMillis - previousMillis >= offTime)
      {
        //turns on DUT and camera sync to capture first image
        previousMillis = currentMillis;        //resets previousMillis to currentMillis
        PORTB = B00000011;
        _delay_us(1);
        PORTB &= ~(1 << syncIn);
        ++capture;
        sample += EST;                         //increments sample by the equivalent sampling time each cycle
      }


then it is equivalent to this:

Code: [Select]
        PORTB = B00000011;
        _delay_us(1);
        PORTB &= ~(1 << syncIn);
        ++capture;
        sample += EST;                         //increments sample by the equivalent sampling time each cycle

sterretje

#8
Nov 08, 2019, 06:47 pm Last Edit: Nov 08, 2019, 06:47 pm by sterretje
The basics of your program; I've added >> for comments and they assume that EST equals 1. Do you now see why we want complete programs; we have to assume something. We also have no idea where you reset any of those variables (and if you indeed do).
Code: [Select]
  while (capture < frames)
  {
    if (sample == 0)
    {
      do something and increment capture and sample
    }
    >> sample is now either 0 or 1
    >> capture is now either 0 or 1
    if (sample == 1)
    {
      do something and increment capture and sample
    }
    >> sample is now either 0 or 2
    >> capture is now either 0 or 2
    if (sample == 2)
    {
      do something and increment capture and sample
    }
    >> sample is now either 0 or 3
    >> capture is now either 0 or 3
    if (sample >= 3 && sample <= 15999)
    {
      do something and increment capture and sample
    }
    >> sample is now either 0 or 4
    >> capture is now either 0 or 4
  }


Your while (capture < frames) contains 4 steps that each increment capture. So the minimum value of capture after one iteration is 4 and you will have taken 4 photos.

If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

Sdlyons

Thank you sterretje! I would have posted all of my code, but the forum would not allow me too. I apologize for that. You are right about the four steps. I took out the ++capture and and sample += EST from each while loop (currentMillis - previousMillis >= offTime) and moved it to the very end of my first while loop (capture < frames) and it fixed the problem. I do apologize for all of the confusion.

sterretje

In future, if code is too big, attach it.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

wvmarle

Yes, I want it to run only once. Isn't that how blinkwithoutdelay works?
No, it's not. Read this tutorial, it may help you understand what's actually going on there.

The point of the whole technique is to keep loop() looping as fast as possible.
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

Go Up