Using millis() to get elapsed time

Hi,

I am trying to use millis() to time the interval for which a pin is in a LOW state. I have been examining the stopwatch sketch in the Arduino playground. I think the problem is in line 12, the first line of loop(). I can't figure out where this line should go. I need to use a laststate in some way.

int ledTX = 12; //Receives InfraRed signal
int photodiodePin = 2;              // Photodiode connected to digital pin 2
int lastState;
unsigned long startTime;
unsigned long elapsedTime;
void setup() {                
  Serial.begin(9600);          
  pinMode(ledTX, OUTPUT); 
  pinMode(photodiodePin, INPUT);    // sets the digital pin as input to read photodiode
}
void loop() {
  lastState = photodiodePin;
  digitalWrite(ledTX, HIGH);   // turn the TX Infrared LED on
  Serial.println(digitalRead(photodiodePin));    // Read the pin and display the value
  if(photodiodePin == LOW && lastState == HIGH){
    startTime = millis();
  }
  if(photodiodePin == HIGH && lastState == LOW){
    elapsedTime = millis() - startTime;
    Serial.print("Total time: ");
    Serial.println(elapsedTime);
  }
  delay(1000);
}

(Physically I am trying to time when an object passes through a photo-gate.)

Any help would be greatly appreciated.

Thanks,

Shane

int photodiodePin = 2;              // Photodiode connected to digital pin 2
...
  if(photodiodePin == LOW && lastState == HIGH){

LOW is defined to be zero, so photodiodePin will never be LOW.

  lastState = photodiodePin;

Why are you setting a state variable to a pin number?

Hint: digitalRead()
http://arduino.cc/en/Reference/DigitalRead

Hi,

Yes I see it now. Seems to be working now. Do you think it is correct to update 'lastState' in the three places I did?

int ledTX = 12; //Receives InfraRed signal
int photodiodePin = 2; // Photodiode connected to digital pin 2
int lastState;
unsigned long startTime;
unsigned long elapsedTime;
void setup() {
Serial.begin(9600);
pinMode(ledTX, OUTPUT);
pinMode(photodiodePin, INPUT); // sets the digital pin as input to read photodiode
}
void loop() {
lastState = digitalRead(photodiodePin);
digitalWrite(ledTX, HIGH); // turn the TX Infrared LED on
Serial.println(digitalRead(photodiodePin)); // Read the pin and display the value
if(digitalRead(photodiodePin) == LOW && lastState == HIGH){
startTime = millis();
lastState = digitalRead(photodiodePin);
}
if(digitalRead(photodiodePin) == HIGH && lastState == LOW){
elapsedTime = millis() - startTime;
Serial.print("Total time: ");
Serial.println(elapsedTime);
lastState = digitalRead(photodiodePin);
}
}

Thank you both,

Shane

ofey:
Hi,

Yes I see it now. Seems to be working now. Do you think it is correct to update 'lastState' in the three places I did?

Not really. That's the current state if you do it at the start of the loop. More like (and note the use of "code" tags) ...

void loop()
  {
  byte currentState = digitalRead(photodiodePin);
  digitalWrite(ledTX, HIGH);   // turn the TX Infrared LED on
  Serial.println(currentState);    // Read the pin and display the value
  if(currentState == LOW && lastState == HIGH)
    {
    startTime = millis();
    }
  if(currentState == HIGH && lastState == LOW)
    {
    elapsedTime = millis() - startTime;
    Serial.print("Total time: ");
    Serial.println(elapsedTime);
    }
  lastState = currentState;
} // end of loop

Hi Nick,

Thanks that's much better. I am getting some strange characters in the serial monitor. I can't copy and paste them but they are the elapsed times and a backward P with two legs and a dollar sign.

int ledTX = 12; //Receives InfraRed signal
int photodiodePin = 2;              // Photodiode connected to digital pin 2
int lastState;
unsigned long startTime;
unsigned long elapsedTime;
void setup() {                
  Serial.begin(9600);          
  pinMode(ledTX, OUTPUT); 
  pinMode(photodiodePin, INPUT);    // sets the digital pin as input to read photodiode
}
void loop() {
  byte currentState = digitalRead(photodiodePin);
  digitalWrite(ledTX, HIGH);   // turn the TX Infrared LED on
  if(currentState == LOW && lastState == HIGH){
    startTime = millis();
  }
  if(currentState == HIGH && lastState == LOW){
    elapsedTime = millis() - startTime;
    Serial.print(elapsedTime);
    Serial.write(elapsedTime);
  }
  lastState = currentState;
}

I am also trying to send the elapsedTime variable to processing.

Thanks,

Shane

ofey:
Hi Nick,

Thanks that's much better. I am getting some strange characters in the serial monitor. I can't copy and paste them but they are the elapsed times and a backward P with two legs and a dollar sign.

On every line? Or just the first couple of characters? If it's the first couple that's pretty normal, as the USB chip tries to detect the baud rate. Try doing a Serial.println() just after the Serial.begin().

Hi,

Each value of elapsedTime is preceeded by a strange character and they are always different. Sometimes its " or £ etc. So each line has one of these characters and an elapsedTime value, no space between them. I am trying to read the elapsedTime value in Processing but is it sending just the value or the strange character plus the value?

The processing code is, (maybe I should not be posting it here!)

import processing.serial.*;

Serial port;
float elapsedTime;

void setup() {
  size(200, 200);
  background(204);
  noStroke();
  port = new Serial(this, 9600);
}

void draw() {
  if (0 < port.available()) {
    elapsedTime = port.read();
  }
  println(elapsedTime);
}

Thanks,

Shane

float elapsedTime;
...
void draw() {
  if (0 < port.available()) {
    elapsedTime = port.read();
  }
  println(elapsedTime);
}

First, I hate this style:

If 0 < the number of apples in the room ...

No-one talks like that.

Why not:

If the number of apples in the room is > 0 ...

Second, you are printing elapsedTime even if you haven't read it.

Hi Nick,

Ok so is this better?

void draw() {
  if (port.available() > 0) {
    elapsedTime = port.read();
    println(elapsedTime);
  }

Thanks,

Well, you tell me. Does it work better?

I'm no expert in Processing, but on the Arduino, you can't read into a float like that. A float is 4 bytes and a read reads one byte. Maybe a Processing expert can elaborate.

Thanks Nick,

I'll try to read up on it and if that's not successful maybe someone on the processing forum might have an insight.

Thanks for your help,

Shane

Seeing the sending code would be useful. As Nick says, the read() function in Processing only reads one byte or char at a time. There are other methods that read more than one byte/char at a time. Which of them would be useful for you depends on how you are sending the data to the serial port.

Hi PaulS,

I think it is only a 4 digit integer number that i am sending, Well here is the code,

Arduino:

int ledTX = 12; //Receives InfraRed signal
int photodiodePin = 2;              // Photodiode connected to digital pin 2
int lastState;
unsigned long startTime;
unsigned long elapsedTime;
void setup() {                
  Serial.begin(9600);          
  pinMode(ledTX, OUTPUT); 
  pinMode(photodiodePin, INPUT);    // sets the digital pin as input to read photodiode
}
void loop() {
  byte currentState = digitalRead(photodiodePin);
  digitalWrite(ledTX, HIGH);   // turn the TX Infrared LED on
  if(currentState == LOW && lastState == HIGH){
    startTime = millis();
  }
  if(currentState == HIGH && lastState == LOW){
    elapsedTime = millis() - startTime;
    Serial.println(elapsedTime);
    Serial.write(elapsedTime);
  }
  lastState = currentState;
}

Processing: the elapsedTime variable has been declared as an integer but I am only getting a print out of 0. There is no change when I put anything in the photogate.

import processing.serial.*;

Serial port;
int elapsedTime;

void setup() {
  size(200, 200);
  background(204);
  noStroke();
  port = new Serial(this, 9600);
}

void draw() {
  if (0 < port.available()) {
    elapsedTime = port.read();
  }
  println(elapsedTime);
}

Thanks,

Shane

I think it is only a 4 digit integer number that i am sending, Well here is the code,

    Serial.println(elapsedTime);

The print()/println() methods convert the value to a string. Suppose that millis() returns a value of 873. You are then sending '8', '7', '3', , to the serial port.

You are then reading one character at a time, '8', '7', '3', , and , and assuming that you are getting an integer value ('8' != 8), which is not the case.

The Serial class in Processing has a bufferUntil() method, where you can tell Processing to call serialEvent() only when the , for instance, arrives.

In the serialEvent() method, you can then use the readUntil() method to get all the data (as a string) that has arrived ("873") up to the specified character (). Then, int() will convert that string to an int.

Hi,

I am trying to solve this on the Processing forum. Here is a link in case it is of any interest to anyone.

I have also included a Fritzing schematic.

Thanks,

Shane

Photogate.fzz (3.35 KB)