This is only a preview of the April 2025 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:
Articles in this series:
|
MAX’S COOL BEANS
By Max the Magnificent
WEIRD & WONDERFUL
ARDUINO PROJECTS
Part 4: full power ahead (to the main array)!
M
y head hurts; I’m about to
make your head hurt too
(you’re welcome.) As you may
recall, in our previous column, we used
our strip of 144 tricolour light-emitting
diodes (LEDs) to create the 14 × 10
(width × height) array that will form the
main display area for our retro games
console. This left us with four unused
LEDs; fear not, we’ll find a use for these
later (so don’t lose them).
We decided to refer to each of the
LEDs in our array as ‘pixels’ (short
for picture elements), each of which
has red, green, and blue (RGB) subelements. We also decided to view our
array in terms of (x, y) coordinates and
to employ a ‘bottom-left’ origin system,
in which (x, y) = (0, 0) is in the lowerleft corner, and (x, y) = (13, 9) is in the
upper-right corner.
We noted that it’s possible to connect
our ten 14-pixel segments in a variety
of different ways and to sort things
out in software later. To this end, once
we’d verified that everything worked,
we created a GetNeoNum() function
that accepts x and y integer values as
arguments and returns the number n of
the corresponding pixel in the string.
As I noted in that column, the great
thing about this is that it doesn’t matter
if you organise your segments differently to me. So long as we both have
GetNeoNum() functions that work with
our own arrays, and with identical external interfaces, all you need to do to
run one of my programs is to exchange
your version of this function for mine.
After performing various experiments,
we ended by creating a program that repeatedly (a) lit each row from bottom to
top, (b) lit each row from top to bottom,
(c) lit each column from left to right,
and (d) lit each column from right to
left. Since we are currently powering
our array from the Arduino, we made
sure that only a single row or column
was active at any time.
To refresh your memory, you can
download a copy of this code in the
file named CB-Apr25 Code-01.txt. As
usual, all the files mentioned in this
column are available from the April
2025 page of the PE website: https://
pemag.au/link/ac44
I left you pondering how we could
extend our program to light the pixels
in diagonal lines, one line at a time,
starting with the one-pixel diagonal
‘line’ in the bottom left corner at (x,
y) = (0, 0) and ending with the 1-pixel
diagonal ‘line’ in the top right corner
at (x, y) = (13, 9). This is what we are
poised do shortly but we’ll take things
step-by-step to ensure we are all dancing to the same tune.
Black and white
Listing 1(a): a code snippet to light rows
of LEDs using 8-bit RGB values.
8
Let’s start by looking at the portion
of our existing program that lights each
row from bottom to top as illustrated in
Listing 1(a). The listing number (1 in this
case) corresponds to part of the name
of the matching code file (“01” here).
Remember that Neos is the identifier
we’ve chosen for our pixel strings. Observe the calls to the Neos.setPixelColor()
function on lines 41 and 49. This function accepts two arguments. The first is
the number of the pixel whose colour
we wish to change. The second is a
24-bit colour value comprising 8 bits
each for the RGB components.
Also remember that this function
only modifies the colour of the pixel
stored in the Arduino’s memory. Nothing changes in the outside world until
we call the Neos.show() function on
lines 43 and 51 to stream the values
from memory into the physical string
of pixels forming our array.
Practical Electronics | April | 2025
Currently, we are generating these
24-bit values using the Neos.Color()
function, which accepts three 8-bit
RGB values and combines them into a
single 24-bit value.
Our compiler understands only 8-bit,
16-bit, and 32-bit integer values (most
computers have no native support for
three-byte [24-bit] integers). As a result,
our 24-bit colours are stored in 32-bit
variables and we simply ignore the
most-significant (uppermost) eight bits,
which remain unused.
Each of our 8-bit RGB fields can have
values ranging from 0 to 255 in decimal, which equates to 0b00000000 to
0b11111111 in binary (the ‘0b’ indicates
binary) or 0x00 to 0xFF in hexadecimal
(the ‘0x’ indicates hexadecimal). Driving the RGB fields with all the same
values results in white light.
The reason we are using RGB values
of 32 (0x20) on line 41 is to reduce the
amount of power we are consuming to
32 ÷ 255 ≃ 12.5% of full power.
The data sheet tells us that, when
fully on, each of our pixels consumes
60mA (milliamperes); that’s 20mA for
each of the RGB components. So, when
displaying white light at 12.5% of full
power, each pixel consumes 60mA ×
0.125 = 7.5mA. This calculation assumes everything is linear, which may
not be the case, but this approximation
is ‘close enough for government work’,
as they say.
In the case of our existing program,
our worst case is for all 14 pixels on the
same row to be lit up at the same time.
The resulting 7.5mA × 14 = 105mA
is well within the capabilities of our
Arduino.
As opposed to using the Neos.Color()
function, we can simply define our colours as 24-bit values:
Listing 2(a): a code snippet to light LEDs
in rows using 24-bit colour values.
#define WHITE 0x202020
#define BLACK 0x000000
This allows us to modify (and simplify) the calls to our Neos.setPixelColor()
functions, as seen in lines 45 and 53
of Listing 2(a). You can download the
new version of our program in the file
named CB-Apr25 Code-02.txt.
Although this may not appear to be a
great leap forward, working with 24-bit
colour values will make our lives a lot
easier in the future.
Declaring utility functions
Most of the code in the main body of
our program currently lives in the loop()
function. Instead of writing things as
one large ‘blob’ of code (I hope I’m not
getting too technical), a fundamental
practice in programming is to create
a suite of low-level utility functions.
These functions can then be called
Practical Electronics | April | 2025
Listing 3(a): declaring utility functions.
from other parts of the program (they
can even call each other).
Employing utility functions improves
the readability, reusability, and scalability of our code. It also makes our
programs easier to debug and maintain.
What’s not to love?
We already have one utility function
in the form of our GetNeoNum() routine. The next iteration of our program
(in the file named CB-Apr25 Code-03.
txt) contains three more, as seen in
Listing 3(a).
The SetPixelColorXY() function at
line 92 sets the colour of a single pixel
(once again, it modifies the pixel value
stored in the Arduino’s memory, not in
the physical string). This function accepts three parameters: the x and y coordinates of the pixel in question, and
9
Listing 3(b):
using
our utility
functions.
the color we wish to assign to that pixel.
The SetRowColor() function at line
100 sets all the pixels in a row to the
same colour. It accepts two parameters: the row in question (from 0 to 9)
and the color we wish to assign to the
pixels in that row.
Similarly, the SetColColor() function at line 110 sets all the pixels in a
column to the same colour. It accepts
two parameters: the col in question
(from 0 to 13), and the color we wish
to assign to the pixels in that column.
Observe that, in all three functions,
we’ve declared the colour variable as
being of type uint32_t, which refers to a
32-bit (4-byte) unsigned (non-negative)
integer. Ideally, we would prefer to use
a uint24_t, but this type isn’t supported
by most compilers.
Happily, when we pass a 24-bit
value into our function, the compiler will automatically pad the unused
eight most-significant bits with 0s to
generate the 32-bit value expected by
the function.
You may be wondering why we used
a data type of uint32_t instead of an unsigned long, which is what we would
expect to see in most Arduino documentation. We don’t want to get into this
here, but we will discuss the various integer data types in excruciating exhilarating detail in next month’s column.
Observe that our SetPixelColorXY()
function calls our existing GetNeoNum()
function. Similarly, both our SetRowColor() and SetColColor() functions
call our SetPixelColorXY() function.
The result is a cascading hierarchy of
function calls.
Using our utility functions
Now that we’ve declared our utility
functions, we can modify our loop()
function to take advantage of them.
Let’s consider the new incarnation of
the portion of our program that lights
each row from bottom to top as illustrated in Listing 3(b).
As is always the case with programming, there are many different approaches we could use. For example, in our
SetRowColor() function, we could move
10
the show() and
delay( ) function calls on
lines 41 and 42
(and on lines
45 and 46) into
the body of the
SetRowColor()
function itself.
Since we use
different delay
values at different times,
we could pass
the delay duration into the
SetRowColor()
function as an
additional argument.
As tempting
as this may be, Listing 4(a): controlling multiple rows and columns of LEDs.
it would place limitations on how we on line 42 and the delay() function on
could use our SetRowColor() function line 43. Similarly, we set the two rows
for other tasks in the future. For exam- to be BLACK on lines 45 and 46 before
ple, suppose we decided that we wished calling the show() function on line 47
to modify our loop() function to start and the delay() function on line 48.
by lighting rows 0 and 9 (bottom and
The point of all this is that we are
top), then turn these rows off and light performing a programming balancing
rows 1 and 8, then 2 and 7, then 3 and act. In one possible scenario, we don’t
6, ending with 9 and 0.
create any utility functions, but instead
This is easy-peasy lemon squeezy implement everything as a great big glob
with our existing SetRowColor( ) of code in the main loop() function.
function, but we would be stressedAt the other end of the spectrum,
depressed lemon zest if we had modi- we stick everything into separate funcfied our function as discussed above.
tions, but this could make them clunky
To illustrate this in action. I created a and unwieldy, possibly requiring us
dual-row version of the program using to create multiple versions of each
our existing SetRowColor() function (in function to satisfy the needs of differthe file named CB-Apr25 Code-04.txt). ent use cases.
As illustrated in Listing 4(a), the
The ‘Goldilocks’ solution is to put
modified manipulation of our rows just the right amount of code into our
occurs from line 38 to line 49. I’ve utility functions (not too much and not
also implemented a similar treatment too little). The trick is knowing where
to work with dual columns, as seen to draw the metaphorical line.
from line 53 to line 64.
Since we are now lighting two rows Dutch angles
This is where we return to the task
(or two columns) at the same time, our
new worst-case current draw will be of lighting our pixels in diagonal lines
210mA, which is still well within the across the display, one line at a time.
We will start with what I think of as
capabilities of our Arduino.
Observe the way in which we set ‘backward slash diagonals’ (like the \
two rows to be WHITE on lines 40 and character). That is, starting with the
41 before calling the show() function one-pixel ‘line’ in the bottom left corner
Practical Electronics | April | 2025
0
1
Fig.1: determining
the number of
diagonals based on
the number of rows
and columns.
2
1
4
0
3
0
0
0
1
2
1
5
0
4
2
0
1
2
3
4
5
1
2
3
d = (x + y – 1) = 6
6
7
8
9 10 11 12 13
9
8
22
7
21
6
20
5
19
4
18
3
17
2
16
1
15
0
14
0
1
2
3
4
5
6
7
8
9 10 11 12 13
Fig.2: lighting diagonal lines on our full-size LED array.
at (x, y) = (0, 0) and ending with the
1-pixel ‘line’ in the top right corner at
(x, y) = (13, 9).
Once we have this working, your
homework assignment this month
will be to implement what I think of
as ‘forward slash diagonals’ (like the
/ character). That is, starting with the
1-pixel ‘line’ in the top left corner at (x,
y) = (0, 9) and ending with the 1-pixel
‘line’ in the bottom right corner at (x,
y) = (13, 0).
Before we proceed, for any maths
nerds amongst us, I should admit to
being a little loose with my use of the
word “diagonal”. In mathematics, a
diagonal is a line that connects two
vertices of a polygon or a solid where
these vertices are not on the same edge.
In the case of a square or rectangle, for
example, we are talking about the line
that connects the top left and bottom
right corners or the line that connects
the bottom left and top right corners.
In our case, by comparison, I’m using
‘diagonal’ to mean a line 45° from
horizontal. Actually, even this isn’t
Practical Electronics | April | 2025
1
2
3
3
1
d = (x + y – 1) = 5
0
x=3
2
y=3
y=3
2
x=4
true because our pixels aren’t spaced
equally in the horizontal and vertical
dimensions. But let’s not worry about
that too much.
In the case of ‘backward slash diagonals’, diagonal 0 would be at pixel (x,
y) = (0, 0); diagonal 1 would follow the
(x, y) pixel path (0, 1), (1, 0); diagonal
2 would follow the (x, y) path (0, 2),
(1, 1), (2, 0); diagonal 3 would follow
the (x, y) path (0, 3), (1, 2), (2, 1), (3,
0); and so forth.
Our array has 10 horizontal rows
and 14 vertical columns, so how many
of our 45° diagonals do we have? As
I’ve mentioned on previous occasions,
I often find that sketching pictorial
representations gives me insights that
aid in my program creation activities.
For example, consider the three small
arrays shown in Fig.1.
From this we can deduce that, irrespective of the size of the array, the
number of diagonals is one less than
the sum of the number of rows and
number of columns. In the case of our
14 × 10 array, this means we will have
y=4
x=3
2
5
1
4
0
3
0
1
2
d = (x + y – 1) = 6
(14 + 10 – 1) = 23 diagonals.
As you may recall, our existing programs currently have four definitions
associated with the number of rows and
columns in our array. To these we can
now add a definition associated with
the number of diagonals, resulting in
the following:
#define NUM_ROWS 10
#define NUM_COLS 14
#define NUM_DIAGS 23
#define MAX_X
13
#define MAX_Y
9
Instead of 23, if we wanted to be
really clever, we could put (NUM_
ROWS + NUM_COLS – 1). Then we
wouldn’t need to change the value
if we changed the number of rows or
columns.
Now let’s scale things up to our fullsize array (Fig.2). In the real world,
since we can perform only one task
at a time, when we ‘draw’ our backward slash diagonals on the display,
we must start at one end and work our
way to the other. There are two ways
to do this: either we start with the
upper-left pixel and end on the lowerright pixel (the approach I opted for),
or vice versa.
So, what algorithm are we going to
use? The way I usually approach this
sort of thing is to pick an element at
random and see if I can deduce anything from it. We’ll start with diagonal
d = 6 (highlighted in orange) because
6 is my lucky number.
In this case, our start x value will be
0, our end x value will be 6, and our
start y value will also be 6. Hmmm,
this means that end x and start y are
both equal to d. Well, that’s convenient, but when we delve a little deeper,
we discover that it doesn’t work for all
the diagonals.
Another tool I often use to provide insights for my program creation activities is to create tabular representations of things. For example,
11
Diag d
Start x
End x
Start y
0
1
2
3
4
5
6
7
8
9
0
0
0
0
0
0
0
0
0
0
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
10
11
12
13
9
9
9
9
14
15
16
17
18
19
20
21
22
5
6
7
8
9
10
11
12
13
13
13
13
13
13
13
13
13
13
9
9
9
9
9
9
9
9
9
Listing 5(a): our
‘backward slash’
diagonal LED lighting
utility function.
< NUM_ROWS
< NUM_COLS
< NUM_DIAGS
Fig.3: a table representing our diagonal algorithm.
based on the full-size array in Fig.2,
I created the table shown in Fig.3.
Three distinct areas jump out at us
from the table shown in Fig 3. These
areas are associated with the diagonal
d being (a) less than NUM_ROWS, (b)
greater than or equal to NUM_ROWS
and less than NUM_COLS, or (c) greater
than or equal to NUM_COLS and less
than NUM_DIAGS.
This new intelligence allows us to
create an updated representation of our
array as illustrated in Fig.4. More importantly, the algorithm we are going to use
practically jumps out of our tabular representation. Still, before we go there…
Foxy for() loops
As I mentioned many yonks ago (PE,
May 2020), there’s something rather
clever about for() loops in C/C++ that
professional programmers don’t even
think to mention, which may explain
why many non-professional program0
1
2
3
4
5
6
7
8
mers don’t know anything about it.
Consider the following:
for( initialisation; condition; modification )
As we see, there are three semicolon
separated parts to this statement:
initialisation, which is where we initialise
our control variable; condition, which is
where we test our control variable; and
modification, which is where we modify
our control variable. For example, we
wouldn’t be surprised to see a statement
looking something like the following:
for ( int i = 0; i < 10; i++ )
9 10 11 12 13
9
8
22
7
21
6
20
5
19
4
18
3
17
2
16
1
15
0
14
0
1
2
3
4
5
6
7
8
9 10 11 12 13
Fig.4: full-size array reflecting the info from our table.
12
There are several
aspects to this that
aren’t immediately
obvious to beginners.
Firstly, the modification isn’t obliged
to be a simple increment (++) or
decrement (--), but
can instead be a
more complex expression, such as
“i = i + 3”.
Secondly, the
condition can be
as complicated as
required, such as
“( (i < 10) && (j == 0) )”, for example.
Thirdly, both the initialisation and
modification sections can comprise
multiple comma-separated elements.
We could have something like “i = 0, j
= 0” in the initialisation section. Similarly, we could have something like
“i++, j--” in the modification section.
Let’s keep all this in mind as we proceed to our…
Awesome algorithm
I created a new version of our program in the file named CB-Apr25 Code05.txt. The first thing I did was to create
an additional utility function called
SetBwdSlashDiagColor(), illustrated in
Listing 5(a). This sets all the pixels
in a backward slash diagonal to the
same colour.
It accepts two parameters: the diag
(‘diagonal’) in question, from 0 to 22,
and the color we wish to assign to the
pixels in that diagonal.
Observe that on line 148, we declare three local integer variables:
startX, endX, and startY. These reflect
the columns in our table from Fig.3.
We set the values of these variables
based on the number of the diagonal
we’re working with. This occurs on
lines 150 to 167. I dare to hope that the
way this works is self-explanatory—just
compare this portion of the code to the
three sections of our table.
Practical Electronics | April | 2025
Photo 1: a 7805
linear voltage regulator
in the TO-220 package.
Listing 5(b):
modifications
to the loop()
function.
Last, but certainly not least, we use the
for() loop on line 169 to cycle through
all the pixels forming our diagonal.
This is a prime example of such a loop
employing multiple elements in its initialisation and modification sections.
All that remains is to augment our
loop() function to cycle through the
diagonals on the display. This is illustrated in Listing 5(b). In lines 91 to
100, we illuminate the diagonals, one
at a time, from bottom-left to top-right.
Next, in lines 104 to 113, we reverse the
process, illuminating the diagonals, one
at a time, from top-right to bottom-left.
I’m running this on my array as we
speak - it looks awesome! I can’t wait
for you to see it running you your
own array.
Scotty, I need more power!
I don’t know about you, but I’m tired
of not being able to light all the pixels
on my array simultaneously. That’s
about to change. To do so, however, we
are going to need more power.
Of course, as is usually the case in
engineering, there are multiple options open to us. As I’ve mentioned in
previous columns, my chum Joe Farr
has already built a prototype version
of our retro games console. Before we
turn our attention to my own solution,
it will be instructive for us to consider
the decisions Joe made.
The first key point is that Joe is using
a PIC microprocessor from Microchip
Technology. A related point is that Joe’s
PIC runs at 5V, which is the same as
his main LED array. This means that
Practical Electronics | April | 2025
‘dropout’ nomenclature is that, if the
input voltage falls below the required
level, the regulator cannot maintain
the desired output voltage. Instead,
the output will begin to ‘drop out’ and
follow the input voltage, resulting in
an unregulated output.
According to its data sheet, the absolute maximum input voltage for the
7805 is 35V, but the recommended
input voltage range is 7–25V.
The amount of heat dissipated by a
linear voltage regulator is a function
of the difference between input and
output voltages and how much current we are drawing. If we are pulling
a lot of power, these devices can get
hot. Hotter than one can touch without shouting “Ouch!”. As a result, it’s
common to attach them to a heatsink
(Joe used a strip of metal mounted
inside his console).
As seen in Photo 1, the 7805 is a
3-terminal device. Many (but not all)
of these are prefixed with “LM”, which
stands for “Linear Monolithic”. These
originated with National Semiconductor, which was acquired by Texas Instruments (TI) in 2011. Other versions
of this regulator have related names,
like the L7805CV shown in the photo.
All the 7805 needs is a couple of
extra components in the form of capacitors, and you are ‘off to the races’.
A typical 7805-based circuit is shown
in Fig.5. The voltage rating of the capacitors should be at least a few volts
higher than the maximum they are
Joe’s console requires only a single 5V
supply. Another consideration is that
Joe decided his console should be capable of being powered either from an external source or from internal batteries.
Since the battery-based solution is a
limiting factor, that’s where Joe started.
He opted to use six high-capacity, rechargeable, AA nickel metal hydride
(NiMH) batteries, whose combined 6
× 1.2V gave him 7.2V to play with.
Furthermore, Joe decided to employ
a linear voltage regulator in the form of
a 7805 (Photo 1). Why this particular
device? Joe happens to have a drawer
full of these little scamps in his workshop. This provides a prime example
of how our decisions are sometimes
made for us.
A linear voltage regulator is an electronic device that maintains a constant
output voltage regardless of variations
in the input voltage or load current
(within certain limits). It achieves this
by dissipating any excess power as heat.
One important term associated with
linear voltage regulators is ‘dropout
voltage’. This is the minimum difference between the input voltage and
the output voltage that
the regulator requires
IN (7V to 35V)
to maintain a stable,
LM7805
regulated output. The
7805 supplies an output
100µF
0.1µF
0.1µF
voltage of 5V, and its
dropout voltage is 2V,
which means its input
voltage must be at least
GND (0V)
5V + 2V = 7V.
The reason for the Fig.5: a typical LM7805 regulator-based circuit.
OUT (5V)
10µF
13
expected to see. As always, consult the
data sheet for whatever regulator (and
manufacturer) you are using.
A simplified representation of Joe’s
setup is illustrated in Fig.6. As we
previously discussed, the input voltage must be greater than 7V, and this
input can either come from an external source or from batteries mounted
inside the console.
The 5V output from Joe’s regulator
feeds both his microcontroller and his
LED array. This scheme has the virtues
of low cost and simplicity. The biggest
downside is the fact that the 7805 can
generate a substantial amount of heat
when its output is loaded, which will
occur if we light all the LEDs on our
array, for example.
14
3.3V
5V
GND
GND
Vin
A0
A1
A2
A3
A4
A5
RESET
IOREF
AREF
GND
13
12
~11
~10
~9
8
7
~6
~5
4
~3
2
TX-1
RX-0
We are assuming
>7V
5V
that the current used
LM7805
by the shift registers
themselves will be
MCU
LED
negligible for this
(PIC)
Array
application. It’s hard
to get data sheets for
0V
these modules, but
we are assuming Fig.6: Joe’s power supply setup using a linear regulator.
5mA per segment,
which equates to 40mA if all the seg- reserve the right to change my mind
ments (including the decimal point) are later, in our existing programs, I’m currently running my LEDs with values
lit on a display. This gives us 80mA
of 32 (0x20), which is ~12.5% of their
per module, or 240mA for all three
maximum value (that’s twice the brightmodules.
Let’s add this 240mA to the 50mA ness being used by Joe).
This means that if I’m driving all
for the PIC board and round things up
to 300mA, thereby leaving Joe with the pixels on my array white, this will
result in a current draw of 8400mA ×
700mA for his main array.
Remember that we have 140 pixels, 0.125 = 1050mA (1.05A). If we add
Back of an envelope
each containing R, G, and B LEDs, each 250mA to cover my six 7-segment disThe phrase “back-of-an-envelope of which is specified as consuming plays, this comes to 1300mA (1.3A).
calculation” refers to the practice of 20mA at full power (so 60mA per pixel). I’m going to round this up to 1500mA
performing quick, rough calculations This means that if we actually ran our (1.5A) ‘just to be sure’.
on any piece of paper that’s close to
Note that I’ve excluded the Arduino
LEDs at full power, this would equate
hand, such as the back of a postage to 140 × 60mA = 8400mA (8.4A). Wow! from these calculations because—as
envelope.
After some experimentation, Joe de- we will see—it’s covered by a differIn his version of these calculations, termined that a value of 16 (0x10) out ent power budget.
Joe allocated himself a total power
of a maximum of 255 (0xFF) results
budget of 1A. Starting with the micro- in a display that’s more than bright Powering an Arduino
Unlike Joe, I’m using an Arduino Uno
controller, Joe used an old PIC board enough for gaming without being dazfrom a previous project. This board al- zling. Assuming a linear universe, this R3 to drive my retro games console.
ready had one LED on it. Joe thinks the means he’s running his LEDs at 16 ÷ Also, unlike Joe, I’m not planning on
powering my prototype console using
LED probably consumes more power 255 (or 0x10 ÷ 0xFF) ≃ 6.3%.
than the PIC, but he allocated 50mA
This means that if Joe instructs all batteries; I’m more than happy to use
to the board as a worst-case scenario.
the pixels on his array to display white an external power supply.
There are several ways to power
Joe’s console boasts a total of six 7-seg- light, this will result in 8,400mA ×
ment displays. As we previously dis- 0.063 ≃ 530mA, well within his 700mA an Arduino Uno R3 (Fig.7). One is to
feed 7–12V into the power jack. Also
cussed in the February issue, Joe and budget.
note the bank of header pins marked
I are both using dual-digit 7-segment
POWER. For all intents and purposes,
display modules that include 74HC595 No restraint!
I must admit that I’m impressed with
the VIN pin on this bank is connected to
shift registers. Also, we’re both using
three of these modules in our consoles, Joe’s self-restraint. Sad to relate, how- the positive terminal of the power jack.
ever, I never ran an LED at only 6.3% This means that, as opposed to using
which means a total of six 7-segment
of its rated value in my life. Whilst I the power jack, we can feed 7–12V didisplays and six shift registers.
rectly into the VIN pin.
The Arduino has two onboard regulators. The first takes the voltage
from the power jack (or VIN pin) and
delivers 5V to the board’s internal
5V power rail. In addition to powerDIGITAL IN/OUT (PWM ~)
ing the Arduino itself, this 5V power
USB
rail is also presented as an output on
the POWER section of the Arduino’s
Orange
LED
5V
header pins.
Green LED
Via its header pin, this 5V supply can
be
used to drive external circuits, like
ATmega328P
the breadboard-based clock we created
in our Arduino Bootcamp columns.
Although the Arduino Uno R3 runs
on
5V, many sensors, displays, and
Power
POWER ANALOG IN
other chips use 3.3V. Thus, the 5V
Jack
power rail feeds the input to a second
onboard regulator, which produces
7V to
3.3V. This 3.3V supply is also present12V
ed as an output on the POWER section
of the Arduino’s header pins.
3.3V
5V 7V to 12V
Last, but certainly not least, we can
power the Arduino via its USB port.
Fig.7: this shows a few different ways you can powering the Arduino.
Practical Electronics | April | 2025
9V
BUCK
MCU
(Arduino)
Fig.8: my power
supply setup.
5V
LED
Array
0V
When USB is connected, the Arduino
automatically selects USB as its power
source, overriding any external power
sources.
Since USB provides a stable 5V
supply, this power source bypasses
the board’s 5V regulator and directly
drives the board’s 5V power rail. As
we already discussed, this powers the
Arduino, drives the input to the 3.3V
regulator, and appears on the POWER
header.
Now, here’s the tricky part. Since the
5V pin on the POWER header is directly
connected to the board’s 5V power rail,
as opposed to using it as an output, it
is possible to treat it as an input. However, I wouldn’t recommend doing this.
The 5V pin bypasses the Arduino’s
onboard voltage regulators and protection circuits. This means that if the
power supply you feed into this pin
is unregulated or noisy, it can damage
the microcontroller and other components on the board.
Also, if you connect a 5V power
source to the 5V pin and simultaneously connect the Arduino to a computer via USB, the two power sources
can conflict, possibly damaging your
Arduino and/or your computer.
A well-regulated microcontroller
Based on what we just discussed, I
decided to feed my console with a 9V
power supply. Inside the console, I’m
going to feed this 9V signal directly to
the Arduino’s power jack while prototyping (and to its VIN pin once we’ve
started implementing our games cartridge boards).
I’m also going to feed this 9V signal
through a 5V regulator and use the
output from the regulator to power my
LED array and other console components requiring a 5V supply, like my
7-segment displays, for example.
The next question is how to convert
my 9V source into the 5V I need to power
my array. I could use a linear regulator
like Joe, but I’m not keen on generating
a lot of heat inside my console.
There are two types of DC-to-DC
converters that rely on high-frequency
switching to transfer energy efficiently
from input to output (there are more, but
let’s stick with the two most common
types). DC stands for ‘direct current’,
which means a current that is steady
and flows in one direction only.
Practical Electronics | April | 2025
Photo 2: a 5V buck (stepdown) DC/DC converter module
that claims to be able to deliver 5A
with an input voltage of 9–24V. Spoiler:
it can’t achieve its rated output power...
A ‘boost converter’ steps up the input
voltage to a higher-level output voltage. By comparison, a ‘buck converter’ steps down the input voltage to a
lower-level output voltage. The main
consideration for me is that these devices generate negligible heat (at least,
as compared to their linear regulator
counterparts).
Why “buck”? I think this is like the
way a horse bucks to get someone off
their back; in this case, the buck regulator is relieving the circuit of some
unnecessary voltage, rather than an
unwanted rider.
I found some buck converter modules
on Amazon here in the USA (Photo 2).
At two for only $15, this seemed like a
reasonably good deal. There are equivalents to these modules on Amazon UK
(https://pemag.au/link/ac2m).
These really are rather handy. On
the input side, we have a 2.1mm jack
socket (centre pin positive) and a twoway screw terminal block that’s wired
in parallel with the jack socket. On the
output side, we have another a two-way
screw terminal block wired in parallel
with a USB-A connector, which means
you can also use this to charge your
USB devices if you wish.
These converters purport to accept
anywhere from 9–24V DC as input and
generate up to 5A at 5V at the output.
Since I require only 1.5A (as per our
earlier discussions), these are more
than adequate for my design (Fig.8).
All the 0V rails on the Arduino,
buck converter, and LED array must
be connected (0V is equivalent to GND
for the purposes of these discussions).
The reason why these must all be connected was discussed in detail in the
September 2024 issue.
One point that may prove puzzling to
a beginner involves the buck converter.
Let’s look at the bottom of this board
as shown in Photo 3 (remember this
is my board, yours may vary slightly).
The VIN+ and VIN- annotations correspond to the screw terminal block
on the input side of the board. The 5V
and GND annotations correspond to the
screw terminal block on the output side
of the board. The point is that the VINand GND pins are directly connected
on the board, and these correspond to
the 0V rail in Fig.8.
Photo 3: the underside of the buck converter module.
15
This is designed
to
‘sink’ current and
BUCK
absorb power from a
0V
VINMCU
power source. It’s used
(Arduino)
to simulate a device
0V
that would draw electricity from that source,
Fig.9: another way of looking at my power supply arrangment.
thereby allowing the
user to test the perforWhat this means is that we could re- mance of power supplies, batteries,
draw my setup as illustrated in Fig.9. solar panels, and other energy sources
Although they look a little different, under different load conditions.
the circuits in Fig.8 and Fig.9 are funcWhen Joe applied his electronic
tionally the same.
load to the output of his DC-to-DC
converter, he found it held steady at
Too good to be true
5V up to a load of about 1.7A. How“Caveat emptor” is a Latin phrase that ever, the output sagged to 4.7V when
translates to “let the buyer beware”. It the load reached around 1.8A, and it
refers to the fact that people can and started to fall off rapidly (ie, collapsed)
will try to sell you any old nonsense; by the time the load reached approxiit’s up to you to make sure you’re get- mately 2.1A.
ting what you want.
On the one hand, this is disappointI must admit that when I saw the ing compared to its claims of deliveraforementioned buck converter mod- ing 5A (you can’t trust anyone these
ules—especially their claim to be able days). On the other hand, since I’ve set
to supply up to 5A at 5V—I thought, my maximum power budget at 1.5A,
“that sounds too good to be true”.
my converter will satisfy my requireJoe agreed, so he purchased some
ments, even if it has the same limitasimilar modules of his own for test- tions as Joe’s modules.
ing purposes. Joe has a pretty handy
Note that the output current likely
piece of test equipment called a ‘DC depends on the input voltage, but if
electronic load’.
it can’t even deliver 2A with a 12V
9V
VIN+
5V
Photo.4: I love my new bench power supply.
16
LED
Array
input, there’s no way it will manage 5A
even with the maximum 24V supply
voltage applied.
As one final point, Joe’s electronic
load is an expensive piece of professional equipment, but cheaper hobbyist versions are available. I just found
one on Amazon here in the USA for
only $42.99 (https://pemag.au/link/
ac45), which is around £34.50. This
isn’t something most of us need on a
daily basis, but I can see how it could
come in handy one day, so I’ve added
one to my birthday wish list.
I’ve got the power!
Returning to my setup (Fig.9), the
next thing I’m going to need is a 9V
DC power supply that can deliver at
least 2A. I know we set the maximum
at 1.5A earlier, but I always like to give
myself some headroom.
I could purchase yet another standalone power supply, like the 9V 2A
unit I just found on Amazon in the UK
for about £10 (https://pemag.au/link/
ac46). If you decide to go this route,
make sure to buy the centre-positive
version, which means the centre pin
of the barrel jack carries the positive
voltage while the outer sleeve has the
negative voltage.
This is because the power jacks on
both the Arduino Uno and our DC-to-DC
converter module are centre-positive.
Connecting a centre-negative supply
will either do nothing or do something
very bad, depending on how well designed the powered device is.
To be honest, I’ve bought loads of different power supplies over the years,
but I still never seem to have the one I
need. Joe has a couple of bench power
supplies in his workshop, but I don’t
have the room for one of these in my
study at home (which is where I’m
writing these columns).
I don’t know why it took me so long,
but I looked on Amazon here in the USA
and found an awesome bench power
supply for only about $45 (https://
pemag.au/link/ac47 & Photo 4). I just
found the same unit on Amazon UK
for £50 (https://pemag.au/link/ac48).
This can supply up to 30V and up
to 10A (you set the voltage you want
and the maximum current you wish
the supply to… well, supply). When in
operation, it reports the actual output
voltage along with how much current
your load is sinking, and even the
amount of power it’s delivering.
This little rascal comes with a bunch
of bells and whistles. Best of all, it’s
only around 3.5 inches (9cm) wide,
6 inches (15cm) tall, and 7.5 inches
(19cm) deep, which means it occupies a negligible amount of space on
my desk.
Practical Electronics | April | 2025
One step at a time
I always like to take things step by
step. I’m going to describe what I did
with my setup; you can vary these
steps to reflect your own situation as
required.
First, with its output disabled, I set
my bench power supply to 9V DC and
limited the output current to 250mA
(just in case). Then I connected two
pairs of black (0V) and red (5V) leads
to the black and red terminals on my
power supply. The other ends of these
leads were connected to 2.1mm power
jack plugs.
Before I connected these plugs to
anything, I activated the power supply’s output and used my multimeter
to confirm I was seeing 9V on each
jack’s inner connector.
Then I disabled the power supply’s
output, plugged one of my cables into
my DC-to-DC converter’s input jack,
and re-enabled the power supply’s
output. The power supply showed it
was delivering 9V and 5mA, so now
we know that the converter draws 5mA
even when it’s not driving anything.
I used my multimeter to confirm that
I was seeing 5V at the output of the
converter.
I want to protect my array at all costs.
So, before I did anything else, I disconnected it from my Arduino.
Next, I connected the USB cable from
my PC to the Arduino, and loaded the
standard “Blink” program that comes
with the Arduino (you can use the Arduino IDE to find this under the File →
Examples → 0.1.Basics → Blink menu
item). This repeatedly flashes the Arduino’s onboard LED on for a second
and off again for a second.
Once the Blink program was running, I unplugged the USB cable from
the Arduino, disabled the power supply’s output and plugged the second
cable from the power supply into the
Arduino’s input jack. When I reactivated the power supply’s output, the
Arduino powered up and returned
to running its Blink program. Also,
the power supply now showed it was
delivering 9V and 55mA.
Subtracting the 5mA for the converter shows the Arduino is pulling
50mA, which is as expected.
I disabled the power supply’s output,
reconnected the LED array to the Arduino and enabled the power supply’s
output once again. Remember that I’m
still running the Blink program. Also,
all the pixels in the array power up in
their off condition.
Now, my power supply shows it’s
delivering 9V and 125mA. This is interesting. If we subtract 5mA for the
DC-to-DC converter (whose output we
still aren’t using) and 50mA for the ArPractical Electronics | April | 2025
duino, this leaves
70mA being consumed by the
array. Since we
have 140 pixels,
this means each
pixel consumes
half a milliamp,
even when it’s
not displaying
anything. I must
admit, I wasn’t
expecting that.
Next, I plugged
the USB cable
back into the
Arduino. As we
discussed earlier, when a USB
cable is connected, the Arduino
automatically selects USB as its
power source,
overriding any Listing 6(a): activating all the pixels simultaneously.
external power
sources. Thus, it wasn’t surprising that on working as before. The only differthe power supply returned to deliver- ence was that the Arduino was being
ing only 5mA to power the converter. powered with 9V directly from the
I reloaded our current latest-and- power supply, while the array was
greatest program into the Arduino— being powered by the 5V from the DCthe one that displays single rows, col- to-DC converter.
umns, and diagonals (in the file named
CB-Apr25 Code-05.txt). This program It’s go time!
Now that we have sufficient power,
continued to work as expected.
Finally, I disabled the output from we can activate all the pixels in our
the power supply. I left the control array at the same time. I’ve modified
signal from digital pin 12 on the Ardui- our existing program to do this. The
no feeding the array, but I removed the new version is in the file named CBred (5V) and black (0V) leads from the Apr25 Code-06.txt.
Arduino—the ones that were powering
First, I changed the definitions for
the array—and connected these to the ON_TIME and GAP_TIME to be 2000
output from the DC-to-DC converter.
and 1000 or two seconds and one
When I re-enabled the output from second, respectively.
the power supply, everything carried
Next, I changed the loop() function
Here I am, using my
new power supply
for the first time!
17
to repeatedly turn all the pixels on
(for ON_TIME) and off again (for GAP_
TIME). This portion of the program is
shown in Listing 6(a).
Remember that we are currently
driving our pixels at 12.5% of their
full power. The data sheet says full
power is 60mA per pixel, so when our
140-pixel array is fully lit at 12.5%,
that would equate to 140 × 60mA ×
0.125 = 1050mA. If we add 5mA for
the converter, 50mA for the Arduino,
and 70mA for the intrinsic current
draw of the array with no pixels lit, this
should give a grand total of 1175mA.
Interestingly enough, my bench
power supply reports a maximum
value of only 450mA when all the
pixels are driven white at 12.5%.
That’s less than half of the expected
current draw. Part of the reason for
this is that 450mA <at> 9V is 4.05W,
and if the buck converter is, say, 90%
efficient, that equates to a 5V output
of 4.05W ÷ 5V = 810mA.
In other words, you get more current
out of the buck converter than you put
in because you’re reducing the voltage by more than you’re reducing the
power. Still, it’s a little on the low side.
I will investigate this further, and I’ll
report back next month.
For shame!
I fear I must hang my head in shame.
In my previous column, I promised
that we would be performing some
more experiments with our eightsegment bar graph display in conjunction with a shift register. Sadly, I got
carried away with our retro games console, but we will certainly do this in
my next column (no, my fingers aren’t
crossed behind my back—why would
you ask?).
Until that frabjous day, if you have
any thoughts that you’d care to share
on anything you’ve read here, please
feel free to drop me an email at max<at>
clivemaxfield.com. Until next time,
PE
have a good one!
Useful Bits and Pieces from Our Arduino Bootcamp series
Arduino Uno R3 microcontroller module
Solderless breadboard
8-inch (20cm) jumper wires (male-to-male)
Long-tailed 0.1-inch (2.54mm) pitch header pins
LEDs (assorted colours)
Resistors (assorted values)
Ceramic capacitors (assorted values)
16V 100µF electrolytic capacitors
Momentary pushbutton switches
Kit of popular SN74LS00 chips
74HC595 8-bit shift registers
https://pemag.au/link/ac2g
https://amzn.to/3O2L3e8
https://amzn.to/3O4hnxk
https://pemag.au/link/ac2h
https://amzn.to/3E7VAQE
https://amzn.to/3O4RvBt
https://pemag.au/link/ac2i
https://pemag.au/link/ac2j
https://amzn.to/3Tk7Q87
https://pemag.au/link/ac2k
https://pemag.au/link/ac1n
Other stuff
Soldering guide
Basic multimeter
https://pemag.au/link/ac2d
https://pemag.au/link/ac2f
Components for Weird & Wonderful Projects, part 1
4-inch (10cm) jumper wires (optional)
8-segment DIP red LED bar graph displays
https://pemag.au/link/ac2l
https://pemag.au/link/ac2c
Components for Weird & Wonderful Projects, part 2
144 tricolour LED strip (required)
Pushbuttons (assorted colours) (required)
7-Segment display modules (recommended)
2.1mm panel-mount barrel socket (optional)
2.1mm inline barrel plug (optional)
25-way D-sub panel-mount socket (optional)
25-way D-sub PCB-mount plug* (optional)
15-way D-sub panel-mount socket (optional)
15-way D-sub PCB-mount plug^ (optional)
https://pemag.au/link/ac2s
https://pemag.au/link/ac2t
https://pemag.au/link/ac2u
https://pemag.au/link/ac2v
https://pemag.au/link/ac2w
https://pemag.au/link/ac2x
https://pemag.au/link/ac2y
https://pemag.au/link/ac2z
https://pemag.au/link/ac30
* one required for each game cartridge you build
^ one required for each auxiliary control panel you build
Components for Weird & Wonderful Projects, part 3
22 AWG multicore wire kit
20 AWG multicore wire kit
https://pemag.au/link/ac3m
https://pemag.au/link/ac3n
Components for Weird & Wonderful Projects, part 4
5V Buck converter module
9V 2A power supply (optional)
Bench power supply (optional)
https://pemag.au/link/ac2m
https://pemag.au/link/ac46
https://pemag.au/link/ac48
1551W IP68 miniature enclosures
Learn more: hammondmfg.com/1551w
uksales<at>hammfg.com
01256 812812
18
Practical Electronics | April | 2025
|