This is only a preview of the October 2024 issue of Practical Electronics. You can view 0 of the 80 pages in the full issue. Articles in this series:
Articles in this series:
Articles in this series:
Articles in this series:
Articles in this series:
Articles in this series:
Articles in this series:
|
Teach-In 2024
Learn electronics with
the ESP32 by Mike Tooley
Part 8 – Where Am I? (GNSS)
I
n the last part of our Teach-In series, we showed
how an ESP32 can use an NTP (network time protocol)
server to obtain the current time very accurately. Our
Practical Project was an accurate digital clock displayed on a
low-cost 16 × 2 LCD panel, and our Coding Workshop introduced arrays and structures.
In this instalment, we explore the use of low-cost GNSS/
GPS modules as a means of providing location and time data,
possibly for navigation purposes.
The learning objectives for the eighth part of our series are
to know how to:
n interface with a low-cost GNSS/GPS module
n decode and interpret data received from GNSS satellites
n use satellite data to determine the precise UTC time
n create user-defined functions
The Global Positioning System (GPS) and GNSS
Originally developed for use by the US military, and known as
Navstar (navigation system with timing and ranging), the global
positioning system (GPS) was first used in 1978. However,
the full constellation of satellites was not in place and fully
operational until 1994.
GPS is now widely available for use in many applications
including ship, ground vehicle and aircraft navigation.
GPS works by triangulating the distances from several satellites. A minimum of three satellites is required for a GPS receiver to calculate a unique lateral position, while four or more
provide additional altitude information (a three-dimensional
position fix).
GPS requires a highly accurate time reference. This is provided by atomic clocks in the GPS ground control stations and
the satellites themselves. Because of its global accessibility,
GPS has now become extremely popular as a source of highly
accurate time information.
GPS satellites circle the earth in medium Earth orbit (MEO),
at an altitude of approximately 20,200km (12,550 miles). The
baseline satellite constellation has 24 satellites in six earthcentred orbital planes. The system can support a constellation
of up to thirty satellites in orbit for increased reliability.
The satellites in the GPS constellation are arranged into
six equally-spaced orbital planes with four slots each. This
ensures that GPS receivers are always within view of at least
four baseline satellites.
Individual satellites broadcast their signals on several
frequencies in L-band. The three frequencies used by civilian GPS satellites are 1575.42MHz (L1), 1227.60MHz (L2) and
1176.45MHz (L5).
68
About Teach-In
Our latest Teach-In series is about using the popular ESP32
module as a basis for learning electronics and coding. We
will be making no assumptions about your coding ability
or your previous experience of electronics. If you know one
but not the other, you have come to the right place. On
the other hand, if you happen to be a complete newbie
there’s no need to worry because the series will take a
progressive hands-on approach. There will be plenty of
time to build up your knowledge and plenty of opportunity
to test things out along the way.
We’ve not included too much basic theory because this
can be easily found elsewhere, including several of our
previous Teach-In series, see:
https://bit.ly/pe-ti
https://bit.ly/pe-ti-bundle
Each month, there’ll be projects and challenges to help you
check and develop your understanding of the topics covered.
To improve the accuracy and resolution, a network of groundbased stations sends correction data to GPS satellites. Such
systems include Wide Area Augmentation System (WAAS) in
North America and EGNOS (European Geostationary Navigation
Overlay Service) in Europe.
The signals transmitted by different GPS satellites use a
pseudo-random code comprising a sequence of 1023 binary
1s and 0s. These sequences are modulated using binary phaseshift keying (BPSK).
The resulting modulated signal occupies a significant amount
of spectrum space, and a GPS receiver employs a circuit known
as a ‘correlator’ to recover the original narrowband data from
the received signal.
In practice, several correlators can be present and operating
at the same time. This can significantly reduce the time taken to
obtain an initial position fix (TTFF), with different correlators
operating on signals from different satellites.
In effect, each of these correlators can be acting on a different
information ‘channel’. Modern GPS units can use as many as 50
different channels, but typically no more than about a dozen,
or so will be in use at any time.
Transient data transmitted by GPS satellites is referred to as
“ephemeris data”. It provides information about their current
(and predicted) location, timing and status. Ephemeris data can
also be used to predict future satellite conditions at a specified
location and time.
These days, GPS is not the only satellite navigation system.
There is also Galileo (EU), GLONASS (Russia), BeiDou (China)
Practical Electronics | October | 2024
Sentence type
Information content
GPGGA
Time, position and fix type data
GPGLL
Latitude, longitude, UTC time and status
GPGSA
GPS receiver operating mode, number of
satellites used in the position solution and
DOP values
GPGSV
Number of satellites in view, satellite IDs,
elevation, azimuth and signal-to-noise ratio
(SNR)
GPMSS
SNR, signal strength, frequency and bit rate
from radio-beacon receiver
GPRMC
Time, date, position, course and speed
GPVTG
Course and speed relative to the ground
GPZDA
PPS timing message (synchronized to PPS)
and some regional systems. Many modern ‘GPS’ receivers can
also use some or all of those other systems. With GPS, collectively
they are known as Global Navigation Satellite Systems or GNSS.
GNSS data
The data from a GPS/GNSS receiver is a series of ASCII characters, arranged in a format defined by the National Marine
Electronics Association (NMEA), so they are referred to as
“NMEA sentences”.
Several different types of NMEA sentence are produced by
receivers. The use of standard ASCII characters makes it possible to receive navigation data using common data interfaces
like RS-232, USB, Bluetooth or Wi-Fi. Since not all the received
NMEA sentences will be relevant in a particular application, we
can ignore those that we are not interested in and concentrate
on the sentences containing the data we need.
To do this, we need to recognise the type of sentence before
decoding the data contained in it. Luckily, we don’t need to
write our own code to do this, as there are some excellent
libraries available to perform this task for us.
For normal positioning application, the two most-used NMEA
sentences are GPGGA and GPRMC (see Table 8.1). These carry
GNSS fix data and time, date, position, course and speed data
respectively. Note that in some more complex GPS equipment
GPGGA is replaced by GNGGA which includes navigation data
from multiple global navigation satellite sources (often both
GPS and GLONASS satellites). A more complete list of NMEA
messages is shown in Table 8.1.
Antennas
GNSS receivers require an antenna to collect signals from
GNSS satellites. Since the wavelength is relatively short (approximately 20cm), the antennas can be quite compact. Some
GNSS patch antennas can be as small as 1.5×1.5cm, making
them ideal for situations where the antenna is mounted on a
flat surface, like the windscreen, roof or dashboard of a car.
When mounted on a large ground plane (eg, a car roof), patch
antennas can exhibit relatively large gain values. This, coupled
with their relatively low profile, makes them ideal for use in
vehicle, aircraft and most portable applications.
Small PCB-mounted chip antennas are popular in low-cost
applications where space is paramount. Small helical antennas are also found on some equipment. They are particularly
suitable for applications when the orientation is unpredictable
or a robust external antenna is needed.
NMEA sentences
GNSS data is sent as a series of sentences. Here’s an example
of a typical NMEA GPGGA sentence:
$GPGGA,083258.000,5101.4028,N,00026.9145,
W,1,09,1.3,35.8,M,47.1,M,,0000*7B
Let’s parse this into some useful data. The first thing we
should notice is that the sentence header ($GPGGA) tells us
this sentence contains time, position and fix data. From this
data we can extract latitude and longitude, as well as a variety
of other useful data shown in Table 8.2.
Table 8.2 – Example of the data in a typical NMEA sentence
Name
Value
Message ID
$GPGGA
Time (UTC)
083258.000
hhmmss.sss
Latitude
5101.4028
ddmm.mmmm
N/S Indicator
N
N = north, S = south
Longitude
00026.9145
ddmm.mmmm
E/W indicator
W
E = east, W = west
Position Fix Indicator
1
0=Fix not available or invalid;
1=GPS (SPS mode) fix valid;
2=Differential GPS (SPS mode) fix valid
Satellites used
9
0 to 12
HDOP
1.3
Horizontal dilution of precision
Altitude (relative to MSL)
35.8
MSL = mean sea level
Units
M
Geoid separation
47.1
Units
M
metres
Age of diff. corr.
0
second
Diff. ref. Station ID
0000
Checksum
*7B
Terminator
<CR><LF>
Practical Electronics | October | 2024
Format/units
Note
GGA protocol header
metres
Only valid when DGPS is used
Check for errors
End of message
69
Gotcha!
Different startup times are quoted for GPS units depending
on whether they are started from cold, warm or hot. A cold
start is a restart of a unit after a long period of being powered
off. A warm start assumes that ephemeris data is still present
and available. A hot start is when the previously received
satellite constellation is unchanged from last time, so a fix
can be quickly obtained. This is why you sometimes have
to wait a while for GPS data to become available.
Fig.8.1: Robert Larsson’s excellent online GPRMC and GPGGA
sentence decoder.
You can use an online service to decode the NMEA sentence.
The author’s favourite online parser is https://rl.se/gprmc (see
Fig.8.1).
Location fixing and accuracy
A GNSS unit will attempt to fix its location continuously.
The rate at which this occurs is referred to as the “update
rate”. The standard for most GNSS modules is one update
per second (ie, an update frequency of 1Hz).
This is adequate for many applications, but faster rates
are essential for applications involving aircraft and other
fast-moving vehicles. Some modules default to 1Hz but can
be configured for, say, 10Hz. Faster update rates will require
speedier processing of NMEA sentences.
Several sources of error can affect the GNSS fix. Some
errors are introduced by signals received from multiple
paths. These can be due to reflections from buildings and
other large structures, as well as natural objects such as
cliffs and rocky outcrops.
Others can be caused by unwanted ionospheric and tropospheric effects. All these factors can affect the time taken
for satellite signals to arrive at a GNSS receiver.
The combination of errors introduced when the GNSS
receiver calculates a position are expressed in terms of
dilution of precision (DOP). The DOP depends
on the positions of the GNSS satellites relative to the location of the receiver.
Since the position of the satellites is known, it is possible
to estimate the accuracy of a GNSS position fix. The DOP
calculation uses both the position and number of satellites
available. Since Navstar satellites constantly change position their number and position vary, the DOP will also
change continuosly.
To make things a little more complicated, the DOP can be
divided into vertical and horizontal components (VDOP and
HDOP, respectively). Lower values of VDOP and HDOP are
associated with more accurate indications. For land- and
sea-based operation, HDOP is usually more important.
The conclusion from all of this is that DOP provides you
with a valuable indicator of how much confidence you can
place on a particular GNSS location fix.
With lower DOP values your results are likely to be much
better than when higher values of DOP are prevalent. You
can reduce DOP and improve a GNSS unit’s positional accuracy by one or more of the following:
1. Placing the antenna of your GNSS receiver (or the
complete unit if it has an integrated antenna) so it has
a clear and unobstructed view of the full sky. This
increases the number of satellites in view and gives
the most favourable satellite geometry.
2. Arranging the antenna of your GNSS unit so it is not
susceptible to signals reflected from buildings, aircraft
and other large structures.
3. Allowing your GNSS to average position over a reasonably long period (eg, several minutes). If you can’t,
check on the DOP values returned by the GNSS unit,
placing more confidence on the data when the lowest
values of HDOP (or VDOP) are indicated.
GNSS Modules
The advent of low-cost widely available GNSS receiver
modules, such as the one shown in Fig.8.2, has made it
possible to add some exciting features to a huge range of
microcontroller applications.
Fig.8.2: A low-cost GPS module
based on the NEO-6M chip from
Swiss company u-blox.
Gotcha!
The time taken to obtain an initial position (TTFF) while
waiting for a GPS module to return data is a key performance
indicator of a GPS unit. Since the unit needs to receive
signals from as many satellites as possible, the TTFF can be
significantly degraded when it is not optimally positioned
(eg, indoors) or used in a different location than last time.
70
Fig.8.3: A block diagram of the GPS module shown in Fig.8.2.
Practical Electronics | October | 2024
Fig.8.4: The layout of the GPS module board.
For example, they can be used to record accurate position
information so that objects can be tracked. Not only is it
possible to provide a location fix, but even obtain values
for altitude, speed, bearing, distance and time. This can
literally add a completely new dimension (or three) to your
ESP32 applications!
GNSS modules usually comprise a GNSS receiver chip
and GNSS antenna (or a connector for an external active
antenna), together with the necessary serial interfacing logic
(eg, a UART) and power-conditioning circuitry.
They are available at low cost from suppliers in the UK,
USA and Asia. GNSS modules usually operate from a +5V
or +3.3V DC supply and employ a serial data interface to
transfer information to a computer or microcontroller. This
interface usually operates at quite low baud rates, typically
4800 or 9600 bits per second.
The low-cost module shown in Fig.8.2 is based on the
popular NEO-6M GNSS receiver chip. It is usually supplied
with a matching active antenna measuring a mere 25×25mm.
The matching antenna requires mounting on an external
surface with a clear and unobstructed view of the sky.
The module incorporates one LED that flashes continuously when a position fix is obtained. It uses a standard TTL
serial connection so interfacing with an ESP32 (or another
popular microcontroller) is extremely straightforward.
The functional arrangement and board layout for a typical
low-cost GNSS module are shown in Fig.8.3 & 8.4.
These modules are usually supplied with a 4-way header
that can be soldered in place. Its specifications are shown
in Table 8.3.
Table 8.3 – Typical specifications for a low-cost GPS module
Parameter
Specification
Supply voltage range
3.3 to 6V (onboard 3.3V regulator)
Supply current
35mA (11mA in power saving mode)
Maximum I/O voltage
3.6V
Baud rate
4800 to 115,200bps (default 9600)
Operating frequency
1.57542GHz (L1)
Sensitivity
-156dBm (hot start)
Time to first fix (TTFF)
<1s for hot start, ~27s for cold start
Update rate
10Hz maximum (1Hz default)
Number of channels
Up to 50
Positional accuracy
2m (or better) achievable
Velocity accuracy
Typically within 0.1m/s
Maximum velocity
500m/s
Heading accuracy
0.5° achievable whilst in motion
Memory
Battery-backed EEPROM
Practical Electronics | October | 2024
Fig.8.5: Interfacing a low-cost GPS module to an ESP32
development board only requires five wires.
Checking it out
It’s time to get to grips with GPS! All you need is the simple
four-wire connection from the ESP32 development board to
a low-cost GPS module, as shown in Figs.8.5 & 8.6.
When you’ve completed the wiring, we suggest you jump
right in by downloading, compiling and executing Listing
8.1. The code can be downloaded from the PE website by
going to https://pemag.au/link/abyr
Listing 8.1 – Using the TinyGPS library to decode NMEA
sentences (code extract only)
/* Print TinyGPS data using the Serial Monitor. Uses code
developed by Mikal Hart (see TinyGPS documentation) */
#include <SoftwareSerial.h> // EspSoftwareSerial library
#include <TinyGPS.h>
// Mikal Hart's TinyGPS library
TinyGPS gps;
SoftwareSerial ss(16, 17);
// TX and RX serial pins
static void smartdelay(unsigned long ms);
static void print_float(float val, float invalid,
int len, int prec);
static void print_int(unsigned long val,
unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);
void setup()
{
// The setup code is here
}
void loop()
{
// The code for the main loop is here
}
Fig.8.6: A breadboard layout matching Fig.8.5.
71
When you execute the code in Listing
8.1, you will find that it generates and
continuously updates a table of values like
that shown in Fig.8.7. The data is decoded
for successive NMEA $GPGGA sentences,
and may at first sight appear baffling. To
make it easier to understand, we’ve added
columns (in red) and headings to the figure.
Using GPS data
Now here are a few pointers that might
help you develop your own ESP32 code
to be used with a GPS module. To begin,
you might need to include one or more
of the following libraries:
Fig.8.7: Typical $GPGGA NMEA data in the Serial Monitor, produced by Listing 8.1.
The somewhat tedious problem of converting NMEA format GPS data into variables that you can use in your code
is handled very capably by Mikal Hart’s excellent TinyGPS
and TinyGPS++ libraries.
This useful library package handles the parsing and
conversion of NMEA data and also includes several useful methods and functions that allow you to process and
present data in different ways. The TinyGPS library can be
downloaded and installed using the IDE’s Library Manager.
To include the TinyGPS library, use:
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
#include <TinyGPS.h>
The next few fragments of code will give you an idea of
how data from a GPS module can be handled. For further
information, refer to the full code for Listing 8.1 or the
examples included with the TinyGPS library.
Display the number of satellites being received using the
IDE’s serial monitor:
Serial.print("Satellites: ");
Serial.println(gps.satellites());
... or on an LCD screen:
#include <TinyGPS.h>
Listing 8.1 creates a TinyGPS object (we’ve used the rather
obvious title, gps) using:
lcd.print("Satellites: ");
lcd.print(gps.satellites());
Display the HDOP using the serial monitor:
TinyGPS gps;
Serial.print("HDOP: ");
Serial.println(gps.hdop());
While it is possible to create multiple TinyGPS objects,
you will probably not need to do that. A single TinyGPS
Display the HDOP on an LCD screen:
object will suffice for this and most other applications.
The low-cost GPS module uses a serial interface to comlcd.print("HDOP: ");
municate with the ESP32, so the code includes the ESP
lcd.print(gps.hdop());
SoftwareSerial library. It can also be obtained from the IDE’s
Library Manager (make sure that you download and install
Display the number of characters and sentences received
the ESP32 version of this library).
The serial I/O provided by the GPS module connects di- using the IDE’s serial monitor:
rectly to the RX2 and TX2 pins of the ESP32 development
// First we need the statistics to display
board (see Fig.8.5). These pins correspond to I/O pins D16
unsigned long chars = 0;
and D17, respectively, so those are the pin numbers that
unsigned short sentences = 0, failed = 0;
need to be referenced in your code:
SoftwareSerial ss(16, 17);
// TX and RX serial pins
Each byte present in a received NMEA sentence is handled
by the TinyGPS encode() method, using SoftwareSerial to obtain
data from the GPS module one character at a time. This process
continues as long as valid data is available:
void loop() {
while (ss.available())
{
int c = ss.read();
if (gps.encode(c)) // Valid?
{
// New GPS data is processed here
}
}
}
72
gps.stats(&chars, &sentences, &failed);
// Then we send them to the serial monitor
Serial.print("Characters: ");
Serial.println(chars);
Serial.print("Sentences: ");
Serial.println(sentences);
Display the number of characters and sentences received
on an LCD screen:
Gotcha!
The TX and RX signals of the serial GPS interface must be
cross-connected so that TX for the GPS module is taken to
RX2 (D16) on the ESP32 while RX on the GPS module is
connected to TX2 (D17) on the ESP32.
Practical Electronics | October | 2024
Gotcha!
When you’ve uploaded your code and the ESP32 has reset,
the LCD panel will remain blank until the GPS module starts
reporting data. This may take several minutes from a cold
start and up to a minute following a hot start. Once the unit
has acquired a position fix, the module will blink the onboard
LED and the LCD should show information (see Fig.8.11).
// First we need the statistics to display
unsigned long chars = 0;
unsigned short sentences = 0, failed = 0;
gps.stats(&chars, &sentences, &failed);
// Send the # of characters to the first
// line of the LCD display
lcd.setCursor(0,0);
lcd.print("Characters: ");
lcd.print(chars);
// Send the # of sentences to the second
// line of the LCD display
lcd.setCursor(0,1);
lcd.print("Sentences: ");
lcd.print(sentences);
Fig.8.8: Some date and time data provided by Listing 8.2.
Fig.8.9: The interconnections for the GPS location fixer.
Telling the time (again)
In Part 7 of Teach-In, we showed how the ESP32 could be
This uses the same interface and wiring arrangement that
configured for use as an accurate clock using an NTP time we described earlier, in Figs.8.5 and 8.6, and the code is
server. We’ll now look at an alternative technique for obtain- shown in Listing 8.2. The output from the Serial Monitor
ing date and time information using GNSS.
is shown in Fig.8.8.
Listing 8.2 – Extracting GPS data and time information
/* GPS time/date displayed using the ESP32's Serial Monitor */
#include <TinyGPS++.h> // The GPS library file
#define GPSbaud 9600
// Set GPS baud rate
TinyGPSPlus gps;
// The GPS object
void setup() {
// Confirm connection
Serial.begin(115200);
Serial2.begin(GPSbaud);
Serial.println(F("ESP32 GPS data"));
delay(2000);
}
void loop() {
if (Serial2.available() > 0) {
// Check serial port
if (gps.encode(Serial2.read())) { // Read the data
if (gps.location.isValid()) {
// Check if valid
if (gps.date.isValid() && gps.time.isValid()) {
Serial.print(F("GPS Date/Time: "));
Serial.print(gps.date.day());
Serial.print(F("-"));
Serial.print(gps.date.month());
Serial.print(F("-"));
Serial.print(gps.date.year());
Serial.print(F(" "));
Serial.print(gps.time.hour());
Serial.print(F(":"));
Serial.print(gps.time.minute());
Serial.print(F(":"));
Serial.println(gps.time.second());
} else {
Serial.println(F("Data invalid!"));
}
Serial.println(); // Blank line for spacing
}
}
Practical Project
Our Practical Project involves the construction of a
simple GPS location fixer using an ESP32 development
board, low-cost GPS module, and a 20×4 LCD screen.
The required interconnections and wiring are shown in
Figs.8.9 and 8.10.
The 20-character, four-line display is like those used
previously in this Teach-In series and, as before, it employs
an I2C interfaced to minimise wiring and avoid the use of
multiple digital I/O lines.
The I2C interface is usually supplied together with the
display, and either already soldered in place or comes with
a suitable header for interconnection.
The complete code listing for the GPS location fixer is
shown in Listing 8.3. The code uses the following libraries: LCD.h, LiquidCrystal_I2C.h, SoftwareSerial.h and
TinyGPS.h.
Before finalising your code, you will need to determine
the I2C address of your display.
Often this will be 0x27 (ie,
hexadecimal 27 or decimal
39). You can determine
it by running the I2C
if (millis() > 5000 && gps.charsProcessed() < 10)
Serial.println(F("Error - GPS data unavailable!"));
}
}
Practical Electronics | October | 2024
Fig.8.10: The wiring layout for the GPS location fixer.
73
Scanner application provided in Listing 5.3 (available for
download from the PE website at https://pemag.au/link/abys).
Listing 8.3 – Complete code listing for the GPS location fixer
Coding workshop
/* ESP32 GPS data displayed on an 20x4 LCD panel */
Our Teach-In code examples and listings have made liberal use of functions, so you will know that a function
is simply a block of code that’s been given a name and
incorporates statements that will be executed when the
function is called.
Functions are a great way to perform repetitive tasks.
They help to minimise and simplify your code, making it
easier to understand and re-use.
All of our full code listings have included the two most
fundamental functions, setup() and loop(). If you’ve been
wondering about the void prefix, it just indicates that the
function does not return a value directly.
If a function returns a value, the function definition needs
to begin by indicating the type returned (eg, int). The standard format for a function declaration is thus:
type functionName(parameters) {
statement1;
statement2;
statement3;
etc.
return value;
}
Note how the list of function statements is enclosed in
curly braces and each statement ends with a semicolon.
The parameters that follow a function name enclosed in
brackets (parenthese) will be passed to the function. If there
are none, the brackets are simply left empty.
Here’s an example of a function with a void type that
doesn’t return anything:
void checkLevel() {
if (tankFull == 1) {
Serial.println("Warning - tank full!");
} else {
Serial.println("Filling, please wait");
}
}
While void functions can still do useful work, you can’t
use them within expressions, because they don’t evaluate
to anything.
#include <TinyGPS++.h> // The GPS library file
#define GPSbaud 9600
// Set GPS baud rate
TinyGPSPlus gps;
// The GPS object
#include <LiquidCrystal_I2C.h>
int lcdColumns = 20;
int lcdRows = 4;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
void setup() {
lcd.init();
lcd.backlight();
// Confirm connection
Serial.begin(115200);
Serial2.begin(GPSbaud);
Serial.println(F("ESP32 GPS data"));
delay(2000);
}
void loop() {
if (Serial2.available() > 0) {
// Check serial port
if (gps.encode(Serial2.read())) { // Read the data
Serial.println("Data read OK ");
if (gps.location.isValid()) {
// Check if valid
Serial.println("Data is valid");
lcd.setCursor(0, 0);
lcd.print("Lat: ");
lcd.setCursor(7, 0);
lcd.print(gps.location.lat(), 6);
lcd.setCursor(0, 1);
lcd.print("Lon: ");
lcd.setCursor(7, 1);
lcd.print(gps.location.lng(), 6);
lcd.setCursor(0, 2);
lcd.print("Alt: ");
if (gps.altitude.isValid()) {
lcd.setCursor(7, 2);
lcd.print(gps.altitude.meters());
lcd.setCursor(12, 2);
lcd.print(" m");
}
lcd.setCursor(0, 3);
lcd.print("Speed: ");
if (gps.speed.isValid()) {
lcd.setCursor(7, 3);
lcd.print(gps.speed.kmph());
lcd.setCursor(11, 3);
lcd.print(" km/h");
}
lcd.setCursor(18, 3);
lcd.print(gps.satellites.value());
lcd.print("*");
Serial.print(F("DATE/TIME: "));
if (gps.date.isValid() && gps.time.isValid()) {
Serial.print(gps.date.day());
Serial.print(F("-"));
Serial.print(gps.date.month());
Serial.print(F("-"));
Serial.print(gps.date.year());
Serial.print(F(" "));
Serial.print(gps.time.hour());
Serial.print(F(":"));
Serial.print(gps.time.minute());
Serial.print(F(":"));
Serial.println(gps.time.second());
} else {
Serial.println(F("Invalid data"));
}
}
Fig.8.11: the position, altitude and speed data are
shown on the LCD panel of the ESP32 GPS location fixer.
74
}
Serial.println();
} else {
lcd.setCursor(0, 3);
lcd.print("Wait!");
}
if (millis() > 5000 && gps.charsProcessed() < 10)
Serial.println(F("No GPS data received: check wiring"));
}
Practical Electronics | October | 2024
Listing 8.4 – Passing parameters to a user-defined function
Gotcha!
/* Example of passing parameters to a function */
Several LCD libraries with similar names exist, so it is
important to ensure that you use the correct library for the
LCD panel that you use. In many cases, guidance is provided
by suppliers, but it is worth double-checking that you are
using the correct library for the display that you will be using.
int analogPin = 15;
void setup() {
// Use the serial monitor to display the results
Serial.begin(9600);
}
void loop() {
int rawReading;
int percent;
// Get a raw reading from the potentiometer
rawReading = analogRead(analogPin);
// Send the raw reading to the function
percent = getPercent(rawReading);
// Print the result using the Serial Monitor
Serial.println(percent);
delay(2000);
}
int getPercent(int inputValue) {
int result;
// Map the value to a percentage
result = map(inputValue, 0, 4095, 0, 100);
return result; // and return the value
}
location such as your home, place of work, or intended
destination.
The TinyGPS library provides you with methods that will
allow you to do this but to get you started here’s some code
fragments that will get you started.
To get the distance from one location (lat1, long1) to another (lat2, long2), use the following function call:
TinyGPS::distance_between(lat1, long1, lat2, long2)
It returns the distance in metres between two positions
where both are specified as signed decimal degrees of latitude and longitude.
You can get the course from one location (lat1, long1) to
another (lat2, long2) using this function call:
TinyGPS::course_to(lat1, long1, lat2, long2)
It returns the course in degrees (North = 0°, West =
270°) from the first to the second position, where both
are specified as signed decimal degrees of latitude and
longitude.
Using the above lines of code, if one of the two locations
is obtained from gps.get_position() or gps.fget_position() ,it’s
possible to compute and display the distance and bearing
from a fixed point of reference.
The point of reference could be defined as a constant
using a line of the form:
Parameters can be passed into a function and results
returned to the main loop. Listing 8.4 provides you with
a simple example that shows how this is done. The example displays the setting of a potentiometer that has its
slider connected to D15 and its two ends taken to +3.3V
and GND.
The raw data read from the analog port is passed to the
getPercent() function. It, in turn, determines the percentage
of the control setting using the map() function. The resulting static const double LONDON_LAT = 51.508131,
value is returned to the main loop where, it is displayed
LONDON_LON = -0.128002;
using the Serial Monitor.
Note that although we’ve used a simple loop in this exFinally, to carry out tests while moving around, you will
ample, the getPercent() function could be called whenever need a portable source of USB power. You can easily do this
a new percentage reading is needed.
with an ordinary USB 5V “power bank”.
Another option is to use four rechargeable NiMH cells
Teach-In Challenge
mounted in a suitable battery holder (see Fig.8.12). Note
Extend the functionality of the basic location fixer so that it that, when series-connected, four standard alkaline cells
displays navigational information relative to a destination will provide a higher voltage (6V) and are therefore unsuitable for this use.
Next month
Next month we will be bringing Teach-In to a close by
showing you how to interface a matrix keypad and use
your ESP32 as the basis of a password-protected entry
control system.
Coding workshop will introduce files and file handling
techniques that will allow you to save data
to an SD or microSD card for later analysis.
Finally, the Checkpoint section will provide you with the ultimate test of your ESP32
PE
knowledge.
Howzat!
Fig.8.12: a power supply for portable operation using four
rechargeable NiMH cells.
Practical Electronics | October | 2024
Function names can use alphanumeric characters (A to Z;
a to z; 0 to 9) and the underscore character, but they must
not start with a number. When choosing names for your
functions, they must not be the same as the keywords or
functions that are already provided by the language.
75
|