StopWatch does not always work the same

Hi All

I am using the Stop Watch library but it does not always work the same and I would like to know what is the correct way to prevent the problem.

I know that the Stop Watch library uses millis() and that timer will overflow (go back to zero), after approximately 50 days. But the problem that I have happens all the time even right after reset.

I use the Stop Watch to switch Relays on and off for a certain time period. There is also two sensors that stops the process if activated depending on the direction.

The correct result is:

tMiliDelay UP = 568 // time given to function
tTimerVal UP = 568 //time used by Stop Watch

What I sometimes get is:

tMiliDelay UP = 568 // time given to function
tTimerVal UP = 8 //time used by Stop Watch
What I also don't understand is the the tTimerVal is smaller than tMiliDelay and it should not exit the while loop?

If I add a extra delay it does not seem to happen
Here is the code bit:

//_______________MoveWindow Begin________________________
void MoveWindow(char *choice, unsigned long tMiliDelay)
{  

  StopWatch MySW;
  
  unsigned long tTimerVal = 0;
  
  
  if( (choice == "UP") && (Move_Flag == 1)  )  //2011/03/30
  {
    Serial.println("Winch UP Begin");
    DistCounter ++;
    CollectData("Winch UP");
    Serial.println( strM ); 
    WriteData(); 
   
 
    Serial.print("tMiliDelay UP = " );
    Serial.println( tMiliDelay );
    
    MySW.reset();
    MySW.start();
    
    ControlWinch("UP");  //Extra line added to fix problem	//2011/08/28
    delay(200);  // This delay seem to fix the problem, Why?? //2011/08/28
          

    while( (digitalRead(TopWindowSPin) == HIGH) && ( tTimerVal < (tMiliDelay)  )  )   
    {
      ControlWinch("UP");
      tTimerVal = MySW.value();
    }
    ControlWinch("STOP");
    MySW.stop()

    Serial.println("Winch UP End");
    Serial.print("tTimerVal UP = " );
    Serial.println( tTimerVal ); 

  }
  else if( (choice == "DOWN") && (Move_Flag == 1) )   //2011/03/30
  {


etc ….
….

Please let me know if you need more info and what is the correct way to prevent the mentioned problem.

Thank you in advanced

Regards

Luan

if( (choice == "UP") && (Move_Flag == 1) ) //2011/03/30

The variable choice is a pointer. It will NEVER equal "UP". If you want to compare the value pointed to be choice to the value "UP", you must use a function. The strcmp() function comes to mind.

choice will never equal "DOWN", either.

Hi Paul

The Up and Down Part of the function is working at the moment. I will look into using strcmp() and chage it.

I need to know why the StopWatch goes out of the while loop before it reaches the correct value.
The top and bottom sensors it not triggered when it exits the loop unexpectedly.
The while loop works most of the time.

Thank you for your help so far.

Ttfn

What I also don't understand is the the tTimerVal is smaller than tMiliDelay and it should not exit the while loop?

First:
The while loop in your function can stop because of two reasons:

  1. digitalRead(TopWindowSPin) == HIGH fails
  2. tTimerVal < (tMiliDelay) fails

If the code fails because of (1) one cannot say anything about tTimerVal. It can be lower, equal or larger than tMiliDelay.
If the code fails because of (2) one knows that tTimerVal is equal or larger than tMiliDelay.

The chance tTimerVal equals tMiliDelay is therfor very small, one should measure it the exact 1/1000 of a second to get them equal.

Because the value is (far) lower we can only conclude that the while loop stopped because of (1) . That means that digitalRead() returned LOW (expected or not)

The fact that tTimerVal > 0 implies that the while loop is executed at least once, so at least once the value of digitalRead() returned HIGH. At the first iteration tTimerVal == 0 so it is by definition < tMiliDelay (if that one is 568)

Second:
StopWatch is based upon millis().
The code shows two calls - ControlWinch("UP"); and ControlWinch("STOP"); - that are not provided by you.
==> so I cannot say if these function calls affect the millis() and therefor the StopWatch.

Q: please provide the code of this function.

Third:
digitalRead(TopWindowSPin) == HIGH;

Q: can you tell more about (the relation between) TopWindowSPin and the choice / "UP" ? I have a strong feeling these are related somehow...

Fourth:
Adding the delay and the function call at least give the stopwatch more time to "run" so the value will be closer to (or larger than) the expected one.

I use the Stop Watch to switch Relays on and off for a certain time period. There is also two sensors that stops the process if activated depending on the direction.

Can you tell more about the goal of your project as this is quite minimal.

The Up and Down Part of the function is working at the moment. I will look into using strcmp() and chage it.

I need to know why the StopWatch goes out of the while loop before it reaches the correct value.

I don't think that what you are saying is right.

if( (choice == "UP") && (Move_Flag == 1)  )

Both parts of this statement need to evaluate to true before the while loop can ever be executed, and the first part will NEVER be true. So, I fail to see how the while loop can ever be executed.

I would be cautious about saying that Paul. Try this:

void MoveWindow(char *choice, unsigned long tMiliDelay)
{
 if (choice == "UP")
    Serial.println ("true");
  else
    Serial.println ("false");
}

void setup ()
{
  Serial.begin (115200);
  MoveWindow ("UP", 1000); 
}

void loop () {}

This prints true, not false. So choice was in fact "UP".

@Luan - before I get all the experienced programmers telling me what an idiot I am, I hasten to add that my example prints "true" for the wrong reasons. Or more exactly, not for the reason you think it does.

The code you posted compares pointers, and two pointers to the (constant) word "UP" happen to be the same. But you really should be using strcmp (string compare) in case one day you decide to compare a variable with a constant.

The code you posted compares pointers, and two pointers to the (constant) word "UP" happen to be the same.

That's called a feature, Nick :wink:

Hi All

Thank you all for helping so far.

Let me give more info on my project.

I use a winch to open and close a window in increments at a time depending on the temperature.
There are two limit switches one at the top and one at the bottom called TopWindowSPin and BottomWindowSPin. The limit switches is pulled high to 5V with a pull up resistor and when one of them are trigged the go low to ground.

I added code to check if one of the switches gets trigged unexpectedly but that does not happen.

At start up of the code the Arduino measures the time it takes to open and close the window, the time is the divided by the amount of times I want the winch to move all the way in one direction.

The winch will keep moving Up until TopWindowSPin is LOW and keep moving down until BottomWindowSPin is LOW.

Here is the other code as requested:

Example for using the function:

int Move_Flag, WindowSize_Flag = 1;
unsigned long MiliMoveUp, MiliMoveDown = 0; 
int CU = 4;  //CU = Curtian Unit it is the No of units to divide curtain into


void setup(void) 
{
      Serial.begin(57600);
      Move_Flag = 1;
      WindowSize_Flag = 1;
      Serial.println("GetWindowSize ");
      GetWindowSize();

}

void loop(void) 
{
    if( “to cold” )  // 
    {        
      MoveWindow("UP", MiliMoveUp);
    }


    if( “to hot” )  // 
    {        
      MoveWindow("DOWN", MiliMoveDown);
    }

    wait(); //use RTC to wait 5min and check again code here
 

}

ControlWinch:

//_______________ControlWinch Begin________________________
void ControlWinch(char *choice)
{
  if( choice == "UP" )
  {    
    digitalWrite(WinchDownPin, LOW ); //Motor switch ) 
    digitalWrite(WinchUpPin, HIGH ); //Motor switch 
  }
  else if( choice == "DOWN" )
  {    
    digitalWrite(WinchUpPin, LOW ); //Motor switch ) 
    digitalWrite(WinchDownPin, HIGH ); //Motor switch 
  }
  else if( choice == "STOP" )
  {    
    digitalWrite(WinchUpPin, LOW ); //Motor switch ) 
    digitalWrite(WinchDownPin, LOW ); //Motor switch 
    delay(100);   //Added on 2011/08/26 
  }
  else
  {
    Serial.println("Winch wrong choice");    
    digitalWrite(WinchUpPin, LOW ); //Motor switch ) 
    digitalWrite(WinchDownPin, LOW ); //Motor switch 
    delay(100);  
    delay(100);   //Added on 2011/08/26  
  }  
}
//_______________ControlWinch End________________________

MoveWindow full code:

//_______________MoveWindow Begin________________________
void MoveWindow(char *choice, unsigned long tMiliDelay)
{  

  StopWatch MySW;
  
  char FloatBuffer[10];
  PString strFloat(FloatBuffer, sizeof(FloatBuffer)); 

  strFloat.begin();

  unsigned long tTimerVal = 0;
  
  float tAjustVal, tWinAVal = 0;
  
  if( (choice == "UP") && (Move_Flag == 1)  )  //2011/03/30
  {
    Serial.println("Winch UP Begin");
    DistCounter ++;
    CollectData("Winch UP");
    Serial.println( strM ); 
    WriteData(); 
    
    tWinAVal = WUAM;
    tAjustVal = (tWinAVal/100)+1;
    if( tAjustVal  == 0 )
    {
      tAjustVal = 1;
    }
    
    Serial.print("tAjustVal UP = " );
    Serial.println( tAjustVal ); 
 
    Serial.print("tMiliDelay UP = " );
    Serial.println( tMiliDelay );
    
    MySW.reset();
    MySW.start();
    
    ControlWinch("UP");  //Extra 
    delay(200);  // This delay seem to fix the problem, Why??
          
    //while( (digitalRead(TopWindowSPin) == HIGH) && ( tTimerVal < (tMiliDelay * tAjustVal)  )  )  //2011/03/25
    while( (digitalRead(TopWindowSPin) == HIGH) && ( tTimerVal < (tMiliDelay)  )  )  //2011/08/28 testing  
    {
      ControlWinch("UP");
      tTimerVal = MySW.value();
    }
    ControlWinch("STOP");
    MySW.stop();
    
    if( digitalRead(TopWindowSPin) == LOW )  //added on 2011/08/27
    {
      Serial.println("TopWindowSPin trigered");
      CollectData("TopWindowSPin");
      Serial.println( strM );
      WriteData();
    }
    else
    {
      Serial.println("Timer end reached");
      strFloat.print(tTimerVal);
      CollectData(FloatBuffer);
      Serial.println( strM );
      WriteData();
    }
    Serial.println("Winch UP End");
    Serial.print("tTimerVal UP = " );
    Serial.println( tTimerVal ); 


  }
  else if( (choice == "DOWN") && (Move_Flag == 1) )   //2011/03/30
  {
    Serial.println("Winch DOWN Begin");
    DistCounter -- ;
    CollectData("Winch DOWN");
    Serial.println( strM ); 
    WriteData(); 
    
    tWinAVal = WDAM;
    tAjustVal = (tWinAVal/100)+1;
    if( tAjustVal  == 0 )
    {
      tAjustVal = 1;
    }
    Serial.print("tAjustVal down" );
    Serial.println( tAjustVal );
    Serial.print("tMiliDelay UP = " );
    Serial.println( tMiliDelay );
    
    MySW.reset();
    MySW.start();
    while( (digitalRead(BottomWindowSPin) == HIGH) && ( tTimerVal < (tMiliDelay * tAjustVal) )  )   //2011/03/25 (tMiliDelay * 1.02) to move a bit more than time /CU
    {
      ControlWinch("DOWN");
      tTimerVal = MySW.value();
    }
    ControlWinch("STOP");
    MySW.stop();
    
    
    if( digitalRead(BottomWindowSPin) == LOW )  //added on 2011/08/27
    {
      Serial.println("BottomWindowSPin trigered");
      CollectData("BottomWindowSPin");
      Serial.println( strM );
      WriteData();
    }
    else
    {
      Serial.println("Timer end reached");
      strFloat.print(tTimerVal);
      CollectData(FloatBuffer);
      Serial.println( strM );
      WriteData();
    }
    Serial.println("Winch Down End");
    Serial.print("tTimerVal Down = " );
    Serial.println( tTimerVal ); 


  }  
  else if( choice == "STOP" )
  {
    Serial.println("Winch STOP");
    ControlWinch("STOP");
    MySW.stop();
  }
  else
  {
    ControlWinch("STOP");   
  }
  ResetDistCounterIfAtMagnets();
  CheckCurtainMovementAndSirenIfNeeded();
  
}
//_______________MoveWindow End________________________

GetWindowSize function:

void GetWindowSize()  //window stop must be depending on temp if cold at top, if hot at bottom
{
  StopWatch MySW; 

  Serial.println("up 1 begin = ");
  MySW.start();

  while( (digitalRead(TopWindowSPin) != LOW) && (WindowSize_Flag == 1)  )  // Move up and save setting
  {
    ControlWinch("UP");
  }
  MySW.stop();
  ControlWinch("STOP");
  
  if( digitalRead(TopWindowSPin) == LOW )  //added on 2011/08/27
  {
    Serial.println("TopWindowSPin trigered");
  }
  else
  {
    Serial.println("Time Out");
  }

  Serial.print("Up 1 end = ");
  Serial.println(MySW.value());
  MiliMoveUp = (MySW.value() / CU);
  Serial.println(MiliMoveUp);

  MySW.reset();


  Serial.print("Window TOP stop = ");

  Serial.print("CU = ");
  Serial.println(CU);


  //___________LFC Move window down  Begin___________________________
  delay(500);  //Dely before direction change


 
  Serial.println("down 2 begin = ");
  MySW.reset();
  MySW.start();

  while( (digitalRead(BottomWindowSPin) == HIGH) && (WindowSize_Flag == 1) )  //LFC Move window down 
  {
    ControlWinch("DOWN");
  }
  ControlWinch("STOP");
  MySW.stop();

  if( digitalRead(BottomWindowSPin) == LOW )
  {
    Serial.println("BottomWindowSPin trigered");
  }
  else
  {
    Serial.println("Time Out");
  }

  Serial.println("Window UP and stop ");
  //___________LFC Move window down End___________________________
  ControlWinch("STOP");
  Serial.print("down 2 end = ");
  Serial.println(MySW.value());
  MiliMoveDown = MySW.value() / CU;
  Serial.println(MiliMoveDown);
  
}
//_______________GetWindowSize End________________________

Here is a lot of code now but I hope this answers your questions.

Thank you so far

Regards

Luan :slight_smile:

Instead of passing strings around ("UP", "DOWN", "STOP", etc.), you should create an enum with symbolic names:

enum motion {UP, DOWN, STOP};

Values will be assigned to the names, but the values are not important.

void ControlWinch(motion dir)
{
  if(dir == UP)
    // Do the up thing
  else if(dir == DOWN)
    // Do the down thing
  else if(dir == STOP)
    // Knock it off
}

With enums, you can't make a typo. With strings, you can. There is a lot less overhead to using enums vs. strings.

Luan

HI all

I am busing trying to use enum and started a new topic for it.

Rob please let me know if you have any suggestions for the Stop Watch problem.

Thnx

Luan

Rob please let me know if you have any suggestions for the Stop Watch problem.

The problem is not in the StopWatch Class,

Hi Rob

I agree the problem in not with the Stop Watch class.
I am not using any interrupts.
Please help me to identify the problem.

I run everything form a 12V car battery, the winch uses a few Amps when it is moving.
Can the voltage drop cause the problem?
I have a 1000uF Cap between 12v and GND.

I have double check the while loop it does not exit because of the switches.
It exits the loop prematurely what I don't understand is the when it exits it is a small value and not even close to the required value. When I add the small delay is seem to fix the problem.
Does the small delay help the Arduino to work properly again?

I would like to understand why it happens

Thank you

Best regards

Luan

 if( “to cold” )  // 

{       
      MoveWindow("UP", MiliMoveUp);
    }

if( “to hot” )  //
    {       
      MoveWindow("DOWN", MiliMoveDown);
    }

Huh? If what is "to cold" or "to hot"?

Hi Nick

I was just trying to show how my code works.
There is a different function to check the Temperature and then move the window and switch the cooler or heater On/Off.

ttfn