Hello!
This is my first Arduino project, and my second post on this forum. I'm having a lot of fun learning about Arduino and happy with the progress I've made on my own, but I'm at a place where I think I need help. I would welcome feedback on how to make my question more clear to this group, if needed!
Project Overview:
I'm attempting to create a Laser Lap Timer to use outdoors for a dirtbike event my friends have set for later in the summer. The timer should record:
- Current Lap Time
- Current Lap number
- Last Lap
- Best Lap
The Hardware being used:
- Mega2560
- ISO103 Receivers
- HiLetgo 3.5" TFT LCD Display ILI9486/ILI9488 480x320 36 Pins for Arduino Mega2560
- connection wires
The Library that I'm using for the TFT display is:
Because I'm still learning about how to make things with Arduino, the project lives as a mashup between two existing projects. I took the example project from the TFT_HX8357 library (TFT_Print_Test) and inserted what I believed to be the important portions of code from this Laser Lap Timer project that I found on Gadgetronicx >> [Lap timer for slot cars using Laser and Arduino] Note: because I'm a new user, I'm only allowed to post two links, so I'm unable to link the project here. However it is the first thing that comes up when doing a Google Search for the words in BOLD.
Initially I was struggling with getting the TFT display to work, but thanks to this forum I was able to figure that, and a few other things out in this thread, if you're interested, or it helps someone else in the future.
I thought I had everything figured out, until I set it up for testing with a slot car track. After lining everything up and ensuring the car would break the beam on the pass, the timer isn't registering new laps. It appears that the break in the laser beam doesn't last long enough to trigger a new lap. The delay on this portion of the setup is set to 1, and I've messed around with the debounce time (i'm still learning about this, so it truly was "messing around") but no positive outcome.
The curious part is that in a previous test to learn about the laser sensors and the basics of Arduino - I set up a buzzer to ring when the beam is broken. This involved no display, just the sensor, and the buzzer and it worked perfectly. I could flick a pencil between the beam and it would register a sound.
I'm at a loss on how to troubleshoot from here. So my question,
- Is there a solve for getting the program to register very quick breaks in the laser beam?
As a secondary question/topic, because I am still very new at this, I would welcome any feedback on the code as a whole! As stated above it is a bit of a "mish-mash" of two previously existing projects/examples. I'm very confident that there are more elegant ways to accomplish what I'm trying to do.
Thank you for your help.
Here is a youtube video of the test from today.
And here is my code, as it sits today.
#include <TFT_HX8357.h> // Hardware-specific library
TFT_HX8357 tft = TFT_HX8357(); // Invoke custom library
// laps info
unsigned long currentRunStartMillis;
unsigned long lastRunInMillis;
unsigned long bestRunInMillis;
int currentLap;
unsigned long savedMillis;
// global for display
int min_val, sec_val, milli_val;
// laser gate
const int gateSensorPin = 2; // the number of the gate sensor pin
int gateSensorState; // the current reading from the sensor
int lastgateSensorState = LOW; // the previous reading from sensor
unsigned long lastDebounceTime = 0; // the last time the sensor pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
void setup(void) {
tft.init();
tft.setRotation(3);
// pin mode
pinMode(gateSensorPin, INPUT);
delay(1); // to late the sensor and laser work, so we wont get the lap triggered.
// reset params
currentRunStartMillis = 0;
lastRunInMillis = 0;
bestRunInMillis = 0;
currentLap = 0;
tft.fillScreen(TFT_BLACK);
}
void loop() {
// read the state of the laser sensor:
int reading = digitalRead(gateSensorPin);
// If the switch changed, due to noise or pressing:
if (reading != lastgateSensorState) {
// reset the debouncing timer
lastDebounceTime = millis();
} //end if
// if passes the debounce time
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != gateSensorState) {
gateSensorState = reading;
// If we went low, this mean the beam was broken
if (gateSensorState == LOW) {
// save the millis so all the math on it will be done with the same value.
savedMillis = millis();
// if its not the first lap
if (currentLap > 0) {
// save the last run
lastRunInMillis = savedMillis - currentRunStartMillis;
// if last run is faster then best run
if (lastRunInMillis < bestRunInMillis || bestRunInMillis == 0) {
//save as best
bestRunInMillis = lastRunInMillis;
} //end if
} //end if
//reset the current
currentRunStartMillis = savedMillis;
// move lap counter
currentLap++;
} //end if
} //end if
} //end if
lastgateSensorState = reading;
// save current milis
savedMillis = millis();
// if we start the first lap
if (currentLap > 0) {
calcResultFromMillis(savedMillis - currentRunStartMillis, &min_val, &sec_val, &milli_val);
} else {
calcResultFromMillis(0, &min_val, &sec_val, &milli_val);
} //end if
tft.setCursor(20, 0, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.setTextSize(3);
// We can now plot text on screen using the "print" class
tft.println("CURRENT LAP");
tft.fillRect(10, 50, 440, 60, TFT_BLACK);
tft.setCursor(50, 40, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.setTextSize(5);
// We can now plot text on screen using the "print" class
if (min_val < 10) {
tft.print('0');
}
tft.println(min_val);
tft.setCursor(132, 40, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setTextSize(5);
// We can now plot text on screen using the "print" class
tft.println(':');
tft.setCursor(150, 40, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.setTextSize(5);
if (sec_val < 10) {
tft.print('0');
}
tft.println(sec_val);
tft.setCursor(232, 40, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setTextSize(5);
// We can now plot text on screen using the "print" class
tft.println(':');
tft.setCursor(250, 40, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.setTextSize(5);
if (milli_val < 1) {
tft.print('0');
}
tft.println(milli_val);
tft.setCursor(20, 110, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.setTextSize(3);
// We can now plot text on screen using the "print" class
tft.println("LAST");
calcResultFromMillis(lastRunInMillis, &min_val, &sec_val, &milli_val);
tft.fillRect(50, 160, 400, 60, TFT_BLACK);
tft.setCursor(50, 150, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.setTextSize(5);
// We can now plot text on screen using the "print" class
if (min_val < 10) {
tft.print('0');
}
tft.println(min_val);
tft.setCursor(132, 150, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setTextSize(5);
// We can now plot text on screen using the "print" class
tft.println(':');
tft.setCursor(150, 150, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.setTextSize(5);
if (sec_val < 10) {
tft.print('0');
}
tft.println(sec_val);
tft.setCursor(232, 150, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setTextSize(5);
// We can now plot text on screen using the "print" class
tft.println(':');
tft.setCursor(250, 150, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.setTextSize(5);
if (milli_val < 1) {
tft.print('0');
}
tft.println(milli_val);
tft.setCursor(20, 220, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setTextSize(3);
// We can now plot text on screen using the "print" class
tft.println("BEST");
calcResultFromMillis(bestRunInMillis, &min_val, &sec_val, &milli_val);
tft.fillRect(50, 265, 400, 50, TFT_BLACK);
tft.setCursor(50, 250, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE);
tft.setTextSize(5);
// We can now plot text on screen using the "print" class
if (min_val < 10) {
tft.print('0');
}
tft.println(min_val);
tft.setCursor(132, 250, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setTextSize(5);
// We can now plot text on screen using the "print" class
tft.println(':');
tft.setCursor(150, 250, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.setTextSize(5);
if (sec_val < 10) {
tft.print('0');
}
tft.println(sec_val);
tft.setCursor(232, 250, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setTextSize(5);
// We can now plot text on screen using the "print" class
tft.println(':');
tft.setCursor(250, 250, 2);
// Set the font colour to be white with a black background, set text size multiplier to 1
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.setTextSize(5);
if (milli_val < 1) {
tft.print('0');
}
tft.println(milli_val);
delay(1);
}
// calculate millis into 2 values, seconeds and millis for display
void calcResultFromMillis(unsigned long value, int *min_val, int *sec_val, int *milli_val) {
*min_val = int(value / 60000);
*sec_val = int(value / 1000);
*milli_val = value - *sec_val * 1000;
*sec_val = *sec_val % 60;
*min_val = *min_val % 60;
}