Collin Wentzien
Published © GPL3+

Easy and Affordable Track Timing System

An affordable and automatic system letting athletes time themselves or their peers quickly and easily.

IntermediateShowcase (no instructions)6,525
Easy and Affordable Track Timing System

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Arduino Nano R3
Arduino Nano R3
×1
SparkFun Transceiver Breakout - nRF24L01+ (RP-SMA)
SparkFun Transceiver Breakout - nRF24L01+ (RP-SMA)
×2
TFmini-s LIDAR Sensor
×1
1.3" OLED Screen
×1
Speaker: 3W, 4 ohms
Speaker: 3W, 4 ohms
×1
General Purpose Dual Op-Amp
Texas Instruments General Purpose Dual Op-Amp
×1
Tactile Switch, Top Actuated
Tactile Switch, Top Actuated
×3
Rocker Switch, Non Illuminated
Rocker Switch, Non Illuminated
×2
5 mm LED: Red
5 mm LED: Red
×2
9V battery (generic)
9V battery (generic)
×1
9V Battery Clip
9V Battery Clip
×1
Machine Screw, M2
Machine Screw, M2
×10

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)
Hot glue gun (generic)
Hot glue gun (generic)
Multitool, Screwdriver
Multitool, Screwdriver

Story

Read more

Custom parts and enclosures

Start Module Base

Start Module Top

Battery Holder for Start Line Module

Slightly different than the battery holder for the finish module due to a CAD error on my part.

Finish Module Base

Finish Module Top

Battery Holder for Finish Line Module

Slightly different than the battery holder for the start module due to a CAD error on my part.

Schematics

Start Module Schematic

Finish Module Schematic

Code

Start Module

Arduino
#include <EEPROM.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
#include <Fonts/nunitoTiny.h>
#include <Fonts/makoSmall.h>

#define OLED_CLK   2
#define OLED_MOSI  3
#define OLED_RESET 4
#define OLED_DC    5
#define OLED_CS    6

Adafruit_SH1106 tft(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

RF24 radio(7, 8);
const byte addr[6] = "00001";

int up, down, select;
int pressed = -1;

int app = 0;
int mode = 0;
int menu = 0;

int m1 = 0; int m2 = 0; int s1 = 0; int s2 = 0; int s = 0;
int mm1 = 0; int mm2 = 0; int ss1 = 0; int ss2 = 0; int ss = 0;
boolean tme = false;
boolean done = false;
int times = 0;
int amt = 0;

unsigned long curr;
unsigned long prev;
int interval = 92;
int last;

// ----- BITMAPS ----- //
const unsigned char sprint[] PROGMEM = {
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x7f, 0xfe, 
  0x00, 0x00, 
  0x01, 0x40, 
  0x02, 0xc0, 
  0x00, 0x00, 
  0x7f, 0xfe, 
  0x00, 0x00, 
  0x3c, 0x00, 
  0x20, 0x00, 
  0x00, 0x00, 
  0x7f, 0xfe, 
  0x00, 0x00, 
  0x00, 0x00
};

const unsigned char lap[] PROGMEM = {
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x0f, 0xf0, 
  0x3f, 0xfc, 
  0x38, 0x1c, 
  0x70, 0x0e, 
  0x60, 0x06, 
  0x60, 0x06, 
  0x70, 0x0e, 
  0x38, 0x1c, 
  0x3f, 0xfc, 
  0x0f, 0xf0, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00
};

const unsigned char count[] PROGMEM = {
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x7f, 0xfe, 
  0x6f, 0xb6, 
  0x55, 0x2a, 
  0x57, 0xba, 
  0x55, 0xb6, 
  0x6f, 0xa2, 
  0x7f, 0xfe, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00
};

static const unsigned char PROGMEM settings[] = {
  0x00, 0x00, 
  0x01, 0x80, 
  0x01, 0x80, 
  0x19, 0x98, 
  0x1d, 0xb8, 
  0x0f, 0xf0, 
  0x07, 0xe0, 
  0x7e, 0x7e, 
  0x7e, 0x7e, 
  0x07, 0xe0, 
  0x0f, 0xf0, 
  0x1d, 0xb8, 
  0x19, 0x98, 
  0x01, 0x80, 
  0x01, 0x80, 
  0x00, 0x00
};

static const unsigned char PROGMEM autos[] = {
  0x00, 0x00, 
  0x03, 0xc0, 
  0x01, 0x80, 
  0x03, 0xc0, 
  0x0d, 0x30, 
  0x10, 0x28, 
  0x10, 0x48, 
  0x20, 0x44, 
  0x21, 0x8c, 
  0x31, 0x84, 
  0x20, 0x04, 
  0x10, 0x08, 
  0x10, 0x08, 
  0x0c, 0xb0, 
  0x03, 0xc0, 
  0x00, 0x00
};

static const unsigned char PROGMEM manual[] = {
  0x00, 0x00, 
  0x00, 0x00, 
  0x03, 0xc0, 
  0x0c, 0x30, 
  0x10, 0x08, 
  0x10, 0x08, 
  0x26, 0x64, 
  0x28, 0x94, 
  0x2a, 0x94, 
  0x26, 0x64, 
  0x10, 0x08, 
  0x10, 0x08, 
  0x0c, 0x30, 
  0x03, 0xc0, 
  0x00, 0x00, 
  0x00, 0x00
};

static const unsigned char PROGMEM back[] = {
  0x00, 0x00, 
  0x00, 0x00, 
  0x08, 0x00, 
  0x18, 0x00, 
  0x3f, 0xe0, 
  0x3f, 0xf8, 
  0x18, 0x38, 
  0x08, 0x1c, 
  0x00, 0x1c, 
  0x00, 0x38, 
  0x0f, 0xf8, 
  0x0f, 0xe0, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00
};

static const unsigned char PROGMEM dist[] = {
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x7f, 0xfe, 
  0x7f, 0xfe, 
  0x6f, 0xbe, 
  0x6d, 0xb6, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00
};

static const unsigned char PROGMEM sound[] = {
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x20, 
  0x02, 0x10, 
  0x06, 0x88, 
  0x1e, 0x48, 
  0x1e, 0x48, 
  0x06, 0x88, 
  0x02, 0x10, 
  0x00, 0x20, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00
};

static const unsigned char PROGMEM nosound[] = {
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x80, 
  0x01, 0x80, 
  0x07, 0x80, 
  0x07, 0x80, 
  0x01, 0x80, 
  0x00, 0x80, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00
};

static const unsigned char PROGMEM racecal[] = {
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x7f, 0xfe, 
  0x00, 0x00, 
  0x51, 0xc0, 
  0x2a, 0x20, 
  0x50, 0x40, 
  0x28, 0x80, 
  0x50, 0x00, 
  0x28, 0x80, 
  0x00, 0x00, 
  0x7f, 0xfe, 
  0x00, 0x00, 
  0x00, 0x00, 
  0x00, 0x00
};

void setup() {
  Serial.begin(115200);

  pinMode(14, INPUT);
  pinMode(15, INPUT);
  pinMode(16, INPUT);
  pinMode(9, INPUT);
  
  tft.begin(SH1106_SWITCHCAPVCC);
  
  radio.begin();
  radio.openReadingPipe(0, addr);
  radio.setPALevel(RF24_PA_MIN);
  radio.startListening();
  radio.flush_rx();

  tft.clearDisplay();
  tft.setTextColor(WHITE);

  int x, y;
  int16_t x1, y1;
  uint16_t w, h;
  tft.setFont(&nunitoTiny);
  tft.getTextBounds("Welcome", x, y, &x1, &y1, &w, &h);
  tft.setCursor(63 - (w / 2), 37);
  tft.print("Welcome");
  
  tft.display();

  int bar = 0;
  while(bar < 128) {
    tft.fillRect(0, 61, bar, 4, WHITE);
    bar = bar + random(1, 6);
    delay(random(4, 8));
    tft.display();
  }

  tft.fillRect(0, 61, 128, 4, BLACK);
  tft.display();
  
  if(EEPROM.read(0) > 2) {
    EEPROM.write(0, 0);
  }
  
  if(EEPROM.read(1) > 10) {
    EEPROM.write(1, 5);
  }

  if(EEPROM.read(0) == 0) {
    tone(9, 440, 100);
    delay(100);
    tone(9, 659, 100);
    delay(100);
  }
  
  noTone(9);

  delay(800);

  app = 0;
  menu = 0;
  drawApp(app);
  drawMenu(app, menu);
}

void drawApp(int appl) {
  tft.clearDisplay();
  
  if(appl == 0) {
    tme = false;
    tft.setFont(&makoSmall);
  
    tft.setCursor(46, 18);
    tft.print("Sprint");
  
    tft.setCursor(46, 29);
    tft.print("Lap");
  
    tft.setCursor(46, 40);
    tft.print("Counter");
    
    tft.setCursor(46, 51);
    tft.print("Settings");
    
  } else if(appl == 1) {
    tft.setFont(&makoSmall);
    
    tft.setCursor(46, 20);
    tft.print("Automatic");
  
    tft.setCursor(46, 36);
    tft.print("Manual");
  
    tft.setCursor(46, 52);
    tft.print("Back");
    
  } else if(appl == 2) {
    tft.setFont(&makoSmall);
    tft.setCursor(3, 8);
    tft.print("Sprint");

    tft.drawLine(3, 49, 123, 49, WHITE);

    tft.drawLine(88, 54, 91, 57, WHITE);
    tft.drawLine(91, 57, 88, 60, WHITE);
    tft.setCursor(100, 60);
    tft.print("Back");
    
    tft.setFont(&nunitoTiny);
    tft.setCursor(3, 28);
    m1 = 0; m2 = 0; s1 = 0; s2 = 0; s = 0;
    tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));
    
    tft.display();

    tme = true;

    delay(100);
    
    if(EEPROM.read(0) == 0) {
      tone(9, 523, 150);
      delay(random(1800, 3500));
      tone(9, 523, 150);
      delay(random(2300, 4100));
      tone(9, 1047, 300);
    }
    
  } else if(appl == 3) {
    tft.setFont(&makoSmall);
    tft.setCursor(3, 8);
    tft.print("Sprint");

    tft.drawLine(3, 49, 123, 49, WHITE);

    tft.setCursor(15, 60);
    tft.print("Start");
    tft.setCursor(100, 60);
    tft.print("Back");
    
    tft.setFont(&nunitoTiny);
    tft.setCursor(3, 28);
    m1 = 0; m2 = 0; s1 = 0; s2 = 0; s = 0;
    tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));
    
  } else if(appl == 4) {
    tft.setFont(&makoSmall);
    tft.setCursor(3, 8);
    tft.print("Lap");

    tft.drawLine(3, 49, 123, 49, WHITE);
    tft.drawLine(74, 3, 74, 46, WHITE);

    tft.drawLine(88, 54, 91, 57, WHITE);
    tft.drawLine(91, 57, 88, 60, WHITE);
    tft.setCursor(100, 60);
    tft.print("Back");
    
    tft.setFont(&nunitoTiny);
    tft.setCursor(3, 28);
    m1 = 0; m2 = 0; s1 = 0; s2 = 0; s = 0;
    tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));

    tft.display();

    tme = true;
    times = 0;

    delay(100);
    if(EEPROM.read(0) == 0) {
      tone(9, 523, 150);
      delay(random(1800, 3500));
      tone(9, 523, 150);
      delay(random(2300, 4100));
      tone(9, 1047, 300);
    }
    
  } else if(appl == 5) {
    tft.setFont(&makoSmall);
    tft.setCursor(3, 8);
    tft.print("Lap");

    tft.drawLine(3, 49, 123, 49, WHITE);
    tft.drawLine(74, 3, 74, 46, WHITE);

    tft.drawLine(88, 54, 91, 57, WHITE);
    tft.drawLine(91, 57, 88, 60, WHITE);
    tft.setCursor(100, 60);
    tft.print("Back");
    tft.setCursor(3, 36);
    tft.print("Sel to Start");
    
    tft.setFont(&nunitoTiny);
    tft.setCursor(3, 28);
    m1 = 0; m2 = 0; s1 = 0; s2 = 0; s = 0;
    tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));

    tft.display();

    tme = false;
    done = false;
    times = 0;
    
  } else if(appl == 6) {
    tft.setFont(&makoSmall);
    tft.setCursor(3, 8);
    tft.print("Current");
    tft.setCursor(3, 40);
    tft.print("Last");
    int x, y;
    int16_t x1, y1;
    uint16_t w, h;
    tft.getTextBounds("Lane", x, y, &x1, &y1, &w, &h);
    tft.setCursor(124 - w, 8);
    tft.print("Lane");
    tft.getTextBounds("Num", x, y, &x1, &y1, &w, &h);
    tft.setCursor(124 - w, 40);
    tft.print("Num");
    
    tft.setFont(&nunitoTiny);
    tft.setCursor(3, 26);
    m1 = 0; m2 = 0; s1 = 0; s2 = 0; s = 0;

    tft.setCursor(3, 58);
    tft.print("No Data");

    tft.setCursor(116, 26);
    tft.print(EEPROM.read(1));

    tft.getTextBounds("0", x, y, &x1, &y1, &w, &h);
    tft.setCursor(124 - w, 58);
    tft.print("0");

    tft.display();

    tme = false;
    done = false;
    amt = 0;
    
  } else if(appl == 8) {
    tme = false;
    tft.setFont(&makoSmall);
  
    tft.setCursor(46, 18);
    tft.print("Distance");
  
    tft.setCursor(46, 29);
    tft.print("Sound");
  
    tft.setCursor(46, 40);
    tft.print("Lane Calib");
    
    tft.setCursor(46, 51);
    tft.print("Back");
    
  } else if(appl == 9) {
    tme = false;
    tft.setFont(&makoSmall);
    tft.setCursor(7, 25);
    tft.print("Select Lane");

    tft.drawLine(88, 54, 91, 57, WHITE);
    tft.drawLine(91, 57, 88, 60, WHITE);
    tft.setCursor(100, 60);
    tft.print("Back");

    tft.setFont(&nunitoTiny);
    tft.setCursor(7, 45);
    tft.print(EEPROM.read(1));
  }
  
  tft.display();
}

void drawMenu(int app, int item) {
  if(app == 0) {
    tft.fillRect(0, 0, 43, 64, BLACK);
    tft.drawLine(33, 0, 33, 63, WHITE);
  
    if(item == 0) {
      tft.drawLine(33, 12, 33, 18, BLACK);
      tft.drawLine(33, 11, 37, 15, WHITE);
      tft.drawLine(37, 15, 33, 19, WHITE);
      tft.drawBitmap(8, 24, sprint, 16, 16, WHITE);
  
    } else if(item == 1) {
      tft.drawLine(33, 23, 33, 29, BLACK);
      tft.drawLine(33, 22, 37, 26, WHITE);
      tft.drawLine(37, 26, 33, 30, WHITE);
      tft.drawBitmap(8, 24, lap, 16, 16, WHITE);
  
    } else if(item == 2) {
      tft.drawLine(33, 34, 33, 40, BLACK);
      tft.drawLine(33, 33, 37, 37, WHITE);
      tft.drawLine(37, 37, 33, 41, WHITE);
      tft.drawBitmap(8, 24, count, 16, 16, WHITE);
  
    } else if(item == 3) {
      tft.drawLine(33, 45, 33, 51, BLACK);
      tft.drawLine(33, 44, 37, 48, WHITE);
      tft.drawLine(37, 48, 33, 52, WHITE);
      tft.drawBitmap(8, 24, settings, 16, 16, WHITE);
    }
    
  } else if(app == 1) {
    tft.fillRect(0, 0, 43, 64, BLACK);
    tft.drawLine(33, 0, 33, 63, WHITE);
  
    if(item == 0) {
      tft.drawLine(33, 13, 33, 19, BLACK);
      tft.drawLine(33, 12, 37, 16, WHITE);
      tft.drawLine(37, 16, 33, 20, WHITE);
      tft.drawBitmap(8, 24, autos, 16, 16, WHITE);
  
    } else if(item == 1) {
      tft.drawLine(33, 29, 33, 35, BLACK);
      tft.drawLine(33, 28, 37, 32, WHITE);
      tft.drawLine(37, 32, 33, 36, WHITE);
      tft.drawBitmap(8, 24, manual, 16, 16, WHITE);
  
    } else if(item == 2) {
      tft.drawLine(33, 45, 33, 51, BLACK);
      tft.drawLine(33, 44, 37, 48, WHITE);
      tft.drawLine(37, 48, 33, 52, WHITE);
      tft.drawBitmap(8, 24, back, 16, 16, WHITE);
    }
    
  } else if(app == 3) {
    if(item == 0) {
      tft.fillRect(87, 53, 7, 10, BLACK);
      tft.drawLine(3, 54, 6, 57, WHITE);
      tft.drawLine(6, 57, 3, 60, WHITE);
      
    } else if(item == 1) {
      tft.fillRect(0, 53, 7, 10, BLACK);
      tft.drawLine(88, 54, 91, 57, WHITE);
      tft.drawLine(91, 57, 88, 60, WHITE);
    }
    
  } else if(app == 5) {
    if(item == 0) {
      tft.fillRect(87, 53, 7, 10, BLACK);
      tft.drawLine(3, 54, 6, 57, WHITE);
      tft.drawLine(6, 57, 3, 60, WHITE);
      
    } else if(item == 1) {
      tft.fillRect(0, 53, 7, 10, BLACK);
      tft.drawLine(88, 54, 91, 57, WHITE);
      tft.drawLine(91, 57, 88, 60, WHITE);
    }
    
  } else if(app == 7) {
    if(item == 0) {
      tft.fillRect(87, 53, 7, 10, BLACK);
      tft.drawLine(3, 54, 6, 57, WHITE);
      tft.drawLine(6, 57, 3, 60, WHITE);
      
    } else if(item == 1) {
      tft.fillRect(0, 53, 7, 10, BLACK);
      tft.drawLine(88, 54, 91, 57, WHITE);
      tft.drawLine(91, 57, 88, 60, WHITE);
    }
    
  } else if(app == 8) {
    tft.fillRect(0, 0, 43, 64, BLACK);
    tft.drawLine(33, 0, 33, 63, WHITE);
  
    if(item == 0) {
      tft.drawLine(33, 12, 33, 18, BLACK);
      tft.drawLine(33, 11, 37, 15, WHITE);
      tft.drawLine(37, 15, 33, 19, WHITE);
      tft.drawBitmap(8, 24, dist, 16, 16, WHITE);
  
    } else if(item == 1) {
      tft.drawLine(33, 23, 33, 29, BLACK);
      tft.drawLine(33, 22, 37, 26, WHITE);
      tft.drawLine(37, 26, 33, 30, WHITE);
      if(EEPROM.read(0) == 0) {
        tft.drawBitmap(8, 24, sound, 16, 16, WHITE);
      } else {
        tft.drawBitmap(8, 24, nosound, 16, 16, WHITE);
      }
  
    } else if(item == 2) {
      tft.drawLine(33, 34, 33, 40, BLACK);
      tft.drawLine(33, 33, 37, 37, WHITE);
      tft.drawLine(37, 37, 33, 41, WHITE);
      tft.drawBitmap(8, 24, racecal, 16, 16, WHITE);
  
    } else if(item == 3) {
      tft.drawLine(33, 45, 33, 51, BLACK);
      tft.drawLine(33, 44, 37, 48, WHITE);
      tft.drawLine(37, 48, 33, 52, WHITE);
      tft.drawBitmap(8, 24, back, 16, 16, WHITE);
    }
    
  }
  
  tft.display();
}

void events(int button) {
  if(app == 0) {
    if(button == 0) {
      if(menu != 0) {
        menu = menu - 1;
        drawMenu(app, menu);
      }
    } else if(button == 1) {
      if(menu != 3) {
        menu++;
        drawMenu(app, menu);
      }
    } else if(button == 2) {
      if(menu == 0) {
        app = 1;
        mode = 0;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
        
      } else if(menu == 1) {
        app = 1;
        mode = 1;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
        
      } else if(menu == 2) {
        app = 6;
        drawApp(app);
        
      } else if(menu == 3) {
        app = 8;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
      }
    }
    
  } else if(app == 1) {
    if(button == 0) {
      if(menu != 0) {
        menu = menu - 1;
        drawMenu(app, menu);
      }
      
    } else if(button == 1) {
      if(menu != 2) {
        menu++;
        drawMenu(app, menu);
      }
      
    } else if(button == 2) {
      if(menu == 0) {
        if(mode == 0) {
          app = 2;
          menu = 0;
          radio.flush_rx();
          drawApp(app);
          drawMenu(app, menu);
          
        } else if(mode == 1) {
          app = 4;
          menu = 0;
          radio.flush_rx();
          drawApp(app);
          drawMenu(app, menu);
          
        } else if(mode == 2) {
          app = 6;
          menu = 0;
          radio.flush_rx();
          drawApp(app);
          drawMenu(app, menu);
        }
        
      } else if(menu == 1) {
        if(mode == 0) {
          app = 3;
          menu = 0;
          drawApp(app);
          drawMenu(app, menu);
          
        } else if(mode == 1) {
          app = 5;
          menu = 0;
          drawApp(app);
          drawMenu(app, menu);
          
        } else if(mode == 2) {
          app = 7;
          menu = 0;
          drawApp(app);
          drawMenu(app, menu);
        }
        
      } else if(menu == 2) {
        app = 0;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
      }
    }
    
  } else if(app == 2) {
    if(button == 2) {
      app = 0;
      menu = 0;
      drawApp(app);
      drawMenu(app, menu);
    }
    
  } else if(app == 3) {
    if(button == 0) {
      if(menu == 0)
        menu = 1;
      else
        menu = 0;
      drawMenu(app, menu);
      
    } else if(button == 1) {
      if(menu == 0)
        menu = 1;
      else
        menu = 0;
      drawMenu(app, menu);
      
    } else if(button == 2) {
      if(menu == 0) {
        delay(100);
        if(EEPROM.read(0) == 0) {
          tone(9, 1047, 300);
        }
        
        tme = true;
        
      } else if(menu == 1) {
        app = 0;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
      }
    }
    
  } else if(app == 4) {
    if(button == 2) {
      app = 0;
      menu = 0;
      drawApp(app);
      drawMenu(app, menu);
    }
    
  } else if(app == 5) {
    if(button == 0) {

      
    } else if(button == 1) {
      if(done == false) {
        app = 0;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
      }
      
    } else if(button == 2) {
      if(done == false) {
        delay(100);
        if(EEPROM.read(0) == 0) {
          tone(9, 523, 150);
          delay(random(1800, 3500));
          tone(9, 523, 150);
          delay(random(2300, 4100));
          tone(9, 1047, 300);
        }
        
        tme = true;
        
      } else if(menu == 1) {
        app = 0;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
      }
    }
    
  } else if(app == 6) {
    if(button == 2) {
      if(done == false) {
        delay(100);
        if(EEPROM.read(0) == 0) {
          tone(9, 1047, 300);
        }
        
        tme = true;
        done = true;
        
      } else if(done == true) {
        app = 0;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
      }
    }
    
  } else if(app == 7) {
    if(button == 0) {

      
    } else if(button == 1) {
      if(done == false) {
        app = 0;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
      }
      
    } else if(button == 2) {
      if(done == false) {
        delay(100);
        if(EEPROM.read(0) == 0) {
          tone(9, 523, 150);
          delay(random(1800, 3500));
          tone(9, 523, 150);
          delay(random(2300, 4100));
          tone(9, 1047, 300);
        }
        
        tme = true;
        
      } else if(menu == 1) {
        app = 0;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
      }
    }
    
  } else if(app == 8) {
    if(button == 0) {
      if(menu != 0) {
        menu = menu - 1;
        drawMenu(app, menu);
      }
    } else if(button == 1) {
      if(menu != 3) {
        menu++;
        drawMenu(app, menu);
      }
    } else if(button == 2) {
      if(menu == 0) {
        app = 9;
        drawApp(9);
        
      } else if(menu == 1) {
        if(EEPROM.read(0) == 0) {
          EEPROM.write(0, 1);
          tft.fillRect(8, 24, 16, 16, BLACK);
          tft.drawBitmap(8, 24, nosound, 16, 16, WHITE);
        } else {
          EEPROM.write(0, 0);
          tft.fillRect(8, 24, 16, 16, BLACK);
          tft.drawBitmap(8, 24, sound, 16, 16, WHITE);
        }

        tft.display();
        
      } else if(menu == 2) {
        
      } else if(menu == 3) {
        app = 0;
        menu = 0;
        drawApp(app);
        drawMenu(app, menu);
      }
    }
    
  } else if(app == 9) {
    if(button == 0) {
      if(EEPROM.read(1) != 8) {
        EEPROM.write(1, EEPROM.read(1) + 1);
        tft.fillRect(6, 32, 20, 20, BLACK);
        tft.setFont(&nunitoTiny);
        tft.setCursor(7, 45);
        tft.print(EEPROM.read(1));
        tft.display();
      }
    } else if(button == 1) {
      if(EEPROM.read(1) != 1) {
        EEPROM.write(1, EEPROM.read(1) - 1);
        tft.fillRect(6, 32, 20, 20, BLACK);
        tft.setFont(&nunitoTiny);
        tft.setCursor(7, 45);
        tft.print(EEPROM.read(1));
        tft.display();
      }      
    } else if(button == 2) {
      app = 8;
      menu = 0;
      drawApp(app);
      drawMenu(app, menu);
    }
    
  }
}

void getTime() {
  if(s == 9) {
    s = 0;
    s2++;
    
    if(s2 > 9) {
      s2 = 0;
      s1++;
      
      if(s1 > 5) {
        s1 = 0;
        m2++;
        
        if(m2 > 9) {
          m2 = 0;
          m1++;
          
          if(m1 > 9) {
            m1 = 0;
          }
        }
      }
    }
  } else {
    s++;
  }
}

boolean hasData() {
  if(radio.available()) {
    int distance;
    radio.read(&distance, sizeof(distance));
    
    if(distance < (EEPROM.read(1) * 100)) {
      return true;
    }
  }
  
  return false;
}

void loop() {
  up = digitalRead(16);
  down = digitalRead(15);
  select = digitalRead(14);
  
  if(up == HIGH && pressed == -1) {
    pressed = 0;
    events(0);
    
  } else if(down == HIGH && pressed == -1) {
    pressed = 1;
    events(1);
    
  } else if(select == HIGH && pressed == -1) {
    pressed = 2;
    events(2);
  }
  
  if(up == LOW) {
    if(pressed == 0)
      pressed = -1;
  }

  if(down == LOW) {
    if(pressed == 1)
      pressed = -1;
  }

  if(select == LOW) {
    if(pressed == 2)
      pressed = -1;
  }

  if(app == 2) {
    if(hasData()) {
      int text;
      radio.read(&text, sizeof(text));
      tme = false;
    } else {
      curr = millis();
    }
  
    if(curr - prev >= interval && tme == true) {
      prev = curr;
      getTime();
      delay(10);
    }
  
    tft.fillRect(0, 16, 72, 13, BLACK);
    tft.setFont(&nunitoTiny);
    tft.setCursor(3, 28);
    tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));
  
    tft.display();
    
  } else if(app == 3) {
    if(hasData()) {
      int text;
      radio.read(&text, sizeof(text));
      tme = false;
      
    } else {
      if(tme == true)
        curr = millis();
    }
  
    if(curr - prev >= interval && tme == true) {
      prev = curr;
      getTime();
      delay(10);
    }
  
    tft.fillRect(0, 16, 72, 13, BLACK);
    tft.setFont(&nunitoTiny);
    tft.setCursor(3, 28);
    tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));
  
    tft.display();
    
  } else if(app == 4) {
    if(hasData() && last > 10) {
      int text;
      radio.read(&text, sizeof(text));
      
      if(times < 4) {
        tft.setFont(&makoSmall);
        tft.setCursor(84, 12 + (times * 10));
        tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));
        mm1 = m1; mm2 = m2; ss1 = s1; ss2 = s2; ss = s;
        times++;
        last = 0;
        curr = millis();

        if(times == 4) {
          tme = false;
        }
      }
      
    } else if(hasData()) {
      int text;
      radio.read(&text, sizeof(text));
      curr = millis();
      
    } else {
      curr = millis();
    }
  
    if(curr - prev >= interval && tme == true) {
      prev = curr;
      getTime();
      last++;
    }
  
    tft.fillRect(0, 16, 72, 13, BLACK);
    tft.setFont(&nunitoTiny);
    tft.setCursor(3, 28);
    tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));
  
    tft.display();
    
  } else if(app == 6) {
    if(hasData() && last >= 5) {
      int text;
      radio.read(&text, sizeof(text));
    
      tft.setFont(&nunitoTiny);
      tft.fillRect(0, 46, 128, 13, BLACK);
      tft.setCursor(3, 58);
      tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));
      mm1 = m1; mm2 = m2; ss1 = s1; ss2 = s2; ss = s;
      last = 0;
      curr = millis();
      amt++;

      int x, y;
      int16_t x1, y1;
      uint16_t w, h;
      tft.getTextBounds(String(amt), x, y, &x1, &y1, &w, &h);
      tft.setCursor(124 - w, 58);
      tft.print(String(amt));

      //Serial.println("Runner " + String(amt) + ": " + String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));
      
    } else if(hasData()) {
      int text;
      radio.read(&text, sizeof(text));
      curr = millis();
      
    } else {
      curr = millis();
    }
  
    if(curr - prev >= interval && tme == true) {
      prev = curr;
      getTime();
      last++;
      delay(10);
    }
  
    tft.fillRect(0, 14, 72, 13, BLACK);
    tft.setFont(&nunitoTiny);
    tft.setCursor(3, 26);
    tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));
  
    tft.display();
  }
}

Finish Module

Arduino
#include <DFRobot_TFmini.h>
#include <nRF24L01.h>
#include <RF24.h>

SoftwareSerial mySerial(4, 5);
RF24 radio(7, 8);

DFRobot_TFmini TFmini;
uint16_t distance;
const byte addr[6] = "00001";

void setup(){
  Serial.begin(115200);
  
  TFmini.begin(mySerial);
  
  radio.begin();
  radio.openWritingPipe(addr);
  radio.setPALevel(RF24_PA_MIN);
  radio.stopListening();
  
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);

  delay(500);

  digitalWrite(3, HIGH);
}

void loop(){
  if(TFmini.measure()){
    distance = TFmini.getDistance();

    if(distance < 20000 && distance > 0) {
      Serial.println(distance);
      radio.write(&distance, sizeof(distance));
    }
  }
}

Credits

Collin Wentzien

Collin Wentzien

1 project • 13 followers
Hello! My name is Collin Wentzien, and I am a high school student who enjoys electrical and mechanical engineering.

Comments