2

I need to build a timer that uses the breaking of copper strips to trigger its starting and stopping. The intention is to measure the speed of a rocket with this - it will break the first wire, starting the timer, and then break the second, stopping it.

I am using an Arduino Uno, and a couple of lengths of wire for now.

I can plug one wire into the 1st 5V power supply on the board, and the other end into one of the analog pins (AO), (and then the second wire into the 2nd 5v supply and A1) so that when it is pulled out of the pin socket, it is 'broken'. Is this the correct method to go about this, and if so, how do I tell the Arduino to look for those signals as its 'start' and 'stop' and then record the time difference accordingly?

So far, I have managed to read a signal from the wire using the Analog Read Signal tutorial on Arduino.cc (https://www.arduino.cc/en/Tutorial/AnalogReadSerial). I noted whilst watching the printed data that once the wire is removed from the pin, the voltage value slowly decreased, and held at around 290 (starting at 1023, as per the tutorial). Is this simply a side effect of not using a grounded potentiometer, but a wire?

void setup() {
  // set up comms:
  Serial.begin(9600); 
}

void loop() {
  // check and read value of input:
  int sensorValue = analogRead(A0);
  Serial.println(sensorValue);
  delay(1);
}

I am new to Arduino, so please explain in detail, or point me to a thread that will! Thanks in advance for help!

UPDATE Having played around with analogWrite some more, I have managed to get a situation where I can output the relative value from both A0 and A1. However, I am still struggling to make it operate as a timer.

// declare variables
unsigned long startTime, stopTime;
unsigned long totalTime = (stopTime - startTime);

void setup() {
  Serial.begin(9600);   // set up comms 
}

void loop() {
  // check and read value of input:
  int sensorValue1 = analogRead(A0);
  int sensorValue2 = analogRead(A1);

  if (sensorValue1 < 1023) {
    startTime = micros();
    Serial.println(sensorValue1);
  }
  if (sensorValue2 < 1023) {
    stopTime = micros();
    Serial.println(sensorValue2);
  }

  Serial.println("Time: ");   // prints "Time: "
  Serial.println(totalTime);  // prints time value
    delay(1000); 
}

I have also tried to convert this to use digitalRead rather than analogRead but have not had much success - I am still failing to get a time. I know my method is wrong, but have struggled to find guidance on how to correct it.

    // declare variables
boolean timingFinished = false;
unsigned long startTime, stopTime;

String strTime = "Time:";


void setup() {
  Serial.begin(9600);   // set up comms
  pinMode(7, INPUT);   // set up pin 7
  pinMode(6, INPUT);   // set up pin 6
}

void loop() {
  // check and read value of input:
  int sensorValue1 = digitalRead(7);
  int sensorValue2 = digitalRead(6);
  Serial.println(sensorValue1);
  Serial.println(sensorValue2);

  if (sensorValue1 = HIGH) {
    startTime = micros();
    Serial.println(sensorValue1);
  }
  if (sensorValue2 = HIGH) {
    stopTime = micros();
    Serial.println(sensorValue2);
  }
  unsigned long totalTime = (sensorValue1 - sensorValue2);
  String strPrint = strTime + totalTime;
  Serial.println(strPrint);      // prints "Time"

}

4 Answers 4

3

You have a number of problems in your code. For one thing, you are doing a lot of printing:

void loop() {
  // check and read value of input:
  int sensorValue1 = digitalRead(7);
  int sensorValue2 = digitalRead(6);
  Serial.println(sensorValue1);
  Serial.println(sensorValue2);

  if (sensorValue1 = HIGH) {
    startTime = micros();
    Serial.println(sensorValue1);
  }
  if (sensorValue2 = HIGH) {
    stopTime = micros();
    Serial.println(sensorValue2);
  }
  unsigned long totalTime = (sensorValue1 - sensorValue2);
  String strPrint = strTime + totalTime;
  Serial.println(strPrint);      // prints "Time"

}

At 9600 baud each byte output takes 1/960 seconds (about 1 ms). A println adds a carriage-return/linefeed to what you are printing so I estimate:

3 + 3 + 7 + 7 = 20 bytes (20 ms)

That is every time around the loop! You will soon find the output buffer filling up, and thus are limiting the rate at which you can test times to be the nearest 20 ms which makes using micros() a bit redundant. You won't get that accuracy.


Plus, the String class does dynamic memory allocation which will slow things down. Why use String at all? For example, you can print "Time" like this:

Serial.println ("Time:");

Next, this assigns not compares:

  if (sensorValue1 = HIGH) {

That statement makes sensorValue1 HIGH (always) and then tests if it is true, which it always will be. You want:

  if (sensorValue1 == HIGH) {

Finally, as mentioned by Majenko, make the inputs INPUT_PULLUP and wire the other end to ground, like this:

  pinMode(7, INPUT_PULLUP);   // set up pin 7
  pinMode(6, INPUT_PULLUP);   // set up pin 6

Edit - after amended question.

// declare variables
unsigned long startTime, stopTime;
unsigned long totalTime = (stopTime - startTime);

You don't declare totalTime like that. It appears you want totalTime to eventually subtract startTime from stopTime.

Just declare totalTime without any calculations, and do the calculation when it is needed. eg.

// declare variables
unsigned long startTime, stopTime;
unsigned long totalTime;

...

  if (sensorValue2 == HIGH) {
    stopTime = micros();
    totalTime = stopTime - startTime;
    Serial.print ("Time: ");
    Serial.println (totalTime);
    }  // end of second sensor tripped

Note the "==" there, without it the code thinks both sensors tripped immediately.

1

A broken wire is just a button that's held in until you release it. Just treat it like any other button.

schematic

simulate this circuit – Schematic created using CircuitLab

Just like a button, when it's all connected (button is pressed), it reads LOW, and when it's disconnected / broken (button is released) it reads HIGH. No need for messing around with analog inputs - you only care about two states, OPEN (HIGH) and CLOSED (LOW).

You can even use interrupts to make it respond even faster.

Here is an example using a simple state machine for how you could code it (untested):

const uint8_t startPin = 4;
const uint8_t stopPin = 5;

uint32_t startTime;
uint32_t stopTime;

#define ARMED = 0
#define STARTED = 1
#define STOPPED = 2

uint8_t state = ARMED;

void setup() {
    Serial.begin(115200);
    pinMode(startPin, INPUT_PULLUP);
    pinMode(stopPin, INPUT_PULLUP);
}

void loop() {

    switch (state) {
        case ARMED:  // If first wire disconnects then start.
            if (digitalRead(startPin) == HIGH) {
                startTime = micros();
                state = STARTED;
            }
            break;

        case STARTED:  // If second wire disconnects then stop
            if (digitalRead(stopPin) == HIGH) {
                stopTime = micros();
                state = STOPPED;
                Serial.print(F("Duration: "));
                Serial.print(stopTime - startTime);
                Serial.println("us");
            }
            break;

        case STOPPED:  // If both wires reconnected then start over
            if ((digitalRead(startPin) == LOW) &&
                (digitalRead(stopPin) == LOW)) {
                    state = ARMED;
            }
            break;

        default:
            break;
    }
}
4
  • Thanks, but could you go into more detail please? How would I write such a code? I had previously tried using digitalWrite, but could not work out how to get a time out of it.
    – EpicFlamo
    Commented Feb 18, 2018 at 16:16
  • As I said above: Think buttons. How would you read the state of a button? How could you use that to start or stop a timer (or more properly, record two times and then subtract one from another)?
    – Majenko
    Commented Feb 18, 2018 at 16:17
  • If you have a chance to glance over my updated code, I would appreciate it. I haven't managed to get a time value other than 0 (suggesting that it is recording the startTime and stopTime at the same time.
    – EpicFlamo
    Commented Feb 18, 2018 at 16:30
  • The problem with your code is you are constantly setting your timestamps all the time the inputs are HIGH, not just at the moment they go HIGH. You only want to set them once, and once only. Simplest way: first set them to 0, then only set them to micros() if they are currently 0.
    – Majenko
    Commented Feb 18, 2018 at 16:33
0

A better approach for your problem which was to measure the speed of a rocket (i am assuming at launch) would be to use non touch style sensors. Rather then the rocket having to hit two wires which would interrupt the flight path. You could use IR sensors Like in this article.

It would use much of the same logic you are working on now, but would use the IR sensors rather then wires (buttons)

0

Regardless of what you use as the sensors, wires or photo detectors, you should use interrupts. Each sensor should go to an interrupt and that interrupt routine should be as short as possible, basically just saving the processor time micros(), into a storage location and returning. Your main loop can then look at the storage and see if a calculation or printout is necessary. That way your result will not be dependent on where in your loop the event was detected. The inputs should be digital, high or low as described above. If you are using photo detectors that are analog, build some external circuits to turn their outputs into digital signals. I would say this isn't rocket science, but apparently it is. I just hope I am not helping a terrorists :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.