Project in progress
Kayak GPS Navigation

Kayak GPS Navigation

Kayaking GPS: speed, time, latitude, longitude, distance and azimuth to waypoints, odometer, tide clock, battery monitoring.

  • 2,757 views
  • 2 comments
  • 13 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)

Apps and online services

About this project

I make this GPS for my kayak. I want to be sufficiently robust to permanently attached to it (sea condition) and can be run forever for long sea kayak excursions.

-GPS is powered only by solar energy and can run 1-2 days without sun if need with a integrate lithium-ion battery (if the battery is full).

-Screen can be read in the sunlight or night with back light LED. On sunlight the back light LED is turns OFF for reduce the consumption.

-Waterproof, epoxy sealed .

-Tide clock base on moon rotation 12 heures 25 minutes and 14 secondes. hours until low or high tide are display has a count-down of hours from 5 to 1

-The GPS doesn't have integrate map and should be use in conjunction with paper map for route planning or can simply use for to see speed, time and odometer as a dashboard.

-GPS Info available: Time, Latitude and Longitude, Speed, Tide Clock, Azimuth compass rose, Azimuth Returns/distance and Odometer,

-Pro mode display; Display Speed, Time, Azimuth/compass rose , and alternatively Azimuth/distance, Tide clock and Odometer

-Dashboard mode display; Big character speed, odometer, time.

-controlled by 4 push buttons (select, Up, Down and Power ON)

-the power on / off are controlled by the MCU and the MCU can turn off if the battery voltage is too low (battery protection).

-low energy mode, the GPS module is put in sleeping mode for 10 sec and Hot Start to get data and back on Sleeping Mode...

Next generation will use Arduino Nano pro, GPS module and LCD display at 3.3 volts, more efficient with 3.7 battery. Controlled by tree push buttons (select/PowerON, Up and Down) , It will be smaller. better box design, new option Navigation flashing light (Red and Green). may be a integrate a buzzer for alarm clock. temperature info... I will need more Mem or help for optimise the code.

Sorry my English is not my first langage :(

Code

Kayak GPSArduino
Navigation GPS powered by solar energy.
/*
*/

#include <SoftwareSerial.h>
#include <TinyGPS.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>

#include <avr/pgmspace.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);  //8>RS,9>E, 4-7>D4-D7,RW>0V,
SoftwareSerial gpsSerial(2, 3); //RX, TX 2>bleuTX, 3>VertRX
TinyGPS gps;

byte clo_n = 0;
boolean eco_mode = false;
boolean pro_mode = false;
static int vref = 211; // 1023/4.9 volts
byte solPanel = 3;     //pin
byte batt = 4;         //pin
byte LCD_LED = 11;
byte power_pin = 12;
byte sw_sel = 14;// select
byte sw_up = 15;// up
byte sw_dwn = 16;//down
byte fonction = 0;
int gmt;//, hr ;
long Year_Min;
long Tide_one;
unsigned long time_On;
unsigned long time_run;
unsigned long time_old;

int year;//,  vinfo;
int menu_index = 0;
int cum_n;
static float rad2deg = 0.01745;
float Odometre;
char msg[6];
byte LCD_LED_N = 220;  //OFF 0-a-255 ON
byte col, row, nb = 0, bc = 0;                            // general
byte bb[8];
byte month, day, hour, minute, second, sped; //hundredths,
long lat, lon;                 //,  latmin, lonmin; //angle
long lat2 = 0;
long lon2 = 0;
long wp_lat, wp_lon ;

const char*azimuts[] = {"N  ", "NE ", "E  ", "SE ", "S  ",  "SW ",  "W  ", "NW " };
const char custom[][8] PROGMEM = {                        // Custom character definitions
  { 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00 }, // char 1
  { 0x18, 0x1C, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }, // char 2
  { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0F, 0x07, 0x03 }, // char 3
  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F }, // char 4
  { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1C, 0x18 }, // char 5
  { 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x1F }, // char 6
  { 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F }, // char 7
  { 0x03, 0x07, 0x0F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }, // char 8

};
const char bigChars[][8] PROGMEM = {
  { 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Space
  { 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // !
  { 0x05, 0x05, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00 }, // "
  { 0x04, 0xFF, 0x04, 0xFF, 0x04, 0x01, 0xFF, 0x01 }, // #
  { 0x08, 0xFF, 0x06, 0x07, 0xFF, 0x05, 0x00, 0x00 }, // $
  { 0x01, 0x20, 0x04, 0x01, 0x04, 0x01, 0x20, 0x04 }, // %
  { 0x08, 0x06, 0x02, 0x20, 0x03, 0x07, 0x02, 0x04 }, // &
  { 0x05, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // '
  { 0x08, 0x01, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00 }, // (
  { 0x01, 0x02, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00 }, // )
  { 0x01, 0x04, 0x04, 0x01, 0x04, 0x01, 0x01, 0x04 }, // *
  { 0x04, 0xFF, 0x04, 0x01, 0xFF, 0x01, 0x00, 0x00 }, // +
  { 0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //
  { 0x04, 0x04, 0x04, 0x20, 0x20, 0x20, 0x00, 0x00 }, // -
  { 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // .
  { 0x20, 0x20, 0x04, 0x01, 0x04, 0x01, 0x20, 0x20 }, // /
  { 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00 }, // 0
  { 0x01, 0x02, 0x20, 0x04, 0xFF, 0x04, 0x00, 0x00 }, // 1
  { 0x06, 0x06, 0x02, 0xFF, 0x07, 0x07, 0x00, 0x00 }, // 2
  { 0x01, 0x06, 0x02, 0x04, 0x07, 0x05, 0x00, 0x00 }, // 3
  { 0x03, 0x04, 0xFF, 0x20, 0x20, 0xFF, 0x00, 0x00 }, // 4
  { 0xFF, 0x06, 0x06, 0x07, 0x07, 0x05, 0x00, 0x00 }, // 5
  { 0x08, 0x06, 0x06, 0x03, 0x07, 0x05, 0x00, 0x00 }, // 6
  { 0x01, 0x01, 0x02, 0x20, 0x08, 0x20, 0x00, 0x00 }, // 7
  { 0x08, 0x06, 0x02, 0x03, 0x07, 0x05, 0x00, 0x00 }, // 8
  { 0x08, 0x06, 0x02, 0x07, 0x07, 0x05, 0x00, 0x00 }, // 9
};

const static byte gpsDefault[] PROGMEM = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0x1F, 0x9E};
const static byte gpsSave[] PROGMEM = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x31, 0xBF, 0x13};
const static byte gpsSleep[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x16, 0x74};
const static byte gpsHot[]  = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x68};
const static byte Disable_GPDTM[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x44, 0x54, 0x4d, 0x2a, 0x33, 0x42, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x0a, 0x00, 0x04, 0x23}; //->Disable_GPDTM
const static byte Disable_GPGBS[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x47, 0x42, 0x53, 0x2a, 0x33, 0x30, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x09, 0x00, 0x03, 0x21}; //->Disable_GPGBS
const static byte Disable_GPGGA[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x47, 0x47, 0x41, 0x2a, 0x32, 0x37, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x00, 0x00, 0xfa, 0x0f}; //>Disable_GPGGA
const static byte Disable_GPGLL[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x47, 0x4c, 0x4c, 0x2a, 0x32, 0x31, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x01, 0x00, 0xfb, 0x11}; //->Disable_GPGLL
const static byte Disable_GPGRS[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x47, 0x52, 0x53, 0x2a, 0x32, 0x30, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x06, 0x00, 0x00, 0x1b}; //->Disable_GPGRS
const static byte Disable_GPGSA[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x47, 0x53, 0x41, 0x2a, 0x33, 0x33, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x02, 0x00, 0xfc, 0x13}; //->DisableGPGSA
const static byte Disable_GPGST[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x47, 0x53, 0x54, 0x2a, 0x32, 0x36, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x07, 0x00, 0x01, 0x1d}; //->Disable_GPGST
const static byte Disable_GPGSV[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x47, 0x53, 0x56, 0x2a, 0x32, 0x34, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x03, 0x00, 0xfd, 0x15}; //->Disable_GPGSV
const static byte Disable_GPRMC[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x52, 0x4d, 0x43, 0x2a, 0x33, 0x41, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x04, 0x00, 0xfe, 0x17}; //->Disable_GPRMC
const static byte Disable_GPVTG[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x56, 0x54, 0x47, 0x2a, 0x32, 0x33, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x05, 0x00, 0xff, 0x19}; //->Disable_GPVTG
const static byte Disable_GPZDA[] PROGMEM = {0x24, 0x45, 0x49, 0x47, 0x50, 0x51, 0x2c, 0x5a, 0x44, 0x41, 0x2a, 0x33, 0x39, 0x0d, 0x0a, 0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x08, 0x00, 0x02, 0x1f}; //->Disable_GPZDA

///////////////////////////////////////////////////////
//           Minute depuis debut annee               //
///////////////////////////////////////////////////////
int days[] = {0,  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; // Number of days at the beginning of the month in a not leap year.
long DofY(int yr, int mo, int dy, int h, int mi)
{
  int DfY;
  long Min2Date;
  if (mo == 1 || mo == 2)
  {
    DfY = days[mo] + dy - 1;                 //for any type of year, it calculate the number of days for January or february
  }
  else if ((yr % 4 == 0 && yr % 100 != 0) ||  yr % 400 == 0)
  {
    DfY = days[mo] + dy + 1 - 1;
  }
  else
  {
    DfY = days[mo] + dy - 1;
  }
  Min2Date = (long)DfY * 1440l + (long)h * 60l + (long)mi;
  return (Min2Date);
}
///////////////////////////////////////////////////////
//                      SETUP                        //
///////////////////////////////////////////////////////
void setup()
{
  pinMode(power_pin, OUTPUT);
  digitalWrite (power_pin, HIGH);   // POWER ON!
  analogReference(DEFAULT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.begin(9600);
  gpsSerial.begin(9600);
  pinMode(LCD_LED, OUTPUT);
  //pinMode(buz, OUTPUT);
  pinMode(sw_sel, INPUT);
  pinMode(sw_up, INPUT);
  pinMode(sw_dwn, INPUT);
  lcd.begin(16, 2);
  analogWrite(LCD_LED, 100);

  ///////////////////////////////////////////////////////
  //                    EE PROM Variable               //
  ///////////////////////////////////////////////////////
  hour = EEPROM.read(0);                //lire le gmt
  pro_mode = EEPROM.read(4);
  EEPROM.get(10, wp_lat);
  EEPROM.get(15, wp_lon);
  EEPROM.get(20, Tide_one);
  EEPROM.get(25, Odometre);
  EEPROM.get(30, time_On);
  if (isnan(Odometre)) // test if NAN value
  {
    Odometre = 0;
  }
  if (hour > 127)                       //numbre negatif
  {
    gmt =  hour - 256;
  }
  else
  {
    gmt = hour;
  }
  ///////////////////////////////////////////////////////
  ///               R E V                             ///
  ///////////////////////////////////////////////////////
  lcd.clear();
  lcd.print(F("Ultimate YAK GPS"));
  lcd.setCursor(0, 1);
  lcd.print(F("GPS_1602B rev 92.1"));                                // Revision  Version<<<<
  delay (2000);
  lcd.clear();
  lcd.print("GMT="); lcd.print(gmt);
  float vbatt = (float) analogRead(batt) / vref + .21; //
  lcd.setCursor(0, 1);
  lcd.print(F("Batterie:"));
  lcd.print(vbatt);
  lcd.print("V");
  delay (2000);
  lcd.clear();
  lcd.print(F("Odometre:"));
  lcd.print(Odometre);
  delay (2000);
  lcd.clear();
  lcd.print("WPLat:");
  lcd.print(wp_lat);
  lcd.setCursor(0, 1);
  lcd.print("WPLon:");
  lcd.print(wp_lon);
  delay (2000);
  lcd.clear();
  lcd.print("Last Time ON:");
  lcd.setCursor(0, 1);
  lcd.print(time_On / 60000); lcd.print("Min");
  delay (4000);


  /*lcd.clear();
    lcd.print("TIDE: ");
    lcd.print(Tide_one);
    float a = (float)Tide_one / 288;   //288 = 24hr * 60/ 5 min/hr)
    int tide_jr = (int)a;
    float b = (a - (float) tide_jr) * 24;
    tide_hr = (int)b;
    tide_min = (b - (float) tide_hr) * 60 ;
    lcd.setCursor(0, 1);
    lcd.print(tide_jr + 1);
    lcd.print("Days ");
    lcd.print(tide_hr);
    lcd.print(":");
    lcd.print(tide_min);
    delay(2000);
  */


  if (vbatt < 2.8)//volts
  {
    lcd.setCursor(0, 1); lcd.print("Batt. LOW!");
    delay (4000);
    //digitalWrite(power_pin, LOW); //off
  }
  analogWrite(LCD_LED, 20);

  ///////////////////////////////////////////////////////
  //                    GPS Reset                      //
  ///////////////////////////////////////////////////////
  lcd.clear();

  if (gps.encode(gpsSerial.read()))
  {
    lcd.print("GPS Reset");
    gpsSerial.write(gpsHot, sizeof(gpsHot));  gpsSerial.flush();
    gpsSerial.write( gpsDefault, sizeof( gpsDefault));  gpsSerial.flush();
    gpsSerial.write( Disable_GPDTM, sizeof( Disable_GPDTM));  gpsSerial.flush();
    gpsSerial.write( Disable_GPGBS, sizeof( Disable_GPGBS));  gpsSerial.flush();
    gpsSerial.write( Disable_GPGLL, sizeof( Disable_GPGLL));  gpsSerial.flush();
    gpsSerial.write( Disable_GPGRS, sizeof( Disable_GPGRS));  gpsSerial.flush();
    gpsSerial.write( Disable_GPGSA, sizeof( Disable_GPGSA));  gpsSerial.flush();
    gpsSerial.write( Disable_GPGSV, sizeof( Disable_GPGSV));  gpsSerial.flush();
    gpsSerial.write( Disable_GPVTG, sizeof( Disable_GPVTG));  gpsSerial.flush();
    gpsSerial.write( Disable_GPGGA, sizeof( Disable_GPGGA));  gpsSerial.flush();
  }
  lcd.setCursor(0, 1); lcd.println(F("Wait satellites."));
  ///////////////////////////////////////////////////////
  ///           create 8 custom characters            ///
  ///////////////////////////////////////////////////////
  for (nb = 0; nb < 8; nb++ )
  {
    for (bc = 0; bc < 8; bc++)
      bb[bc] = pgm_read_byte( &custom[nb][bc] );
    lcd.createChar ( nb + 1, bb );
  }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///                                    L O O P                                                             ///
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
  while (gpsSerial.available())                       // check for gps data
  {
    if (gps.encode(gpsSerial.read()))                 // encode gps data
    {
      gps.get_position(&lat, &lon);                   // get lat and long
      gps.crack_datetime(&year, &month, &day, &hour, &minute, &second);
      lat = lat / 100; //enlever les d-secondes
      lon = lon / 100;
      //     lcd.setCursor(0, 0); lcd.print (lat); lcd.print (" "); lcd.print (lon); delay (4000);
      hour = hour + gmt;
      if (hour > 128) //        reference a gmt
      {
        hour = hour + 24;
        day = day - 1;
      }
      ////Serial.print ("DofY=");//Serial.println (DofY (year,month,day,hour,minute));
      //Serial.print (year); //Serial.print ("/"); //Serial.print (month); //Serial.print ("/"); //Serial.print (day); //Serial.print (" "); //Serial.print (hour); //Serial.print (":"); //Serial.println (minute);
      Year_Min = DofY ((int)year, (int)month, (int)day, (int)hour, (int)minute);
      //Serial.print ("Year2min ="); //Serial.println (Year_Min);


      if (digitalRead(sw_sel) == LOW) {
        lcd.clear();
        while (digitalRead(sw_sel) == 0) {} //  wait for release
        menu(0);
      }
      if (digitalRead(sw_dwn) == LOW)
      {
        lcd.clear();
        while (digitalRead(sw_dwn) == 0) {} //  wait for release
        if (pro_mode == false)
        {
          lcd.clear();  lcd.print("PRO Display        ");
          delay (1500);
          pro_mode = true;
          EEPROM.write(4, pro_mode);
        }
        else
        {
          lcd.clear();  lcd.print("Dashboard MODE  ");
          pro_mode = false;
          EEPROM.write(4, pro_mode);
          delay (1500);
        }
        lcd.clear ();
      }
      ///////////////////////////////////////////////////////
      //           LCD LED  & test de batt                 //
      ///////////////////////////////////////////////////////
      float vsol = (float) analogRead(solPanel) / vref ; //    1024/2.5voltsRef
      if (eco_mode == true) {
        LCD_LED_N = 20;
      }
      else {
        LCD_LED_N = 150;
      }
      if (vsol > 1) {//volt
        vsol = 1;//volt
      }
      LCD_LED_N = LCD_LED_N - (vsol * LCD_LED_N);
      analogWrite(LCD_LED, LCD_LED_N);

      float vbatt = (float) analogRead(batt) / vref + .21; //    1024/5voltsRef
      if (vbatt < 2.8) // Volts  2.8
      {
        lcd.clear();  lcd.print("LOW BATT   ");
        lcd.setCursor(0, 1); lcd.print(vbatt); lcd.print("Volts");
        EEPROM.put(25, Odometre); //save odometre
        delay (5000);
        digitalWrite(power_pin, LOW);// power off
      }
      if (vbatt > 4.2) // Volts
      {
        analogWrite(LCD_LED, 255);
        digitalWrite(LED_BUILTIN, HIGH);
      }
      else
      {
        digitalWrite(LED_BUILTIN, LOW);
      }
      float speedf = gps.speed() * .01852;           // 1.852 /100  knot to kmph

      if (speedf < .5)
      {
        speedf = 0;
      }
      ///////////////////////////////////////////////////////
      ///                 ODOMETRE                        ///
      ///////////////////////////////////////////////////////
      if (cum_n >= 10)
      {
        if (lat2 == 0)
        {
          lat2 = lat;
          lon2 = lon;
        }
        cum_n = 0;
        float lon2_dec = lon2 / 10000.0;
        /////////////////////convert decimal degree into radian////////////////
        float lat1_Rad = lat / 10000.0 * rad2deg;
        float lon1_Rad = lon / 10000.0 * rad2deg;
        float lat2_Rad = lat2 / 10000.0 * rad2deg;
        float lon2_Rad = lon2 / 10000.0 * rad2deg;

        //Calculate the distance  KM
        float latSin = sin((lat1_Rad - lat2_Rad) / 2);
        float lonSin = sin((lon1_Rad - lon2_Rad) / 2);

        float P2P = 2 * asin(sqrt((latSin * latSin) + cos(lat1_Rad) * cos(lat2_Rad) * (lonSin * lonSin)));
        P2P = P2P * 6371;                      //Earth radius = 6,371 km

        if (P2P < 5 && speedf != 0)  // plus de 5 km est une erreur ou speed =0kmh
        {
          Odometre += P2P;
          lat2 = lat;
          lon2 = lon;
          EEPROM.put(25, Odometre);
          time_run = time_run + (millis() - time_old);
          
          EEPROM.put(30, millis()); //future reference
        }
        time_old = millis();
      }
      else
      {
        cum_n ++;
      }
      ///////////////////////////////////////////////////////
      //                 V I T E S S E                     //
      ///////////////////////////////////////////////////////

      dtostrf (speedf, 3, 1, msg) ;
      if (pro_mode == false)
      {
        writeBigString(msg, 0, 0);
        lcd.setCursor(7, 0); lcd.print ("KM    ");
        lcd.setCursor(7, 1); lcd.print ("/H    ");
        lcd.setCursor(10, 0);
        if (Odometre < 100)
        {
          dtostrf (Odometre, 1, 1, msg) ;
        }
        else
        {
          dtostrf (Odometre, 1, 0, msg) ;
        }
        lcd.print (msg); lcd.print ("KM   ");

        horloge (10, 1);
      }
      else
      {
        lcd.setCursor(0, 0);
        lcd.print(msg); lcd.print("KMH  ");//dtostrf (speedf, 3, 1, msg) ;
        Print_Azimut(8, 0);
        horloge(0, 1) ;
        ///////////////////////////////////////////////////////
        //          Display Fonction Variable                //
        ///////////////////////////////////////////////////////
        fonction++;
        switch (fonction / 3)
        {
          case 1:
            {
              Print_wpazimut(6, 1);
              EEPROM.put(30, millis());
            }
            break;
          case 4:
            {
              Print_Tide(6, 1);
            }
            break;
          case 2:
            {
              lcd.setCursor(6, 1);
              if (Odometre < 100)
              {
                dtostrf (Odometre, 1, 1, msg) ;
              }
              else
              {
                dtostrf (Odometre, 1, 0, msg) ;
              }
              lcd.print ("Od:"); lcd.print (msg); lcd.print ("KM   ");
            }
            break;
          case 3:
            {
              lcd.setCursor(6, 1);
              lcd.print ("Run:");
              if (time_run > 10000000L)//msec
              {
                lcd.print (time_run / 3600000L);//msec
                lcd.print ("Hr   ");
              }
              else
              { 
                lcd.print (time_run / 60000L);//msec
                lcd.print ("Min   ");
              }
            }
            break;
          default:
            {
              fonction = 2;
            }
            break;
        }
        ///////////////////////////////////////////////////////
        //                  eco  mode    
        //
        ///////////////////////////////////////////////////////
        if (eco_mode == true)
        {
          //char buffer[4]; //2del
          gpsSerial.write(gpsSleep, sizeof(gpsSleep));
          gpsSerial.flush();
          for (int n = 0; n < 6 ; n++)//Sec.
          {
            lcd.setCursor(15, 0); lcd.print (n);
            Print_Tide(6, 1);
            delay (1500);
            Print_wpazimut(6, 1);
            delay (1500);
            if (digitalRead(sw_sel) == 0)
            {
              lcd.clear ();
              while (digitalRead(sw_sel) == 0) {}; delay(10); // debounce
              menu(0);
            }
          }
          gpsSerial.write(gpsHot, sizeof(gpsHot));
          gpsSerial.flush();
          delay (2000); //
          //vinfo = 1;
        }
      }
    }
  }
}

///////////////////////////////////////////////////////
//                     MENU                          //
///////////////////////////////////////////////////////
static char* menu_items [] = {"Sel-UP-down", "Power OFF", "Lat-Long & WP ", "Power Moniteur",
                              "Eco Mode",  "GMT set  ", "TIDE set" , "Display Mode", "Odometre", "Retour", "Sel-up-DOWN"
                             };
void menu(int menu_index)
{
  lcd.clear();  lcd.print(menu_items[menu_index]);
  while (digitalRead(sw_sel) == LOW) {}; delay(5);             //Debounce
  while (digitalRead(sw_sel) != LOW)// Select
  {
    if (digitalRead(sw_up) == LOW)
    {
      lcd.clear();
      while (digitalRead(sw_up) == LOW) {}; delay(10);             //Debounce
      menu_index ++;
      if (menu_index > 8)
      {
        menu_index = 0;
      }
      lcd.clear();
      //lcd.setCursor(0, 0); lcd.print(menu_items[0]);
      lcd.setCursor(0, 1);
      lcd.print(menu_items[menu_index]);
    }
    if (digitalRead(sw_dwn) == LOW)
    {
      lcd.clear();
      while (digitalRead(sw_dwn) == LOW) {}; delay(10);               //Debounce
      menu_index -= 1;
      if (menu_index < 0)
      {
        menu_index = 8;
      }
      lcd.clear();
      lcd.print(menu_items[0]);
      lcd.setCursor(0, 1);
      lcd.print(menu_items[menu_index]);
    }
  }
  lcd.clear();
  while (digitalRead(sw_sel) == LOW) {}; delay(100);               //Debounce
  switch (menu_index)
  {
    case 1:
      ///////////////////////////////////////////////////////
      //          POWER OFF                                //
      ///////////////////////////////////////////////////////
      {
        lcd.clear();
        lcd.print ("POWER OFF....");
        delay (1500);
        digitalWrite(power_pin, LOW);
        delay (50);
        asm volatile ("  jmp 0");
      }
      break;
    case 2:
      ///////////////////////////////////////////////////////
      //          LAT et LONG MEMO                         //
      ///////////////////////////////////////////////////////
      {
        lcd.clear ();
        lcd.setCursor (0, 0);
        lcd.print("Push DWN to Save") ;
        lcd.setCursor (0, 1);
        lcd.print("WayPoint  ") ;
        delay (1000); lcd.clear ();
        while (digitalRead(sw_sel) != LOW)
        {
          Print_Latitude (0, 0);
          Print_Longitude (0, 1);
          if (digitalRead(sw_dwn) == LOW)
          {
            wp_lat  = lat;
            wp_lon  = lon;
            EEPROM.put(10, lat);
            EEPROM.put(15, lon);
            lcd.clear ();
            lcd.setCursor (0, 0);
            lcd.print("WayPoint SAVED") ;
            delay (1500);
            break;
          }
          if (digitalRead(sw_up) == LOW)
          {
            lcd.clear ();
            lcd.setCursor (0, 0);
            lcd.print("Push DWN to Save") ;
            while (digitalRead(sw_up) == LOW) {};
            delay(1000);
            lcd.clear ();
          }
          gps.get_position(&lat, &lon);
          lat = lat / 100; //enlever les d-secondes
          lon = lon / 100;
        }
        lcd.clear ();
        while (digitalRead(sw_sel) == LOW) {};
      }
      break;
    case 3:
      ///////////////////////////////////////////////////////
      //          POWER MONITOR batt sol                   //
      ///////////////////////////////////////////////////////
      {
        gpsSerial.write(gpsSleep, sizeof(gpsSleep));
        while (3)
        {
          float vsol = (float) analogRead(solPanel) / 204; //    1024/5voltsRef
          dtostrf (vsol, 3, 1, msg) ;
          lcd.setCursor(0, 0);
          lcd.print ("Solaire=");
          lcd.print (msg);
          lcd.print ("V ");
          float vbatt = (float) analogRead(batt) / vref + .21; //    1024/5voltsRef
          dtostrf (vbatt, 3, 1, msg) ;
          lcd.setCursor(0, 1);
          lcd.print ("Batterie=");
          lcd.print (msg); lcd.print ("V ");
          if ((vsol - vbatt) > .4)//volts
          {
            lcd.setCursor(12, 1); lcd.print ("V Charge ");
          }
          else
          {
            lcd.setCursor(12, 1); lcd.print ("V        ");
          }
          delay (1000);
          if (digitalRead(sw_sel) == LOW)
          {
            lcd.clear();
            while (digitalRead(sw_sel) == LOW) {}              ;
            gpsSerial.write(gpsHot, sizeof(gpsHot));
            return;
          }
          delay (1000);
        }
      }
      break;
    case 4:
      ///////////////////////////////////////////////////////
      ///               ECO MODE select                   ///
      ///////////////////////////////////////////////////////
      {
        if (eco_mode == false)
        {
          lcd.setCursor(0, 0); lcd.print("ECONO MODE ON    ");
          delay (1500);
          eco_mode = true;
          analogWrite(LCD_LED, 0);              // off lcd led
        }
        else
        {
          lcd.setCursor(0, 0); lcd.print("ECONO MODE OFF    ");
          eco_mode = false;
          delay (1500);
          analogWrite(LCD_LED, LCD_LED_N);              // off lcd led
        }
        lcd.clear ();
      }
      break;
    case 5:
      ///////////////////////////////////////////////////////
      //                     GMT                           //
      ///////////////////////////////////////////////////////
      {
        //gmt = 0;
        while (digitalRead(sw_sel) != LOW)
        {
          if (digitalRead(sw_up) == LOW)
          {
            lcd.clear ();
            while (digitalRead(sw_up) == LOW) {} ;
            gmt ++;
          }
          if (digitalRead(sw_dwn) == LOW)
          {
            lcd.clear ();
            while (digitalRead(sw_dwn) == LOW) {} ;
            gmt --;
          }
          lcd.clear();
          lcd.print ("GMT");
          lcd.print(gmt);
          delay (300);
        }
        lcd.clear ();
        while (digitalRead(sw_sel) == LOW) {} ;
        lcd.setCursor (0, 1);
        lcd.print ("SET GMT");
        lcd.print(gmt);
        EEPROM.write(0, gmt);
        delay(1000);
        return;
      }
      break;
    case 6:
      ///////////////////////////////////////////////////////
      //                     SET TIDE                      //
      ///////////////////////////////////////////////////////
      {
        //int tide_min, tide_hr;
        lcd.setCursor (0, 0);
        lcd.print ("Set ");
        lcd.setCursor (0, 1);
        lcd.print ("FullMoonHighTide");
        EEPROM.get(20, Tide_one);
        int tide_mth = 1;
        //float a = (float)Tide_one / 288;   //288 = 24hr * 60/ 5 min/hr)
        int tide_jr = 12;           //(int)a;
        //float b = (a - (float) tide_jr) * 24;
        int tide_hr = 7;                // (int)b;
        int tide_min = 45;              //(b - (float) tide_hr) * 60 ;

        ///////////////////////////////////////////////////////
        lcd.clear ();
        while (digitalRead(sw_sel) != LOW)
        {
          lcd.setCursor (0, 1);
          lcd.print (tide_mth); lcd.print("/");
          lcd.setCursor (3, 1); lcd.print(tide_jr); lcd.print(" ");
          lcd.setCursor (8, 1); lcd.print(tide_hr); lcd.print(":"); lcd.print(tide_min); lcd.print("  ");
          lcd.setCursor (0, 0)  ;
          lcd.print("v--Month  ");
          delay (350);
          if (digitalRead(sw_up) == LOW)
          {
            tide_mth ++;
          }
          if (digitalRead(sw_dwn) == LOW)
          {
            tide_mth --;
          }
        }
        ///////////////////////////////////////////////////////
        lcd.clear ();
        while (digitalRead(sw_sel) == LOW) {}; delay (100);
        while (digitalRead(sw_sel) != LOW)
        {
          lcd.setCursor (0, 1);
          lcd.print (tide_mth); lcd.print("/");
          lcd.setCursor (3, 1); lcd.print(tide_jr ); lcd.print(" ");
          lcd.setCursor (8, 1); lcd.print(tide_hr); lcd.print(":"); lcd.print(tide_min); lcd.print("  ");
          lcd.setCursor (3, 0);
          delay (350);
          lcd.print("v--Day  ");
          if (digitalRead(sw_up) == LOW)
          {
            tide_jr ++;
          }
          if (digitalRead(sw_dwn) == LOW)
          {
            tide_jr --;
          }
        }
        ///////////////////////////////////////////////////////

        lcd.clear ();
        while (digitalRead(sw_sel) == LOW) {}; delay (100);
        while (digitalRead(sw_sel) != LOW)
        {
          lcd.setCursor (0, 1);
          lcd.print (tide_mth); lcd.print("/");
          lcd.setCursor (3, 1); lcd.print(tide_jr ); lcd.print(" ");
          lcd.setCursor (8, 1); lcd.print(tide_hr); lcd.print(":"); lcd.print(tide_min); lcd.print("  ");
          lcd.setCursor (8, 0);
          lcd.print("v--Hr  ");
          delay (350);
          if (digitalRead(sw_up) == LOW)
          {
            tide_hr ++;
          }
          if (digitalRead(sw_dwn) == LOW)
          {
            tide_hr --;
          }
        }
        ///////////////////////////////////////////////////////
        lcd.clear ();
        while (digitalRead(sw_sel) == LOW) {}; delay (100);
        while (digitalRead(sw_sel) != LOW)
        {
          lcd.setCursor (0, 1);
          lcd.print (tide_mth); lcd.print("/");
          lcd.setCursor (3, 1); lcd.print(tide_jr ); lcd.print(" ");
          lcd.setCursor (8, 1); lcd.print(tide_hr); lcd.print(":"); lcd.print(tide_min); lcd.print("  ");
          lcd.setCursor (5, 0);
          lcd.print("Min--v  ");
          delay (350);
          if (digitalRead(sw_up) == LOW)
          {
            tide_min += 5;
          }
          if (digitalRead(sw_dwn) == LOW)
          {
            tide_min -= 5;
          }
          if (tide_min < 1) {
            tide_min = 1; // prevention 0/5
          }
        }
        lcd.clear ();
        while (digitalRead(sw_sel) == LOW) {}
        Tide_one =  DofY (year, tide_mth, tide_jr, tide_hr, tide_min);
        lcd.setCursor (0, 0);
        lcd.print ("Tide_one="); lcd.print (Tide_one); lcd.print ("  ");
        lcd.setCursor (0, 1);
        lcd.print (tide_mth); lcd.print("/"); lcd.print (tide_jr ); lcd.print (" "); lcd.print (tide_hr); lcd.print (":"); lcd.print (tide_min);
        delay (3500);
        while (digitalRead(sw_sel) == LOW) { }
        lcd.clear ();
        lcd.print ("Push Dwn to Save");
        while (digitalRead(sw_sel) != LOW)
        {
          if (digitalRead(sw_dwn) == LOW)
          {
            if (Tide_one > 0)
            {
              EEPROM.put(20, Tide_one);
              lcd.clear ();
              lcd.print ("TIDE SAVED");
              lcd.setCursor (0, 1);
              lcd.print (Tide_one);
              delay (2000);
              while (digitalRead(sw_dwn) == LOW) { }
              lcd.clear ();
              return;
            }
            else
            {
              lcd.clear ();
              lcd.print ("TIDE E R R O R");
              lcd.setCursor (0, 1);
              lcd.print (Tide_one);
              delay (2500);
              lcd.clear ();
              return;
            }
          }
          delay (50);
        }
        lcd.clear ();
        return;
      }
      break;
    case 7:
      ///////////////////////////////////////////////////////
      //                    PRO MODE                       //
      ///////////////////////////////////////////////////////
      {
        if (pro_mode == false)
        {
          lcd.clear();  lcd.print("PRO Display ");
          delay (1500);
          pro_mode = true;
          EEPROM.write(4, pro_mode);
        }
        else
        {
          lcd.clear();  lcd.print("Dashboard    ");
          pro_mode = false;
          EEPROM.write(4, pro_mode);
          delay (1500);
        }
        lcd.clear ();
      }
      break;
    case 8:
      ///////////////////////////////////////////////////////
      //                     ODOMETRE                      //
      ///////////////////////////////////////////////////////
      {
        Odometre = 0;
        time_run = 0;
        lat2 = lat;
        lon2 = lon;
        lcd.clear();  lcd.print("Odometre Reset");
        delay (1500); lcd.clear ();
      }
      break;
    default:
      {
      }
      return;
  }
}
/////////////////////////////////////////////////////////////////////////////////////
//                              SUBROUTINES                                        //
/////////////////////////////////////////////////////////////////////////////////////
// writeBigChar: writes big character 'ch' to column x, row y; returns number of columns used by 'ch'
int writeBigChar(char ch, byte x, byte y) {
  if (ch < ' ' || ch > '_') return 0;               // If outside table range, do nothing
  nb = 0;                                           // character byte counter
  for (bc = 0; bc < 8; bc++) {
    bb[bc] = pgm_read_byte( &bigChars[ch - ' '][bc] ); // read 8 bytes from PROGMEM
    if (bb[bc] != 0) nb++;
  }
  bc = 0;
  for (row = y; row < y + 2; row++) {
    for (col = x; col < x + nb / 2; col++ ) {
      lcd.setCursor(col, row);                      // move to position
      lcd.write(bb[bc++]);                          // write byte and increment to next
    }
  }
  return nb / 2 - 1;                                  // returns number of columns used by char
}
// writeBigString: writes out each letter of string
void writeBigString(char *str, byte x, byte y)
{
  char c;
  while ((c = *str++))
    x += writeBigChar(c, x, y) + 1;
}
///////////////////////////////////////////////////////
//                  HORLOGE                          //
///////////////////////////////////////////////////////
void horloge(int C, int R)
{
  lcd.setCursor(C, R);
  lcd.print(hour); lcd.print(":");
  if (minute < 10)
  {
    lcd.print("0");
  }
  lcd.print(minute);
  lcd.print(" ");
}
///////////////////////////////////////////////////////
//                    LATITUDE                       //
///////////////////////////////////////////////////////
void Print_Latitude(int C, int R)
{
  long latdeg = (lat / 10000);
  lcd.setCursor(C, R);
  lcd.print("Lat:");
  lcd.print(abs(latdeg));
  lcd.print((char)223);
  float x = (float)(lat - latdeg * 10000) * .6 / 100;
  lcd.print(x); lcd.print("'");
  if (lat > 0)
  {
    lcd.print ("N");
  }
  else
  {
    lcd.print("S");
  }
}
///////////////////////////////////////////////////////
//            PRINT  LONGITUDE                      //
///////////////////////////////////////////////////////
void Print_Longitude(int C, int R)
{
  long londeg = (lon / 10000);
  lcd.setCursor(C, R);
  lcd.print("Lon:");
  lcd.print(abs(londeg));
  lcd.print((char)223);
  float x = (float) (abs(lon) - abs(londeg) * 10000) * .6 / 100;
  lcd.print(x); lcd.print("'");
  if (lon > 0) {
    lcd.print("E");
  }
  else {
    lcd.print("W");
  }
}

///////////////////////////////////////////////////////
//               TIDE CLOCK display                  //
///////////////////////////////////////////////////////
void Print_Tide(int C, int R)
{
  EEPROM.get(20, Tide_one);
  const char*tideclock [] {"HIGH   ", "L 5Hr  ", "L 4Hr  ", "L 3Hr  ", "L 2Hr  ", "L 1Hr  ", "LOW    ", "H 5Hr  ", "H 4Hr  ", "H 3Hr  ", "H 2Hr  ", "H 1Hr  ", "HIGH   ", "ERR   "};
  //Serial.print ("y min="); //Serial.println (Year_Min);
  //Serial.print ("tide 1="); //Serial.println (Tide_one);
  long tide_cycle = (Year_Min - Tide_one);
  //Serial.print ("tide cycle="); //Serial.println (tide_cycle);
  float tide_cyclef = (float)tide_cycle / 745.233333f;        //Tide 12h25m14sec (745.23 min)
  dtostrf (tide_cyclef, 1, 6, msg) ;
  //Serial.print ("tide cyclef="); //Serial.println (msg);
  tide_cyclef = tide_cyclef - int(tide_cyclef);
  dtostrf (tide_cyclef, 1, 6, msg) ;
  //Serial.print ("tide cyclefraction="); //Serial.println (msg);
  tide_cyclef = tide_cyclef * 12;
  dtostrf (tide_cyclef, 1, 6, msg) ;
  tide_cycle = round (tide_cyclef);
  lcd.setCursor(C, R);
  lcd.print ("Tide:");
  lcd.print (tideclock[tide_cycle]);
  //; break;
...

This file has been truncated, please download it to see its full contents.

Custom parts and enclosures

YAK GPS Mk ii CASING

Schematics

circuit
yak_gps_sketch_2_nNy76yhBWV.fzz

Comments

Similar projects you might like

GPS Location Display With GPS And TFT Display Shields

Project tutorial by Boian Mitov

  • 10,817 views
  • 5 comments
  • 29 respects

Log GPS Information to MicorSD Card with Visuino

Project tutorial by Boian Mitov

  • 7,192 views
  • 9 comments
  • 29 respects

GPS Datalogger, Spatial Analysis, and Azure IoT Hub.

Project tutorial by Shawn Cruise

  • 18,280 views
  • 4 comments
  • 70 respects

Robot for supercool indoor navigation

Project tutorial by Team oblu

  • 14,508 views
  • 9 comments
  • 45 respects

GPS Tracking Using Helium, Azure IoT Hub, and Power BI

Project tutorial by Team Helium

  • 11,793 views
  • 17 comments
  • 34 respects
Add projectSign up / Login