2

My question is: how do I read multiple inputs at the same time without using interrupts on an UNO. I'm building an RC drag strip with tree and finish line that will calculate run time as well as calculate each run in mph. I'm using lasers and non modulated laser detectors for the beams and I'm using a 1" beam gap(between 1st beam and 2nd beam) at the finish line(for mph calculation). My concern comes in when two cars come close enough at the finish line for one to break the first beam at set the win flag but the car in the other lane is close enough to cross the 1st beam before the 1st car actually crosses the 2nd beam then the detection loop is going to miss one of them. (just a note: a few of these cars can top 100 mph when crossing the line)

  • 100mph *5280ft/mi*12in/ft/(3600s/h)=1760in/s, so your system needs to measure on the order of 1in/1760in/s = 568 microseconds, broken down tighter for ties. How many multiples? Just two? Why not use interrupts? From arduino.stackexchange.com/a/12958/6628 you could approach 0.01" resolution. – Dave X Feb 3 '16 at 3:24
  • then the detection loop is going to miss one of them - how long are the cars? Isn't the bigger issue that the first beam will still be broken, and that the second car won't register at all, regardless of how you program it? – Nick Gammon Feb 3 '16 at 5:13
  • With the beams crossing both/all lanes, overlapping cars will always be an issue. Whether for determining how fast the first car is or who is second with more than two lanes. You will need to use separate detectors per lane if you want to avoid this. – Dave X Feb 3 '16 at 16:27
  • @nick, your code in arduino.stackexchange.com/a/12958/6628 detected and switched in 1.52us. One could maybe save (PIND_last ^PIND) and a timer/counter in a table of events with each pin change, and then leave the arming and interpretation to the loop(). You could store timing information at the resolution of the counter, and differentiate ties at the resolution of the interrupt servicing routine. Maybe I'll copy your code and try that as an answer. – Dave X Feb 3 '16 at 16:31
  • 2
    Yes, I was going to try a timing test once we cleared up the issue of the overlapping readings. But I agree it looks like you can get pretty good results. – Nick Gammon Feb 3 '16 at 20:14
2

ONE:

What you can do is use a while loop waiting for the first pulse and then wait until the last pulse, for an idea look at this code from Gadjet, he made a chronograph with a similar operation, you would just need to adapt the design, this might not be as accurate for an 1". Also it will be the issue of having ties between cars. This is short as I don't like this option.

TWO:

Another option, although using what you don't want to use, would be using the interrupts on the Arduino. I am basing the following on the fact that you are using two cars.

What you can do is have a finish line for both vehicles and detect a break with a interrupt, one interrupt pin per lane(UNO has to interrupts).

The trick here is that you place both the outputs from one lane onto a single interrupt pin with a edge detector type of circuit1 to generate a pulse while the vehicle crosses a point, especially important as it will be in the inch area for a while. The code handles the double pulse on one pin. I know this works as I used this on a ballistic chronograph which works in microseconds detecting shots >2000fps over a 0.406 foot distance.

1 This is an example of the circuit you would use at the output of each sensor before the OR gates: enter image description here

The hardware would just become a duplicate for each lane, and to combine the input on one pin you can use an OR gate IC or you can use diode OR gate: from ee.se

Interrupts are actually easy to use with Arduinos, and there are a lot of examples out there.

Have a look at the below flow chart to get an idea of operation in the code:

RSM code

A small thing would be that the code ignores a interrupt once the cars have passed so it doesn't calculate a second time.

2

Building upon Nick Gammon's excellent answer at How many interrupt pins can an Uno handle? here's some untested code:

 const int events = 256; // events to store
 unsigned volatile int index;  
 byte pinStates[events];
 unsigned int times[events];

 ISR (PCINT1_vect) //  Watch for pin changes on the C port (Uno pins A0-A5)
 {
   if (index == 0) { // start clock
    TCCR1B = bit(CS12) | bit (CS10) ;    // clock/1024 for <4.19s x 64us
    //TCCR1B = bit(CS12);                // clock/256  for <1.05s x 16us 
    //TCCR1B = bit(CS11) | bit (CS10) ;  // clock/64   for <0.25s x 4us
    //TCCR1B = bit(CS11) ;               // clock/8    for <0.03s x 0.5us
    //TCCR1B = bit(CS10) ;               // clock/1    for <0.004s x 62ns
   }
   times[index] = TCNT1;
   pinStates[index] = PORTC;
   index = (index+1) & 0xff; // increment and protect from overflow

 }  // end of PCINT1_vect

void setup ()
  { 
  // activate pin change interrupts on port C / pins A0-A5

  PCICR   =  bit (PCIE1);    // enable PCINT[14:8] pin triggers 
  PCMSK1 |=  bit (PCINT8) | 
             bit (PCINT9) | 
             bit (PCINT10) | 
             bit (PCINT11) | 
             bit (PCINT12) | 
             bit (PCINT13);     // enable individual pins

  // stop and clear 16 bit timer  CS1[0-2]=0; TCNT1 = 0;
  TCCR1A = 0;  // no comparisons, normal WGM mode, stop the counting 
  TCCR1B = 0;  
  TCNT1  = 0;  // Clear the counter

  pinMode (A0, INPUT_PULLUP);
  pinMode (A1, INPUT_PULLUP);
  pinMode (A2, INPUT_PULLUP);
  pinMode (A3, INPUT_PULLUP);
  pinMode (A4, INPUT_PULLUP);
  pinMode (A5, INPUT_PULLUP);

  index = 0 ; // nothing happened yet

  pinMode (5, OUTPUT);
  }  // end of setup

void loop ()
  {

   // check index, parse and report times, check for arming, etc...

  }

The point is to use the pin change interrupt to record state changes on the pins and the times. The clock/1024 prescaler would give a 1/16MhZ*1024*65536= 4.19s window at 64us resolution timing counts, but you could go to higher resolution with a tighter window by using a smaller prescaler.

Also, if you wanted longer timing windows, you could cascade timer1 into timer0 (messing up millis(), etc.,) and get 24 bits of range before overflow, but a better way than cascading timers might be to add another interrupt to increment a variable. For much longer timing windows add another quick interrupt to handle for timer1 overflow.

...
volatile unsigned long int t1Cycles,times[events];
...

ISR(TIMER1_OVF_vect){t1Cycles++;}  

void setup(){
    ...
    TIMSK1 = bit(TOIE1);
    t1Cycles = 0;
    ...
} 

ISR (PCINT1_vect)
{
    ...
    times[index] = t1Cycles << 16 | TCNT1; // store 32 bit count of clocks
    ...
}

This is still untested, but it looks like it could be capable of 268 seconds worth of 62ns resolution multichannel timing. With the longer period, you could move the conditional clock-starting code out of the pin-change ISR.

  • 1
    I think I would use a much lower prescaler. Since you have kept the timer stopped until the first pulse, it won't take 4 seconds for the car to cross to the second laser. – Nick Gammon Feb 3 '16 at 21:53
  • One certainly could use a lower prescaler. I chose the slower speed because my kids just did a pinewood derby race, and wanted to allow plenty of time to measure the slow cars to cross the line. – Dave X Feb 4 '16 at 2:44
  • 1
    Are you trying to catch all entries? In that case 4s might be too little. You could catch overflows ... wait you just edited that in. Excellent. Tip: make t1Cycles volatile. Also I think you want to shift t1Cycles left 16, as Timer 1 is a 16-bit timer. – Nick Gammon Feb 4 '16 at 4:39
  • Yes, catching all entries was what I was aiming at. Thanks for the tips. – Dave X Feb 4 '16 at 4:52
  • I made more edits and it seems to compile for an Uno. To test it on the AT90usb1286 hardware I've got, I'd need to switch things over to port B. – Dave X Feb 4 '16 at 5:16
0

One option, if you want very-real-time processing, for a task like this that break neatly into chunks: Have one Arduino per vehicle.

Arduinos are cheap. If they are too expensive, use AtTiny's - they can be had for about a dollar a piece (depending on your currency). You can share a clock/power between a large number of them.

You can either have a "master" Arduino talk to each individual one, to collect the information, or have daisy-chained bus - each one can pass it's data to the next one in the chain (once is has the data, and the next one in the chain indicates it's ready for it).

  • 1
    I think my objection to this would be synchronizing them. Especially if they are each doing different lanes. If they didn't agree exactly on what the time was, they might report the runner-up as the winner. – Nick Gammon Feb 4 '16 at 5:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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