This is only a preview of the November 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:
Items relevant to "Multi-Channel Volume Control, part one":
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 9 – Putting it all together
I
n the last part of our Teach-In series, we
showed how a low-cost GPS module can be used with
an ESP32 to provide location, navigation and time data.
Our Practical Project involved the construction of a simple
GPS location fixer using an ESP32 development board, a GPS
module and a 20 × 4 LCD screen, while Coding Workshop
looked at passing parameters into user-defined functions.
In this final part, we begin by introducing keypad interfacing and our Practical Project deals with the construction of
a simple passcode-protected entry control system. Coding
Workshop deals with files and file handling, and shows how
you can easily store data using an SD card interface. Checkpoint
brings the series to a conclusion with another opportunity to
test your knowledge of the ESP32.
The learning objectives for the ninth part of our series are
to know how to:
n interface with a matrix keypad
n set and use passcodes
n read data from and write data to an SD (or microSD) card
n use basic file handling techniques
Keypads
Many simple interfacing projects require only a few buttons
and switches for user input. Where that’s the case, you can
use some of the ESP32’s digital I/O pins configured as inputs
as described previously in this Teach-In.
However, if you need to deal with quite a few buttons or
switches, things can get a little
complicated, and you can
Fig.9.1: A low-cost
easily run out of
4 × 4 matrix
digital inputs.
keypad using
individual
button
keys.
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.
That’s certainly the case if you need to interface a keypad.
Fortunately, those are usually arranged in the form of a matrix of rows and columns, requiring fewer of your precious
I/O lines, leaving you more for other devices such as motors,
relays and displays.
Figs.9.1 & 9.2 show some typical low-cost matrix keypads
suitable for use with the ESP32. They are both arranged as a
4 × 4 matrix, but the keypad in Fig.9.1 is based on 16 individual pushbutton keys while that shown in Fig.9.2 uses a
membrane. Fig.9.3 shows their circuit arrangements, whilst
Fig.9.4 shows pin numbering for the keypad’s 8-way ribbon
connector in Fig.9.2.
A standard 4 × 4 matrix keypad will give
you a total of 16 keys to play with: 0 to 9
and A to D with additional * and #
characters. The keys are placed
at the intersection of the
rows and columns so
that, for example,
when the A key is
pressed, the top row
is linked to the rightmost column and
Fig.9.2: An
alternative type of
4 × 4 matrix keypad.
42
Practical Electronics | November | 2024
Fig.9.3: The wiring
diagram of the
4 × 4 matrix
keypad.
Fig.9.4: The ribbon
cable numbering
for the 4 × 4 matrix
keypad.
Fig.9.5: Connecting a
keypad to an ESP32.
consequently, pins 1 and 8 will be connected. On the
other hand, if the key marked 9 is pressed, pins 3 and
7 will be joined.
All we need to detect a keypress and decide which
key is being pressed is code that will address the rows
in turn and look for a signal returned on one of the columns.
So, if pin 1 is taken high and a high level is detected on pin
8, the A key is being pressed. Similarly, if pin 3 is taken high
and a high is detected on pin 7, the 9 key has been pressed.
Note that in these cases, you would need some sort of pulldown on the input pins (either internal to the microcontroller
or in the form of an external resistor) to ensure the pins stay
low unless being pulled high via the keypad switches.
Depending on your code, the key scanning could be done
in a few places. If your program has an ‘inner loop’ that executes contiuously and loops frequently enough (say, at least
10 times per second), you could add a call to a function to
scan the keypad within that inner loop.
Alternatively, a better approach would be to use a timer to
trigger an interrupt frequently (say, around 50 times per second) that could read the state of the inputs and note whether
any key has been pressed (for the main loop to act on later).
After that, it would update the state of the outputs to scan
the next row or column. That method would work even if the
code is busy with other tasks.
Fig.9.6: A breadboard layout
matching Fig.9.5, using
joined jumper wires to make
the connections.
Practical Electronics | November | 2024
If that all sounds a bit complicated, fortunately, there’s no
need to write your own keypad scanning code. Someone else
has already performed that arduous task for you!
Check it out
To check out the matrix keypad, all you need is an eight-wire
connection from the ESP32 development board to the keypad,
as shown in Figs.9.5 & 9.6.
The problem of connecting the keypad ribbon cable to the
ESP32 is easily solved using a coloured ribbon multi-jumper
lead with male and female connectors at the ends, as shown
in Fig.9.7.
When you’ve completed the wiring, you will need to download, compile and execute Listing 9.1. But before you do that,
you will need to locate and install the keypad library.
You can use the Library Manager to install the keypad
library file. Open the Library Manager then click on “Tools”,
followed by “Manage Libraries”.
The Library Manager will open, and you will be presented
with a list of installed libraries as well as those that are
Fig.9.7: A close-up showing the
wires used to connect to the
keypad ribbon cable. Note the
standard colour coding: 1 = brown,
2 = red, 3 = orange and so on.
43
Listing 9.1 – Keypad test code
#include <Keypad.h>
// Include the keypad library
const byte ROWS = 4; // The keypad has four rows
const byte COLS = 4; // and four columns
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'},
};
// Use an array to hold the key values
byte colPins[ROWS] = {16,17,18,19}; // Define the I/O
byte rowPins[COLS] = {32,33,25,26}; // pin numbers
Keypad keypad =
Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
void setup() {
Serial.begin(9600);
}
// Initialize the Serial Monitor
void loop() {
char key = keypad.getKey();
if (key != NO_KEY){
Serial.println(key);
}
}
Fig.9.8: Using the Library Manager to
install the Keypad library.
// Let's check the keypad
// and if a key was
// pressed, print it!
available for installation. To shorten the list, enter “keypad”
in the search field and then scroll down to find the keypad
library, as shown in Fig.9.8.
Having located the library, you just need to click on “INSTALL” and wait for the IDE to install it. Depending on the
speed of your Internet connection, downloading might take
a few minutes.
When the installation is complete, you should notice that
the “INSTALL” button has been replaced by a “REMOVE”
button. You should also notice the messages that appear
in the status window (see Fig.9.9). You can now close the
Library Manager.
To include the keypad (and before you make use of the
keypad object), you will need to add this line at the beginning of the code:
n
n
n
n
n
an ESP32 development board on a breadboard
a 4 × 4 keypad
a backlit 16 × 2 alphanumeric LCD screen
a 5V piezoelectric sounder
a 3.3/5V relay module
Practical project
The ESP32 makes an ideal candidate for use in a wide range of
simple security and alarm systems. Our Practical project this
month shows how you can implement a simple but effective
entry system. You will need the following items:
The complete circuit of the simple entry system is shown
in Fig.9.11. It uses low-cost, commonly available components.
The 16 × 2 LCD screen and 16-key keypad are widely available
from several suppliers, including those based in the Far East.
The relay module is like those that we’ve used earlier in this
Teach-In series: a 3.3/5V type with suitably rated contacts.
Connection to the door solenoid is provided by a three-way
terminal block fitted to the relay module. The breadboard
layout is shown in Fig.9.12.
In practise, the user enters a passcode consisting of a string
of alphanumeric characters, followed by the ‘#’ key. A beep
from the piezoelectric sounder provides confirmation that the
user has entered a character on the keypad.
When the correct passcode has been entered, the LED will
illuminate and the relay will operate for a time that can be
preset within the code. The passcode for access is also preset
in the code.
Listing 9.2 shows the complete code for the simple ESP32based entry system. As usual, we’ve added comments to help
you understand what’s going on.
The code requires three libraries; LiquidCrystal.h, keypad.h
and Password.h. The first two of these provide functions that
facilitate the use of the LCD display and the matrix keypad,
whilst the third deals with setting and checking the passcode
string.
You could develop some of your own code to do those
tasks, but there’s little point in doing that if someone else
Fig.9.9: The meessages at the bottom of the window show that
the Keypad library has been successfully installed.
Fig.9.10: These characters in the Serial Monitor were generated
by pressing buttons on the keypad.
#include <Keypad.h>
The keypad test code shown in Listing 9.1 is available for
download from the PE website at https://pemag.au/link/abyx.
When the code has been compiled and executed, you will be
able to press the keys and note the characters displayed via
the Serial Monitor (see Fig.9.10).
44
Practical Electronics | November | 2024
Listing 9.2 – Code for the simple ESP32 entry system
Fig.9.11: The complete
circuit diagram of the simple
ESP32 entry system.
// Include the library code:
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <Password.h>
// Define the LCD display parameters
int lcdColumns = 16;
int lcdRows = 2;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
const byte ROWS = 4; // The keypad has four rows
const byte COLS = 4; // and four columns
char keys[ROWS][COLS] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' },
}; // Use an array to hold the key values
byte colPins[ROWS] = { 16, 17, 18, 19 }; // Keypad
byte rowPins[COLS] = { 32, 33, 25, 26 }; // pins
int outPiezo = 2;
// Audible transducer
int outRelay = 15;
// Door actuator relay
has already provided a simple and elegant solution that they
have shared with the rest of the community!
The password library can be downloaded and installed
using the Library Manager (as explained earlier).
When you’ve corrected any coding errors reported by the
compiler, you will be ready to execute your code. Just click
on the arrow and watch the progress report. When the ESP32
performs a reset, you will see some characters appearing across
the LCD for a short time, after which the display will clear
and show the message, “Enter Passcode”.
At this point, the ESP32 is waiting for user input from the
keypad. If you then press a key, you will hear a beep from the
piezoelectric sounder, which informs you that the character
that you’ve pressed has been accepted.
If you press several further characters in succession, followed by the ‘#’ key, the entered passcode will be checked
and a message, either “Welcome” or “Invalid Passcode” will
appear. If the correct passcode (ABCD) has been entered prior
to the ‘#’ key, the relay module’s green LED should illuminate and the relay will operate for two seconds (sufficient to
release the door). This time interval can easily be changed
by modifying the value shown in the code.
As usual, there’s a great deal of scope for going further with
the entry control system. The most obvious enhancement
would be the addition of access codes that
would enable different levels of access
(eg, open some doors but not others). A
Fig.9.12: The complete ESP32 entry system, showing the
backlit 16 × 2 LCD above the breadboard, the 4 × 4 matrix
keypad at upper right and the relay at the bottom.
Practical Electronics | November | 2024
Keypad keypad = Keypad(makeKeymap(keys), rowPins,
colPins, ROWS, COLS);
Password password = Password(“ABCD”);
// Can change
void setup() {
pinMode(outPiezo, OUTPUT);
pinMode(outRelay, OUTPUT);
// Initialize the LCD display
lcd.init();
// Turn on the LCD backlight
lcd.backlight();
// Deactivate the door relay
digitalWrite(outRelay, HIGH); // High to deactivate
// Set up the number of columns and rows on the LCD
lcd.begin(16, 2);
// Print a message to the LCD
lcd.print(“Enter Passcode”); // Prompt the user
keypad.addEventListener(keypadEvent);
keypad.setDebounceTime(250);
}
void loop() {
keypad.getKey();
}
void keypadEvent(KeypadEvent eKey) {
switch (keypad.getState()) {
case PRESSED:
lcd.setCursor(0, 1);
lcd.print(“*”);
digitalWrite(outPiezo, HIGH); // Keypress beep
delay(50);
digitalWrite(outPiezo, LOW);
delay(50);
lcd.setCursor(0, 1);
lcd.print(“ “);
switch (eKey) {
case '#': checkPasscode(); break; // is right?
default:
password.append(eKey);
}
}
}
void checkPasscode() {
if (password.evaluate()) {
lcd.setCursor(0, 1);
lcd.print(“* Welcome *”);
//
digitalWrite(outRelay, LOW); // Activate relay
delay(2000);
// and wait 2s
digitalWrite(outRelay, HIGH); // Deactivate relay
delay(2000);
// afterwards
lcd.setCursor(0, 1);
lcd.print(“
“);
password.reset(); // Reset passcode after valid entry
} else {
lcd.setCursor(0, 1);
lcd.print(“* Invalid *”);
delay(2000);
lcd.setCursor(0, 1);
lcd.print(“
“);
password.reset(); // Reset after invalid entry
}
}
45
Next, you will need to set up the variables that you will be
using with the SD library:
// Set up variables for use with the SD library
Sd2Card card;
SdVolume volume;
SdFile root;
Fig.9.13: A typical
microSD card module
with an SPI interface.
Note the onboard 3.3V
regulator (on the left) and
the 14-pin logic level
translator IC to its right.
The next step is rather important because you will need to
specify the pin number that will be used for the chip select
(CS) signal to the SD module. Because this varies with SD
card modules and shields from different manufacturers, you
will need to check the documentation supplied. Here’s a line
of code that sets I/O pin 5 as the chip select line:
// CS signal (change as required)
const int chipSelect = 5;
Reading and writing data
Data can be very easily written to an SD card or read from it.
lock-out feature could be incorporated to prevent multiple First you will need to initialize the card. This can be done
attempts at code entry. This could enforce an obligatory time using a few lines of code:
delay after, say, the third or fourth attempt.
Alternatively, the system could be placed in a ‘lock down’ Serial.print("Initializing SD card...");
mode, triggering an alarm or sending a message to a remote if (!SD.begin(10)) {
Serial.println("Card not ready!");
supervisory system.
return;
}
Coding workshop
For some applications, it can be useful to store data in the Serial.println("Card ready!");
form of a file that can be saved and later recalled or transNotice in this code that we’ve explicitly stated the pin used
ferred to another system for further processing and analysis.
This can be accomplished with the aid of an ordinary SD (or for the CS signal (in this case, pin 10). We could do this in a
microSD) card and some simple code to handle the necessary more elegant way by defining the chip select pin as an integer
file processing.
at the start of the code, like this:
The main difference between an SD card and a microSD
card is the size; a microSD card can be placed in a passive const int chipSelect = 10; // CS on pin 10
adaptor for use in an SD card slot.
The most convenient way of attaching an SD card is using
We would then need to change the initializing code so that
an outboard SD card module with an SPI bus interface like it reads as follows:
that shown in Fig.9.13.
We previously described the Serial Peripheral Interface (SPI) Serial.print("Initializing SD card...");
bus in Part 4 of Teach-in. The bus can operate at high speed if (!SD.begin(chipSelect)) {
over short distances (faster than the I2C bus) and is thus ideal
Serial.println("Card not ready!");
return;
for transferring data to and from an SD card.
}
Serial.println("Card ready!");
Using the SD Library
The Arduino’s built-in SD Library provides you with a useful
Before you can write to a file you need to open it using the
set of tools for reading from and writing to an SD card. The
library supports the popular FAT16 and FAT32 file systems SD.open() function, as follows:
commonly used with standard SD and SDHC cards. Filenames
should follow the old DOS ‘8 + 3’ convention, and can include myFile = SD.open("data.dat", FILE_WRITE);
paths separated by forward-slashes, ‘/’.
It is worth noting that, because the working directory is
always the root of the SD card, a name refers to the same file
whether it includes a leading slash or not. Thus “mydata.dat”
is the same as “/mydata.dat”. Note also that the SD library
currently supports multiple file opening.
To communicate with an SD card, you will need to make
use of the SPI bus available on digital I/O pins 18, 19, and
23. A further pin must be used to select the SD card via the
chip select (CS) pin. We’ve used pin 5, but an alternative pin
can be specified in the call to SD.begin().
At the start of your code, you will need to include the SPI
and SD card libraries:
// Include the SD and SPI libraries
#include <SPI.h>
#include <SD.h>
46
Fig.9.14: The simple
circuit of the ESP32 data
logger.
Practical Electronics | November | 2024
Fig.9.17(a): The
pin connections for
the unmounted
DHT22 combined
humidity/
temperature
sensor.
Fig.9.17(b): The
pin connections
for the mounted
DHT22 combined
humidity/
temperature
sensor.
Fig.9.15: The breadboard layout and wiring for the ESP32-based data logger.
If the file opens without an error, you will be able to write myFile = SD.open("test.txt");
to it. If myFile returns true, the file has been opened, but if
Then you need to read data from the file, sending it to the
myFile returns false, an error has occurred and you will be
Serial Monitor until you reach the end:
unable to write to the file.
Here’s some code that writes a series of values to the file
if (myFile) {
that we’ve (hopefully) just opened.
Serial.println("test.txt:");
Note that you must close the file when you have finished
while (myFile.available()) {
writing to it to avoid data loss; closing the file ensures that
Serial.write(myFile.read());
any data which has been buffered in RAM is written to the
}
SD card’s flash memory:
myFile.close(); // Close the file
} else {
if (myFile) {
// It didn’t open so print an error message
Serial.print("Writing file ...");
Serial.println("Error opening the file!");
myFile.println("207, 188, 219, 155, 0");
}
myFile.close(); // Close the file
Serial.println(" done.");
An ESP32 data logger
} else {
To put Coding workshop into context, let’s look at a simple
// It didn’t open so print an error message
ESP32 data logger that stores temperature and humidity data
Serial.println("Error opening the file!");
obtained from a DHT22 sensor (described in Part 5). The data
}
will be written to an SD card and can then used for later
Reading a file is just as easy. First, you need to open the analysis with virtually any spreadsheet package.
Readings are taken and then stored periodically, allowing
file for reading:
you to later plot a graph showing how the temperature and
Fig.9.16: The ESP32 data logger, assembled and ready to test.
humidity changed over time.
Having relative humidity and
temperature readings also allows
you to calculate absolute humidity values later, in case you are
interested in that.
The complete circuit of the
data logging application is in
Fig.9.14 and the wiring layout is
given in Fig.9.15, while Fig.9.16
shows the prototype itself. The
white DHT22 sensor to the right
of the ESP32 is used to obtain
temperature and humidity data.
Fig.9.17(a) shows the pin
connections for an unmounted
sensor, while Fig.9.17(b) shows
the pin numbering for a mounted
sensor. Since there is some
variation in the pin numbering
Practical Electronics | November | 2024
47
Gotcha!
Fig.9.18: Serial Monitor diagnostic messages confirming that an
SD card is present and the data file has been found.
between different manufacturers, it’s important to check your
module’s pin connections before wiring it up (see the Gotcha!
panel below).
Listing 9.3 (opposite) shows the complete code for the ESP32
data logger. As always, we’ve included numerous comments
in the code to help you understand what’s going on.
The code requires three libraries: DHT.h (or dhtnew.h), SPI.h
and SD.h. The first of these provide functions that facilitate
the use of the DHT family of humidity/temperature sensors,
whilst the second deals with the serial peripheral interface
(SPI) used by the sensor, and the third provides the functions
associated with reading from and writing to the SD card.
Note that if you are using a very early version of the IDE,
you might also need to include the mathematics library that
provides the function for rounding the temperature values
before they are stored on the SD card, <math.h>. The rounding function is important to remove the fractional part of the
values returned from the sensor that might otherwise confuse
a conventional spreadsheet program (which might regard the
data as text rather than numerical).
When you’ve corrected any coding errors that the compiler
reports, you will be ready to execute the code. After the
ESP32 performs a reset, if all is well you will be greeted by a
It’s possible to substitute the lower-cost DHT11 for the
DHT22 sensor. However, the 8-bit resolution of the DHT11
humidity/temperature sensor means that the readings
will not have a decimal point (the fractional part will be
zero). The more expensive (and more accurate) DHT22
fills the fractional parts with data. However, that isn’t
crucial as the accuracy of the sensor is typically quoted
as ±4% for relative humidity and ±2°C for temperature,
making the data after the decimal point suspect.
diagnostic message like that shown in Fig.9.18. If the SD card
is not present, or if the SD card interface is not functioning
correctly, the program will stop, and an error message will
appear. If that is the case, the first thing to check is that you
have set the chip select line correctly.
Once the interface is ready, it will start to collect data, writing new information to the SD card on each pass through the
loop. You should always wait until the program terminates
before attempting to remove the SD card to transfer the data
to a PC or other device.
If you run the program several times (without removing the
SD card), you will find that further data will be appended to
the file (ie, added at the end). If necessary, you can always
remove the SD card, place it in a card reader and simply
rename the file manually if you want it to start a new file.
The data stored on the SD card is in comma-delimited
(CSV) format. On each pass, the data values will be displayed via the Serial Monitor and stored in the file saved
to the SD card.
The data displayed by the Serial Monitor should look like
that shown in Fig.9.19. If you need to process or visualise this
data, you can easily import it into a spreadsheet with each
set of values appearing in a different column.
Fig.9.19: The format of the data
stored on the SD card (with the
CSV format converted to columns
in a spreadsheet).
Fig.9.20: Similar data plotted in a chart using Microsoft Excel.
48
Gotcha!
Gotcha!
Some DHT22 manufacturers use different pinouts, so
check the pin markings on the module that you are
planning to use. If you are using a basic sensor in its fourpin package, connect a 10kΩ resistor between the data
terminal (OUT) and the positive supply (VS or VCC). This
‘pull-up’ resistor is not needed if your sensor is already
mounted on a PCB with an onboard pull-up resistor.
Conventional SD cards are designed for operation from
a 3.3V supply and thus it is necessary to ensure that the
I/O levels and supply voltage are level-shifted within the
hardware interface. This is normally the case with external
modules, but it is important to check when modules may
have been designed for operation with other systems and
may have links or switches fitted.
Practical Electronics | November | 2024
Listing 9.3 – A simple data logging application
#include <dhtnew.h>
#include <SPI.h>
#include "SD.h"
#include "FS.h"
// DHT library
// SPI library
// SD library
// File handling
DHTNEW mySensor(16);
#define SD_CS 5
const int interval = 5000;
String dataMessage;
String dataString = "";
// UART RXD input
// CS output pin
// Interval between readings
// A string to hold the data
void setup() {
Serial.begin(115200);
// Initialize the SD card
Serial.println("Initializing SD card ...");
if (!SD.begin(SD_CS)) {
Serial.println("SD card not mounted!");
return;
}
// Check the SD card type
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
Serial.println("SD card missing!");
return;
}
// Open the data file
File file = SD.open("/THDATA.DAT");
if (!file) {
Serial.println("THDATA not found on this card!");
Serial.println("Creating the file ...");
writeFile(SD, "/THDATA.DAT",
"Temperature and humidity data\r\n");
} else {
Serial.println("File already exists!");
}
file.close();
// Write data to the SD card
void writeFile(fs::FS &fs, const char *path,
const char *message) {
Serial.printf("Writing the data file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if (!file) {
Serial.println("Couldn't open file for writing");
return;
}
if (file.print(message)) {
Serial.println("File written");
} else {
Serial.println("File not written!");
}
file.close();
}
// Append data to the SD card
void appendFile(fs::FS &fs, const char *path,
const char *message) {
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if (!file) {
Serial.println("Couldn't open file for appending!");
return;
}
if (file.println(message)) { // ln ADDED
Serial.println("Data appended to the file");
} else {
Serial.println("Failed to append the data!");
}
file.close();
}
void readTHdata() {
// Read data from the sensor
mySensor.read();
}
void loop() {
readTHdata();
logSDCard();
delay(interval); //Wait before writing the next data
}
// Then display the returned data
Serial.print("Temperature: ");
Serial.print(mySensor.getTemperature(), 1);
Serial.print(" deg.C\t");
Serial.print("Humidity: ");
Serial.print(mySensor.getHumidity(), 1);
Serial.println(" %\t");
// Log the current sensor readings
void logSDCard() {
dataMessage = dataString;
Serial.print("Saving data: ");
Serial.println(dataMessage);
appendFile(SD, "/THDATA.DAT", dataMessage.c_str());
}
// Now update the data
dataString = "";
dataString += String(mySensor.getTemperature());
dataString += ","; // Comma separator
dataString += String(mySensor.getHumidity());
dataString += ","; // Comma separator
In common with many spreadsheet packages, if you open
the data file in Excel, you will need to specify that the file uses
‘delimiters’ and that the delimiter is a comma. You may find
that is the default since, while other delimiters are sometimes
used, commas are the most common.
Fig.9.20 shows how the data can be represented visually
within Excel; other spreadsheet programs, like the free-to-use
LibreOffice Calc, can be used to make similar plots. You can
also perform numerical analysis, like calculating minimums,
maximums, means, standard deviations and all sorts of other
useful values. Check your spreadsheet’s help file or manual
for details on how to perform those calculations.
As always, there’s a great deal of scope for going further
with the ESP32 data logger. Alarms could be set when critical values are detected and outputs could be used to operate
indicators, piezoelectric sounders, and relays.
Another refinement might be date/time stamping of the
filename so that a unique name is generated every time the
program is executed (keeping time was covered last month).
Practical Electronics | November | 2024
}
You could also add a column to the data generated that includes the date and time of the measurement, so that you can
leave the device running long-term, then plot (for example)
a full day’s worth of data by extracting that particular set of
data points. The sky is the limit!
Another, related improvement would be to change the
main loop so that, rather than simply taking recordings at set
intervals, it (for example) makes measurements every minute,
on the minute.
Even if you set the interval to be one minute long, it would
‘drift’ over time due to differences in how long each function
call took and the exact time spent in the delay function (which
can vary slightly between calls). So having a real-time clock
or using a timer to determine when to make measurements
would give more consistent results.
All of those enhancements would be relatively simple
to add and would provide you with a great opportunity to
further develop your coding skills and learn more about how
the ESP32 works.
49
Check Point
Now that we’ve complete our Teach-in series, Check Point
replaces our usual Teach-in challenge. This is a great an
opportunity to test your knowledge of the ESP32. Just select one answer to each of these questions. When you’ve
finished, you can check your answers at the end of the
page. Good luck!
1. To use a library file called WebServer.h in your code,
which one of the following lines would you use?
(a) #include WebServer
(b) #include “WebServer.h”
(c) #include <WebServer.h>
2. Multi-line comments are enclosed within:
(a) * and *
(b) // and //
(c) /* and */
3. An IPv4 address requires:
(a) two bytes
(b) four bytes
(c) eight bytes
4. On an I2C bus, the lines are:
(a) usually pulled high; driven low when data is present
(b) usually pulled low; driven high when data is present
(c) always floating regardless of whether data is present
5. A digital input is fitted with a pull-up resistor. In the
absence of any connection, this input will be in:
(a) a low state
(b) a high state
(c) an indeterminate state
6. When using Wi-Fi, an ESP32:
(a) can only be configured as a Server
(b) can only be configured as an Access Point
(c) can be configured either as an Access Point or a Server
7. Errors introduced in the calculations performed by a
GPS/GNSS receiver are expressed in terms of:
(a) dilution of precision (DOP)
(b) a percentage of erroneous values (PEV)
(c) received signal strength indication (RSSI)
8. Which serial bus uses SDA and SCL signals?
(a) I2C
(b) SPI
(c) USB.
12. The individual segments of a typical seven-segment
LED display are conventionally labelled:
(a) a to g and decimal point
(b) 0 to 9 and decimal point
(c) 0 to 7 and decimal point
13. MOSI and MISO are signals present on the:
(a) I2C bus
(b) SPI bus
(c) UART serial bus.
14. How many keys are present on a 4 × 4 matrix keypad?
(a) 4
(b) 8
(c) 16
15. Internal pull-ups and pull-downs are available for:
(a) all the ESP32’s digital I/O pins
(b) none of the ESP32’s digital I/O pins
(c) some of the ESP32’s digital I/O pins
16. Wi-Fi Protected Access (WPA) uses:
(a) a pre-shared key
(b) a trusted certificate
(c) an encrypted passphrase
17. When x = 1 and y = 0.5, the expression pow(x, y)
evalulates to:
(a) 0.5
(b) 1
(c) 2
18. A Hall effect sensor responds to:
(a) electric charge
(b) magnetic field strength
(c) temperature and humidity
19. Which one of the following lines contains an error?
(a) int a == 1.59;
(b) pinMode(32, INPUT);
(c) const byte ROWS = 4;
20. When a function is declared void, it:
(a) does not return a value
(b) returns a value that’s discarded
(c) generates an error when the code is executed
9. Why is an LCD panel often fitted with an I2C add-on?
(a) To improve response time
(b) To reduce the number of I/O lines required
(c) To provide a buffer memory to retain display data.
10. To read the state of a digital I/O pin, you would use:
(a) readInput();
(b) inputState();
(c) digitalRead();
Answers:
1. c
2. c
3. b 4. a
5. b 6. c
7. a
8. a
9. b 10. c 11. c 12. a 13. b 14. c
15. c 16. a 17. b 18. b 19. a 20. a
How did you do? If you scored 19 or more, you’ve become
11. DHT11/DHT22 temperature/humidity interface via:
an ESP32 expert! If you scored between 16 and 18, you’re
(a) an I2C interface
nearly there. It’s well taking another look at the earlier parts
(b) an SPI bus interface
PE
of this Teach-in series if you scored 15 or less.
(c) the ESP32’s serial UART interface
50
Practical Electronics | November | 2024
|