GPS lat long to morse code converter

Thanks for anyone’s help on this in advance. My goal is to combine a GPS receiver (NEO-6M), and a Nano or Pro mini to convert the lat and longitude numbers coming out of the TinyGPS library to the Morse Code equivalent which would key an output pin with the Morse Code characters. I have two separate programs now working that do the tasks individually: Program 1) Receive data from the GPS module and display lat/long from the TinyGPS library on the serial monitor screen , and Program 2) Take a hardcoded character (letter or number or message) and convert to a Morse character and key an output pin.
What I can’t figure out is how to now combine both programs so the Morse generator program receives the lat/long numbers from the GPS program and ultimately keys the output pin with the lat/long numbers in Morse.
Seems like I need to convert the lat/long numbers to a serial stream of characters that the Morse program will accept one at time.
The TinyGPS library outputs two items, one called gps.location.lat and the other is gps.location.long. I am not sure if these are characters or actual numbers like a float.
I would then think I would need to create maybe a string that has the numbers in the correct serial sequence to be fed as characters to the Morse program one at time. This is where I get totally lost on what to do.
So I guess my question would be: How do you convert the TinyGPS output to a serial stream of characters, not actual numbers, that the Morse program would accept.
Here is the program that processes the GPS data:

/*
 * Rui Santos 
 * Complete Project Details http://randomnerdtutorials.com
 */
 
#include <TinyGPS++.h>
#include <SoftwareSerial.h>

static const int RXPin = 4, 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(9600);
  ss.begin(GPSBaud);
}

void loop(){
  // This sketch displays information every time a new sentence is correctly encoded.
  while (ss.available() > 0){
    gps.encode(ss.read());
    if (gps.location.isUpdated()){
      Serial.print("Latitude= "); 
      Serial.print(gps.location.lat(), 6);
      Serial.print(" Longitude= "); 
      Serial.println(gps.location.lng(), 6);
    }
  }
}

Here is the program that processes the Morse code characters:

//
// Simple Arduino Morse Beacon
// Written by Mark VandeWettering K6HX
// Email: k6hx@arrl.net
// 
// This code is so trivial that I'm releasing it completely without 
// restrictions.  If you find it useful, it would be nice if you dropped
// me an email, maybe plugged my blog @ https://brainwagon.org or included
// a brief acknowledgement in whatever derivative you create, but that's
// just a courtesy.  Feel free to do whatever.
//


struct t_mtab { char c, pat; } ;

struct t_mtab morsetab[] = {
    {'.', 106},
  {',', 115},
  {'?', 76},
  {'/', 41},
  {'A', 6},
  {'B', 17},
  {'C', 21},
  {'D', 9},
  {'E', 2},
  {'F', 20},
  {'G', 11},
  {'H', 16},
  {'I', 4},
  {'J', 30},
  {'K', 13},
  {'L', 18},
  {'M', 7},
  {'N', 5},
  {'O', 15},
  {'P', 22},
  {'Q', 27},
  {'R', 10},
  {'S', 8},
  {'T', 3},
  {'U', 12},
  {'V', 24},
  {'W', 14},
  {'X', 25},
  {'Y', 29},
  {'Z', 19},
  {'1', 62},
  {'2', 60},
  {'3', 56},
  {'4', 48},
  {'5', 32},
  {'6', 33},
  {'7', 35},
  {'8', 39},
  {'9', 47},
  {'0', 63}
} ;

#define N_MORSE  (sizeof(morsetab)/sizeof(morsetab[0]))

#define SPEED  (20)
#define DOTLEN  (1200/SPEED)
#define DASHLEN  (3*(1200/SPEED))

int LEDpin = 13 ;

void dash()

{
  digitalWrite(LEDpin, HIGH) ;
  delay(DASHLEN);
  digitalWrite(LEDpin, LOW) ;
  delay(DOTLEN) ;
}

void dit()

{
  digitalWrite(LEDpin, HIGH) ;
  delay(DOTLEN);
  digitalWrite(LEDpin, LOW) ;
  delay(DOTLEN);
}

void
send(char c)
{
  int i ;
  if (c == ' ') {
    Serial.print(c) ;
    delay(7*DOTLEN) ;
    return ;
  }
  for (i=0; i<N_MORSE; i++) {
    if (morsetab[i].c == c) {
      unsigned char p = morsetab[i].pat ;
      Serial.print(morsetab[i].c) ;

      while (p != 1) {
          if (p & 1)
            dash() ;
          else
            dit() ;
          p = p / 2 ;
      }
      delay(2*DOTLEN) ;
      return ;
    }
  }
  /* if we drop off the end, then we send a space */
  Serial.print("?") ;
}

void
sendmsg(char *str)
{
  while (*str)
    send(*str++) ;
  Serial.println("");
}

void setup(){
  pinMode(LEDpin, OUTPUT); 
  Serial.begin(9600);
  Serial.println("Simple Arduino Morse Beacon v0.0");
  Serial.println("Written by Mark VandeWettering <k6hx@arrl.net>");
  Serial.println("Check out my blog @ https://brainwagon.org");
  Serial.println("");
}

void loop() {
  sendmsg("THIS IS A TEST MORSE MESSAGE") ;
  delay(3000) ;
}

Thanks again for any help.

The TinyGPS library outputs two items, one called gps.location.lat and the other is gps.location.long. I am not sure if these are characters or actual numbers like a float.

Is the library documentation not clear on that point?

I can't tell from the TinyGPS documentation if it is a character output or a number output. Do you know?
Thanks

Please post a link to the TinyGPS documentation in question. Then I will be happy to help clarify any misunderstanding.

Nm, I found it for you. Please next time spend some time looking before asking what is basically not a mystery if you look in the normal place.

Each provides methods to examine its current value, sometimes in multiple formats and units. Here’s a complete list:

Serial.println(gps.location.lat(), 6); // Latitude in degrees (double)
Serial.println(gps.location.lng(), 6); // Longitude in degrees (double)
[...]

Thanks aarg. Where did you find this in the TinyGPS document. I am looking here:
http://arduiniana.org/libraries/tinygps/
What document did you find?
So if it is a double precision number, is there a way to convert each digit into a character?
Does the char() do this?
Thanks

I found it here
http://arduiniana.org/libraries/tinygpsplus/

You can use snprintf() to convert the float value into a char string for whatever purpose you desire, in this case conversion to Morse.

dtostrf() converts floating point numbers to ASCII text.

snprintf() float conversion is disabled by default on AVR based Arduinos (some Nanos, Pro Mini).

Thanks jremington. Feeling like I am going deeper down the rabbit hole. Will now research dtostrf. I assume this will also work on double numbers.
Thanks again

OK so I made some progress on this. Using dtostrf I was able to convert a double number to a char string and have the Morse code program accept it and send it out in Morse code. Here is the Morse code sketch:

//
// Simple Arduino Morse Beacon
// Written by Mark VandeWettering K6HX
// Email: k6hx@arrl.net
// 
// This code is so trivial that I'm releasing it completely without 
// restrictions.  If you find it useful, it would be nice if you dropped
// me an email, maybe plugged my blog @ https://brainwagon.org or included
// a brief acknowledgement in whatever derivative you create, but that's
// just a courtesy.  Feel free to do whatever.
//


struct t_mtab { char c, pat; } ;

struct t_mtab morsetab[] = {
    {'.', 106},
  {',', 115},
  {'?', 76},
  {'/', 41},
  {'A', 6},
  {'B', 17},
  {'C', 21},
  {'D', 9},
  {'E', 2},
  {'F', 20},
  {'G', 11},
  {'H', 16},
  {'I', 4},
  {'J', 30},
  {'K', 13},
  {'L', 18},
  {'M', 7},
  {'N', 5},
  {'O', 15},
  {'P', 22},
  {'Q', 27},
  {'R', 10},
  {'S', 8},
  {'T', 3},
  {'U', 12},
  {'V', 24},
  {'W', 14},
  {'X', 25},
  {'Y', 29},
  {'Z', 19},
  {'1', 62},
  {'2', 60},
  {'3', 56},
  {'4', 48},
  {'5', 32},
  {'6', 33},
  {'7', 35},
  {'8', 39},
  {'9', 47},
  {'0', 63}
} ;

#define N_MORSE  (sizeof(morsetab)/sizeof(morsetab[0]))

#define SPEED  (20)
#define DOTLEN  (1200/SPEED)
#define DASHLEN  (3*(1200/SPEED))

int LEDpin = 13 ;

double lat = 12.345678;  //I added this
char outstr[10];     //I added this


void dash()

{
  digitalWrite(LEDpin, HIGH) ;
  delay(DASHLEN);
  digitalWrite(LEDpin, LOW) ;
  delay(DOTLEN) ;
}

void dit()

{
  digitalWrite(LEDpin, HIGH) ;
  delay(DOTLEN);
  digitalWrite(LEDpin, LOW) ;
  delay(DOTLEN);
}

void
send(char c)
{
  int i ;
  if (c == ' ') {
    Serial.print(c) ;
    delay(7*DOTLEN) ;
    return ;
  }
  for (i=0; i<N_MORSE; i++) {
    if (morsetab[i].c == c) {
      unsigned char p = morsetab[i].pat ;
      Serial.print(morsetab[i].c) ;

      while (p != 1) {
          if (p & 1)
            dash() ;
          else
            dit() ;
          p = p / 2 ;
      }
      delay(2*DOTLEN) ;
      return ;
    }
  }
  /* if we drop off the end, then we send a space */
  Serial.print("?") ;
}

void
sendmsg(char *str)
{
  while (*str)
    send(*str++) ;
  Serial.println("");
}

void setup(){
  pinMode(LEDpin, OUTPUT); 
  Serial.begin(9600);
  //Serial.println("Simple Arduino Morse Beacon v0.0");
 // Serial.println("Written by Mark VandeWettering <k6hx@arrl.net>");
 // Serial.println("Check out my blog @ https://brainwagon.org");
  //Serial.println("");
}

void loop() {
   dtostrf(lat,9, 6,  outstr); // dtostrf(gps.location.lat(),7, 2, outstr);
   Serial.println(outstr);
   sendmsg(outstr);
   //sendmsg("THIS IS A TEST MORSE MESSAGE") ;
   delay(3000) ;
}

I then added this to the sketch that reads the GPS module and I keep getting an error that says send is out of scope on line 34 of the GPS read sketch. Here is the combined GPS read and Morse sketch:

/*
 * Rui Santos 
 * Complete Project Details http://randomnerdtutorials.com
 */
 
#include <TinyGPS++.h>
#include <SoftwareSerial.h>

static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
char outstr[10];// originally 15
int LEDpin = 13 ;

// The TinyGPS++ object
TinyGPSPlus gps;

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

void setup(){
  Serial.begin(9600);
  ss.begin(GPSBaud);
  pinMode(LEDpin, OUTPUT); 
  Serial.begin(9600);
//  Serial.println("Simple Arduino Morse Beacon v0.0");
 // Serial.println("Written by Mark VandeWettering <k6hx@arrl.net>");
 // Serial.println("Check out my blog @ https://brainwagon.org");
 // Serial.println("");
 }
void 
sendmsg(char *str)
{
   while (*str)
    send(*str++) ;
  Serial.println("");
}

void loop(){
  // This sketch displays information every time a new sentence is correctly encoded.
  while (ss.available() > 0){
    gps.encode(ss.read());
    if (gps.location.isUpdated()){
     Serial.print("Latitude= "); 
    Serial.print(gps.location.lat(), 6);
 //     Serial.print(" Longitude= "); 
 //     Serial.println(gps.location.lng(), 6);
  dtostrf(gps.location.lat(),9, 6, outstr);
  Serial.println(outstr);
  sendmsg(outstr);
  delay(3000) ;
}
      }
  }


//
// Simple Arduino Morse Beacon
// Written by Mark VandeWettering K6HX
// Email: k6hx@arrl.net
// 
// This code is so trivial that I'm releasing it completely without 
// restrictions.  If you find it useful, it would be nice if you dropped
// me an email, maybe plugged my blog @ https://brainwagon.org or included
// a brief acknowledgement in whatever derivative you create, but that's
// just a courtesy.  Feel free to do whatever.
//


struct t_mtab { char c, pat; } ;

struct t_mtab morsetab[] = {
    {'.', 106},
  {',', 115},
  {'?', 76},
  {'/', 41},
  {'A', 6},
  {'B', 17},
  {'C', 21},
  {'D', 9},
  {'E', 2},
  {'F', 20},
  {'G', 11},
  {'H', 16},
  {'I', 4},
  {'J', 30},
  {'K', 13},
  {'L', 18},
  {'M', 7},
  {'N', 5},
  {'O', 15},
  {'P', 22},
  {'Q', 27},
  {'R', 10},
  {'S', 8},
  {'T', 3},
  {'U', 12},
  {'V', 24},
  {'W', 14},
  {'X', 25},
  {'Y', 29},
  {'Z', 19},
  {'1', 62},
  {'2', 60},
  {'3', 56},
  {'4', 48},
  {'5', 32},
  {'6', 33},
  {'7', 35},
  {'8', 39},
  {'9', 47},
  {'0', 63}
} ;

#define N_MORSE  (sizeof(morsetab)/sizeof(morsetab[0]))

#define SPEED  (20)
#define DOTLEN  (1200/SPEED)
#define DASHLEN  (3*(1200/SPEED))

//int LEDpin = 13 ;

void dash()

{
  digitalWrite(LEDpin, HIGH) ;
  delay(DASHLEN);
  digitalWrite(LEDpin, LOW) ;
  delay(DOTLEN) ;
}

void dit()

{
  digitalWrite(LEDpin, HIGH) ;
  delay(DOTLEN);
  digitalWrite(LEDpin, LOW) ;
  delay(DOTLEN);
}

void
send(char c)
{
  int i ;
  if (c == ' ') {
    Serial.print(c) ;
    delay(7*DOTLEN) ;
    return ;
  }
  for (i=0; i<N_MORSE; i++) {
    if (morsetab[i].c == c) {
      unsigned char p = morsetab[i].pat ;
      Serial.print(morsetab[i].c) ;

      while (p != 1) {
          if (p & 1)
            dash() ;
          else
            dit() ;
          p = p / 2 ;
      }
      delay(2*DOTLEN) ;
      return ;
    }
  }
  /* if we drop off the end, then we send a space */
  Serial.print("?") ;
}

Here is the error message:

Arduino: 1.8.2 (Windows 7), TD: 1.36, Board: "Arduino/Genuino Uno"

C:\Users\Kenny\Documents\Arduino\gps_beacon_v2_working_combined_v1\gps_beacon_v2_working_combined_v1.ino: In function 'void sendmsg(char*)':

gps_beacon_v2_working_combined_v1:34: error: 'send' was not declared in this scope

     send(*str++) ;

                ^

exit status 1
'send' was not declared in this scope

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

I did find that the TinyGPS library kicks out a double number representing Lat and Long that has 6 digits to the right of the decimal.
So my question is send not declared in this scope in the combined sketch yet in the standalone Morse sketch it is OK?
Thanks for anyones help in advance.

The code you posted compiles and uploads without error on an Arduino Pro Mini. I can't test it, though.

a double number representing Lat and Long that has 6 digits to the right of the decimal.

In fact, on AVR based Arduinos (e.g. original Nano or Pro Mini) lat and lon are each single precision float variables, with 6 to 7 meaningful digits total (double is the same as float).

Thanks Jremington for posting. Don't understand why different compilers allow some things while others don't.
Turns out 4 significant digits in the lat long numbers give a 11.1 meter accuracy level. Which seems sufficient for locating things.
Thanks again for your post.

why different compilers allow some things while others don't

The designers of the original Arduino decided to save on code space by making doubles and floats the same. This decision is clearly documented. Lots of other language features are unsupported, for similar reasons.

Turns out 4 significant digits in the lat long numbers give a 11.1 meter accuracy level.

You mean 4 digits to the right of the decimal point.

In a float, 24 bits, or between 6 and 7 decimal digits, are significant.