Accurate elapsed time calculation

This is more a "What's the best way to do this" than a "my code doesn't work" question. I made a bike speedometer last year with a Nano Every, a GPS module and a 3.5" TFT display. For the most part I'm happy with it, it shows, latitude, longitude, a compass display and I can log the route I took and download that onto Google Maps. It also has the distance traveled and elapsed time of the ride, Neither one of those are very accurate and that is what I would like some help with. Both of those use a 1 second loop update using millis().

I'm going to change the distance traveled using a Ebike sensor that detects a magnet on the wheel. Looks like a hall effect sensor so that should be fairly straight forward. The time has got me stumped.

I've tried a couple of different ways of using gps.time.second() from the TinyGPS++ library I'm using. There's problems when the seconds resets back to "0" I've tried a few ways but obviously none are working well or I wouldn't be asking. I was think I could make a accurate 1 second pulse from the GPS time and just count the pulses but have the same basic problems. I could use a RTC but currently everything is mounted on a PCB board I had made and wanted to see if I could use what I have before adding more hardware, which I will if that's the best way.

So that's the question, how do I get a accurate elapsed time?

I've included the code I currently have.

Thanks for any help and suggestions.
John

/*
  Changed to Nano Every
  with Adafruit 3.5 TFT display
  Rev 2 Added touch, made 2 pages for displaing info
        No logging function
  Rev 6 added compass by G6EJD - David
*/

// Include required libraries
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_GFX.h>         // Core graphics library
#include <Adafruit_HX8357.h>      // Hardware-specific library
#include "TouchScreen.h"


// GPS Connections
static const int RXPin = 6, TXPin = 7;

// GPS Baud rate (change if required)
static const uint32_t GPSBaud = 9600;

// SD Card Select pin
const int chipSelect = 5;

// Write LED
const int recLED = 8;

// String to hold GPS data
String gpstext;

// GPS write delay counter variables
// Change gpsttlcount as required
int gpscount = 0;
int gpsttlcount = 70;
int fileMade = 0; // check to see if a new file was made on SD card

// TinyGPS++ object
TinyGPSPlus gps;

// SoftwareSerial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);

// display
#define TFT_CS   10
#define TFT_DC   9
Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC);

// These are the four touchscreen analog pins
#define YP A2  // must be an analog pin, use "An" notation!
#define XM A3  // must be an analog pin, use "An" notation!
#define YM 3   // can be a digital pin
#define XP 4   // can be a digital pin

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 110
#define TS_MINY 80
#define TS_MAXX 900
#define TS_MAXY 940

#define MINPRESSURE 10
#define MAXPRESSURE 1000

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

// Color definitions
#define BLACK    0x0000
#define BLUE     0x001F
#define RED      0xF800
#define GREEN    0x07E0
#define CYAN     0x07FF
#define MAGENTA  0xF81F
#define YELLOW   0xFFE0 
#define WHITE    0xFFFF

bool newData = false;
float log_Dist = 0.0;
unsigned long int scan_time = millis();
int currentPage = 1;
int SD_Status = 0;
int GPS_Status = 0;
float Heading = 0.0;
String RideTime = "";
int RideHr = 0;
int RideMin = 0;
int RideSec = 0;
int StartHr = 0;
int StartMin = 0;
int StartSec = 0;
int readStartTime = 0;
char RideTm[80];
int TestTm = 0;

// Compass
float Bearing;
const int centreX  = 160; // Location of the compass display on screen
const int centreY  = 280;
const int diameter = 70; // Size of the compass
int  dx = centreX, dy = centreY;
int  last_dx = centreX, last_dy = centreY - diameter * 0.85;


// the logging file
File logfile;
char logFileName[20] = " "; // current log file name
int errorNumb = 0; // system error number to display message
int RunLogger = 0; // run logging file
int LogPBOld = 0;
int LogPBNew = 0;
File dataFile;
long int lastLogTime = 0; // last time log sample was read
int logDelay = 10000; // time delay between log samples

void setup()
{

    // Set all chip selects high to avoid bus contention during initialisation of each peripheral
 // digitalWrite(21, HIGH); // Touch controller chip select (if used)
  digitalWrite(10, HIGH); // TFT screen chip select
  digitalWrite( 5, HIGH); // SD card chips select, must use GPIO 5 (ESP32 SS)
  
  // Set LED pin as output
  pinMode(recLED, OUTPUT);

  // Start Serial Monitor for debugging
  Serial.begin(115200);

  // Start SoftwareSerial
  ss.begin(GPSBaud);

  // start display driver
  tft.begin();          // Initialize screen
  //tft.fillScreen(BLACK); //clears screen, sets to Black
  tft.setRotation(0);  // rotates screen 90' for landscape mode
 
// load Speedometer page
  tft.fillScreen(BLACK); //clears screen, sets to Black
  SpeedometerPage();

  // Initialize SD card
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    //don't do anything more:
    tft.fillCircle(30, 30, 10, RED);
     while (1);
  }
  Serial.println("card initialized.");

  // Blink LED so we know we are ready
  //digitalWrite(recLED, HIGH);
  tft.fillCircle(30, 30, 10, BLACK);
  delay(500);
  //digitalWrite(recLED, LOW);
  tft.fillCircle(30, 30, 10, GREEN);
  delay(500);
  //digitalWrite(recLED, HIGH);
  tft.fillCircle(30, 30, 10, BLACK);
  delay(500);
  //digitalWrite(recLED, LOW);
  tft.fillCircle(30, 30, 10, GREEN);
  delay(500);
  //digitalWrite(recLED, HIGH);
  tft.fillCircle(30, 30, 10, BLACK);
  delay(500);
  //digitalWrite(recLED, LOW);
  tft.fillCircle(30, 30, 10, GREEN);
 
scan_time = millis(); // reset scan time

} // end setup

void loop()
{
  // Turn off LED
  digitalWrite(recLED, LOW);
  
  // Retrieve a point on touch screen
  TSPoint p = ts.getPoint();
  // See if GPS data available
  while (ss.available() > 0)
    if (gps.encode(ss.read()))

 // If we press the Speedometer Button 
  if ((p.x>=130) && (p.x<=290) && (p.y>=810) && (p.y<=890)) {
    currentPage = 1; // Indicates that we are the first example
    tft.fillScreen(BLACK); //clears screen, sets to Black
    Serial.println("Speed pressed");
    SpeedometerPage(); // It is called only once, because in the next iteration of the loop, this above if statement will be false so this funtion won't be called. This function will draw the graphics of the first example.
  
  } // end if for Speedometer button pressed


// If we press the GPS Info Button 
  if ((p.x>=420) && (p.x<=600) && (p.y>=810) && (p.y<=890)) {
    currentPage = 2;
    tft.fillScreen(BLACK); //clears screen, sets to Black
    Serial.println("GPS Pressed");
    GPS_Info_Page();
  } // end if for GPS Info page  

// Start/Stop logging file with Log PB
if ((p.x>=725) && (p.x<=890) && (p.y>=810) && (p.y<=890)) {
  RunLogger = !RunLogger;  // toggle RunLogger
  
  delay(500);
  } // end RunLogger = !RunLogger

// Data logger control PB

if(RunLogger == 0 && LogPBOld == 1){
  tft.fillRoundRect(240, 410, 70, 50, 10, RED);
  tft.setCursor(257, 427);
  tft.setTextColor(WHITE, RED);
  tft.setTextSize(2);
  tft.print("LOG");
  LogPBOld = 0;
  fileMade = 0;
} // end RunLogger == 0

else if(RunLogger == 1 && LogPBOld == 0){
  tft.fillRoundRect(240, 410, 70, 50, 10, GREEN);
  tft.setCursor(257, 427);
  tft.setTextColor(BLACK, GREEN);
  tft.setTextSize(2);
  tft.print("LOG");
  LogPBOld = 1;
} // end else if

// call logger function
if(RunLogger == 1){
  // logger();
  } // end if RunLogger == 1
    else {
      logfile.close();
      fileMade = 0;
    } // end else


// Update variables

// display GPS status
//if(GPS_Status == 1){
  if(gps.location.isValid()){
    tft.fillCircle(290, 30, 10, GREEN);
}
//if(GPS_Status == 0) {
  if(!gps.location.isValid()){
    tft.fillCircle(290, 30, 10, RED);
}

newData = true;
     
  if (((millis() - scan_time) > 1000)) { // Update every second

   //if (gps.location.isValid())
    if(newData == true)
  {
      newData = false;

      // ride start time
      if(readStartTime == 0){
      StartHr = gps.time.hour();
      StartMin = gps.time.minute();
      StartSec = gps.time.second();
      readStartTime = 1;
      } // end if(readStartTime == 0)

  } // if(newdata == true)
  else
  {
      Serial.println(F("INVALID"));
    } // end else

  // Update screen variables

if(currentPage == 1){
    tft.setCursor(50, 120);
    tft.setTextColor(WHITE, BLACK);
    tft.setTextSize(6);
    tft.print(gps.speed.mph(), 1);

  Bearing = gps.course.deg();
  Display_Compass(Bearing); // show compass
  
} // end if current page =1

if(currentPage == 2){
   tft.setCursor(50, 110);
   tft.setTextColor(WHITE, BLACK);
   tft.setTextSize(4);
   tft.print(gps.location.lng(), 4);

// Display Latitude
    tft.setCursor(50, 190);
    tft.setTextColor(WHITE, BLACK);
    tft.setTextSize(4);
    tft.print(gps.location.lat(), 4);  

// Display log_Dist
    tft.setCursor(50, 270);
    tft.setTextColor(WHITE, BLACK);
    tft.setTextSize(4);
    tft.print(log_Dist, 1);

// Display Ride Time
    tft.setCursor(50, 350);
    tft.setTextColor(WHITE, BLACK);
    tft.setTextSize(4);
    sprintf(RideTm, "%02d:%02d:%02d", RideHr, RideMin, RideSec);
    tft.print(RideTm);
    
} // end if current page = 2

  if(millis() > 5000 && gps.charsProcessed() > 10){
    GPS_Status = 1;
  }
  if (millis() > 5000 && gps.charsProcessed() < 10)
  {
      Serial.println(F("No GPS detected: check wiring."));
      GPS_Status = 0;
    //while(true);
  }

   
   // calculate ride time
if(RunLogger == 1){
    RideSec = (RideSec + 1);
     
   if(RideHr  >= 24){
    RideHr = 0;
   }
   if(RideMin >= 60){
    RideMin = 0;
    RideHr = (RideHr + 1);
   }
   if(RideSec >= 60){
    RideSec = 0;
    RideMin = (RideMin + 1);
   }

    // calculate log_Dist
   if(gps.speed.mph() > 0.5){
    log_Dist = log_Dist+(gps.speed.mph()/3600); 

   } // end if(GPS.speed.mph() > 0.5)
} // end if(RunLogger == 1)

  if(RunLogger == 0){
    log_Dist = 0; //clear log distance 
    RideHr = 0; // clear log hours
    RideMin = 0; // clear log minutes
    RideSec = 0; // clear log seconds
  } // end if(RunLogger == 0)

  scan_time = millis(); // reset scan time
  
  } // end (((millis() - scan_time) > 1000)
  
// Run GPS Logger
if(RunLogger == 1){

  // Turn off LED
  digitalWrite(recLED, LOW);

// *************  Dronebot GPS logging code   **************
 
  // See if data available
  
  while (ss.available() > 0)    
    if (gps.encode(ss.read()))
    
  // See if we have a complete GPS data string
      if (displayInfo() != "0")
      {

        // Check GPS Count
       // Serial.println(gpscount);
        if (gpscount == gpsttlcount) {

          // LED On to indicate data to write to SD card
          digitalWrite(recLED, HIGH);

     // create a new data logging file
    if(RunLogger == 1 && fileMade == 0){
        Serial.println("Create file");
        char filename[] = "File00.CSV";
        for (uint8_t i = 0; i < 100; i++) {
          filename[4] = i / 10 + '0';
          filename[5] = i % 10 + '0';
          
          if (! SD.exists(filename)) {
            // strcpy(logFileName, filename);
            // only open a new file if it doesn't exist
            dataFile = SD.open(filename, FILE_WRITE);
            Serial.println(filename);
            strcpy(logFileName, filename);
            fileMade = 1;
            break;  // leave the loop!
          } // end if (! SD.exist)
        } // end for (uint8_t i = 0; i < 100; i++)
    } // end if RunLogger == 1 && fileMade == 0
   
      //Open the file on card for writing
       dataFile = SD.open(logFileName, FILE_WRITE);
       Serial.println(logFileName);
      //File dataFile = SD.open("gpslog.csv", FILE_WRITE);

   // Get GPS string
        gpstext = displayInfo();
  
          if (dataFile) {

            // If the file is available, write to it and close the file
            dataFile.println(gpstext);
            dataFile.close();

            // Serial print GPS string for debugging
            Serial.println(gpstext);
          }
          // If the file isn't open print an error message for debugging
          else {
            Serial.println("error opening datalog.txt");
          }

        }
        // Increment GPS Count
        gpscount = gpscount + 1;
        if (gpscount > gpsttlcount) {
          gpscount = 0;
        }

      } // end if (displayInfo() != "0")


} // end run logger

  
} // end loop()

void SpeedometerPage(){

 // Prints the title on the screen
  tft.setCursor(65, 20);
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.print("Speedometer"); 
  tft.drawFastHLine(10, 60, 320, RED);

// Display SS Initialized status
  tft.fillCircle(30, 30, 10, GREEN);
   
// Display Speed
    tft.setCursor(50, 90); 
    tft.setTextColor(WHITE);
    tft.setTextSize(2);
    tft.print("Speed"); 
 
   
// Draw buttons
// fillRoundRect(X, Y, width, height, radius, color);
// Speedometer page select PB
  tft.fillRoundRect(10, 410, 70, 50, 10, BLUE);
  tft.setCursor(16, 427);
  tft.setTextColor(WHITE, BLUE);
  tft.setTextSize(2);
  tft.print("Speed");

// GPS Info Page select PB
  tft.fillRoundRect(126, 410, 70, 50, 10, MAGENTA);
  tft.setCursor(143, 427);
  tft.setTextColor(BLACK, MAGENTA);
  tft.setTextSize(2);
  tft.print("GPS");

// Data logger control PB
if(RunLogger == 0){
  tft.fillRoundRect(240, 410, 70, 50, 10, RED);
  tft.setCursor(257, 427);
  tft.setTextColor(WHITE, RED);
  tft.setTextSize(2);
  tft.print("LOG");
} // end RunLogger == 0

else if(RunLogger == 1){
  tft.fillRoundRect(240, 410, 70, 50, 10, GREEN);
  tft.setCursor(257, 427);
  tft.setTextColor(BLACK, GREEN);
  tft.setTextSize(2);
  tft.print("LOG");
} // end else if

} // end Speedometer page

void GPS_Info_Page(){

// Prints the title on the screen
  tft.setCursor(90, 20);
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.print("GPS Info"); 
  tft.drawFastHLine(10, 60, 320, RED);

// Display SS Initialized status
  tft.fillCircle(30, 30, 10, GREEN);
     
// Display Longitude
    tft.setCursor(50, 80); 
    tft.setTextColor(WHITE);
    tft.setTextSize(2);
    tft.print("Longitude"); 
  
// Display Latitude
    tft.setCursor(50, 160); 
    tft.setTextColor(WHITE);
    tft.setTextSize(2);
    tft.print("Latitude"); 

// Display Distance
    tft.setCursor(50, 240); 
    tft.setTextColor(WHITE);
    tft.setTextSize(2);
    tft.print("Distance"); 
  
// Display Time
    tft.setCursor(50, 320); 
    tft.setTextColor(WHITE);
    tft.setTextSize(2);
    tft.print("Time"); 
 
    

// Draw buttons
// fillRoundRect(X, Y, width, height, radius, color);
// Speedometer page select PB
  tft.fillRoundRect(10, 410, 70, 50, 10, BLUE);
  tft.setCursor(16, 427);
  tft.setTextColor(WHITE, BLUE);
  tft.setTextSize(2);
  tft.print("Speed");

// GPS Info Page select PB
  tft.fillRoundRect(126, 410, 70, 50, 10, MAGENTA);
  tft.setCursor(143, 427);
  tft.setTextColor(BLACK, MAGENTA);
  tft.setTextSize(2);
  tft.print("GPS");

// Data logger control PB
if(RunLogger == 0){
  tft.fillRoundRect(240, 410, 70, 50, 10, RED);
  tft.setCursor(257, 427);
  tft.setTextColor(WHITE, RED);
  tft.setTextSize(2);
  tft.print("LOG");
} // end RunLogger == 0

else if(RunLogger == 1){
  tft.fillRoundRect(240, 410, 70, 50, 10, GREEN);
  tft.setCursor(257, 427);
  tft.setTextColor(BLACK, GREEN);
  tft.setTextSize(2);
  tft.print("LOG");
} // end else if

  
} // End GPS_Info_Page

// Function to return GPS string
String displayInfo()
{
  // Define empty string to hold output
  String gpsdata = "";

  // Get latitude and longitude
  if (gps.location.isValid())
  {
    gpsdata = String(gps.location.lat(), 6);
    gpsdata += (",");
    gpsdata += String(gps.location.lng(), 6);
    gpsdata += (",");
  }
  else
  {
    return "0";
  }

  // Get Date
  if (gps.date.isValid())
  {
    gpsdata += String(gps.date.year());
    gpsdata += ("-");
    if (gps.date.month() < 10) gpsdata += ("0");
    gpsdata += String(gps.date.month());
    gpsdata += ("-");
    if (gps.date.day() < 10) gpsdata += ("0");
    gpsdata += String(gps.date.day());
   // gpsdata += (",");
  }
  else
  {
    return "0";
  }

  // Space between date and time
  gpsdata += (",");

  // Get time
  if (gps.time.isValid())
  {
    if (gps.time.hour() < 10) gpsdata += ("0");
    gpsdata += String(gps.time.hour() - 4);
    gpsdata += (":");
    if (gps.time.minute() < 10) gpsdata += ("0");
    gpsdata += String(gps.time.minute());
    gpsdata += (":");
    if (gps.time.second() < 10) gpsdata += ("0");
    gpsdata += String(gps.time.second());
  }
  else
  {
    return "0";
  }

  // Return completed string
  return gpsdata;
} // end String displayInfo()

//#####################################################################
void Display_Compass(float dBearing) {
  int dxo, dyo, dxi, dyi;
  tft.setCursor(0, 0);
  tft.drawCircle(centreX, centreY, diameter, WHITE); // Draw compass circle
  for (float i = 0; i < 360; i = i + 22.5) {
    dxo = diameter * cos((i - 90) * 3.14 / 180);
    dyo = diameter * sin((i - 90) * 3.14 / 180);
    dxi = dxo * 0.9;
    dyi = dyo * 0.9;
    tft.drawLine(dxo + centreX, dyo + centreY, dxi + centreX, dyi + centreY, WHITE);
  }
  PrintText((centreX - 5), (centreY - diameter - 18), "N", WHITE, 2);
  PrintText((centreX - 5), (centreY + diameter + 5) , "S", WHITE, 2);
  PrintText((centreX + diameter + 5),  (centreY - 5), "E", WHITE, 2);
  PrintText((centreX - diameter - 15), (centreY - 5), "W", WHITE, 2);
  dx = (0.85 * diameter * cos((dBearing - 90) * 3.14 / 180)) + centreX; // calculate X position
  dy = (0.85 * diameter * sin((dBearing - 90) * 3.14 / 180)) + centreY; // calculate Y position
  draw_arrow(last_dx, last_dy, centreX, centreY, 5, 5, BLACK);   // Erase last arrow
  draw_arrow(dx, dy, centreX, centreY, 5, 5, WHITE);           // Draw arrow in new position
  last_dx = dx;
  last_dy = dy;

  // display compass azimuthal points
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.fillRect(230, 355, 60, 22, BLACK);
  tft.setCursor(230, 355);
  tft.print(Bearing_to_Ordinal(Bearing));
  
}// end Display_Compass;

//#####################################################################
void PrintText(int x, int y, String text, int colour, byte text_size) {
  tft.setCursor(x, y);
  tft.setTextColor(colour);
  tft.setTextSize(text_size);
  tft.print(text);
  tft.setTextColor(YELLOW); // Default colour
  tft.setTextSize(2);       // Default Text Size
} // end Printtext

//#####################################################################
void draw_arrow(int x2, int y2, int x1, int y1, int alength, int awidth, int colour) {
  float distance;
  int dx, dy, x2o, y2o, x3, y3, x4, y4, k;
  distance = sqrt(pow((x1 - x2), 2) + pow((y1 - y2), 2));
  dx = x2 + (x1 - x2) * alength / distance;
  dy = y2 + (y1 - y2) * alength / distance;
  k = awidth / alength;
  x2o = x2 - dx;
  y2o = dy - y2;
  x3 = y2o * k + dx;
  y3 = x2o * k + dy;
  x4 = dx - y2o * k;
  y4 = dy - x2o * k;
  tft.drawLine(x1, y1, x2, y2, colour);
  tft.drawLine(x1, y1, dx, dy, colour);
  tft.drawLine(x3, y3, x4, y4, colour);
  tft.drawLine(x3, y3, x2, y2, colour);
  tft.drawLine(x2, y2, x4, y4, colour);
} // end draw_arrow

//#####################################################################
String Bearing_to_Ordinal(float bearing) {
  if (bearing >= 348.75 || bearing < 11.25)  return "N  ";
  if (bearing >=  11.25 && bearing < 33.75)  return "NNE";
  if (bearing >=  33.75 && bearing < 56.25)  return "NE ";
  if (bearing >=  56.25 && bearing < 78.75)  return "ENE";
  if (bearing >=  78.75 && bearing < 101.25) return "E  ";
  if (bearing >= 101.25 && bearing < 123.75) return "ESE";
  if (bearing >= 123.75 && bearing < 146.25) return "SE ";
  if (bearing >= 146.25 && bearing < 168.75) return "SSE";
  if (bearing >= 168.75 && bearing < 191.25) return "S  ";
  if (bearing >= 191.25 && bearing < 213.75) return "SSW";
  if (bearing >= 213.75 && bearing < 236.25) return "SW ";
  if (bearing >= 236.25 && bearing < 258.75) return "WSW";
  if (bearing >= 258.75 && bearing < 281.25) return "W  ";
  if (bearing >= 281.25 && bearing < 303.75) return "WNW";
  if (bearing >= 303.75 && bearing < 326.25) return "NW ";
  if (bearing >= 326.25 && bearing < 348.75) return "NNW";
  return "?";
} // end Bearing_to_Ordinal

Just use millis() directly.

unsigned long StartTime;

void loop()
{
  // When it is time to start the ride:
  StartTime = millis();

  // Any time you want elapsed seconds:
  unsigned long elapsedSeconds = (millis() - StartTime) / 1000;
}

Thanks @johnwasser I'll give that a try

How accurately do you need to know the bicycle's speed? Using GPS PPS implies that you desire to know the difference between, say, 11.00000 kph and 11.000001 kph.

Are you that precise on the pedals? :slight_smile:

Also for a speedometer, latency is an issue. If you want to read miles per hour, you don't want to accumulate miles and then calculate miles/hour once every hour. You want to examine the interval that it takes to travel a much smaller distance, and then calculate speed using V = d/t.

If you do that, your trip statistics will be more accurate too because the measurement interval begin/ends won't be truncated.

@anon57585045 I'm not doing time trials or anything like that so it doesn't have to be right on. Actually the speed seemed to be OK, I really don't have anything thing to compare it with. What was off mainly was the total time and distance I went. For a 1 to 2 hour ride it would be off by 15 minutes or so and a couple of miles. Again it's not a big deal for what I'm doing but if you're going to do something it should be right and there is no reason I couldn't get it better. This is more of a coding challenge than I need to know my time.

@johnwasser the elapsed time method you showed me is working great. I manipulated the elapsed seconds to get minutes and hours and after 5 hours of running I'm only off by around 20 seconds. Which is fine, I don't do 5 hour rides and as mentioned it's not for time trials.

Thanks both for your comments

I doubt that. To me, it looks more like you have a design challenge. You need to find the correct mathematical model and then flesh that out into a design, which you can then code.

But, if you have a solution, that's fine for now.

If you are getting lat/lon data from GPS, aren't you already reading the serial data from the GPS module? Doesn't that stream also give you the exact time? Why can't TinyGPS++ tell you the time? No experience with this myself, but it seems that should work.

1 Like

@ShermanP I do get the time from the GPS, very accurate time, the problem was trying to capture a starting time and calculate the time of the ride. For a basic example if I start the ride at 20 seconds into the minute, I then subtracted the start seconds from the current seconds. When a new minute starts the seconds goes back to zero, I had accumulated 40 seconds I'm now subtracting 40 seconds from 0 and get negative seconds. I'm sure there's way to keep track of that and some if/then/else statements, reset this when, which I tried, but it seemed to me that it was getting more complicated than it need to be, so I asked for suggestions on the forum and got a very simple method that is working well.

Thanks

Why is that a problem? You've also got the minutes and hours, use them to calculate total seconds. That's not going to back to zero, unless you're riding through the night.

Time interval calculations are much easier in integer seconds. Use seconds after midnight, or Epoch time to simplify the comparisons.

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