SODAQ not finding SoftwareSerial.h

Hi, I have an arduino sodaq with a MIcrochip LoRabee attached, as well as a GPS module. I am trying to use SoftwareSerial to read the GPS data but it won’t recognise it!

The sketch was previously working on a Chinese cloned Nano and I was able to read the data fine. I’ve changed the ports to 4 and 5 (I was using 3 and 4 on the Chinese Nano) but other than that the code is identical.

Any ideas?

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 2, TXPin = 3;
static const uint32_t GPSBaud = 9600;

// The TinyGPS++ object
TinyGPSPlus gps;

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

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

Serial.println(F(“FullExample.ino”));
Serial.println(F(“An extensive example of many interesting TinyGPS++ features”));
Serial.print(F(“Testing TinyGPS++ library v. “)); Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F(“by Mikal Hart”));
Serial.println();
Serial.println(F(“Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum”));
Serial.println(F(” (deg) (deg) Age Age (m) — from GPS ---- ---- to London ---- RX RX Fail”));
Serial.println(F("---------------------------------------------------------------------------------------------------------------------------------------"));
}

void loop()
{
static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;

printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
printInt(gps.hdop.value(), gps.hdop.isValid(), 5);
printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
printFloat(gps.location.lng(), gps.location.isValid(), 12, 6);
printInt(gps.location.age(), gps.location.isValid(), 5);
printDateTime(gps.date, gps.time);
printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2);
printFloat(gps.course.deg(), gps.course.isValid(), 7, 2);
printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.value()) : "*** ", 6);

unsigned long distanceKmToLondon =
(unsigned long)TinyGPSPlus::distanceBetween(
gps.location.lat(),
gps.location.lng(),
LONDON_LAT,
LONDON_LON) / 1000;
printInt(distanceKmToLondon, gps.location.isValid(), 9);

double courseToLondon =
TinyGPSPlus::courseTo(
gps.location.lat(),
gps.location.lng(),
LONDON_LAT,
LONDON_LON);

printFloat(courseToLondon, gps.location.isValid(), 7, 2);

const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);

printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6);

printInt(gps.charsProcessed(), true, 6);
printInt(gps.sentencesWithFix(), true, 10);
printInt(gps.failedChecksum(), true, 9);
Serial.println();

smartDelay(1000);

if (millis() > 5000 && gps.charsProcessed() < 10)
Serial.println(F(“No GPS data received: check wiring”));
}

// This custom version of delay() ensures that the gps object
// is being “fed”.
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.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);
}

I don’t think there is a version of SoftwareSerial for the SAMD platform. There are multiple hardware Serial available on the Autonomo. If you need more than the default two, you will need to select one of the board’s sub-variants.

Software based emulation creates a whole range of issues, it should be avoided wherever possible.

Unfortunately, it seems that this specific library/code is highly dependent on using SoftwareSerial. It will take a bit of work to adapt it to use a hardware Serial instance.

1 Like

Hi there! Thanks so much! I’ve been fiddling with it to try to get it to work on my autonomo, and am basically printing some increasingly large numbers and asterisks…I think basically i’m getting a lot of information from the GPS but it’s not parsing it properly. I think the ‘serial’ and ‘serialUSB’ functions are working correctly though. Could you suggest another library that’s not ‘TinyGPS’ that might work here? Or perhaps a tweak to get my code printing the lovely GPS chart that I could get on my nano clone?!

#include <TinyGPS++.h>

/*
This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 0, TXPin = 1;
static const uint32_t GPSBaud = 9600;

// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device

void setup()
{
Serial.begin(9600);
Serial1.begin(GPSBaud);

SerialUSB.println(F(“FullExample.ino”));
SerialUSB.println(F(“An extensive example of many interesting TinyGPS++ features”));
SerialUSB.print(F(“Testing TinyGPS++ library v. “)); Serial.println(TinyGPSPlus::libraryVersion());
SerialUSB.println(F(“by Mikal Hart”));
SerialUSB.println();
SerialUSB.println(F(“Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum”));
SerialUSB.println(F(” (deg) (deg) Age Age (m) — from GPS ---- ---- to London ---- RX RX Fail”));
SerialUSB.println(F("---------------------------------------------------------------------------------------------------------------------------------------"));
}

void loop()
{
static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;

printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
printInt(gps.hdop.value(), gps.hdop.isValid(), 5);
printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
printFloat(gps.location.lng(), gps.location.isValid(), 12, 6);
printInt(gps.location.age(), gps.location.isValid(), 5);
printDateTime(gps.date, gps.time);
printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2);
printFloat(gps.course.deg(), gps.course.isValid(), 7, 2);
printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.value()) : "*** ", 6);

unsigned long distanceKmToLondon =
(unsigned long)TinyGPSPlus::distanceBetween(
gps.location.lat(),
gps.location.lng(),
LONDON_LAT,
LONDON_LON) / 1000;
printInt(distanceKmToLondon, gps.location.isValid(), 9);

double courseToLondon =
TinyGPSPlus::courseTo(
gps.location.lat(),
gps.location.lng(),
LONDON_LAT,
LONDON_LON);

printFloat(courseToLondon, gps.location.isValid(), 7, 2);

const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);

printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6);

printInt(gps.charsProcessed(), true, 6);
printInt(gps.sentencesWithFix(), true, 10);
printInt(gps.failedChecksum(), true, 9);
Serial.println();

smartDelay(1000);

if (millis() > 5000 && gps.charsProcessed() < 10)
Serial.println(F(“No GPS data received: check wiring”));
}

// This custom version of delay() ensures that the gps object
// is being “fed”.
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (Serial.available())
gps.encode(Serial.read());
} while (millis() - start < ms);
}

static void printFloat(float val, bool valid, int len, int prec)
{
if (!valid)
{
while (len-- > 1)
SerialUSB.print(’*’);
SerialUSB.print(’ ‘);
}
else
{
SerialUSB.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)
SerialUSB.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] = ’ ';
SerialUSB.print(sz);
smartDelay(0);
}

static void printDateTime(TinyGPSDate &d, TinyGPSTime &t)
{
if (!d.isValid())
{
SerialUSB.print(F("********** "));
}
else
{
char sz[32];
sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
SerialUSB.print(sz);
}

if (!t.isValid())
{
SerialUSB.print(F("******** "));
}
else
{
char sz[32];
sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
SerialUSB.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)
SerialUSB.print(i<slen ? str[i] : ’ ');
smartDelay(0);
}

If you want to test the GPS functionality, I was suggest starting with a pass through sketch from Serial to SerialUSB (Serial1 is the Bee socket).

You will need to initialise Serial at the correct baud rate for the GPS module to pins D0/D1.

Then in loop copy any available data from the SerialUSB receive buffer and sent it to the Serial stream, then repeat the process for Serial->SerialUSB.

You should see a regular stream of NMEA sentences, you will need make sure that the RX / TX pins are connected in the right order and that the baud rate is correct.

Hi, I’m still fiddling with it and not having much luck.

In the sketch I pasted and can compile and run, I think the Serial is automatically initialised on pins 0 and 1 (the autonomo does that automatically) and SerialUSB is always the USB, right?

I can’t see where I’m going wrong and why it’s not working like on my nano

Try this:

#define GPS_BAUD 9600

void setup() 
{
  Serial.begin(GPS_BAUD);
}

void loop() 
{
  while (Serial.available()) {
    SerialUSB.write(Serial.read());
  }

  while (SerialUSB.available()) {
    Serial.write(SerialUSB.read());
  }
}

You should see repeating output something like this:

$GPGSV,4,1,14,26,78,195,,21,64,101,,16,61,294,,27,33,263,*73
$GPGSV,4,2,14,04,26,240,,29,20,078,,20,19,046,,31,17,197,*79
$GPGSV,4,3,14,18,13,137,,05,11,027,,07,04,337,,09,04,307,*78
$GPGSV,4,4,14,19,03,257,,01,02,241,*73
$GPRMC,174117.099,V,,,,,0.00,0.00,290515,,,N*42
$GPGGA,174118.099,,,,,0,0,,,M,,M,,*42
$GPGSA,A,1,,,,,,,,,,,,,,,*1E

If you haven’t achieved a fix/lock many of the fields will be empty or blank.

One other thing, on UART type connection (Serial), the RX from the GPS connects to the TX pin on Autonomo, and the TX pin on the GPS connects to the RX pin on the Autonomo. Due to this crossover, there is sometimes confusion in the labelling and you may have to try swapping the pins.

Hi Gabriel,

Thanks so much this works brilliantly!

Alex