Pinewood Derby Timer with NewSoftSerial

I had this posted over in the hardware section and got no response, so I thought I'd try it over here in software. Sorry if you've seen it already.

I am attempting to make an affordable pinewood derby timer for a 4 lane track. I'm using the Arduino Duemilanove controller, a lever switch for the gate, 4 optical sensors to detect the cars, and 4 of the 7 segment serial displays (COM-09230) to display the times.

My plan is to have the system be able to stand alone with the displays, or have a more automated VB front end that will display the times via screen. I will communicate with the displays using NewSoftSerial on the digital pins, leaving the main serial port for programming and hopefully the VB front end.

I have written some test code (see below), to try out the displays. When working properly, it will display 1234 in each display, and when a button is pressed, display only the decimal points.

The problem that I'm having is this. When I have the USB connected, it messes with the displays so that they do not display properly (see pics below). If I disconnect the USB and cycle power, it works fine.

I'd like to have both the displays functional and the USB connection available. I appreciate any help you guys can offer.

Thanks!

Here is a link to my wiring diagram:
http://users.zoominternet.net/~classicmustangefi/Arduino/Main_Circuit%20Rev1.pdf

A pic of my panel.....

Pics of displays working properly......

Pics of displays not working properly.....

#include <NewSoftSerial.h>

int Lane_1Pin = 10;
int Lane_2Pin = 11;
int Lane_3Pin = 12;
int Lane_4Pin = 13;
int Gate_Pin = 9;
int Lane_1_LEDPinTX = 8;
int Lane_2_LEDPinTX = 7;
int Lane_3_LEDPinTX = 6;
int Lane_4_LEDPinTX = 5;
int Lane_1_LEDPinRX = 14;
int Lane_2_LEDPinRX = 15;
int Lane_3_LEDPinRX = 16;
int Lane_4_LEDPinRX = 17;

int test = 0;


NewSoftSerial Lane_1Serial (Lane_1_LEDPinRX, Lane_1_LEDPinTX);
NewSoftSerial Lane_2Serial (Lane_2_LEDPinRX, Lane_2_LEDPinTX);
NewSoftSerial Lane_3Serial (Lane_3_LEDPinRX, Lane_3_LEDPinTX);
NewSoftSerial Lane_4Serial (Lane_4_LEDPinRX, Lane_4_LEDPinTX);
//SoftwareSerial Lane_1Serial (Lane_1_LEDPinRX, Lane_1_LEDPinTX);
//SoftwareSerial Lane_2Serial (Lane_2_LEDPinRX, Lane_2_LEDPinTX);
//SoftwareSerial Lane_3Serial (Lane_3_LEDPinRX, Lane_3_LEDPinTX);
//SoftwareSerial Lane_4Serial (Lane_4_LEDPinRX, Lane_4_LEDPinTX);


// The setup() method runs once, when the sketch starts

void setup()   {                
  // initialize the Lane Signal Pins
  pinMode(Lane_1Pin, INPUT);     
  pinMode(Lane_2Pin, INPUT);     
  pinMode(Lane_3Pin, INPUT);     
  pinMode(Lane_4Pin, INPUT);  
  pinMode(Gate_Pin, INPUT);
  // Turn on Pull Up Resistor on Gate Input
  digitalWrite(Gate_Pin,HIGH);  
  //Initialize the LED Serial Pins
  pinMode(Lane_1_LEDPinTX, OUTPUT);     
  pinMode(Lane_2_LEDPinTX, OUTPUT);     
  pinMode(Lane_3_LEDPinTX, OUTPUT);     
  pinMode(Lane_4_LEDPinTX, OUTPUT);     
  pinMode(Lane_1_LEDPinRX, INPUT);     
  pinMode(Lane_2_LEDPinRX, INPUT);     
  pinMode(Lane_3_LEDPinRX, INPUT);     
  pinMode(Lane_4_LEDPinRX, INPUT);     
  Lane_1Serial.begin(9600);
  Lane_2Serial.begin(9600);
  Lane_3Serial.begin(9600);
  Lane_4Serial.begin(9600);
  
}

// the loop() method runs over and over again,
// as long as the Arduino has power

void loop()     
{  
  int delaytime = 0;
  int OneShotOn = 0;
  int OneShotOff = 0;
  
  test = digitalRead(Gate_Pin);

  if ((test == 1) && (OneShotOn == 0)){ 
    Lane_1Serial.print(1);    
    delay(delaytime);
    Lane_1Serial.print(2);    
    delay(delaytime);
    Lane_1Serial.print(3);    
    delay(delaytime);
    Lane_1Serial.print(4);  
    delay(delaytime);
    
    Lane_2Serial.print(0x01,BYTE);    
    delay(delaytime);
    Lane_2Serial.print(0x02,BYTE);    
    delay(delaytime);
    Lane_2Serial.print(0x03,BYTE);    
    delay(delaytime);
    Lane_2Serial.print(0x04,BYTE);  
    delay(delaytime);
   
    Lane_3Serial.print(0x01,BYTE);    
    delay(delaytime);
    Lane_3Serial.print(0x02,BYTE);    
    delay(delaytime);
    Lane_3Serial.print(0x03,BYTE);    
    delay(delaytime);
    Lane_3Serial.print(0x04,BYTE);
    delay(delaytime);

    Lane_4Serial.print(0x01,BYTE);    
    delay(delaytime);
    Lane_4Serial.print(0x02,BYTE);    
    delay(delaytime);
    Lane_4Serial.print(0x03,BYTE);    
    delay(delaytime);
    Lane_4Serial.print(0x04,BYTE);
    delay(delaytime);
    OneShotOn = 1;
    OneShotOff = 0;
  }
  else if ((test == 0) && (OneShotOff == 0)){
    /*Lane_1Serial.print(0x78,BYTE);    
    Lane_1Serial.print(0x78,BYTE);    
    Lane_1Serial.print(0x78,BYTE);    
    Lane_1Serial.print(0x78,BYTE);  

    Lane_2Serial.print(0x78,BYTE);    
    Lane_2Serial.print(0x78,BYTE);    
    Lane_2Serial.print(0x78,BYTE);    
    Lane_2Serial.print(0x78,BYTE);  

    Lane_3Serial.print(0x78,BYTE);    
    Lane_3Serial.print(0x78,BYTE);    
    Lane_3Serial.print(0x78,BYTE);    
    Lane_3Serial.print(0x78,BYTE);  

    Lane_4Serial.print(0x78,BYTE);    
    Lane_4Serial.print(0x78,BYTE);    
    Lane_4Serial.print(0x78,BYTE);    
    Lane_4Serial.print(0x78,BYTE);*/
    Lane_1Serial.print(0x77,BYTE); 
    Lane_1Serial.print(0x01,BYTE);    
    Lane_2Serial.print(0x77,BYTE); 
    Lane_2Serial.print(0x01,BYTE);    
    Lane_3Serial.print(0x77,BYTE); 
    Lane_3Serial.print(0x01,BYTE);    
    Lane_4Serial.print(0x77,BYTE); 
    Lane_4Serial.print(0x01,BYTE);    
   
    
    OneShotOff = 1;
    OneShotOn = 0;
  }

}

I don't know if it's relevant, or not, but I've never seen anyone else using NewSoftSerial with the analog-pins-as-digital-pins.

My first test would be to switch the lane pins to the analog pins, and use the now free digital pins for the NewSoftSerial pins.

Again, I don't know if it makes any difference, or not, but typically adjacent pins are used for one serial connection, like 7 and 8, 9 and 10, etc., rather than 7 and 14.

Having both pins on the same port may be necessary.

Just tossing out ideas. I don't know whether they are good ones, or not.

Try this...

  • Copy the Sketch
  • Edit the copy
  • Remove all but one of the NewSoftSerial objects (leave Lane_1Serial but remove Lane_2Serial through Lane_4Serial)
  • Clean up any problems created by removing the three NewSoftSerial objects
  • Test

Does that make any difference?

Thanks to both of you for the fine suggestions. I tried a combo of what you suggested . I removed all code but one lane, and I put it on pin 4 as the TX, pin 3 as the RX. This makes no difference. Still the same output.

I suspect its some type of software conflict between the serial ports. It seems like something is making the display miss a beat, and then the numbers get offset. This is something that I can work around, but its less than ideal.

These displays only have an RX pin on them, there is no TX function, so there is only one comm wire going to them. Should I be grounding the arduino declared TX line thru a resistor or something?

Here is the test code.....

#include <NewSoftSerial.h>

int Gate_Pin = 9;
int Lane_1_LEDPinTX = 4;
int Lane_1_LEDPinRX = 3;


int test = 0;


NewSoftSerial Lane_1Serial (Lane_1_LEDPinRX, Lane_1_LEDPinTX);
//SoftwareSerial Lane_1Serial (Lane_1_LEDPinRX, Lane_1_LEDPinTX);

// The setup() method runs once, when the sketch starts

void setup()   {                
  // initialize the Lane Signal Pins
  pinMode(Gate_Pin, INPUT);
  // Turn on Pull Up Resistor on Gate Input
  digitalWrite(Gate_Pin,HIGH);  
  //Initialize the LED Serial Pins
  pinMode(Lane_1_LEDPinTX, OUTPUT);     
  pinMode(Lane_1_LEDPinRX, INPUT);     
  Lane_1Serial.begin(9600);
  
}

// the loop() method runs over and over again,
// as long as the Arduino has power

void loop()     
{  
  int delaytime = 0;
  int OneShotOn = 0;
  int OneShotOff = 0;
  
  test = digitalRead(Gate_Pin);

  if ((test == 1) && (OneShotOn == 0)){ 
    Lane_1Serial.print(1);    
    delay(delaytime);
    Lane_1Serial.print(2);    
    delay(delaytime);
    Lane_1Serial.print(3);    
    delay(delaytime);
    Lane_1Serial.print(4);  
    delay(delaytime);
    
    OneShotOn = 1;
    OneShotOff = 0;
  }
  else if ((test == 0) && (OneShotOff == 0)){
    Lane_1Serial.print(0x77,BYTE); 
    Lane_1Serial.print(0x01,BYTE);    
    OneShotOff = 1;
    OneShotOn = 0;
  }

}

OK so for now I'm moving beyond this. In theory I have 4 displays working as long as the USB isn't connected, so why not go for broke. I wrote code for the whole shebang. I trigger the gate, start the timers, and display the count. First problem. Only the first 2 displays do what I want them to do. The other ones either hold zeros, or flash randomly. Since the code is the same for each one (I think), and all 4 pins will work with the test code(above), I'm leaning again towards a problem with the serial software. I'm still playing with it though.

I've separated out the working ones, and tried them on the non-working pins, no dice. I've moved one of the working displays to a completely different pin, no dice. I went back and tried my test program, and it works for all of the pins.

Has anybody ever done this many serial ports with the digital pins before?
Am I asking too much for this board/software, or is there a different approach I should be taking?
Am I missing something painfully obvious here?
Is there any type of console program that I can run to debug some of the logic in the code? This is painful without any type of output.
I've got some other debug stuff I want to try, but I'm open to any and all suggestions.

I may be forced to give up on this and focus on the serial to computer interface as my backup plan. That would be a bummer, as I've got some money wrapped up in the displays.....

Here is the code....

#include <PinewoodDefs.h>
#include <NewSoftSerial.h>



int Lane_1Pin = 10;
int Lane_2Pin = 11;
int Lane_3Pin = 12;
int Lane_4Pin = 13;
int Gate_Pin = 9;
int Lane_1_LEDPinTX = 8;
int Lane_2_LEDPinTX = 7;
int Lane_3_LEDPinTX = 6;
int Lane_4_LEDPinTX = 5;
int Lane_1_LEDPinRX = 14;
int Lane_2_LEDPinRX = 15;
int Lane_3_LEDPinRX = 16;
int Lane_4_LEDPinRX = 17;

NewSoftSerial Lane_1Serial (Lane_1_LEDPinRX, Lane_1_LEDPinTX);
NewSoftSerial Lane_2Serial (Lane_2_LEDPinRX, Lane_2_LEDPinTX);
NewSoftSerial Lane_3Serial (Lane_3_LEDPinRX, Lane_3_LEDPinTX);
NewSoftSerial Lane_4Serial (Lane_4_LEDPinRX, Lane_4_LEDPinTX);


// The setup() method runs once, when the sketch starts

void setup()   {                
  // initialize the Lane Signal Pins
  pinMode(Lane_1Pin, INPUT);     
  pinMode(Lane_2Pin, INPUT);     
  pinMode(Lane_3Pin, INPUT);     
  pinMode(Lane_4Pin, INPUT);  
  pinMode(Gate_Pin, INPUT);
  // Turn on Pull Up Resistor on Gate Input
  digitalWrite(Gate_Pin,HIGH);  
  //Initialize the LED Serial Pins
  pinMode(Lane_1_LEDPinTX, OUTPUT);     
  pinMode(Lane_2_LEDPinTX, OUTPUT);     
  pinMode(Lane_3_LEDPinTX, OUTPUT);     
  pinMode(Lane_4_LEDPinTX, OUTPUT);     
  pinMode(Lane_1_LEDPinRX, INPUT);     
  pinMode(Lane_2_LEDPinRX, INPUT);     
  pinMode(Lane_3_LEDPinRX, INPUT);     
  pinMode(Lane_4_LEDPinRX, INPUT);     
  Lane_1Serial.begin(9600);
  Lane_2Serial.begin(9600);
  Lane_3Serial.begin(9600);
  Lane_4Serial.begin(9600);
  DisplayBlank();
}

// the loop() method runs over and over again,
// as long as the Arduino has power

void loop()     
{
  int GateTrigger;
  int GateOS;
  int RunOS;
  LaneStruct Lane1, Lane2, Lane3, Lane4;
  
  Lane1.Running = 0;
  Lane2.Running = 0;
  Lane3.Running = 0;
  Lane4.Running = 0;
  GateOS = 0;
  RunOS = 0;
  GateTrigger = digitalRead(Gate_Pin);
  
  //Wait for Gate to Drop
  while(GateTrigger == HIGH){
    GateTrigger = digitalRead(Gate_Pin);
    //Only call display blank once
    if (GateOS==0) {
      GateOS = 1;
      DisplayBlank();
      DisplayDecimalsOff();
    }
  }
  //Gate is triggered.  Note Lane Start Times
  Lane1.Start = micros();
  Lane2.Start = micros();
  Lane3.Start = micros();
  Lane4.Start = micros();
  Lane1.Running = 1;
  Lane2.Running = 1;
  Lane3.Running = 1;
  Lane4.Running = 1;

  while(GateTrigger == LOW){
    GateTrigger = digitalRead(Gate_Pin);
    Lane1.PinStatus = digitalRead(Lane_1Pin);
    Lane2.PinStatus = digitalRead(Lane_2Pin);
    Lane3.PinStatus = digitalRead(Lane_3Pin);
    Lane4.PinStatus = digitalRead(Lane_4Pin);
    
    if (RunOS==0){
      RunOS==1;
      DisplayDecimalsOn();
    }
    if (Lane1.Running ==1 && Lane1.PinStatus == HIGH) {          
      TimeCalc (&Lane1);
      DisplayTime (Lane1.Time,1);
    }
    else if (Lane1.Running ==1 && Lane1.PinStatus == LOW) {
      Lane1.Running = 0;
      TimeCalc (&Lane1);
      DisplayTime (Lane1.Time,1);
    }
    if (Lane2.Running ==1 && Lane2.PinStatus == HIGH) {          
      TimeCalc (&Lane2);
      DisplayTime (Lane2.Time,2);
    }
    else if (Lane2.Running ==1 && Lane2.PinStatus == LOW) {
      Lane2.Running = 0;
      TimeCalc (&Lane2);
      DisplayTime (Lane2.Time,2);
    }
    if (Lane3.Running ==1 && Lane3.PinStatus == HIGH) {          
      TimeCalc (&Lane3);
      DisplayTime (Lane3.Time,3);
    }
    else if (Lane3.Running ==1 && Lane3.PinStatus == LOW) {
      Lane3.Running = 0;
      TimeCalc (&Lane3);
      DisplayTime (Lane3.Time,3);
    }
    if (Lane4.Running ==1 && Lane4.PinStatus == HIGH) {          
      TimeCalc (&Lane4);
      DisplayTime (Lane4.Time,4);
    }
    else if (Lane4.Running ==1 && Lane4.PinStatus == LOW) {
      Lane4.Running = 0;
      TimeCalc (&Lane4);
      DisplayTime (Lane4.Time,4);
    }    
  }  
}


//Sends Blanks Commands to the 7 Seg LED Display
void DisplayBlank(){
  //Blank the displays
  Lane_1Serial.print(0x78,BYTE);    
  Lane_1Serial.print(0x78,BYTE);    
  Lane_1Serial.print(0x78,BYTE);    
  Lane_1Serial.print(0x78,BYTE);  

  Lane_2Serial.print(0x78,BYTE);    
  Lane_2Serial.print(0x78,BYTE);    
  Lane_2Serial.print(0x78,BYTE);    
  Lane_2Serial.print(0x78,BYTE);  

  Lane_3Serial.print(0x78,BYTE);    
  Lane_3Serial.print(0x78,BYTE);    
  Lane_3Serial.print(0x78,BYTE);    
  Lane_3Serial.print(0x78,BYTE);  

  Lane_4Serial.print(0x78,BYTE);    
  Lane_4Serial.print(0x78,BYTE);    
  Lane_4Serial.print(0x78,BYTE);    
  Lane_4Serial.print(0x78,BYTE);    
}
//Turns on the Decimal Points in the 7 segment LED displays
void DisplayDecimalsOn(){
    Lane_1Serial.print(0x77,BYTE); 
    Lane_1Serial.print(0x01,BYTE);    
    Lane_2Serial.print(0x77,BYTE); 
    Lane_2Serial.print(0x01,BYTE);    
    Lane_3Serial.print(0x77,BYTE); 
    Lane_3Serial.print(0x01,BYTE);    
    Lane_4Serial.print(0x77,BYTE); 
    Lane_4Serial.print(0x01,BYTE);    
}

//Turns off the Decimal Points in the 7 segment LED displays
void DisplayDecimalsOff(){
    Lane_1Serial.print(0x77,BYTE); 
    Lane_1Serial.print(0x00,BYTE);    
    Lane_2Serial.print(0x77,BYTE); 
    Lane_2Serial.print(0x00,BYTE);    
    Lane_3Serial.print(0x77,BYTE); 
    Lane_3Serial.print(0x00,BYTE);    
    Lane_4Serial.print(0x77,BYTE); 
    Lane_4Serial.print(0x00,BYTE);    
}

void TimeCalc (LaneStruct *Lane){
  Lane->Finish = micros();
  Lane->Time = (Lane->Finish - Lane->Start)/1000; 
}

void DisplayTime (unsigned long time, int Lane){

  char myStr[6];
  char zero = {0};
  int i;
  int j;
  
  itoa(time,myStr,10);

//Trying to offset the digits for the first second.  This doesn't work yet.
/*  if (time/1000 == 0){
    for(j=6;j>0;j--){
      myStr[j]=myStr[j-1];
    }
    myStr[0] = zero;
  }*/

  switch (Lane) {
    case 1:
      for (i = 0; i < 4; i++){
        Lane_1Serial.print(myStr[i]);
      }
      break;
    case 2:
      for (i = 0; i < 4; i++){
        Lane_2Serial.print(myStr[i]);
      }
      break;
    case 3:
      for (i = 0; i < 3; i++){
        Lane_3Serial.print(myStr[i]);
      }
      break;
    case 4:
      for (i = 0; i < 4; i++){
        Lane_4Serial.print(myStr[i]);
      }
      break;
  }
}

This is my PinewoodDefs.h file

typedef struct {
  int Trigger;
  
              int Running;
  
              int PinStatus;
  
              int Place;
  
              unsigned long  Start;
  
              unsigned long  Finish;
  
              unsigned long  Time;
} LaneStruct;

Unfortunately, I don't have enough experience to help with your questions. I do have a suggestion. First focus on the core of the project: timing races. Once that is working well then add the displays.

This looks like a fun project, I'd hate to see you give up. It may be worth trying the SPI interface for these displays. It will require 3 pins for the first display and 1 additional pin for each subsequent display, 6 in total (but each display will have 3 wires sharing the MOSI and SCK). It looks like someone else may have done the ground work on talking to this display over SPI:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1247533060/2

Thanks for the help and encouragement. I haven't given up yet (I can't), just got sidetracked a bit. I've found out some interesting stuff, though. I switched over to softwareserial.h, and that seems to work better for this application. I also played around with different pin assignments. It seems like adjacent pins don't like to be TX for the device. I've been able to get 5, 7, 8, and 10 to work separately. Right now I'm waiting for more displays. One of them arrived non-functional, and I inadvertently smoked the other one, or at least scrambled it a little bit. So I'm down to two.

One thing to note, is that if my power supply is off, and the USB is connected, the power somehow backfeeds through the outputs, dimly lighting the display. I fear that might be what scrambled the last one. Not quite sure on that one.

If I can't get this to work, I'll give the SPI a try.

Update. I now have stage 1 of the plan working. All 4 timers will start when the gate switch drops, they will count up until each of the lane sensors are hit, and they will display the final time.

I'm seeing some strange stuff with how I power it up, combined with the USB connection. Sometimes it comes up clean, and sometimes a display comes up funky and refuses to work. I've found if I disconnect the USB, power on the Arduino board first, then the displays, it always works. It sometimes works if I leave the USB connected. It sometimes doesn't. Does this have anything to do with the autoreset feature?

I am considering wiring up the reset lines on the main controller and displays, and manually resetting them all after everything is connected and powered up. Is it ok to wire all the reset lines together, and drive them low all at once, or should they all be tied in separately?

Stage 2 is talking to it thru the USB, but I need to get this power up and connection thing figured out.

Any help is greatly appreciated.

Thanks,
Jonathan

I discovered 2 things tonite.

  1. I tied the resets for the displays together thru a momentary switch to ground. This is useful for resetting the displays if they don't power up properly. Takes care of the power up issues I described above. If the displays come up funky, hit the reset switch, and they are ready to go.

  2. When the USB is connected to the computer, it is tied to a software reset on the board. This is what was screwing up the displays some of the time. I tied the reset to 5V thru a 150 ohm resister with a switch, and the problem went away. From what I have read, you can't download to the board if this is in place. So the switch is for program/run mode.

Hi Pinewood,

I followed your troubleshooting process and I am kind of on the same page as far as the 7-segment serial display goes. It sounds like you were able to clear up the number scrambling by tying the reset of the display to a "momentary switch" to ground. Do you just mean switching off the 5V source momentarily? I will have to try this out. I am not so sure what you meant in your 2nd discovery... that you were frying your boards due to the USB being disconnected and connected to the board?

Thanks!!

Any updates to this project? I am looking for a "winter in the basement" challenge and our AWANA derby is 9 months away.