This is only a preview of the June 2024 issue of Practical Electronics. You can view 0 of the 72 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:
|
Teach-In 2024
Learn electronics with
the ESP32 by Mike Tooley
Part 4 – Using LED displays
I
n the last month’s part of our Teach-In series, we
introduced the ESP32’s ADC and DAC. We showed you how
to read analogue voltages and interface analogue sensors.
We also introduced the ESP32’s Analogue Plotter as a means
of visualising voltage changes over time. Plus, we explained
the principle of pulse-width modulation (PWM) and how this
is used to generate (pseudo) analogue output voltages and
waveforms. Coding Workshop introduced the decimal, binary,
octal and hexadecimal number systems. Our Teach-in project
featured the design, construction and coding of a simple tester
for 1.5V batteries.
The learning objectives for this fourth part of our series are
to know how to:
n Configure and use matrix and seven-segment LED displays
n Interface a motion sensor.
n Generate and use random numbers.
Seven-segment LED displays
Seven-segment LED displays provide you with a simple,
low-cost method of displaying numbers and a limited range
of basic text characters. They comprise seven (or sometimes
eight) individual LEDs arranged as shown in Fig.4.1. Note that
the segments are lettered in sequence from the top, moving
clockwise around the display and ending with the centre
segment. Each of the segments, labelled ‘a’ to ‘g’, are individually
addressable, which means that you can choose to illuminate
one or all of them by applying a small current of typically 5
to 15mA to the segment required. In some displays an extra
decimal point (referred to as ‘d.p.’ or ‘DP’) is also present.
Seven-segment displays are commonly available in various
sizes and may be either common-cathode or common-anode
types depending on which LED connections are linked together.
Thus, for example, the common-cathode display shown in
Fig.4.3(a) has nine connections, of which eight are used for the
anodes of the individual
segments (including the
decimal point), with a
ninth connection common
shared by the cathodes. The
arrangement in Fig.4.3(b)
Fig.4.1 Segment labelling
in a typical seven-segment
LED display.
44
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
Earch month, there’ll be projects and challenges to help you
check and develop your understanding of the topics covered.
is similar but the anodes and cathodes have been interchanged.
The important difference between these two configurations is
that the polarity of the common connection changes according
to the display type. A common-cathode connection is returned
to the common negative rail (usually GND) whereas a common-
Fig.4.2 Hexadecimal numbers displayed using a seven-segment
LED display.
Practical Electronics | June | 2024
Gotcha!
Seven-segment displays come in two basic types: common-anode and commoncathode types. Since they are outwardly identical it’s important to ensure that
you are using the correct type.
Sample code for driving the sevensegment display is shown below in
Listing 4.1. This code simply displays
each number from 1 to (1)0 with the
display held for a period defined by
delayTime(). Note that the time delay
is initialised to one second (1000ms) at
the beginning of the code.
Listing 4.1 Seven-segment LED counter
// 5 => a,c,d,f,g
digitalWrite(a, HIGH);
digitalWrite(b, LOW);
digitalWrite(c, HIGH);
digitalWrite(d, HIGH);
digitalWrite(e, LOW);
digitalWrite(f, HIGH);
digitalWrite(g, HIGH);
delay(delayTime);
// 6 => a,c,d,e,f,g
digitalWrite(a, HIGH);
digitalWrite(b, LOW);
digitalWrite(c, HIGH);
digitalWrite(d, HIGH);
digitalWrite(e, HIGH);
digitalWrite(f, HIGH);
digitalWrite(g, HIGH);
delay(delayTime);
// 7 => a,b,c
digitalWrite(a, HIGH);
digitalWrite(b, HIGH);
digitalWrite(c, HIGH);
digitalWrite(d, LOW);
digitalWrite(e, LOW);
digitalWrite(f, LOW);
digitalWrite(g, LOW);
delay(delayTime);
// 8 => a,b,c,d,e,f,g
digitalWrite(a, HIGH);
digitalWrite(b, HIGH);
digitalWrite(c, HIGH);
digitalWrite(d, HIGH);
digitalWrite(e, HIGH);
digitalWrite(f, HIGH);
digitalWrite(g, HIGH);
delay(delayTime);
// 9 => a,b,c,d,f,g
digitalWrite(a, HIGH);
digitalWrite(b, HIGH);
digitalWrite(c, HIGH);
digitalWrite(d, HIGH);
digitalWrite(e, LOW);
digitalWrite(f, HIGH);
digitalWrite(g, HIGH);
delay(delayTime);
// 0 => a,b,c,d,e,f
digitalWrite(a, HIGH);
digitalWrite(b, HIGH);
digitalWrite(c, HIGH);
digitalWrite(d, HIGH);
digitalWrite(e, HIGH);
digitalWrite(f, HIGH);
digitalWrite(g, LOW);
delay(delayTime);
/* Counter based on a single common
cathode seven-segment LED display */
Fig.4.3 Common-cathode and commonanode LED displays.
// Assign display segments to GPIO pins
int a = 22;
int b = 23;
int c = 18;
int d = 17;
int e = 16;
int f = 21;
int g = 19;
anode connection is invariably taken to
the common positive rail (usually VCC).
// Set delay between counts
int delayTime = 1000; // 1 second
Check it out!
To interface a single seven-segment
display to an ESP32 you will need eight
connections, but an extra connection will
be required if you are using the decimal
point. Fig.4.4 shows how this is done
using a common-cathode display. Seven
series resistors (R1 to R7) each of 330Ω
are used to limit the individual segment
currents to a few mA. Note that when all
the segments are illuminated you will
need to be aware of the total load on the
ESP32 and its power source. In the case
of battery-operated equipment, you may
find it necessary to limit the individual
segment currents to less than about 10mA.
A series resistance of 330Ω should suffice
for most low-power applications yet still
produce a reasonably bright display.
Typical display connections for a
common-cathode seven-segment display
are shown in Fig.4.5. Note that there
are two 0V pins. These are the common
connections, and they will normally
be taken to GND. Fig.4.6 shows the
breadboard wiring.
Fig.4.4 Interfacing an individual sevensegment LED display to an ESP32.
Practical Electronics | June | 2024
void setup() {
// Initialise GPIO pins as outputs
pinMode(a, OUTPUT);
// Segment a
pinMode(b, OUTPUT);
// Segment b
pinMode(c, OUTPUT);
// Segment c
pinMode(d, OUTPUT);
// Segment d
pinMode(e, OUTPUT); // Segment e
pinMode(f, OUTPUT); // Segment f
pinMode(g, OUTPUT); // Segment g
}
void loop() { // Repeat forever
// 1 => b,c
digitalWrite(a, LOW);
digitalWrite(b, HIGH);
digitalWrite(c, HIGH);
digitalWrite(d, LOW);
digitalWrite(e, LOW);
digitalWrite(f, LOW);
digitalWrite(g, LOW);
delay(delayTime);
// 2 => a,b,d,e,g
digitalWrite(a, HIGH);
digitalWrite(b, HIGH);
digitalWrite(c, LOW);
digitalWrite(d, HIGH);
digitalWrite(e, HIGH);
digitalWrite(f, LOW);
digitalWrite(g, HIGH);
delay(delayTime);
// 3 => a,b,c,d,g
digitalWrite(a, HIGH);
digitalWrite(b, HIGH);
digitalWrite(c, HIGH);
digitalWrite(d, HIGH);
digitalWrite(e, LOW);
digitalWrite(f, LOW);
digitalWrite(g, HIGH);
delay(delayTime);
// 4 => b,c,f,g
digitalWrite(a, LOW);
digitalWrite(b, HIGH);
digitalWrite(c, HIGH);
digitalWrite(d, LOW);
digitalWrite(e, LOW);
digitalWrite(f, HIGH);
digitalWrite(g, HIGH);
delay(delayTime);
}
45
Fig.4.5 Typical pin connections for
a common-cathode seven-segment
LED display.
We’ve liberally commented the code in
Listing 4.1 to make it easy to follow. Note
that, as with all our code examples, we’ve
not attempted to oversimplify the code nor
present it in minimal form. Instead, we’ve
tried to make it as clear and unambiguous
as possible. As you become more proficient
with coding you will undoubtedly be able
to improve on our efforts and produce
something more compact.
Using seven-segment display modules
If you’ve checked out our simple sevensegment counter, you might want to
interface more than one display and
be wondering if there’s a better way of
doing things. The answer is, of course,
yes there is!
If you need multiple seven-segment
displays with the segments addressed
along the lines of our previous example,
then this can quickly become extremely
cumbersome – just imagine interfacing
a counter/timer with 10 or 12 sevensegment displays! Furthermore, if you
have more than two seven-segment
displays you will start to run out
of GPIO pins. Fortunately, there’s a
simple solution based on one or more
external driver devices. These are often
packaged along with a two-, four-, or
eight-digit display and require only four
connections to the ESP32, as shown in
Fig.4.7. So, having shown you a rather
clumsy method of interfacing a sevensegment display to the ESP32 let’s now
move on to a much-improved way of
interfacing a multi-digit display.
In the arrangement shown in Fig.4.7
just four connections are needed to
drive a total of 30 display segments. The
connections required are: VCC to the
ESP32’s +5V supply, DIO to D23 on the
ESP32, CLK to D22 on the ESP32, and
last, but not least, GND to GND.
4-digit display implementation
The required breadboard wiring for
checking out a 4-digit display module
is shown in Fig.4.8. If you compare this
46
Fig.4.6 Breadboard wiring for the ESP32 and common-cathode seven-segment display.
with Fig.4.6 you will see just how much
neater this is. The display module uses
a serial interface to the ESP32 based
on a cTM1637 driver chip. This device
does all the hard work, leaving you to
concentrate on getting the best out of it.
Since we have four digits to play with,
we will use them to develop a timer that
produces a display of minutes (the two
left-most digits) and seconds (the two
right-most digits). To ensure accuracy
of the timing, we’ve decided not to
use the ESP32’s delay() function.
Instead, we will be using the ESP32’s
real-time clock (RTC). To make use of
the TMD1637 and the ESP32’s RTC
we will need to include two library
routines in our code. If you refer to
Listing 4.2 Minutes and seconds counter using a TM1637 serial interface
and the ESP32’s RTC
/* Minutes and seconds counter using ESP32 RTC,
TM1637 driver and LED display. Time initialised
to 00:00:00 for use with a 4-digit LED display. */
#include <ESP32Time.h>
#include <TM1637Display.h>
#define CLK 22 // GPIO22 to CLK on the TM1637
#define DIO 23 // GPIO23 to DIO on the TM1637
// Set up RTC and display
ESP32Time rtc(3600); // Seconds offset for GMT+1
TM1637Display display = TM1637Display(CLK, DIO);
void setup() {
display.clear();
display.setBrightness(7); // Set display brightness
rtc.setTime(1609459200);
// Set RTC to Jan 2021 00:00:00
}
void loop() {
int time;
struct tm timeinfo = rtc.getTimeStruct();
time = (rtc.getMinute() * 100) + (rtc.getSecond());
display.showNumberDecEx(time, 0b11100000, true, 4, 0);
delay(1000); // Wait one second
}
Practical Electronics | June | 2024
Listing A – code fragment
// Generate random numbers in the range 1 to 9
long randomValue;
void setup() {
Serial.begin(9600);
// Uncomment next line to use a random seed
// randomSeed(analogRead(0));
}
void loop() {
randomValue = random(1, 10);
Serial.print(randomValue);
Serial.print(“ “);
delay(1000);
}
ESR Electronic Components Ltd
All of our stock is RoHS compliant and CE
approved. Visit our well stocked shop for
all of your requirements or order on-line.
We can help and advise with your enquiry,
from design to construction.
3D Printing • Cable • CCTV • Connectors • Components •
Enclosures • Fans • Fuses • Hardware • Lamps • LED’s •
Leads • Loudspeakers • Panel Meters • PCB Production •
Power Supplies • Relays • Resistors • Semiconductors •
Soldering Irons • Switches • Test Equipment • Transformers
and so much more…
Monday to Friday 08:30 - 17.00, Saturday 08:30 - 15:30
Fig.4.7 Interfacing a 4-digit seven-segment LED display module
to an ESP32.
Station Road
Cullercoats
North Shields
Tyne & Wear
NE30 4PQ
Listing 4.2 you will see the two lines of code that do this:
#include <ESP32Time.h>
// To use the ESP32’s RTC
#include <TM1637Display.h> // To use the TM1637
If you don’t have these library files installed they can be quickly
and easily downloaded from within the Arduino IDE. Just
search for the file that you need using the Library Manager.
Coding Workshop
For applications such as games and password generators
you might sometimes find that you need to generate random
numbers. Unfortunately, this can be something of a problem
in a microcomputer environment where nothing occurs that
can ever be described as truly random. To meet this need the
ESP32’s C++ language includes the random() function. that
generates values that although not truly random in a strict
mathematical sese can at least be considered to be usefully
‘pseudo random’. Let’s suppose that you need a random
integer in the range 1 (minimum) to 9
(maximum). The following line of code
would do the trick:
Tel: 0191 2514363 sales<at>esr.co.uk www.esr.co.uk
nature and the voltage read from an unconnected analogue pin
will also be random. So, to seed the random number generator
from the voltage present on analogue input A0 you would just
need to add the following line of code:
randomSeed(analogRead(0));
Listing A shows a fragment of code that will allow you to
check this for yourself. Note that when you’ve successfully
compiled and uploaded the code you will need to start the
Serial Monitor after execution to see the values produced.
Now for a second example (Listing B) using the random()
function in the form of a random HEADS and TAILS generator.
This time we are only interested in random numbers in the
range 0 and 1, where 0 will display a TAILS result, and 1
randomValue = random(1, 10);
Note that we would need to have
previously defined randomValue as a
variable using a line of the form:
long randomValue;
To improve the randomness of the values
returned from random() it’s possible to
change the seed that’s used by the function
(otherwise the random number generator
will always use the same seed value).
There’s a rather neat way of doing this.
The noise present on any of the ESP32’s
analogue inputs is inherently random in
Practical Electronics | June | 2024
Fig.4.8 Breadboard wiring for the ESP32 and 4-digit seven-segment LED display module.
47
Listing B – code fragment
// Coin toss producing random HEADS and TAILs
long randomValue;
void setup() {
Serial.begin(9600);
// Uncomment next line to use a random seed
// randomSeed(analogRead(0));
}
void loop() {
randomValue = random(0, 2);
if (randomValue == 1) {
Serial.print(“HEADS “);
} else {
Serial.print(“TAILS “);
}
delay(1000);
}
Gotcha!
If you find that the Serial Monitor displays gobbledygook
instead of a series of meaningful values, you should first
check that you have set a baud rate that matches the speed
that you’ve specified in your code. Our previous two
examples operate at 9600 baud. To work correctly this must
match the value that you have set in the Serial Monitor.
will produce HEADS. Once again, you will need to run the
Serial Monitor to check the results.
Using matrix LED displays
Having experimented with seven-segment displays let’s now
move on to a different and more flexible type of LED display
based on a matrix of individual LEDs. The most common types
of small LED matrix display are based on an 8×8 LED array,
as shown in Fig.4.9.
To reduce the number of connections between the display’s
64 LEDs and the outside world, the diodes are arranged in
an array of eight rows (R1 to R8) and eight columns (C1
to C8). With this configuration individual diodes can be
addressed by referencing the rows and columns in which
they are placed. In Fig.4.9 we’ve shown how two of the
LEDs (referenced by R3/C5 and R5/C3) can be illuminated
by a current of typically 5 to 15mA.
Fig.4.9 Basic arrangement of an 8×8 LED matrix display.
Fig.4.10 shows how a typical 8×8 LED matrix display appears
when the following LEDs are addressed:
R1/C3, R1/C4, R1/C5, R1/C6, R2/C2, R2/C3, R2/C6,
R2/C7, R3/C7, R4/C6, R4/C7, R5/C5, R5/C6, R6/C4,
R6/C5, R8/C4, R8/C5.
In case this is beginning to look overcomplicated, the problem of
addressing the necessary LED to display a particular set of text
characters is solved for you. You just need to use the right library!
The interface to an LED matrix display is usually based on
a de facto standard known as Serial Peripheral Interface (SPI).
SPI supports serial communication between a ‘master’ (the
ESP32) and a ‘slave’ (the matrix display).
Gotcha!
The Serial Peripheral Interface (SPI)
SPI is a communication standard that’s used to interface
one or more peripheral devices (known as ‘slaves’) to a
microprocessor
or microcontroller
(referred to as the
‘master’). A wide
The maximum random value generated by random() is
one less than the function’s second parameter. For example,
to generate six different random numbers in the range 1
to 6 (for example, the faces on dice) the function would
need to be random(1, 7) not random(1, 6). This may
sound obvious but it is often forgotten.
Table 4.1 ESP32 SPI implementation
Designation
Function
Direction
VSPI pin
number
HSPI pin
number
SCLK
Serial clock
Output from ESP32
18
14
MOSI
Master output/slave input
Output from ESP32
23
13
MISO
Master input/slave output
Input to ESP32
19
12
CS
Chip select
Output from ESP32
5
15
GND
Ground
Common
GND
GND
48
Fig.4.10 An 8×8 LED matrix display.
Practical Electronics | June | 2024
Fig.4.11 Using SPI to interface a single 8×8
LED matrix display to an ESP32.
Fig.4.13 Circuit arrangement for the dice roller.
Gotcha!
ESP32 development boards usually have SPI pins preassigned along the lines shown in Table 4.1. If you are
using a different type of platform for developing your
application and plan on using SPI then it is important to
check the pin assignment before use.
Practical Project
This month’s Practical Project takes the form of a dice roller
which comprises an ESP32, an 8×8 LED matrix display and a
low-cost motion sensor (see Fig.4.12).
Listing 4.3 Dice roller code
variety of SPI-compatible devices are available, and we
will be introducing several of them in this Teach-In series.
They include displays (both LED and LCD types), ADCs and
DACs, as well as temperature sensors, accelerometers and
GPIO expansion chips. The SPI bus is capable of operating
at high speed over short distances and it normally requires
a four-wire connection with a chip select (CS) connection
dedicated to each peripheral SPI device.
The SPI bus is a synchronous (serial clocked) interface
capable of supporting data transfer in both directions, master
to slave and slave to master, at the same time – this is referred
to as ‘full duplex’ operation. The ESP32’s SPI implementation
uses four signal wires (plus ground). These are listed in Table
4.1 together with the pin connections conventionally used on
ESP32 development boards.
The ESP32 is capable of handling four peripheral
devices connected using the SPI bus with two reserved for
communicating with the built-in flash memory. This leaves two
independent SPI channel for your use, VSPI and HSPI and each
of these can drive up to a maximum of three external slaves.
The method of interfacing a single 8×8 LED matrix display to
an ESP32 via SPI is shown in Fig.4.11. Here, five connections are
needed to drive a total of 64 LED. The connections required are:
VCC
DIN
CLK
CS
GND
to +5V supply for the ESP32
to D23 on the ESP32
to D18 on the ESP32
to D5 on the ESP32
to GND for the ESP32 (don’t forget this one!).
Gotcha!
If you are connecting multiple SPI peripherals it is essential
to ensure that each device has a unique chip select (CS)
connection. Failure to observe this precaution will yield
unpredictable results.
/* Dice roller based on 8x8 LED matrix display
and motion sensor */
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
// Uncomment depending on display type
// #define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define HARDWARE_TYPE MD_MAX72XX::GENERIC_HW
// Define display and I/O pins
#define MAX_DEVICES 1
#define CS_PIN 5
const int sensorPin = 17;
MD_Parola Display = MD_Parola(HARDWARE_TYPE,
CS_PIN, MAX_DEVICES);
void setup() {
Display.begin();
Display.setIntensity(0);
Display.displayClear();
randomSeed(analogRead(27)); // Seed from noise
on pin 27
}
void loop() {
// Wait for input from the motion sensor
int sensorState = digitalRead(sensorPin);
int lastSensorState;
while (sensorState == lastSensorState) {
sensorState = digitalRead(sensorPin);
Display.setInvert(false);
Display.setTextAlignment(PA_CENTER);
Display.print(“?”);
}
// We have movement so roll it
for (int i = 0; i < 10; i++) {
Display.setInvert(true);
Display.setTextAlignment(PA_CENTER);
Display.print(“?”);
delay(50);
Display.setInvert(false);
Display.setTextAlignment(PA_CENTER);
Display.print(“?”);
delay(50);
}
// And then display the result
Display.setTextAlignment(PA_CENTER);
Display.print(String(random(1, 7)));
delay(2000);
lastSensorState = sensorState;
Fig.4.12 A low-cost motion sensor.
Practical Electronics | June | 2024
}
49
+
Listing 4.4 Text message display using four 8×8 LED
matrix displays
/* Text display using an ESP32 and four 8 x 8
matrix LED displays */
// Include the library files
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
// Uncomment depending on display type
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
// #define HARDWARE_TYPE MD_MAX72XX::GENERIC_HW
// Define display and I/O pins
#define MAX_DEVICES 4
#define CS_PIN 5
MD_Parola Display = MD_Parola(HARDWARE_TYPE,
CS_PIN, MAX_DEVICES);
void setup() {
// Intialise the display
Display.begin();
Display.setIntensity(0);
Display.displayClear();
}
void loop() {
Display.setTextAlignment(PA_CENTER);
Display.print(“ON AIR”);
delay(2000);
}
Gotcha!
Large matrix displays can use a very large number of
individual LED. For example, if four 8×8 displays are
cascaded there will be a total of 256 LEDs present. If each
of these LEDs is illuminated simultaneously (unlikely but
not impossible) and if each is fed with a current of 10mA
the total load on the ESP32 power supply will amount to
more than 2.5A. This can easily exceed the capability of
a standard USB port.
Note, that once again, you may need to locate and download
the first two of these library files from within the Arduino IDE.
Fig.4.13 shows the interconnection of an LED matrix
display, motion sensor and ESP32. We’ve not shown a
full wiring diagram this time because the arrangement is
straightforward, and you will doubtless have had plenty
of experience with our two previous examples. Note that
if the motion sensor has an analogue output (as well as a
digital output) this can be ignored. The dice roller code is
shown in Listing 4.3.
Displaying text messages
LED matrix displays can be easily cascaded to produce larger
static and scrolling text displays. The arrangement in Fig.4.14
and code in Listing 4.4 shows how this can be done but note
that the code must be changed to indicate the number of 8×8
displays that are present. This requires the following change
to Listing 4.3:
#define MAX_DEVICES 4
instead of:
#define MAX_DEVICES 1
Fig.4.14 Arrangement for cascading multiple matrix displays.
When physical movement is detected by the motion sensor
(a slight tap is usually enough) this produces a change of logic
level on the DO pin and this in turn is used to break out of
the while() loop in Listing 4.3. Note that we need to include
three libraries at the beginning of the code. This is done with
the aid of the following lines:
#include <MD_Parola.h> // To write text to the display
#include <MD_MAX72xx.h> // To use the MAX72xx driver
#include <SPI.h> // To use the SPI interface
Teach-In Challenge
This month’s Teach-In Challenge involves extending the
hardware and modifying the code in Listing 4.4 to produce
a door entry indicator which will display the messages
‘WAIT’ or ‘ENTER’ depending on the state of a push button
switch connected to one of the ESP32’s digital inputs. If
you need help interfacing the switches look back at Part
2 of our series.
Next month
In Part 5 next month, we will introduce temperature and
humidity sensing, delving into the popular 1-wire and I2C
interface standards, and explain how low-cost LCD displays
can be added to your ESP32 projects. Coding Workshop will
deal with mathematics operators and functions, and our
Practical Project will feature a useful digital temperature and
humidity monitor.
Fig.4.15 Text display produced by Listing 4.4.
50
Practical Electronics | June | 2024
|