help with timing

Hi,

I'm very new to Arduino, so go easy on me please :)

I'm trying to measure scale speed using two input switches and display the result to an LCD. The following code seems to work once and never again for a long time, please help :)

const int SW1 = 7;
const int SW2 = 6;

int PULSE1 = 0;
int PULSE2 = 0;

unsigned long startTime = 0;
unsigned long endTime = 0;
unsigned long timediff = 0;
unsigned long mph = 0;

void setup() {
  pinMode(SW1, INPUT);
  pinMode(SW2, INPUT);
  Serial.begin(9600);
}

void loop() {
  PULSE1 = digitalRead(SW1);
  PULSE2 = digitalRead(SW2);

  if (PULSE1 == HIGH) {
     startTime = millis();
  }

  if (PULSE2 == HIGH) {
     endTime = millis();
  }

timediff = endTime - startTime;
mph = (6/timediff)*0.05682*76.2;
Serial.println("mph:");
Serial.println(mph);
}

I have left out the lcd stuff so that I can just use the serial monitor function for now.

The idea is that an object travelling past two micro-switches triggers the first switch, then after a delay triggers the next and I can then determine its speed.

many thanks

I see floating point, unsigned long, and integer in a single code line. Could you calculate the mph in float ?

float milesph = (6.0 / (float) timediff ) * 0.05682 * 76.2;
Serial.println("milesph:");
Serial.println(milesph);

The "6" is forced into "6.0" to show the compiler and you and me that is floating point. The "timediff" is cast into a floating point before doing the calculations. So everything is with floating point and the result is stored in a floating point.

Your sketch will not work, because it is printing text with every execution of "loop()". At which moment do you want to calculate the timediff ?

Thanks for your reply!

Looking at my code with a fresh pair of eyes this morning and with your advice, I could see that I had made a mess of the ‘if’ statements and nesting arrangements. I have had a search around and found some similar code which I have adapted.

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

unsigned long start, finished, elapsed;

void setup()
{
  lcd.begin(16,2);
  pinMode(7, INPUT); // first button
  pinMode(6, INPUT); // second button
  lcd.print("Waiting...");
}

void displayResult()
{
  int mph;
  elapsed=finished-start;
  mph=(12/(float)elapsed*1000)*0.05682*76.2;
  lcd.setCursor(0,1);
  lcd.print(mph);
  lcd.print("mph");
}

void loop()
{
 if (digitalRead(7) == HIGH)
 {
   start = millis();
   delay (200);
 }
 if (digitalRead(6) == HIGH)
 {
   finished = millis();
   delay (200);
   displayResult();
   delay (2000);
 }
}

This is almost what I am after, although I would like to capture the point at which each pin goes high rather than just if the pin is high on both inputs. I’m not exactly sure what kind of sensor I will use for this, probably an IR detector.

I’m trying to make a speed display for my model railway, when the front of the train breaks the first IR sensor the millis is stored, when it breaks the second IR sensor millis is again stored, using those values I can calculate the speed. The problem is now that spurious readings are displayed as if the second switch continues to be held down the calculation keeps repeating itself, effectively counting down from the first mph reading.

Thanks again :slight_smile:

Do you have microswitches with a lever ? That is easier to test the speed. Some IR modules need extra electronics.

You need to capture the start time and end time just once, at the very moment that the button is activated. That means you have to remember the previous state of the button, or use a global state that defines every state.
Have you heard of a “state machine” ?

Please do not mix integers with float when calculating something. I would like to calculate everything with float, and only at the end convert it to an integer.

The next sketch is not tested.
In the sketch I do not remember the previous button state and not the global state. I use three variables ‘flagReady’, ‘start’ and ‘finished’ to determine the state. However, I prefer a single variable for the global state. I fill ‘start’ and ‘finished’ just once with the time from millis() by testing if they are zero. However, that is a quick fix, but not good programming.

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

unsigned long start;
unsigned long finished;
unsigned long elapsed;
boolean flagReady;

const int pinButton1 = 7;
const int pinButton2 = 6;

void setup()
{
  lcd.begin(16,2);
  pinMode(pinButton1, INPUT); // first button
  pinMode(pinButton2, INPUT); // second button
  lcd.print("Waiting...");
  
  flagReady = false;        // check in the loop() if conditions are okay
  start = 0;                // make zero to detect if it is used already
  finished = 0;             // make zero to detect if it is used already
}

void displayResult()
{
  float mph;
  elapsed = finished - start;
  mph = ( 12.0 / (float)elapsed * 1000.0 ) * 0.05682 * 76.2;
  lcd.setCursor(0,1);
  lcd.print( (int) mph);    // print as integer
  lcd.print("mph");
}

void loop()
{
  // Don't start until both are not active
  if( digitalRead(pinButton1) == LOW && digitalRead(pinButton2) == LOW)
  {
    flagReady = true;
  }
  
  if( flagReady)
  {
    if( digitalRead(pinButton1) == HIGH && start == 0)
    {
      start = millis();
    }

    if( digitalRead(pinButton2) == HIGH && finished == 0)
    {
      finished = millis();
      displayResult();
      flagReady = false;
      start = 0;                // make zero to detect if it is used already
      finished = 0;             // make zero to detect if it is used already
    }
  }
}

Thanks for the advice, there is a lot of useful stuff there. It’s going to take me a little while to understand all of it. I have tried it (modified slightly to match my input hardware) and it works well. I had to add an RC circuit to my inputs for de-bounce, and in doing so needed to swap 'LOW’s for 'HIGH’s.

I’m using it in two different scenarios; with my Uno board (I don’t yet have an LCD display to test that function) using serial monitor, and within a Proteus simulation so I can test the 16x2 display.

I’m finding it difficult to think like a microcontroller and organise my code so that it makes sense to both me and the device :slight_smile:

I guess the more I try, the better I will get, it just seems a little daunting when even this simple task has a complicated method.

I’ve done a little bit of assembly language programming at college, and some embedded C, we were taught to write a specification and then a design structure diagram, but when I tried I always struggled with arranging 'if’s, 'for’s and 'while’s. :confused:

Thanks again :slight_smile:

That is just a matter of getting used to it. You learn while you are using it.