Help with displaying times accurate to the 1/100th

Hi,

I'm hoping someone can help me out. I'm currently building a Track timing system that some has originally been created here

The timing system works fine. However, the code only allows the timer to display results to 1/10th of second. I would like the timer to display to 1/100th of second which will make the results more accurate, especially for sprinting.

So for example, if the timer displayed 11.5 as a result I would like it to display 11.57

I have no experience in coding and looking through the code I don't know what to amend. I've attached some sections of the code that looks like it has something to do with the timing part. Any help would be grateful.

 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;
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(&FreeSans9pt7b);
    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(&FreeSans9pt7b);
    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(&Mako_Regular6pt7b);
        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(&FreeSans9pt7b);
    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(&FreeSans9pt7b);
      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(&FreeSans9pt7b);
    tft.setCursor(3, 26);
    tft.print(String(m1) + String(m2) + ":" + String(s1) + String(s2) + "." + String(s));
  
    tft.display();
  }
}

Please post ALL the code. It is much easier for someone to help if they have the complete sketch.

You will have to find out from the author why interval is set to 92. interval provides the timing and is close to 100ms which would give the 0.1 second accuracy.

So basically every 100ms getTime() is called which increments the time in 0.1 seconds (variable s) and adjusts the other time variables (seconds, 10 seconds, minutes and 10 minutes).

To get more digits (I'm not sure if it will give a higher accuracy), you will need to divide interval by 10 so getTime() is called evevry 10 milliseconds, add a variable to hold the 0.0x seconds and modify getTime() to use that variable. You probably will also have to get rid of the delay(10).

I'm not sure if you want to see it. But here it is

#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();
  }
}
1 Like

It seems the interval value is how often the display will be updated, which is 92 millis. I presume it is set to 92 to take into account that updating the display takes time, but this is a bad way of doing it, as there will be skipped or unprecise updates.

Now, doing 1/100's of seconds, you probably don't need too precise updates, as long as the end result is correct, because our eyes will not easily detect if the timing of display updates are a bit off, with the last digit racing.

Improved implementation

A better implementation would calculate when the display should have been last updated, then update it, and store that value, comparing only to elapsed time, to decide when to next time update the display.

I took the liberty of writing a bit of code for how I would implement the measurements. It has not been tested, as obviously it is incomplete. It's just a better way of ensuring as timely updates of the display, as possible, at least if the time it takes to update the screen is shorter than 1/100'th of a second.

Alternatively you could update the screen every 1/10'th of a second while the timer is running, and when the clock is stopped, extend it to hundreds.

#define UPDATE_INTERVAL_MS			10


unsigned long startTime=0L;
unsigned long endTime=0L;

bool measuringIsActive=false;  // if true, timer is running
bool measurementComplete=false;  // if true, endTime and startTime are frozen 



void processKeypresses() {
	if ( startButtionPressed() ) { 
		startTime=millis();
		measuringIsActive=true;
	} else if ( stopButtonPressed() ) { 
		endTime=millis();
		measuringActive=false;
		measurementComplete=true;
		showElapsedTime (endTime-startTime);
	}
	 :
	 :
}

void showElapsedTime (unsigned long elapsed) {
	unsigned long h=elapsed/10; // time in 1/100's of seconds
	unsigned long s=h/100;
	h=h%100;
	
	int m=s/60;
	s=s%60;
	
	// now got m=minutes, s=seconds, h=hundreds, to display
	...
}


unsigned long lastDisplayUpdateTime=0L;


void loop () {
	 :
	 :
	processKeyPresses();
	 :
	 :
	 
	if (measuringIsActive) {
		unsigned long now=millis();
		unsigned long elapsed=now-startTime;
		
		// reduce elapsed to closest past 1/100'th of a second or whatever, defined by
		// UPDATE_INTERVAL_MS - this is the most recent time when the display 
		// should have been updated
		 
		unsigned long lastExpectedUpdate=elapsed - (elapsed % UPDATE_INTERVAL_MS); 

		// if display wasn't updated at lastExpectedUpdate time, then do so and update
		// global variable lastDisplayUpdateTime 
		
		if (lastExpectedUpdate > lastDisplayUpdateTime) {
			showElapsedTime (elapsed);
			lastDisplayUpdateTime=lastExpectedUpdate; 
		}
	}
}

1 Like

Thank you very much for your response and posting the full code. I've tried contacting the author. Unfortunately, there been been no response.

Thanks for your advise. In terms of coding, I have no idea how to implement this. However, you have given me something to work with.

Thank you for your input and providing some code. What you explained is exactually what i'm hoping to achieve. If possible can you advise where to place the code you kindly created in the sketch. I'm assuming it will replace some of the original code.

The main thing is when the timer stops the result is displayed to 1/100th. When the timer is running it can update as what it is doing now in the original code.

You most certainly do not want to update a LCD display any more often than 10 times per second in any case. :roll_eyes:

The original screen update is fine as it it. I just want the final result to display the time to 1/100th after the athlete crosses the line. So I'm only interested in the accuracy of final result after the timer has been stopped.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.