Here is the code.
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include<SPI.h>
#include<Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
#define batteryPin A2
#define blueLedPin 7
#include <math.h>
#define R1 0.1006//measured res in Mohms
#define R2 0.0997//in Mohms
const float fact=((R2+((46.14*R1)/(46.14+R1)))/((46.14*R1)/(46.14+R1)));
char Buffer[15];
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
const double FOURTHPI = PI / 4;
const double deg2rad = PI / 180;
const double rad2deg = 180.0 / PI;
const double equrad = 6377563;
const double squecc = 0.00667054;
#define TFT_DC 8
#define TFT_CS 6
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, -1);
unsigned long long ms;
float acc;
float bat;
bool first=true, hasUpdate=false;
long easting=0, northing=0;
String GZ; //Grid Zone Designation
String SqID; //Square ID
String estText="";
String norText="";
String mgrsText="";
String statusText="";
String satText;
uint8_t GPSchar;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
void setup()
{
ss.begin(GPSBaud);
pinMode(batteryPin, INPUT);
pinMode(blueLedPin, INPUT);
tft.init(240, 320);
tft.setTextSize(4);
tft.setRotation(3);
tft.invertDisplay(false);
tft.fillScreen(tft.color565(0,0,0));
tft.setTextColor(ST77XX_WHITE);
tft.setCursor(0,0);
tft.println("GNSS Finder");
tft.setTextSize(2);
tft.println("");
tft.setTextSize(3);
tft.print("v1.0\n");
tft.setTextSize(4);
tft.print("\n\n\n\n");
tft.setTextSize(5);
tft.print("MCH170");
delay(1000);
tft.setTextColor(ST77XX_BLACK);
tft.setCursor(0,0);
tft.setTextSize(4);
tft.println("GNSS Finder");
tft.setTextSize(2);
tft.println("");
tft.setTextSize(3);
tft.print("v1.0\n");
tft.setTextSize(4);
tft.print("\n\n\n\n");
tft.setTextSize(5);
tft.print("MCH170");
}
void loop()
{
// This sketch displays information every time a new sentence is correctly encoded.
hasUpdate=false;
while (ss.available() > 0)
if (gps.encode(ss.read())){
ms=millis();
LLtoUTM(gps.location.lat(), gps.location.lng());
acc=30;
acc=gps.hdop.value()/100;
sprintf(Buffer, "EST: %.5ld", easting);
estText=Buffer;
sprintf(Buffer, "NOR: %.5ld", northing);
norText=Buffer;
mgrsText=GZ+" "+SqID+"\n";
if(digitalRead(blueLedPin)){
statusText="BAT: CRG ";
}else{
if(first){
//bat=analogRead(batteryPin)*3.3/1023*fact;
bat=0;
for(int k=0; k<20; k++){
bat+=analogRead(batteryPin);
delay(1);
}
bat=bat/20*3.13/1023*fact;
//bat=(b1+b2+b3+b4+b5)/5/1000/1023*fact;
if(bat>=4.18) statusText="BAT: 100% ";
else if(bat>=4.15) statusText="BAT: 95% ";
else if(bat>=4.11) statusText="BAT: 90% ";
else if(bat>=4.08) statusText="BAT: 85% ";
else if(bat>=4.03) statusText="BAT: 80% ";
else if(bat>=3.99) statusText="BAT: 75% ";
else if(bat>=3.95) statusText="BAT: 70% ";
else if(bat>=3.91) statusText="BAT: 65% ";
else if(bat>=3.87) statusText="BAT: 60% ";
else if(bat>=3.84) statusText="BAT: 55% ";
else if(bat>=3.82) statusText="BAT: 50% ";
else if(bat>=3.80) statusText="BAT: 45% ";
else if(bat>=3.78) statusText="BAT: 40% ";
else if(bat>=3.75) statusText="BAT: 35% ";
else if(bat>=3.72) statusText="BAT: 30% ";
else if(bat>=3.68) statusText="BAT: 25% ";
else if(bat>=3.64) statusText="BAT: 20% ";
else if(bat>=3.60) statusText="BAT: 15% ";
else if(bat>=3.55) statusText="BAT: 10% ";
else if(bat>=3.50) statusText="BAT: 5% ";
else statusText="BAT: LOW ";
}else{
statusText="BAT: --- ";
}
}
if(!first)tft.fillScreen(tft.color565(0,0,0));
first=false;
tft.setCursor(0,0);
tft.setTextColor(tft.color565(255,255,255));
tft.setTextSize(5);
tft.println(estText);
tft.setTextSize(3);
tft.println(" ");
tft.setTextSize(5);
tft.println(norText);
tft.setTextSize(4);
tft.println(" ");
tft.setTextSize(4);
tft.println(mgrsText);
tft.print(statusText);
if(acc<=2.5 && gps.location.isValid()){
tft.setTextColor(tft.color565(0,170,0));
}else{
if(acc<=8 && gps.location.isValid()){
tft.setTextColor(tft.color565(255,189,23));
}else{
tft.setTextColor(tft.color565(227,14,14));
}
}
tft.print("ACC");
while(millis()-ms<=300000 && !hasUpdate){
GPSchar = ss.read();
gps.encode(GPSchar);
if(gps.location.isUpdated() && millis()-ms>=120000){
hasUpdate=true;
}
};
}}
String LLtoUTM(const double Lat, const double Long)
{
double a = 6378137;
double eccSquared = 0.00669438; //WGS-84, 6378137, 0.00669438
double k0 = 0.9996;
double LongOrigin;
double eccPrimeSquared;
double N, T, C, A, M;
double UTMEasting;
double UTMNorthing;
//Make sure the longitude is between -180.00 .. 179.9
double LongTemp = (Long+180)-int((Long+180)/360)*360-180; // -180.00 .. 179.9;
double LatRad = Lat*deg2rad;
double LongRad = LongTemp*deg2rad;
double LongOriginRad;
int ZoneNumber;
ZoneNumber = int((LongTemp + 180)/6) + 1;
if( Lat >= 56.0 && Lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0 )
ZoneNumber = 32;
// Special zones for Svalbard
if( Lat >= 72.0 && Lat < 84.0 )
{
if( LongTemp >= 0.0 && LongTemp < 9.0 ) ZoneNumber = 31;
else if( LongTemp >= 9.0 && LongTemp < 21.0 ) ZoneNumber = 33;
else if( LongTemp >= 21.0 && LongTemp < 33.0 ) ZoneNumber = 35;
else if( LongTemp >= 33.0 && LongTemp < 42.0 ) ZoneNumber = 37;
}
LongOrigin = (ZoneNumber - 1)*6 - 180 + 3; //+3 puts origin in middle of zone
LongOriginRad = LongOrigin * deg2rad;
//compute the UTM Zone from the latitude and longitude
eccPrimeSquared = (eccSquared)/(1-eccSquared);
N = a/sqrt(1-eccSquared*sin(LatRad)*sin(LatRad));
T = tan(LatRad)*tan(LatRad);
C = eccPrimeSquared*cos(LatRad)*cos(LatRad);
A = cos(LatRad)*(LongRad-LongOriginRad);
M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64 - 5*eccSquared*eccSquared*eccSquared/256)*LatRad
- (3*eccSquared/8 + 3*eccSquared*eccSquared/32 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatRad)
+ (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatRad)
- (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatRad));
UTMEasting = (double)(k0*N*(A+(1-T+C)*A*A*A/6
+ (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120)
+ 500000.0);
UTMNorthing = (double)(k0*(M+N*tan(LatRad)*(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
+ (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720)));
if(Lat < 0)
UTMNorthing += 10000000.0; //10000000 meter offset for southern hemisphere
//Preparation of MGRS 100km chars
String UTMTwo = MGRSZoneDesignator(UTMEasting, UTMNorthing);
int corrE = UTMEasting / 100000; //Correction from UTM to MGRS -> cutting first number
UTMEasting = UTMEasting - (corrE * 100000);
int corrN = UTMNorthing / 100000; //Correction from UTM to MGRS -> cutting first two numbers
UTMNorthing = UTMNorthing - (corrN * 100000);
//Preparation to output
String toUTM = String(ZoneNumber);
toUTM += UTMLetterDesignator(Lat);
GZ=toUTM;
toUTM += " ";
toUTM += UTMTwo;
SqID=UTMTwo;
toUTM += " E:";
toUTM += UTMEasting;
easting=UTMEasting;
toUTM += " N:";
toUTM += UTMNorthing;
northing=UTMNorthing;
return toUTM;
}
String MGRSZoneDesignator(double UTMEasting, double UTMNorthing)
{
String e100kLetters[] = {"S","T","U","V","W","X","Y","Z"};
String n100kLetters[] = {"F","G","H","J","K","L","M","N","P","Q","R","S","T","U","V","A","B","C","D","E"};
const int col = floor(UTMEasting /100000); //Cutting first number. Upside is more info
const int row = int(floor(UTMNorthing /100000))%20; //Cutting first two numbers. Upside is more info
String ZoneDesignator = e100kLetters[col-1];
ZoneDesignator += n100kLetters[row];
return ZoneDesignator;
}
char UTMLetterDesignator(double Lat)
{
//Written by Chuck Gantz- chuck.gantz@globalstar.com
char LetterDesignator;
if((84 >= Lat) && (Lat >= 72)) LetterDesignator = 'X';
else if((72 > Lat) && (Lat >= 64)) LetterDesignator = 'W';
else if((64 > Lat) && (Lat >= 56)) LetterDesignator = 'V';
else if((56 > Lat) && (Lat >= 48)) LetterDesignator = 'U';
else if((48 > Lat) && (Lat >= 40)) LetterDesignator = 'T';
else if((40 > Lat) && (Lat >= 32)) LetterDesignator = 'S';
else if((32 > Lat) && (Lat >= 24)) LetterDesignator = 'R';
else if((24 > Lat) && (Lat >= 16)) LetterDesignator = 'Q';
else if((16 > Lat) && (Lat >= 8)) LetterDesignator = 'P';
else if(( 8 > Lat) && (Lat >= 0)) LetterDesignator = 'N';
else if(( 0 > Lat) && (Lat >= -8)) LetterDesignator = 'M';
else if((-8> Lat) && (Lat >= -16)) LetterDesignator = 'L';
else if((-16 > Lat) && (Lat >= -24)) LetterDesignator = 'K';
else if((-24 > Lat) && (Lat >= -32)) LetterDesignator = 'J';
else if((-32 > Lat) && (Lat >= -40)) LetterDesignator = 'H';
else if((-40 > Lat) && (Lat >= -48)) LetterDesignator = 'G';
else if((-48 > Lat) && (Lat >= -56)) LetterDesignator = 'F';
else if((-56 > Lat) && (Lat >= -64)) LetterDesignator = 'E';
else if((-64 > Lat) && (Lat >= -72)) LetterDesignator = 'D';
else if((-72 > Lat) && (Lat >= -80)) LetterDesignator = 'C';
else LetterDesignator = 'Z'; //This is here as an error flag to show that the Latitude is outside the UTM limits
return LetterDesignator;
}
unsigned int readVcc(void) {
unsigned int result;
// set the reference to Vcc and the measurement to the internal 1.1V reference
ADMUX = (1 << REFS0) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= (1 << ADSC); // Start conversion
while (bit_is_set(ADCSRA, ADSC)); // wait until done
result = ADC;
// two readings are better than one
ADCSRA |= (1 << ADSC); // Start conversion
while (bit_is_set(ADCSRA, ADSC)); // wait until done
result = ADC;
// calibrated for Miniduino board
result = 1098700UL / (unsigned long)result; //1126400 = 1.1*1024*1000
return result; // Vcc in millivolts
}
And here is the schematic (never drew one for other people so any feedback is welcome😉)