Measure and display position and time

Hello everyone,
I’m new to Arduino so this might be a basic question.
I have 3 electrodes and gnd connected to pin 2,3 and 4 (like a buttons) and gnd. I also have a metal ball that rolls over them. When the ball roll over one of the electrodes, it makes connection and the position of the ball (which is the number of the pin electrode connected to) is displaced in the serial monitor.

I want to modify the codes to do 2 things
first I don’t want it to show the position of the ball repeatedly . Only once is enough. When the ball moves to another electrode, the new number is displaced.
I also want to count and show the time duration the ball took to move from position x to position y.

So for example,
If the ball is over electrode 2, serial monitor will show 2. Once the ball moves to electrode 3, serial monitor will show 3 and time duration =x milliseconds

Can you please help
thnaks

I attached my current simple code

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input pin:
  if (digitalRead(2)==HIGH)
     Serial.println("2");
  if (digitalRead(3)==HIGH)
     Serial.println("3");
  if (digitalRead(4)==HIGH)
     Serial.println("4");

     
  // print out the postion of the ball:
  delay(1);        // delay in between reads for stability
}

I will assume you have not tried this code yet as I see a couple problems. The if statements are missing { brackets }. Then you are testing for a High condition but you have used pull up on input pins so they are always high the steel ball would need to bring the pins low in which case you would be testing for a LOW in order to print. In this forum you will see Resources in the top bar under which you will find Reference and in there is a list of all the commands used and how they work. Working thru that will be of great help. Things like serialprint and serialprintln. Using if if else. Timers and interupts and pulse in etc. You could do the test as digital read not equal to HIGH. What you are trying to do is very easy. U can msg me

Suppose you keep a variable showing which pin was the last rolled over, with 0 being for none yet?

Then you could use a switch-case statement to run different code depending on which pin was shorted last.

Don't forget to grab micros() in each case to calculate time differences via unsigned subtraction.

For each I/O pin you need to save the value that was detected and only print the value when the new value is not the same as the previous value.

...R

rogertee:
The if statements are missing { brackets }.

In that case the braces are not -needed- as only one thing is being done by the if(). Braces are needed for doing multiple lines.

However I like to use the braces as they make the logic easier to read quickly. I don't like slowing down to unpack bricks.
I place both braces at the indent level of the command they're for on lines of their own JUST to line up for reading ease.

But that's style I arrived at over years, my early code was described as "brick code". It ran on a basic interpreter where every character of the source had to be read and interpreted at runtime so newbie me did not use much white space and endured a LOT of eyestrain. ------------------ save yourself!

rogertee:
I will assume you have not tried this code yet as I see a couple problems. The if statements are missing { brackets }. Then you are testing for a High condition but you have used pull up on input pins so they are always high the steel ball would need to bring the pins low in which case you would be testing for a LOW in order to print. In this forum you will see Resources in the top bar under which you will find Reference and in there is a list of all the commands used and how they work. Working thru that will be of great help. Things like serialprint and serialprintln. Using if if else. Timers and interupts and pulse in etc. You could do the test as digital read not equal to HIGH. What you are trying to do is very easy. U can msg me

Thank you very much for your reply and for the tips.
Actually the code is working fine. I get 2 repeatedly in the serial monitor when the ball is over electrode 2 and 3 repeatedly when electrode is over electrode 3. The first thing I'm trying to do is stop the repeated reading and only display a new reading when the connection changes to another pin .Can I achieve that with an if statement?
I'm reading through the basic commands but still can's put the the correct code togther.

Thanks again

wedyan14:
The first thing I'm trying to do is stop the repeated reading and only display a new reading when the connection changes to another pin .Can I achieve that with an if statement?

Perhaps you missed Reply #3?

...R

Robin2:
Perhaps you missed Reply #3?

...R

Thank you very much. Can you please let me know how I can do it ? like with which commands

wedyan14:
I have 3 electrodes connected to pin 2,3 and 4 (like a buttons) . I also have a metal ball that rolls over them. When the ball roll over one of the electrodes, it makes connection and the position of the ball (which is the number of the pin electrode connected to) is displaced in the serial monitor.

I think you have 3 electrodes and gnd?
How does the potential on the 3 electrodes change if the ball is not connected to gnd?

Can the ball rest on two pins at the same time?

Tom... :slight_smile:

TomGeorge:
I think you have 3 electrodes and gnd?
How does the potential on the 3 electrodes change if the ball is not connected to gnd?

Can the ball rest on two pins at the same time?

Tom... :slight_smile:

YES forgot to mention I have a gnd connected to all. so basically the gnd is common to all.
The ball can never rest on two pins at the same time since the spacing between the pins (electrodes) is larger than the ball.

Please let me know if you need further clarification .
Thanks

If you do what I posted in reply #2, the first time it sees pin 2 it starts looking for pin 3, etc.

GoForSmoke:
If you do what I posted in reply #2, the first time it sees pin 2 it starts looking for pin 3, etc.

Thank you very much. Can you please let me know how I can do in terms of the code? which commands I can use.

Your help is very much appreciated.

Thanks

This is where to look basic Arduino up, it’s not everything but you should skim to have idea of what is there.
https://www.arduino.cc/reference/en/

This is the switch-case statement that makes it easy to “mode your code”.
https://www.arduino.cc/reference/en/language/structure/control-structure/switchcase/

This is micros(), it returns a 32-bit unsigned long value, microseconds since startup that rolls over every 70-some minutes to within 4 microseconds.
https://www.arduino.cc/reference/en/language/functions/time/micros/

Rollover is NOT a problem with unsigned subtraction. End time - start time = elapsed time, every time up to 70-some minutes. The unsigned long variables can hold 0 to 4294967296 = 4294.967296 seconds = 71.582788267 minutes.

You can time 1000x longer with millis() but for short periods it’s not accurate by 1 milli 6x per 1/4 second, so use micros() where it counts. :slight_smile:

this sketch untested in any way, I be surprised if it compiles as is.

byte lookingForPin = 0; // this is the switch value, also the index for the pin[] array
byte pin[ 3 ] = { 2, 3, 4 }; // the pin[] array of pin numbers

unsigned long startMicros, endMicros;

void setup()  // woops! almos forgot
{
  Serial.begin( 115200 ); // set your monitor to match, 9600 takes forever to send/get
  Serial.println( F( "\n\n    Startup" ));

  for ( byte i = 0; i < 3; i++ ) // look up for-next loop
  {
    pinMode( pin[ i ], INPUT_PULLUP );
  }
}

void loop()
{
  switch( lookingForPin )
  {
    case 0 : // look for pin[0] LOW until it is
      if ( digitalRead( pin[ 0 ] ) == LOW ) // the "instant" it hits the pin.......
     {
        startMicros = micros(); // mark the start time
        Serial.print( F( "pin   " ));
        Serial.println( pin[ 0 ] );
        lookingForPin = 1; // ..............., it quits looking
      }
    break;
    case 1 :
      if ( digitalRead( pin[ 1 ] ) == LOW )
      {
        endMicros = micros(); // mark the end time
        Serial.print( F( "pin   " ));
        Serial.print( pin[ 1 ] );
        Serial.print( F( "   time between  " ));
        Serial.print( endMicros - startMicros );
        Serial.println( F( " usecs " ));
        startMicros = endMicros; // because that endpoint is the next startpoint
        lookingForPin = 2;
      }
    break;
    case 2 :
      if ( digitalRead( pin[ 2 ] ) == LOW ) 
     {
        endMicros = micros(); // mark the end time
        Serial.print( F( "pin   " ));
        Serial.print( pin[ 2 ] );
        Serial.print( F( "   time between  " ));
        Serial.print( endMicros - startMicros );
        Serial.println( F( " usecs " ));
        lookingForPin = 0;  // back to start
    }
  }
}

Take your time, I don’t know how big you bite. This will cut some teeth.

That job can be done with less code but this can be customized and is to demonstrate stae machines.

I’m not set up to try it out but when it does run, I can put in a loop() counter and blow your mind about Arduino speed. It’s saw with 16000 teeth that turns 1000x a second unless blocked from doing so in code. This kind of code does not block.

GoForSmoke:
This is where to look basic Arduino up, it's not everything but you should skim to have idea of what is there.
Arduino Reference - Arduino Reference

This is the switch-case statement that makes it easy to "mode your code".
switch...case - Arduino Reference

This is micros(), it returns a 32-bit unsigned long value, microseconds since startup that rolls over every 70-some minutes to within 4 microseconds.
micros() - Arduino Reference

Rollover is NOT a problem with unsigned subtraction. End time - start time = elapsed time, every time up to 70-some minutes. The unsigned long variables can hold 0 to 4294967296 = 4294.967296 seconds = 71.582788267 minutes.

You can time 1000x longer with millis() but for short periods it's not accurate by 1 milli 6x per 1/4 second, so use micros() where it counts. :slight_smile:

this snippet untested in any way:

byte lookingForPin = 0; // this is the index for the pin[] array

byte pin[ 3 ] = { 2, 3, 4 }; // the pin array of pin numbers

unsigned long startMicros, endMicros;

void loop()
{
  switch( lookingForPin )
  {
    case 0 : // look for pin[0] LOW until it is
      if ( digitalRead( pin[ 0 ] ) == LOW )
      {
        startMicros = micros(); // mark the start time
        Serial.print( F( "pin  " ));
        Serial.println( pin[ 0 ] );
        lookingForPin = 1;
      }
    break;
    case 1 :
      if ( digitalRead( pin[ 1 ] ) == LOW )
      {
        Serial.print( F( "pin  " ));
        endMicros = micros(); // mark the end time
        Serial.print( pin[ 1 ] );
        Serial.print( F( "  time between  " ));
        Serial.print( endMicros - startMicros );
        Serial.println( F( " usecs " ));
        startMicros = endMicros; // because that endpoint is the next startpoint
        lookingForPin = 2;
      }
    break;
    case 2 :
        Serial.print( F( "pin  " ));
        endMicros = micros(); // mark the end time
        Serial.print( pin[ 2 ] );
        Serial.print( F( "  time between  " ));
        Serial.print( endMicros - startMicros );
        Serial.println( F( " usecs " ));
        lookingForPin = 0;  // back to start
    }
  }
}




Take your time, I don't know how big you bite. This will cut some teeth.

Thank you so much. This should definitely help. I will take my time understanding everything and will play around with the code you provided.

Probably the best thing is when you modify the code, once you have it working of course.

You could have 2 sets of pins and race ball bearings or something.