CO2 racer timer

Hey everyone,

I have a bit of experience in electronics and coding but am finding the syntax of some of the more advanced scripts a bit out of my realm of experience.

My school builds CO2 racers, little cars usually made from timber powered by a canister of CO2. We have a track set up that goes over 20m and it used to have a timer that told you which car won and what it’s time was. It no longer works and I’m looking at rebuilding it using an Arduino.

The track has a launcher which is basically a swinging arm with spikes that punctures the end of the canisters which causes the cars to go. The arm has an LED light on it, and throug it’s arc it passes a LED sensor which is what was used to start the timer. As far as I know, this part still works its just the processor that died.

I have bought a couple of 4 digit 7 segment displays to use but have found that by the time I attach one and get it working I’ve used 11 pins so I need to be able to use the remaining pins for the sensors. Therefore, I’m hoping to create 2 variables to use to time each track (2 cars run on the track at one time). I will have the display switch between the two times after the cars have both finished… I will also have 2 or 3 LEDS to signify the winning track and show which time is being displayed. I will need 3 pairs of LED lights and light sensors (1 for the launcher and one for each track’s finish line).

I have a couple of little questions that I would love some help with if it is at all possible. I am using the code that came from the display’s spec sheet.

  • First question: The logic of how I would implement a second variable escapes me. I’ve played around with it a little and haven’t managed to solve it yet. Can anyone suggest how I might be able to convert this code to have 2 timers running simultaneously and then switch between displaying both times?

  • Second question: It’s a small thing, but I’m trying to turn on the first decimal point. I tried creating a new variable called SegDP and set it to HIGH for all of the cases but it doesn’t seem to come on.

  • Third question: Can I use a common ground for the remaining 3 LED lights and light sensors which will cut down the number of pins I will need?

/*




int digit1 = 11; //PWM Display pin 1
int digit2 = 10; //PWM Display pin 2
int digit3 = 9; //PWM Display pin 6
int digit4 = 6; //PWM Display pin 8

//Pin mapping from Arduino to the ATmega DIP28 if you need it
//http://www.arduino.cc/en/Hacking/PinMapping
int segA = A1; //Display pin 14
int segB = 3; //Display pin 16
int segC = 4; //Display pin 13
int segD = 5; //Display pin 3
int segE = A0; //Display pin 5
int segF = 7; //Display pin 11
int segG = 8; //Display pin 15
int segDP = 2; //Display pin 15

void setup() {
pinMode(segA, OUTPUT);
pinMode(segB, OUTPUT);
pinMode(segC, OUTPUT);
pinMode(segD, OUTPUT);
pinMode(segE, OUTPUT);
pinMode(segF, OUTPUT);
pinMode(segG, OUTPUT);
pinMode(segDP, OUTPUT);

pinMode(digit1, OUTPUT);
pinMode(digit2, OUTPUT);
pinMode(digit3, OUTPUT);
pinMode(digit4, OUTPUT);

pinMode(13, OUTPUT);
}

void loop() {

//long startTime = millis();
//digitalWrite(segDP, HIGH);
displayNumber(millis());

//while( (millis() - startTime) < 2000) {
//displayNumber(1217);
//}
//delay(1000);
}



void displayNumber(int toDisplay) {
#define DISPLAY_BRIGHTNESS  500

#define DIGIT_ON  HIGH
#define DIGIT_OFF  LOW

long beginTime = millis();

for(int digit = 4 ; digit > 0 ; digit--) {

//Turn on a digit for a short amount of time
switch(digit) {
case 1:
digitalWrite(digit1, DIGIT_ON);
break;
case 2:
digitalWrite(digit2, DIGIT_ON);
break;
case 3:
digitalWrite(digit3, DIGIT_ON);
break;
case 4:
digitalWrite(digit4, DIGIT_ON);
break;
}

//Turn on the right segments for this digit
lightNumber(toDisplay % 10);
toDisplay /= 10;

delayMicroseconds(DISPLAY_BRIGHTNESS); //Display this digit for a fraction of a second (between 1us and 5000us, 500 is pretty good)

//Turn off all segments
lightNumber(10);

//Turn off all digits
digitalWrite(digit1, DIGIT_OFF);
digitalWrite(digit2, DIGIT_OFF);
digitalWrite(digit3, DIGIT_OFF);
digitalWrite(digit4, DIGIT_OFF);
}

while( (millis() - beginTime) < 10) ; //Wait for 20ms to pass before we paint the display again
}

//Given a number, turns on those segments
//If number == 10, then turn off number
void lightNumber(int numberToDisplay) {

#define SEGMENT_ON  LOW
#define SEGMENT_OFF HIGH

switch (numberToDisplay){

case 0:
digitalWrite(segA, SEGMENT_ON);
digitalWrite(segB, SEGMENT_ON);
digitalWrite(segC, SEGMENT_ON);
digitalWrite(segD, SEGMENT_ON);
digitalWrite(segE, SEGMENT_ON);
digitalWrite(segF, SEGMENT_ON);
digitalWrite(segG, SEGMENT_OFF);
digitalWrite(segDP, HIGH);
break;

case 1:
digitalWrite(segA, SEGMENT_OFF);
digitalWrite(segB, SEGMENT_ON);
digitalWrite(segC, SEGMENT_ON);
digitalWrite(segD, SEGMENT_OFF);
digitalWrite(segE, SEGMENT_OFF);
digitalWrite(segF, SEGMENT_OFF);
digitalWrite(segG, SEGMENT_OFF);
digitalWrite(segDP, HIGH);
break;

case 2:
digitalWrite(segA, SEGMENT_ON);
digitalWrite(segB, SEGMENT_ON);
digitalWrite(segC, SEGMENT_OFF);
digitalWrite(segD, SEGMENT_ON);
digitalWrite(segE, SEGMENT_ON);
digitalWrite(segF, SEGMENT_OFF);
digitalWrite(segG, SEGMENT_ON);
digitalWrite(segDP, HIGH);
break;

case 3:
digitalWrite(segA, SEGMENT_ON);
digitalWrite(segB, SEGMENT_ON);
digitalWrite(segC, SEGMENT_ON);
digitalWrite(segD, SEGMENT_ON);
digitalWrite(segE, SEGMENT_OFF);
digitalWrite(segF, SEGMENT_OFF);
digitalWrite(segG, SEGMENT_ON);
digitalWrite(segDP, HIGH);
break;

case 4:
digitalWrite(segA, SEGMENT_OFF);
digitalWrite(segB, SEGMENT_ON);
digitalWrite(segC, SEGMENT_ON);
digitalWrite(segD, SEGMENT_OFF);
digitalWrite(segE, SEGMENT_OFF);
digitalWrite(segF, SEGMENT_ON);
digitalWrite(segG, SEGMENT_ON);
digitalWrite(segDP, HIGH);
break;

case 5:
digitalWrite(segA, SEGMENT_ON);
digitalWrite(segB, SEGMENT_OFF);
digitalWrite(segC, SEGMENT_ON);
digitalWrite(segD, SEGMENT_ON);
digitalWrite(segE, SEGMENT_OFF);
digitalWrite(segF, SEGMENT_ON);
digitalWrite(segG, SEGMENT_ON);
digitalWrite(segDP, HIGH);
break;

case 6:
digitalWrite(segA, SEGMENT_ON);
digitalWrite(segB, SEGMENT_OFF);
digitalWrite(segC, SEGMENT_ON);
digitalWrite(segD, SEGMENT_ON);
digitalWrite(segE, SEGMENT_ON);
digitalWrite(segF, SEGMENT_ON);
digitalWrite(segG, SEGMENT_ON);
digitalWrite(segDP, HIGH);
break;

case 7:
digitalWrite(segA, SEGMENT_ON);
digitalWrite(segB, SEGMENT_ON);
digitalWrite(segC, SEGMENT_ON);
digitalWrite(segD, SEGMENT_OFF);
digitalWrite(segE, SEGMENT_OFF);
digitalWrite(segF, SEGMENT_OFF);
digitalWrite(segG, SEGMENT_OFF);
digitalWrite(segDP, HIGH);
break;

case 8:
digitalWrite(segA, SEGMENT_ON);
digitalWrite(segB, SEGMENT_ON);
digitalWrite(segC, SEGMENT_ON);
digitalWrite(segD, SEGMENT_ON);
digitalWrite(segE, SEGMENT_ON);
digitalWrite(segF, SEGMENT_ON);
digitalWrite(segG, SEGMENT_ON);
digitalWrite(segDP, HIGH);
break;

case 9:
digitalWrite(segA, SEGMENT_ON);
digitalWrite(segB, SEGMENT_ON);
digitalWrite(segC, SEGMENT_ON);
digitalWrite(segD, SEGMENT_ON);
digitalWrite(segE, SEGMENT_OFF);
digitalWrite(segF, SEGMENT_ON);
digitalWrite(segG, SEGMENT_ON);
digitalWrite(segDP, HIGH);
break;

case 10:
digitalWrite(segA, SEGMENT_OFF);
digitalWrite(segB, SEGMENT_OFF);
digitalWrite(segC, SEGMENT_OFF);
digitalWrite(segD, SEGMENT_OFF);
digitalWrite(segE, SEGMENT_OFF);
digitalWrite(segF, SEGMENT_OFF);
digitalWrite(segG, SEGMENT_OFF);
digitalWrite(segDP, HIGH);
break;
}
}

Sorry not to address your questions, but:

Your life might be a lot simpler if you use the 7seg library which has a page in the playground.

It might be made even simpler by using 7 segment modules such as sparkfun’s, which run on the i2c or spi buses thus giving you back most of your pins. Not only that, but with i2c you don’t use any more pins for each new module and for spi you use only 1 extra pin per module.

(I2c uses only 2 pins for any number of devices; spi uses 3, + 1 for each.)

(I realise you already spent some money but it might be worth it for simplicity of connection to spend more?)

Learn.sparkfun.com/tutorials/using-the-serial-7-segment-display/all

delayMicroseconds(DISPLAY_BRIGHTNESS); //Display this digit for a fraction of a second (between 1us and 5000us, 500 is pretty good)


while( (millis() - beginTime) < 10) ; //Wait for 20ms to pass before we paint the display again
}

The use of any delay is going to interfere with the useful work of measuring the timing of the cars. The while() loop is also a delay. A big one. (And the comment is wrong.) Pick a different library to drive the display which doesn’t use delays.

I see no attempt to measure even one car, so adding a second one is difficult without simply completing your homework for you

Mezillious2: I have bought a couple of 4 digit 7 segment displays to use but have found that by the time I attach one and get it working I've used 11 pins so I need to be able to use the remaining pins for the sensors.

That's why the rest of the world uses a driver IC for such displays, such as the common and very cheap TM1637, which is well supported on Arduino. There are lots of dirt cheap 4-digit 7-segment displays out there that have such a chip in place already It not only frees up most of your pins, it also means you don't have to worry about the mutiplexing of the display. That's a serious workload for your Arduino, and if you get anything wrong in the rest of your program you will see glitches. So in short: get a display module with driver chip and make your life MUCH easier. You also get to use the decimal point (or the : if you have a hh:mm type display).

With that multiplexing out of the way, the rest of your code becomes a lot easier.

Look at the state change example: when you see your starting signal go low (could be high of course, depending on your configuration), record the millis() value; when you see your finish signal go low check how much time has passed. Print the resulting value on the display. If you like, print the elapsed time every 0.1 seconds or so on the display.

Add a reset button to restart the whole thing.

And remember: don't use delay() or it's just as evil sibling delayMicroseconds().