XIAO ESP32C3 Multiple Software Serial Ports

LOL, I don’t have anything connected, just checking the ports working
It’s polling the Device.
:v:

What GPS slab are you using, I’ll dig out my Air530 and start with that too, I have a "L76K GNSS " in the package too, so I can try it.
So two GPS units one Xiao that’s the GAme?

Ah’ I see… So red LED’s are a NO -Go right , Green on SAT lock ?
or what?
One is in the wrong plug.

Well… the current project is to read GPS data and echo it to the Nextion Display… but both devices what hardware serial connection

this study has resulted in the understanding that software serial does not work on ESP

Ok, Actually it does, but the implimintation is Nuanced…
i.e. only works a certain way on ESP that works on other either way, Go figure.

STart with the Hardware Serial , method assign the 9 & 10 pin & plugg the last grove wire into one.
Then use the software serial and pins 6 & 7 and two connectors over.
LMK
:v:

You can’t use those last two groves together as uarts
Unless you flip the pins on the first one

USE— > J6 and J8

1 Like

on this gps the red blinks when it is transmitting once per second… but yes, the gps goes not get a good lock when unplugged or inside… but it will communicate the time… and even if it has not even locked the time yet… it will send a checksum that changes… thats why I was using the fullexample sketch

Roger that. I see so both are send a clock…data byte on their respective serial ports.

yes good catch… I tried every port to make sure they all would work with SAMD… I just didnt remove it

Pull J7 and see what you get any ?

I found some stuff ,so I’m going to have a sangwhich and Libation(s) and BRB , I’ll hook up what I have to a c3. :v:
BRB

must be something wrong with the C3 or My C3 because i just ran the S3 and got something working

LOL, I just got it going with the C3 , LOL
and the Air530 on 9 & 10, :slight_smile:
5 sats and counting…

HTH
Gl :slight_smile: PJ :v:

atellites: 5  Latitude: 26.042034  Longitude: -80.220633
Satellites: 5  Latitude: 26.042032  Longitude: -80.220634
Satellites: 5  Latitude: 26.042029  Longitude: -80.220636
Satellites: 5  Latitude: 26.042027  Longitude: -80.220637
Satellites: 5  Latitude: 26.042023  Longitude: -80.220639
Satellites: 5  Latitude: 26.042016  Longitude: -80.220645
Satellites: 5  Latitude: 26.042012  Longitude: -80.220647
Satellites: 5  Latitude: 26.042009  Longitude: -80.220648
Satellites: 5  Latitude: 26.042005  Longitude: -80.220649
Satellites: 5  Latitude: 26.042002  Longitude: -80.220649
Satellites: 5  Latitude: 26.041998  Longitude: -80.220651
Satellites: 5  Latitude: 26.041995  Longitude: -80.220652
Satellites: 5  Latitude: 26.041991  Longitude: -80.220653
Satellites: 5  Latitude: 26.041989  Longitude: -80.220653
Satellites: 5  Latitude: 26.041985  Longitude: -80.220654
Satellites: 5  Latitude: 26.041980  Longitude: -80.220

1 Like

thanks for the proof!

No worries,
Pins 9 & 10 with Hardware serial… Like a BOSS!
straight Grove cable. J8 is the Money! :money_mouth_face:

we have 6 from the Lab Window…

Satellites: 6  Latitude: 26.041696  Longitude: -80.220917
Satellites: 6  Latitude: 26.041696  Longitude: -80.220917
Satellites: 6  Latitude: 26.041696  Longitude: -80.220916
Satellites: 6  Latitude: 26.041697  Longitude: -80.220916
Satellites: 6  Latitude: 26.041704  Longitude: -80.220914
Satellites: 6  Latitude: 26.041712  Longitude: -80.220912
Satellites: 6  Latitude: 26.041721  Longitude: -80.220909
Satellites: 6  Latitude: 26.041729  Longitude: -80.220907
Satellites: 6  Latitude: 26.041729  Longitude: -80.220907
Satellites: 6  Latitude: 26.041728  Longitude: -80.220906
Satelli

up to 8 right NOW :v:

Ok , went to the other code added hardware serial , going , good, adding 2nd gps now…

   1.7   26.041622  -80.220879  176  02/23/2025 02:07:14 176  26.50  284.30 1.00  WNW   7108     43.06  NE    3045  10        0        
6    1.7   26.041618  -80.220879  179  02/23/2025 02:07:15 179  26.60  284.30 1.26  WNW   7108     43.06  NE    3654  12        0        
6    1.7   26.041613  -80.220886  181  02/23/2025 02:07:16 181  26.60  284.30 1.20  WNW   7108     43.06  NE    4263  14        0        
6    1.7   26.041611  -80.220894  193  02/23/2025 02:07:17 193  26.70  284.30 0.00  WNW   7108     43.06  NE    4872  16        0        
6    1.7   26.041607  -80.220901  200  02/23/2025 02:07:18 200  26.70  284.30 0.00  WNW   7108     43.06  NE    5481  18        0        
6    1.7   26.041603  -80.220909  205  02/23/2025 02:07:19 205  26.70  284.30 0.00  WNW   7108     43.06  NE    6090  20        0        
6    1.7   26.041601  -80.220917  209  02/23/2025 02:07:20 209  26.80  284.30 0.00  WNW   7108     43.06  NE    6699  22        0        
6    1.7   26.041603  -80.220909  219  02/23/2025 02:07:21 219  26.80  284.30 0.00  WNW   7108     43.06  NE    7308  24        0        
6    1.7   26.041605  -80.220901  214  02/23/2025 02:07:22 214  26.80  284.30 2.78  WNW   7108     43.06  NE    7917  26        0        
6    1.7   26.041605  -80.220894  220  02/23/2025 02:07:23 220  26.80  284.30 2.83  WNW   7108     43.06  NE    8526  28        0        
6    1.7   26.041605  -80.220886  220  02/23/2025 02:07:24 220  26.70  284.30 2.83  WNW   7108     43.06  NE    9135  30        0        
6    1.7   26.041605  -80.220879  218  02/23/2025 02:07:25 218  26.60  284.30 2.87  WNW   7108     43.06  NE    9744  32        0        
5    15.8  26.041605  -80.220871  216  02/23/2025 02:07:26 216  26.50  284.30 2.89  WNW   7108     43.06  NE    10358 34        0        
5    15.6  26.041603  -80.220871  219  02/23/2025 02:07:27 219  26.40  284.30 1.20  WNW   7108     43.06  NE    10972 36        0        
5    15.5  26.041603  -80.220879  227  02/23/2025 02:07:28 227  26.20  284

I got one hardware going on S3

one of the gps is acting up… i dont know if the cmos battery is dead or what

Hi there,

I got them Both going on the C3, edited the example to add a column for which GPS is sending data , based on Age as Priority GPS-1 or GPS-2

10   1.0   26.041754  -80.220909  267  02/23/2025 10:34:16 769  5.50   0.00   0.00  N     7108     43.06  NE    16160 490       1           GPS 2
10   1.0   26.041754  -80.220909  268  02/23/2025 10:34:17 768  5.50   0.00   0.00  N     7108     43.06  NE    16227 492       1           GPS 2
10   1.0   26.041754  -80.220909  275  02/23/2025 10:34:18 774  5.50   0.00   0.00  N     7108     43.06  NE    16293 494       1           GPS 2
10   1.0   26.041754  -80.220909  276  02/23/2025 10:34:19 776  5.50   0.00   0.00  N     7108     43.06  NE    16360 496       1           GPS 2
10   1.0   26.041754  -80.220909  283  02/23/2025 10:34:20 782  5.50   0.00   0.00  N     7108     43.06  NE    16426 498       1           GPS 2
10   1.0   26.041754  -80.220909  284  02/23/2025 10:34:21 785  5.50   0.00   0.00  N     7108     43.06  NE    16493 500       1           GPS 2
10   1.0   26.041754  -80.220909  289  02/23/2025 10:34:22 790  5.50   0.00   0.00  N     7108     43.06  NE    16559 502       1           GPS 2
7    1.3   26.041683  -80.220894  290  02/23/2025 10:34:23 835  27.80  150.56 0.52  SSE   7108     43.06  NE    14595 321       1           GPS 1
10   1.0   26.041754  -80.220909  296  02/23/2025 10:34:24 796  5.50   0.00   0.00  N     7108     43.06  NE    16692 506       1           GPS 2
10   1.0   26.041754  -80.220909  297  02/23/2025 10:34:25 797  5.50   0.00   0.00  N     7108     43.06  NE    16758 508       1           GPS 2
10   1.0   26.041754  -80.220909  299  02/23/2025 10:34:26 803  5.50   0.00   0.00  N     7108     43.06  NE    16825 510       1           GPS 2
10   1.0   26.041754  -80.220909  299  02/23/2025 10:34:27 800  5.50   0.00   0.00  N     7108     43.06  NE    16891 512       1           GPS 2
10   1.0   26.041754  -80.220909  311  02/23/2025 10:34:28 805  5.40   0.00   0.00  N     7108     43.06  NE    16958 514       1           GPS 2
10   1.0   26.041754  -80.220909  312  02/23/2025 10:34:29 813  5.40   0.00   0.00  N     7108     43.06  NE    17024 516       1           GPS 2
10   1.0   26.041754  -80.220909  317  02/23/2025 10:34:30 818  5.40   0.00   0.00  N     7108     43.06  NE    17091 518       1           GPS 2
7    1.3   26.041712  -80.220924  318  02/23/2025 10:34:31 870  27.70  150.56 0.00  SSE   7108     43.06  NE    15098 337       1           GPS 1
7    1.3   26.041712  -80.22092

Scroll over to the Right most edge…

Hardware Serial on one port and Software Serial on the other. You can swap them too. AFAIK.

#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>
#include <HardwareSerial.h>

// ------------------ GPS Configurations ------------------
// For GPS 1 (HardwareSerial on UART1)
const int gps1RXPin = 9; // Connect GPS1 TX to ESP32 RX (pin 7)
const int gps1TXPin = 10; // Connect GPS1 RX to ESP32 TX (pin 6)
const uint32_t gps1Baud = 9600;

// For GPS 2 (SoftwareSerial)
const int gps2RXPin = D7; // Connect GPS2 TX to ESP32 RX (pin 9)
const int gps2TXPin = D6; // Connect GPS2 RX to ESP32 TX (pin 10)
const uint32_t gps2Baud = 9600;

// ------------------ Objects ------------------
TinyGPSPlus gps1; // For HardwareSerial GPS
TinyGPSPlus gps2; // For SoftwareSerial GPS

// Use UART1 for GPS 1:
HardwareSerial SerialGPS1(1);
// Use SoftwareSerial for GPS 2:
SoftwareSerial SerialGPS2(gps2RXPin, gps2TXPin); // (RX, TX)

// ------------------ Function Prototypes ------------------
static void smartDelay(unsigned long ms);
static void printFloat(float val, bool valid, int len, int prec);
static void printInt(unsigned long val, bool valid, int len);
static void printDateTime(TinyGPSDate &d, TinyGPSTime &t);
static void printStr(const char *str, int len);
static void printGPSSource();

void setup() {
  Serial.begin(9600);
  delay(2000);
  Serial.println("\nFullExample.ino");
  Serial.println("An extensive example of many interesting TinyGPSPlus features");
  Serial.print("Testing TinyGPSPlus library v. "); 
  Serial.println(TinyGPSPlus::libraryVersion());
  Serial.println("by Mikal Hart, tweaked for 2 GPS by PJG");
  Serial.println();
  Serial.println("Sats HDOP  Latitude   Longitude   Fix  Date       Time     Date Alt    Course Speed Card  Distance Course Card  Chars Sentences Checksum   GPS");
  Serial.println("           (deg)      (deg)       Age                      Age  (m)    --- from GPS ----  ---- to London  ----  RX    RX        Fail");
  Serial.println("----------------------------------------------------------------------------------------------------------------------------------------");
  
  // Initialize GPS 1 (HardwareSerial) on UART1 with assigned pins.
  SerialGPS1.begin(gps1Baud, SERIAL_8N1, gps1RXPin, gps1TXPin);
  Serial.println("GPS-1 HardwareSerial initialized on pins 6 (RX) and 7 (TX).");
  
  // Initialize GPS 2 (SoftwareSerial) on pins 9 & 10.
  SerialGPS2.begin(gps2Baud);
  Serial.println("GPS-2 SoftwareSerial initialized on pins 9 (RX) and 10 (TX).");
  Serial.println();
}

void loop() {
  // Process incoming GPS data for both GPS units.
  // For GPS1 via HardwareSerial:
  while (SerialGPS1.available() > 0) {
    char c = SerialGPS1.read();
    gps1.encode(c);
  }
  // For GPS2 via SoftwareSerial:
  while (SerialGPS2.available() > 0) {
    char c = SerialGPS2.read();
    gps2.encode(c);
  }
  
  // Define a reference location (London in this example).
  static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
  
  // We'll decide which GPS to display.
  // Priority: If one has valid location and the other doesn't, choose the valid one.
  // If both are valid, choose the one with a lower "age" (i.e. more recent fix).
  bool valid1 = gps1.location.isValid();
  bool valid2 = gps2.location.isValid();
  TinyGPSPlus *activeGps = nullptr;
  if(valid1 && !valid2) {
    activeGps = &gps1;
  } else if(valid2 && !valid1) {
    activeGps = &gps2;
  } else if(valid1 && valid2) {
    activeGps = (gps1.location.age() <= gps2.location.age()) ? &gps1 : &gps2;
  } else {
    activeGps = &gps1; // default to gps1 if none valid
  }
  
  // Print output using the active GPS data:
  printInt(activeGps->satellites.value(), activeGps->satellites.isValid(), 5);
  printFloat(activeGps->hdop.hdop(), activeGps->hdop.isValid(), 6, 1);
  printFloat(activeGps->location.lat(), activeGps->location.isValid(), 11, 6);
  printFloat(activeGps->location.lng(), activeGps->location.isValid(), 12, 6);
  printInt(activeGps->location.age(), activeGps->location.isValid(), 5);
  printDateTime(activeGps->date, activeGps->time);
  printFloat(activeGps->altitude.meters(), activeGps->altitude.isValid(), 7, 2);
  printFloat(activeGps->course.deg(), activeGps->course.isValid(), 7, 2);
  printFloat(activeGps->speed.kmph(), activeGps->speed.isValid(), 6, 2);
  printStr(activeGps->course.isValid() ? TinyGPSPlus::cardinal(activeGps->course.deg()) : "*** ", 6);
  
  unsigned long distanceKmToLondon = (unsigned long)TinyGPSPlus::distanceBetween(
      activeGps->location.lat(),
      activeGps->location.lng(),
      LONDON_LAT, LONDON_LON) / 1000;
  printInt(distanceKmToLondon, activeGps->location.isValid(), 9);
  
  double courseToLondon = TinyGPSPlus::courseTo(
      activeGps->location.lat(),
      activeGps->location.lng(),
      LONDON_LAT, LONDON_LON);
  printFloat(courseToLondon, activeGps->location.isValid(), 7, 2);
  
  const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);
  printStr(activeGps->location.isValid() ? cardinalToLondon : "*** ", 6);
  
  printInt(activeGps->charsProcessed(), true, 6);
  printInt(activeGps->sentencesWithFix(), true, 10);
  printInt(activeGps->failedChecksum(), true, 9);
  
  // Print additional column indicating source: "GPS 1" or "GPS 2".
  Serial.print("   ");
  if(activeGps == &gps1) {
    Serial.print("GPS 1");
  } else {
    Serial.print("GPS 2");
  }
  
  Serial.println();
  
  smartDelay(1000);
  
  if (millis() > 5000 && activeGps->charsProcessed() < 10)
    Serial.println(F("No GPS data received: check wiring"));
}

// Modified smartDelay() that feeds both GPS streams.
static void smartDelay(unsigned long ms) {
  unsigned long start = millis();
  do {
    while (SerialGPS1.available() > 0)
      gps1.encode(SerialGPS1.read());
    while (SerialGPS2.available() > 0)
      gps2.encode(SerialGPS2.read());
  } while (millis() - start < ms);
}

static void printFloat(float val, bool valid, int len, int prec) {
  if (!valid) {
    while (len-- > 1)
      Serial.print('*');
    Serial.print(' ');
  } else {
    Serial.print(val, prec);
    int vi = abs((int)val);
    int flen = prec + (val < 0.0 ? 2 : 1); // . and -
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
    for (int i = flen; i < len; ++i)
      Serial.print(' ');
  }
  smartDelay(0);
}

static void printInt(unsigned long val, bool valid, int len) {
  char sz[32] = "*****************";
  if (valid)
    sprintf(sz, "%ld", val);
  sz[len] = 0;
  for (int i = strlen(sz); i < len; ++i)
    sz[i] = ' ';
  if (len > 0)
    sz[len - 1] = ' ';
  Serial.print(sz);
  smartDelay(0);
}

static void printDateTime(TinyGPSDate &d, TinyGPSTime &t) {
  if (!d.isValid()) {
    Serial.print(F("********** "));
  } else {
    char sz[32];
    sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
    Serial.print(sz);
  }
  
  if (!t.isValid()) {
    Serial.print(F("******** "));
  } else {
    char sz[32];
    sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
    Serial.print(sz);
  }
  
  printInt(d.age(), d.isValid(), 5);
  smartDelay(0);
}

static void printStr(const char *str, int len) {
  int slen = strlen(str);
  for (int i = 0; i < len; ++i)
    Serial.print(i < slen ? str[i] : ' ');
  smartDelay(0);
}

HTH
GL :slight_smile: PJ :v:

This morning ,Rocking a rolling 2 GPS 30+ sats or 15’ish each… LOL

18   0.6   26.041689  -80.220894  403  02/23/2025 15:42:48 769  -6.40  0.00   0.00  N     7108     43.06  NE    13985 37514     1           GPS 2
18   0.6   26.041689  -80.220894  418  02/23/2025 15:42:49 765  -6.30  0.00   0.00  N     7108     43.06  NE    13986 37516     1           GPS 2
18   0.6   26.041689  -80.220894  418  02/23/2025 15:42:50 775  -6.30  0.00   0.00  N     7108     43.06  NE    13987 37518     1           GPS 2
18   0.6   26.041689  -80.220894  426  02/23/2025 15:42:51 780  -6.30  0.00   0.00  N     7108     43.06  NE    13988 37520     1           GPS 2
17   0.6   26.041689  -80.220894  435  02/23/2025 15:42:52 784  -6.30  0.00   0.00  N     7108     43.06  NE    13989 37522     1           GPS 2
17   0.6   26.041689  -80.220894  440  02/23/2025 15:42:53 799  -6.20  0.00   0.00  N     7108     43.06  NE    13989 37524     1           GPS 2
16   0.6   26.041712  -80.220886  433  02/23/2025 15:42:54 799  0.30   241.83 0.00  WSW   7108     43.06  NE    13955 37343     1           GPS 1
17   0.6   26.041691  -80.220894  434  02/23/2025 15:42:55 801  -6.20  0.00   0.00  N     7108     43.06  NE    13991 37528     1           GPS 2
16   0.6   26.041712  -80.220886  443  02/23/2025 15:42:56 806  0.30   241.83 0.00  WSW   7108     43.06  NE    13956 37347     1           GPS 1
16   0.6   26.041691  -80.220894  452  02/23/2025 15:42:57 815  -6.20  0.00   0.00  N     7108     43.06  NE    13993 37532     1           GPS 2
16   0.6   26.041691  -80.220894  457  02/23/2025 15:42:58 814  -6.20  0.00   0.00  N     7108     43.06  NE    13993 37534     1           GPS 2
16   0.6   26.041691  -80.220894  462  02/23/2025 15:42:59 823  -6.20  0.00   0.00  N     7108     43.06  NE    13994 37536     1           GPS 2
15   0.7   26.041712  -80.220886  455  02/23/2025 15:43:00 819  0.20   241.83 0.00  WSW   7108     43.06  NE    13959 37355     1           GPS 1
16   0.6   26.041712  -80.220886  458  02/23/2025 15:43:01 814  0.30   241.83 0.00  WSW   7108     43.06  NE    13960 37357     1           GPS 1
16   0.6   26.041712  -80.220886  464  02/23/2025 15:43:02 810  0.30   241.83 0.00  WSW   7108     43.06  NE    13961 37359     1           GPS 1
16   0.6   26.041712  -80.220886  467  02/23/2025 15:43:03 821  0.30   241.83 0.00  WSW   7108     43.06  NE    13962 37361     1           GPS 1
16   0.6   26.041712  -80.220886  472  02/23/2025 15:43:04 820  0.30   241.83 0.00  WSW   7108     43.06  NE    13963 37363     1           GPS 1
16   0.6   26.041712  -80.220886  468  02/23/2025 15:43:05 829  0.30   241.83 0.00  WSW   7108     43.06  NE    13963 37365     1           GPS 1
16   0.6   26.041712  -80.220886  477  02/23/2025 15:43:06 820  0.30   241.83 0.00  WSW   7108     43.06  NE    13964 37367     1           GPS 1
16   0.6   26.041712  -80.220886  474  02/23/2025 15:43:07 834  0.30   241.83 0.00  WSW   7108     43.06  NE    13965 37369     1           GPS 1
16   0.6   26.041691  -80.220894  484  02/23/2025 15:43:08 846  -6.10  0.00   0.00  N     7108     43.06  NE    14001 37554     1           GPS 2
16   0.6   26.041691  -80.220894  490  02/23/2025 15:43:09 850  -6.10  0.00   0.00  N     7108     43.06  NE    14002 37556     1           GPS 2
16   0.6   26.041691  -80.220894  497  02/23/2025 15:43:10 852  -6.10  0.00   0.00  N     7108     43.06  NE    14003 37558     1           GPS 2
16   0.6   26.041691  -80.220894  499  02/23/2025 15:43:11 864  -6.10  0.00   0.00  N     7108     43.06  NE    14004 37560     1           GPS 2

:v:

Hi there,

ROCK SOLID performance from the L76K GSS unit. seems to be a TAD faster and fresher than the Grove connected AIR530 Unit.
I was able to run each device with each method Hardware/Software Serial on either Port.
The key seems to be SoftSerial works better on pins that are already defined as a Uart channel. Hardware Serial can make changes to the interconnected PPI in the chips Peripherals to better support a Brute force or bitbanged io approach to serial comms.
Baud rates also play a role so don’t try to fast at first, test , tune and turn up as needed. :v:
I added the labels and posting current code and output. for others to duplicate.

Serial Output Monitor…

16   0.8   26.041662  -80.220924  224  02/23/2025 20:13:50 224  -11.60 134.26 0.00  SE    12348    16.02  NNE   98018 26178     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  227  02/23/2025 20:13:51 227  -11.50 134.26 0.00  SE    12348    16.02  NNE   98025 26180     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  224  02/23/2025 20:13:52 224  -11.50 134.26 0.00  SE    12348    16.02  NNE   98033 26182     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  233  02/23/2025 20:13:53 233  -11.50 134.26 0.00  SE    12348    16.02  NNE   98040 26184     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  233  02/23/2025 20:13:54 233  -11.50 134.26 0.00  SE    12348    16.02  NNE   98048 26186     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  228  02/23/2025 20:13:55 228  -11.40 134.26 0.00  SE    12348    16.02  NNE   98055 26188     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  231  02/23/2025 20:13:56 231  -11.40 134.26 0.00  SE    12348    16.02  NNE   98063 26190     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  236  02/23/2025 20:13:57 236  -11.40 134.26 0.00  SE    12348    16.02  NNE   98071 26192     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  245  02/23/2025 20:13:58 245  -11.40 134.26 0.00  SE    12348    16.02  NNE   98078 26194     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  251  02/23/2025 20:13:59 251  -11.40 134.26 0.00  SE    12348    16.02  NNE   98086 26196     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  254  02/23/2025 20:14:00 254  -11.40 134.26 0.00  SE    12348    16.02  NNE   98093 26198     0           GPS 2- L76K GSS 
16   0.8   26.041662  -80.220924  254  02/23/2025 20:14:01 254  -11.40 134.26 0.00  SE    12348    16.02  NNE   98101 26200     0           GPS 2- L76K GSS 
15   1.0   26.041656  -80.220879  247  02/23/2025 20:14:02 247  -5.50  308.12 2.76  NW    12348    16.02  NNE   96082 26202     0           GPS 1- Air530 
15   1.0   26.041656  -80.220879  268  02/23/2025 20:14:03 268  -5.50  308.12 0.00  NW    12348    16.02  NNE   96089 26204     0           GPS 1- Air530 
15   1.0   26.041656  -80.220879  267  02/23/2025 20:14:04 267  -5.50  308.12 0.00  NW    12348    16.02  NNE   96097 26206     0           GPS 1- Air530 
15   1.0   26.041656  -80.220879  267  02/23/2025 20:14:05 267  -5.50  308.12 0.00  NW    12348    16.02  NNE   96104 26208     0           GPS 1- Air530 
15   0.8   26.041662  -80.220924  277  02/23/2025 20:14:06 277  -11.40 134.26 0.00  SE    12348    16.02  NNE   98139 26210     0           GPS 2- L76K GSS 
15   1.0   26.041656  -80.220879  279  02/23/2025 20:14:07 279  -5.20  308.12 0.54  NW    12348    16.02  NNE   96119 26212     0           GPS 1- Air530 
15   0.8   26.041662  -80.220924  290  02/23/2025 20:14:08 290  -11.40 134.26 0.00  SE    12348    16.02  NNE   98154 26214     0           GPS 2- L76K GSS 
15   0.8   26.041662  -80.220924  295  02/23/2025 20:14:09 295  -11.40 134.26 0.00  SE    12348    16.02  NNE   98161 26216     0           GPS 2- L76K GSS 
15   0.8   26.041662  -80.220924  293  02/23/2025 20:14:10 293  -11.40 134.26 0.00  SE    12348    16.02  NNE   98169 26218     0           GPS 2- L76K GSS 
15   0.8   26.041662  -80.220924  301  02/23/2025 20:14:11 301  -11.40 134.26 0.00  SE    12348    16.02  NNE   98177 26220     0           GPS 2- L76K GSS 
15   0.8   26.041662  -80.220924  303  02/23/2025 20:14:12 303  -11.40 134.26 0.00  SE    12348    16.02  NNE   98184 26222     0           GPS 2- L76K GSS 
15   0.8  

Scroll right to the end. :+1:

FQBN: esp32:esp32:XIAO_ESP32C3
Using board 'XIAO_ESP32C3' from platform in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.7
Using core 'esp32' from platform in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.7
**EDIT... for brevity...**
Using library TinyGPSPlus at version 1.0.3 in folder: D:\Arduino_projects\libraries\TinyGPSPlus 
Using library EspSoftwareSerial at version 8.1.0 in folder: D:\Arduino_projects\libraries\EspSoftwareSerial 
"C:\\Users\\Dude\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp-rv32\\2302/bin/riscv32-esp-elf-size" -A "C:\\Users\\Dude\\AppData\\Local\\arduino\\sketches\\C46D996DDDD904C0FBA2B540A6CCB432/sketch_feb23f_Posted_3_Serial_portsC3.ino.elf"
Sketch uses 284502 bytes (21%) of program storage space. Maximum is 1310720 bytes.
Global variables use 12700 bytes (3%) of dynamic memory, leaving 314980 bytes for local variables. Maximum is 327680 bytes.
"C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\tools\esptool_py\4.6/esptool.exe" --chip esp32c3 --port "COM28" --baud 921600  --before default_reset --after hard_reset write_flash  -z --flash_mode keep --flash_freq keep --flash_size keep 0x0 "C:\Users\Dude\AppData\Local\arduino\sketches\C46D996DDDD904C0FBA2B540A6CCB432/sketch_feb23f_Posted_3_Serial_portsC3.ino.bootloader.bin" 0x8000 "C:\Users\Dude\AppData\Local\arduino\sketches\C46D996DDDD904C0FBA2B540A6CCB432/sketch_feb23f_Posted_3_Serial_portsC3.ino.partitions.bin" 0xe000 "C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.7/tools/partitions/boot_app0.bin" 0x10000 "C:\Users\Dude\AppData\Local\arduino\sketches\C46D996DDDD904C0FBA2B540A6CCB432/sketch_feb23f_Posted_3_Serial_portsC3.ino.bin" 
esptool.py v4.6
Serial port COM28
Connecting...
Chip is ESP32-C3 (revision v0.3)
Features: WiFi, BLE
Crystal is 40MHz
MAC: a0:76:4e:40:08:ec
Uploading stub...
Running stub...
Stub running...

Code running as Posted…

// This is a 3 serial port demo using GPS units from Seeed, 2 GPS setup with ESP32C3
// Hardware Serial & Software Serial are implimented.
// Compiled with BSP 3.0.7 
// added a column at the end for which GPS unit is sending the data
// tested with AIR530 V1.0 & L76K GNSS Seeed Xiao GPS unit.
// Either unit can be used in either Port position.
// See the Seeed Support form for pictures and errata.
#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>
#include <HardwareSerial.h>
// ------------------ GPS Configurations ------------------
// For GPS 1 (HardwareSerial on UART1)
const int gps1RXPin = 9; // Connect GPS1 TX to ESP32 RX (pin 7) AIR530 Grove GPS
const int gps1TXPin = 10; // Connect GPS1 RX to ESP32 TX (pin 6)
const uint32_t gps1Baud = 9600;
// For GPS 2 (SoftwareSerial)
const int gps2RXPin = D7; // Connect GPS2 TX to ESP32 RX (pin 9) L76K GNSS SEEED Studio
const int gps2TXPin = D6; // Connect GPS2 RX to ESP32 TX (pin 10)
const uint32_t gps2Baud = 9600;
// ------------------ Objects ------------------
TinyGPSPlus gps1; // For HardwareSerial GPS
TinyGPSPlus gps2; // For SoftwareSerial GPS
// Use UART1 for GPS 1:
HardwareSerial SerialGPS1(1);
// Use SoftwareSerial for GPS 2:
SoftwareSerial SerialGPS2(gps2RXPin, gps2TXPin); // (RX, TX)

// ------------------ Function Prototypes ------------------
static void smartDelay(unsigned long ms);
static void printFloat(float val, bool valid, int len, int prec);
static void printInt(unsigned long val, bool valid, int len);
static void printDateTime(TinyGPSDate &d, TinyGPSTime &t);
static void printStr(const char *str, int len);
static void printGPSSource();

void setup() {
  Serial.begin(9600);
  delay(2000);
  Serial.println("\nFullExample.ino");
  Serial.println("An extensive example of many interesting TinyGPSPlus features");
  Serial.print("Testing TinyGPSPlus library v. "); 
  Serial.println(TinyGPSPlus::libraryVersion());
  Serial.println("by Mikal Hart, tweaked for 2 GPS by PJG");
  Serial.println();
  Serial.println("Sats HDOP  Latitude   Longitude   Fix  Date       Time     Date Alt    Course Speed Card  Distance Course Card  Chars Sentences Checksum   GPS");
  Serial.println("           (deg)      (deg)       Age                      Age  (m)    --- from GPS ----  ---- to London  ----  RX    RX        Fail");
  Serial.println("----------------------------------------------------------------------------------------------------------------------------------------");
  
  // Initialize GPS 1 (HardwareSerial) on UART1 with assigned pins.
  SerialGPS1.begin(gps1Baud, SERIAL_8N1, gps1RXPin, gps1TXPin);
  Serial.println("GPS-1 HardwareSerial initialized on pins 6 (RX) and 7 (TX).");
  
  // Initialize GPS 2 (SoftwareSerial) on pins 9 & 10.
  SerialGPS2.begin(gps2Baud);
  Serial.println("GPS-2 SoftwareSerial initialized on pins 9 (RX) and 10 (TX).");
  Serial.println();
}

void loop() {
  // Process incoming GPS data for both GPS units.
  // For GPS1 via HardwareSerial:
  while (SerialGPS1.available() > 0) {
    char c = SerialGPS1.read();
    gps1.encode(c);
  }
  // For GPS2 via SoftwareSerial:
  while (SerialGPS2.available() > 0) {
    char c = SerialGPS2.read();
    gps2.encode(c);
  }
  
  // Define a reference location (London in this example).
  //static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
  static const double PITTSBURGH_LAT = 40.4406, PITTSBURGH_LON = 79.9959;
  // We'll decide which GPS to display.
  // Priority: If one has valid location and the other doesn't, choose the valid one.
  // If both are valid, choose the one with a lower "age" (i.e. more recent fix).
  bool valid1 = gps1.location.isValid();
  bool valid2 = gps2.location.isValid();
  TinyGPSPlus *activeGps = nullptr;
  if(valid1 && !valid2) {
    activeGps = &gps1;
  } else if(valid2 && !valid1) {
    activeGps = &gps2;
  } else if(valid1 && valid2) {
    activeGps = (gps1.location.age() <= gps2.location.age()) ? &gps1 : &gps2;
  } else {
    activeGps = &gps1; // default to gps1 if none valid
  }
  
  // Print output using the active GPS data:
  printInt(activeGps->satellites.value(), activeGps->satellites.isValid(), 5);
  printFloat(activeGps->hdop.hdop(), activeGps->hdop.isValid(), 6, 1);
  printFloat(activeGps->location.lat(), activeGps->location.isValid(), 11, 6);
  printFloat(activeGps->location.lng(), activeGps->location.isValid(), 12, 6);
  printInt(activeGps->location.age(), activeGps->location.isValid(), 5);
  printDateTime(activeGps->date, activeGps->time);
  printFloat(activeGps->altitude.meters(), activeGps->altitude.isValid(), 7, 2);
  printFloat(activeGps->course.deg(), activeGps->course.isValid(), 7, 2);
  printFloat(activeGps->speed.kmph(), activeGps->speed.isValid(), 6, 2);
  printStr(activeGps->course.isValid() ? TinyGPSPlus::cardinal(activeGps->course.deg()) : "*** ", 6);
  
  unsigned long distanceKmToLondon = (unsigned long)TinyGPSPlus::distanceBetween(
      activeGps->location.lat(),
      activeGps->location.lng(),
      //LONDON_LAT, LONDON_LON) / 1000;
      PITTSBURGH_LAT, PITTSBURGH_LON) / 1000 ;
  printInt(distanceKmToLondon, activeGps->location.isValid(), 9);
  
  double courseToLondon = TinyGPSPlus::courseTo(
      activeGps->location.lat(),
      activeGps->location.lng(),
      //LONDON_LAT, LONDON_LON);
      PITTSBURGH_LAT, PITTSBURGH_LON);
  printFloat(courseToLondon, activeGps->location.isValid(), 7, 2);
  
  const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);
  printStr(activeGps->location.isValid() ? cardinalToLondon : "*** ", 6);
  
  printInt(activeGps->charsProcessed(), true, 6);
  printInt(activeGps->sentencesWithFix(), true, 10);
  printInt(activeGps->failedChecksum(), true, 9);
  
  // Print additional column indicating source: "GPS 1" or "GPS 2".
  Serial.print("   ");
  if(activeGps == &gps1) {
    Serial.print("GPS 1- Air530 ");
  } else {
    Serial.print("GPS 2- L76K GSS ");
  }
  
  Serial.println();
  
  smartDelay(1000);
  
  if (millis() > 5000 && activeGps->charsProcessed() < 10)
    Serial.println(F("No GPS data received: check wiring"));
}

// Modified smartDelay() that feeds both GPS streams.
static void smartDelay(unsigned long ms) {
  unsigned long start = millis();
  do {
    while (SerialGPS1.available() > 0)
      gps1.encode(SerialGPS1.read());
    while (SerialGPS2.available() > 0)
      gps2.encode(SerialGPS2.read());
  } while (millis() - start < ms);
}

static void printFloat(float val, bool valid, int len, int prec) {
  if (!valid) {
    while (len-- > 1)
      Serial.print('*');
    Serial.print(' ');
  } else {
    Serial.print(val, prec);
    int vi = abs((int)val);
    int flen = prec + (val < 0.0 ? 2 : 1); // . and -
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
    for (int i = flen; i < len; ++i)
      Serial.print(' ');
  }
  smartDelay(0);
}

static void printInt(unsigned long val, bool valid, int len) {
  char sz[32] = "*****************";
  if (valid)
    sprintf(sz, "%ld", val);
  sz[len] = 0;
  for (int i = strlen(sz); i < len; ++i)
    sz[i] = ' ';
  if (len > 0)
    sz[len - 1] = ' ';
  Serial.print(sz);
  smartDelay(0);
}

static void printDateTime(TinyGPSDate &d, TinyGPSTime &t) {
  if (!d.isValid()) {
    Serial.print(F("********** "));
  } else {
    char sz[32];
    sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
    Serial.print(sz);
  }
  
  if (!t.isValid()) {
    Serial.print(F("******** "));
  } else {
    char sz[32];
    sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
    Serial.print(sz);
  }
  
  printInt(d.age(), d.isValid(), 5);
  smartDelay(0);
}

static void printStr(const char *str, int len) {
  int slen = strlen(str);
  for (int i = 0; i < len; ++i)
    Serial.print(i < slen ? str[i] : ' ');
  smartDelay(0);
}

HTH
GL :slight_smile: PJ :v:

Xiao ESP32C3 is All you neeed :stuck_out_tongue:

1 Like

thanks… I think one of my gps battery must be dead or something loosing the alminac … but i am definatly going to use this… I was with ,y cousin today playing with lora transmitters

1 Like

if its not too much trouble can you add a way to toggle between gps units for the printing… maybe a serial command 1 or 2

or maybe to get it to display both?

confirmed operation… i had to take it outside and let it see the sky for a while

1 Like