This is only a preview of the January 2026 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:
Items relevant to "Variable Speed Drive Mk2 For Induction Motors, Part 2":
|
Max’s Cool Beans
By Max the Magnificent
Weird & Wonderful
Arduino Projects
Part 13: numerical superiority & defying logic
G
oodness gracious me; I simply
cannot believe it’s January
2026 already. I haven’t prepared a speech, and I’ve nothing appropriate to wear!
For those who are joining us for the
first time, we are slowly but surely creating a retro games console. My chum,
Joe Farr, already has a prototype up
and running, as shown in Photo 1.
A bird’s-eye, not-to-scale view of the
console’s front panel is shown in Fig.1.
As we previously discussed, you can
fabricate your console’s front panel
using a laser cutter. Also, you can
use a 3D printer to construct the case.
If neither you nor your friends has
a laser cutter or a 3D printer, you can
always join a local makerspace (also
known as a hack space, hacker space,
fab lab or open workshop). Alternatively, you can start off by simply attaching everything to a piece of pressed
board or ¼-inch plywood (remember
Photo 1: an early version of our retro
games console (Photograph by Joe Farr).
26
that hot glue is your friend, unless it
gets on your skin).
We commenced this epic extravaganza by implementing the 14 × 10
array of tricolour LEDs that will
occupy—nay, dominate—the central area of the front panel. This will
form our main play area.
Next, we introduced the concept of
switch bounce and evolved a cunning
scheme to debounce switches in software. In the fullness of time, we will
utilise a modified version of this software to debounce and access the state of
the eight switches at the bottom of the
fascia panel (shown as “Direction Controls” and “Action Controls” in Fig.1).
More recently, we moved to consider
the 7-segment displays at the top of
the front panels. We will be employing these little scamps to display information such as the current player
(in multi-player games), the current
level (in multi-level games) and the
current score.
We’re utilising prebuilt modules that
include the displays, current-limiting
resistors and 74HC595 8-bit
serial-input, paralleloutput (SIPO)
registers
in one handy-dandy package. These
modules come with two, three or four
digits. Like Joe, I’m using three two-digit
modules, but you can use as many (or
as few) as you wish.
Now let’s plunge headfirst into the
fray with gusto and abandon.
Installing the display modules
In our November 2025 column, we
performed some experiments to determine which segments of the 7-segment
displays on our modules are connected to which bits (outputs) from their
8-bit shift registers.
As part of this, much to our (well,
my) surprise, we discovered that my
modules feature common anode (CA)
displays, as opposed to the common
cathode (CC) components we’d been
expecting. We quickly developed a
solution to address this issue in our
software.
In last month’s column, we decided
on a preliminary set of characters we
wish to display: the digits 0 through
9, space (blank), hyphen (minus), “P”
for “Player” (in multi-player games),
“L” for “Level” (in multi-level games),
along with “E” and “F” for “Error”
and “Fail”, respectively.
We also created a few useful functions: one to modify a score with
a positive or negative delta
(change) value while staying
within minimum and maximum
bounds; one to load a numerical value into our display buffer
using a specified number of digits
with a defined offset (from the least
significant, rightmost digit); and one
to copy the contents of the display
buffer to the displays themselves.
In all these early experiments,
we were working with only a single
two-digit display module. Now it’s
time to connect multiple modules together, as illustrated in Fig.2.
Practical Electronics | January | 2026
illustrated in Fig.3(b)
overleaf, then solder
the wires from the
back, as in Fig.3(d).
7-Segment
Displays
Note that the
“Cutting Plane Line”
Reset
shown in Fig.3(a)
Button
does not mean you
Power
cut the panel. In
Jack
technical drawings,
a cutting plane line
14 x 10
(or section line) inTricolor
dicates the location
LED Array
where an imaginary
cut has been made
through an object to
reveal internal features. This allows
us to see how the
7-segment displays
are fitted within the
Action
Direction
openings in the front
Controls
Controls
panel in Fig.3(b).
Regarding the attachment of the modules, I utilised parts
15-way D-sub connector
Additional controls plug in here
Fig.1: the layout of the front panel on our retro games console. from a black M3 PCB
spacer kit (pemag.au/
There are multiple ways to achieve
link/ac4u). As shown
this. For example, if I were planning to
in Figs.3(b) & (c), the 6mm (~¼in) spacmass-manufacture these consoles, I’d ers, in conjunction with 12mm (~½in)
start by making a jig that would allow machine screws and nuts, result in the
me to insert a display module, apply fronts of the 7-segment displays being
power and run some tests using spring- flush with the face of the panel.
loaded pogo-pin contacts instead of
wired connections. This would allow Testing the multi-module display
In the spirit of adventure, the first
me to quickly test each module individually before proceeding. However, test I performed was to take our latest
since I have only three modules to and greatest program from last month
worry about, creating such a jig seems and run it on my new 6-digit display.
For your edification, I’ve made a
like a lot of effort for a small reward.
copy of this code available in the file
From our earlier breadboard-based
experiments, I have already soldered a named CB-jan26-code-01.txt (as usual,
5-pin header onto the left-hand set of all files mentioned in this column are
pins on what will henceforth be known available as part of the January 2026
as Module 2. However, I’ve omitted download package from the PE website at https://pemag.au/link/ac9b).
this from Fig.2 to avoid confusion.
This program includes a function
We could solder the wires connecting the modules from the front before called NumberToBuffer( ) that accepts
three parameters: the number we want
attaching them to the front panel. In
this case, things would appear as shown to load into our display buffer, the
in Fig.2. For myself, I decided to first number of digits we wish to display,
attach the modules to the front panel, as and the number of digits by which we
25-way D-sub connector
SDI = Serial data in
SCLK = Shift register clock
LOAD = Output register clock
Game cartridge plugs in here
Most significant digit (MSD)
Digit 5
Digit 4
wish to offset the value we display
from the least significant digit (LSD)
on the right of the display.
If offset is 0, then the rightmost digit
of the value to be displayed will appear
on digit 0 of the display; if offset is 1,
then the rightmost digit of the value to
be displayed will be loaded into digit
1 in our buffer and appear on digit 1
of the display; and so forth.
As you may recall, the current version of this program is based on a
2-digit display, so its NUM_DIGS
(“number of digits”) preprocessor
macro constant is set to 2.
The program repeatedly modifies
the value of P1Score (Player One’s
score), counting up from MIN_SCORE
to MAX_SCORE and then back down to
MIN_SCORE, where MIN_SCORE and
MAX_SCORE are 0 and 99, respectively.
The key part of this program (insofar
as our discussions here) is where we
call the NumberToBuffer( ) function to
display the current value of P1Score
using the following statement, where
2 is the number of digits to be displayed and 0 is the offset.
NumberToBuffer(P1Score, 2, 0);
Without running the program, what
do you think will happen?
Since the program thinks it’s writing to a 2-digit display, we end up
with the following sequence:
∆∆ ∆∆ ∆∆
00 ∆∆ ∆∆
01 00 ∆∆
02 01 00
03 02 01
04 03 02
: : :
99 98 97
98 99 98
97 98 99
96 97 98
: : :
I’m using triangle (∆) characters to
indicate blanks (all segments off) on
the displays. If things are happening
Least significant digit (LSD)
Digit 3
Digit 2
Digit 1
Digit 0
VCC (+5V)
GND (0V)
SDI [11]
SCLK [13]
LOAD [12]
Arduino
pin numbers
Module 2
Module 1
Module 0
Fig.2: how I connected the display modules together. Your connections will be similar but it will depend on the exact modules used.
Practical Electronics | January | 2026
27
Fig.3: different views showing how I mounted and wired up the display modules. Don't cut along the "Cutting Plane Line!".
too fast for you to see what’s happening on your own setup, you can always
increase the UPDATE_RATE value to,
say, 1000 (one second) or more.
The way to think about this is that
the program is physically writing to
the two digits on the left of the display (digits 5 and 4).
When we shift a new value into
these digits, their original contents
are shifted into the two digits in the
middle (digits 3 and 2).
Similarly, the original contents of
the two digits in the middle are shifted
into the two digits on the right (digits
1 and 0).
For my next test (in the file named
CB-jan26-code-02.txt), I decided to
use all six digits. I reduced the value
of UPDATE_RATE to 10 (ten milliseconds, or a hundredth of a second),
I changed NUM_DIGS (‘number of
digits’) from 2 to 6, and I changed
the MIN_SCORE and MAX_SCORE
values to -99999 to 999999, respectively. I also modified the call to the
28
NumberToBuffer( ) function to read:
NumberToBuffer(P1Score, 6, 0);
the NumberToBuffer() function to read:
NumberToBuffer(P1Score, 4, 1);
This produces the following sequence:
As you would expect (or hope),
this results in the following sequence:
∆∆ ∆∆ ∆∆
-9 99 99
-9 99 98
-9 99 97
: : :
-0 00 01
00 00 00
00 00 01
: : :
99 99 98
99 99 99
99 99 98
: : :
For my next test (in the file named
CB-jan26-code-03.txt), I decided to
present a 4-digit number in the centre
of the display, leaving digits 0 and 5
blank. In this case, I set the MIN_SCORE
and MAX_SCORE values to 0 and 9999,
respectively. Also, I modified the call to
∆∆ ∆∆ ∆∆
∆0 00 0∆
∆0 00 1∆
∆0 00 2∆
: : :
∆9 99 8∆
∆9 99 9∆
∆9 99 8∆
: : :
My next test (in the file named CBjan26-code-04.txt) was a variation on
this theme. All I did was change the
call to the NumberToBuffer( ) function to:
NumberToBuffer(P1Score, 4, 2);
This produces the following sequence:
Practical Electronics | January | 2026
Photo 2: a droolworthy display if ever I saw one.
∆∆ ∆∆ ∆∆
00 00 ∆∆
00 01 ∆∆
00 02 ∆∆
: : :
99 98 ∆∆
99 99 ∆∆
99 98 ∆∆
: : :
For my final experiment (for now),
I went for broke (see the file named
CB-jan26-code-05.txt). In this case, I
decided that my virtual Player One
was playing a game with nine levels
numbered 1 to 9. For each level, the
score ranges from 0000 to 9999.
I display the letter ‘L’ (for level) in the
most-significant digit (digit 5) and the
level itself in digit 4. Meanwhile, the
score is presented on digits 0 through 3.
This results in the following sequence:
∆∆ ∆∆ ∆∆
L1 00 00
L1 00 01
: : :
L1 99 98
L1 99 99
L2 00 00
L2 00 01
: : :
L9 99 98
L9 99 99
L1 00 00
: : :
Photo 2 shows this program running
on my real-world display.
confused about how we perform both
mathematical and bitwise operations
on the contents of the same variable.
If poor old Walter is baffled and bewildered, he’s probably not alone, so I
think it behooves us to take a few moments to ensure we are all tap-dancing
to the same skirl of the bagpipes.
Apart from anything else, the stuff
I’m about to tell you will make some
of the things we’ve already been doing
with respect to bit manipulation and
bit shifting operations a lot clearer.
All of this will come in handy in the
future when we start creating games
for our retro gaming console.
Setting the scene
For the sake of these discussions,
let’s assume that we’ve already declared three 8-bit unsigned integer
variables (of type uint8_t) called a,
b and y.
We could use any of the following
statements to assign a value to variable a:
a = 85;
a = 0x55;
a = 0b01010101;
Bit 7
Practical Electronics | January | 2026
Bit 0
b = 15;
b = 0x0F;
b = 0b00001111;
// Decimal
// Hexadecimal
// Binary
In all cases, the eight bits forming
variable b will end up containing
00001111.
How we view and manipulate these
variables is entirely up to us; for example, we can treat them as numbers
or as collections of bits. Furthermore,
we can switch between these views
and mix them as we wish.
Mathematically speaking
We can perform a variety of mathematical operations on the contents
of our integer variables, including +
(addition), - (subtraction), * (multiplication), / (division), and % (modulo).
For example, consider addition, as
shown in Fig.4(a), and subtraction,
as depicted in Fig.4(b).
Bit 7
Bit 0
Variable a
Variable a
0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1
Variable b
Variable b
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
y=a+b
y=a–b
+
-
A haze of confusion
Before we proceed further, I’m afraid
we may need to ‘wind things back’ just
a little. Don’t worry; this is going to
be interesting. Honest!
I recently received an email from a
reader called Walter. He is confused
about the difference between the bitwise operators (~ [NOT], & [AND]
and | [OR]) and the logical operators
(! [NOT], && [AND] and || [OR]).
Walter has been experiencing several
‘bad hair days’ recently because he’s also
// Decimal
// Hexadecimal
// Binary
In all cases, the eight bits that form
variable a will end up containing
01010101. Similarly, we could use
any of the following statements to
assign a value to variable b:
Bit 7
Bit 0
Bit 7
Bit 0
0 1 1 0 0 1 0 0
0 1 0 0 0 1 1 0
Variable y
Variable y
(a) Addition
(b) Subtraction
Fig.4: example calculations of the sums and differences of 8-bit binary numbers.
29
Bit 7
Bit 0
Bit 7
Bit 0
Bit 7
Bit 0
Bit 7
Bit 0
Variable a
Variable a
Variable a
Variable a
0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1
Variable b
Variable b
Variable b
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
y = ~a
y=a&b
y=a|b
y=a^b
~
&
|
^
Bit 7
Bit 0
Bit 7
Bit 0
Bit 7
Bit 0
Bit 7
Bit 0
1 0 1 0 1 0 1 0
0 0 0 0 0 1 0 1
0 1 0 1 1 1 1 1
0 1 0 1 1 0 1 0
Variable y
Variable y
Variable y
Variable y
(a) NOT
(b) AND
(c) OR
(d) XOR
Fig.5: four different bitwise operations performed on 8-bit integer values: not (~), and (&), or (|) and xor (^).
Not surprisingly, 85 + 15 = 100
in decimal (64 in hexadecimal or
01100100 in binary). Similarly, 85 –
15 = 70 in decimal (46 in hexadecimal or 01000110 in binary).
So, “bitwise” literally means “in
the manner of bits” or “with respect
to individual bits.”
Bitwise operators treat their operands as raw bit patterns rather than
numerical values. When we perform
a bitwise operation, the CPU manipulates each bit independently; it’s not
working on the number as a single
value, but rather bit by bit.
In the case of the & (AND) operation shown in Fig.5(b), for example,
bit 0 of a is ANDed with bit 0 of b,
and the result is stored in bit 0 of y;
bit 1 of a is ANDed with bit 1 of b,
and the result is stored in bit 1 of y,
and so forth.
All these individual AND operations take place simultaneously, so
the operation (a & b) consumes only
a single Arduino clock cycle when
working with 8-bit values.
Feeling a bit bitwise
Once again, let’s assume that we
start with our a variable containing
binary 01010101 and our b variable
containing binary 00001111. There are
four operators known as the ‘bitwise
operators’: ~ (NOT), & (AND), | (OR),
and ^ (XOR). Examples of these operations performed on our 8-bit variables are shown in Figs.5(a), (b), (c),
& (d), respectively.
The ~ (NOT) bitwise operator is a
unary operator, which means it performs its magic on a single operand
(value or variable). As a point of interest, ‘unary’ comes from the Latin
root unus, meaning “one”. The other
bitwise operators are binary operators, which means they act on two
operands (‘binary’ comes from the
Latin bini, meaning “two at a time”
or “in pairs”).
The word “bitwise” comes from
two parts: “bit”, short for binary digit,
which is the smallest unit of data (0
or 1), and “wise”, an English suffix
meaning “in the manner of” or “with
respect to”.
Bit 7
Bit 0
Logically speaking
There are three more operators: !
(NOT), && (AND), and || (OR). These
operators evaluate the ‘truth values’
of their operands (which we can think
of as ‘inputs’) and produce a truth
(Boolean, or true/false) value as a
result.
In the case of the operands (inputs),
a zero (0) value is considered false,
while any non-zero value is considered
Bit 7
Bit 0
Bit 7
Bit 0
Variable a
Variable a
Variable a
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 1 0 1 0 1 0
y = !a
y = !a
y = !a
!
!
!
Bit 7
Bit 0
Bit 7
Bit 0
Bit 7
if (a && b) {}
if (a || b) {}
Bit 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Variable y
Variable y
Variable y
(a) a = false, y = true
(b) a = true, y = false
(c) a = true, y = false
Fig.6: the logical not (!) operator works differently from the bitwise one (~).
30
true. By comparison, the output from
a logical operator is always 0 (false)
or 1 (true).
Let’s start with the ! (NOT) operator, depicted in Fig.6. The first case
shown in Fig.6(a) isn’t surprising; a 0
(false) is transformed into a 1 (true).
Similarly, in Fig.6(b), a 1 (true) is
transformed into a 0 (false).
It’s the example shown in Fig.6(c)
that can trip up beginners. In this case,
even though bit 0 of a is 0, variable a
as a whole contains a non-zero (true)
value, which will be transformed by
the ! (NOT) operator into a 0 (false)
output.
The && (AND) logical operator evaluates the truth values of its operands.
If both are non-zero, (true), then the
result is 1 (true); otherwise, the result
is 0 (false). For example, if a = 5 (nonzero, true) AND b = 9 (non-zero, true),
then the result of y = a && b will be y
= 1 (true). However, if either (or both)
a or b is 0 (false), the result of y = a
&& b will be y = 0 (false).
The || (OR) logical operator also
evaluates the truth values of its operands. If either is non-zero (true),
the result is 1 (true); otherwise, the
result is 0 (false). For example, if a =
5 (non-zero, true) OR b = 9 (non-zero,
true), the result of y = a || b will be
y = 1 (true). However, if both a and
b are 0 (false), the result of y = a || b
will be y = 0 (false).
It’s important to note that these operators can also be used to ask questions, like:
If the result of the logical operation
is true (1), then all the statements contained in the squiggly brackets { } will
be evaluated; otherwise, the processor will skip over them and continue
to the next statement in the program.
Practical Electronics | January | 2026
Original value in variable a
a = a << 1
1 1 1 0 0 1 1 1
Result in variable a
1 1 0 0 1 1 1 0
MSB “falls off the end”
0 shifted into LSB
(a) logical shift left on unsigned 8-bit value (uint8_t)
Original value in variable a
a = a >> 1
1 1 1 0 0 1 1 1
Result in variable a
0 1 1 1 0 0 1 1
LSB “falls off the end”
0 shifted into MSB
(b) logical shift right on unsigned 8-bit value (uint8_t)
Fig.7: logical bit shifts (left and right) on unsigned 8-bit integers.
Original value in variable c
c = c >> 1
1 1 1 0 0 1 1 1
Result in variable c
0 1 1 1 0 0 1 1
LSB “falls off the end”
0 shifted into MSB
(a) logical shift right on signed 8-bit value (int8_t)
Original value in variable c
c = c >> 1
1 1 1 0 0 1 1 1
Old MSB shifted into new MSB
Result in variable c
1 1 1 1 0 0 1 1
LSB “falls off the end”
(b) arithmetic shift right on signed value (int8_t)
Fig.8: the two possible types of right shift options on signed integers (8-bit in this case).
Shift over!
Now, let’s assume that we load our
8-bit unsigned variable a with a value
of 11100111 in binary (E7 in hexadecimal, 231 in decimal). We can use the <<
(left shift) or >> (right shift) operators
to shift this value to the left or right
(Fig.7). The shift operators belong to
the same general category as the bitwise logical operators on the basis
that they manipulate the contents of
variables at the bit level.
In this example, we are shifting by
only a single bit (eg, a = a << 1), but
we can shift by as many bits as we
wish (eg, a = a << 3). Irrespective of
the number of bits shifted, these instructions will consume only a single
Arduino Uno clock cycle when performed on 8-bit variables.
The shifts performed on unsigned
integers are always “logical shifts”,
meaning that the values shifted in are
always 0s, irrespective of the shift direction. If only life were always this
simple, but, of course, it isn’t, as we
shall see…
Assume that we declare an 8-bit
signed integer variable (of type int8_t)
called c. Also, assume that we load
this variable with the same binary
pattern of 11100111 that we started
with before. This still equates to E7
in hexadecimal; however, it now represents –25 in decimal (we’ll discuss
the rationale behind the signed binary
format further in our next column).
Practical Electronics | January | 2026
If we perform a left shift on a signed
integer, then this will be implemented as a logical shift; that is, 0s will be
shifted into the least significant digits.
However, if we perform a right shift
on a signed integer, there are two possibilities, as illustrated in Fig.8.
The first possibility is a logical right
shift, in which 0 is copied into the
most significant digit(s), as illustrated
in Fig.8(a). This is equivalent to a logical right shift on an unsigned integer.
The second possibility is known as an
arithmetic shift right. In this case, the
original value in the MSB is copied
into the most significant digit(s), as
illustrated in Fig.8(b).
The reason we might prefer an arithmetic right shift over a logical right
shift with signed integers is too involved to go into here (we’ll discuss
this further in our next column). However, this point is largely academic because the silly sausages who created
the original C (and later C++) specifications left this choice unspecified,
leaving it up to the compiler implementers.
As a result, we, the users, have no
clue what to expect (although most
modern compilers do the logical thing
and use an arithmetic shift in this case;
we’ll explain why that makes sense
next month). This is why I usually
declare my integer variables as unsigned whenever I intend to perform
bitwise operations on them.
Operator Description
==
Equal to
Example
a == b
!=
Not equal to
a != b
<
Less than
a < b
<=
Less than or equal to
a <= b
>
Greater than
a > b
>=
Greater than or equal to
b >= b
Fig.9: C/C++'s main comparison operators.
Beyond compare
The C/C++ programming languages provide a suite of equality and relational operators; the main ones are
shown in Fig.9. These operators are
used to compare two values; for example, to check whether one is greater
than, less than, or equal to another.
Each comparison produces a Boolean
result: true (1) or false (0).
These operations allow us to ask
questions, like the following:
if (a == b) {}
if (a != b) {}
If the result of the comparison is true
(1), all the statements in the squiggly
brackets { } will be evaluated; otherwise, the processor continues on to
the next statement. This also allows
us to ask questions like:
if (a == true) {}
If a is a Boolean value (true or false),
that is the same as asking:
if (a) {}
Similarly, we could say:
if (a == false) {}
or
if (a != true) {}
Assuming a is Boolean, these are
the same as asking:
if (!a) {}
Of course, we can use the logical
operators to combine multiple comparisons, such as:
If ((a > b) && (c == d)) {}
You can read that as “if a is greater
than b and c equals d, do something;
otherwise, don’t”.
Without precedence
I mentioned this a couple of years
ago, but it’s well worth repeating. In
the context of computer programming
languages like C and C++, the term
31
“precedence of operators” refers to the
order in which operations are performed.
For example, the multiplication,
division, and modulo operators (*, /,
and %) have higher precedence than
the addition and subtraction operators
(+ and –), and all of these arithmetic
operators have higher precedence
than the logical and relational operators discussed above (well, except for
the unary operators ~ and !).
You may recognise this as being
similar to the basic rules of arithmetic, eg, 2 + 3 × 4 = 14, not 24, because
you multiply before adding.
To be honest, this can be a bit of a
minefield. For example, a + b == 7
is evaluated the same as (a + b) == 7,
while a & b == 7 is evaluated identically to a & (b == 7).
Now, how would you expect the
condition a + 6 > b / 2 && c * 3 < d
– 5 to be evaluated? Suffice it to say
that this is why you’ll find my code
includes more than its
fair share of brackets ( )
Compound
to enforce the preceAssignment
dence I require (see
https://w.wiki/FvmS
a += b;
for more details).
Operation
Standard
Assignment
Addition
a = a + b;
Subtraction
a = a - b;
Multiplication
a = a * b;
a *= b;
Division
a = a / b;
a /= b;
Modulo
a = a % b;
a %= b;
Bitwise AND
a = a & b;
a &= b;
Bitwise OR
a = a | b;
a |= b;
Bitwise XOR
a = a ^ b;
a ^= b;
Shift Left
a = a << b;
a <<= b;
Shift Right
a = a >> b;
a >>= b;
a -= b;
Fig.10: the compound operators in C/C++.
Compounding the
problem
Since we’ve already
covered such a lot of
ground, we may as well
remind ourselves that C
and C++ provide a set
of compound operators
that offer a shorthand
way of combining an
operation with an assignment (see Fig.10).
Observe that there
are no ~= or != operators
listed in that table
Devices and components used in this issue
Arduino Uno R3 microcontroller module
Solderless breadboard
4-inch (10cm) jumper wires (optional)
8-inch (20cm) jumper wires (male-to-male)
LEDs (assorted colours)
Resistors (assorted values)
Ceramic capacitors (assorted values)
16V 100µF electrolytic capacitors
8-Segment DIP red LED bar displays
74HC595 8-bit shift registers
Dual 7-segment display modules
0.1” pitch header pins
PCB spacer kit (black, M3)
32
https://pemag.au/link/ac2g
https://amzn.to/3O2L3e8
https://pemag.au/link/ac2l
https://amzn.to/3O4hnxk
https://amzn.to/3E7VAQE
https://amzn.to/3O4RvBt
https://pemag.au/link/ac2i
https://pemag.au/link/ac2j
https://pemag.au/link/ac2c
https://pemag.au/link/ac1n
https://pemag.au/link/ac8i
https://pemag.au/link/ac8j
https://pemag.au/link/ac4u
Photo 3: try pushing my buttons, I dare you!
because bitwise NOT (~) and logical
NOT (!) are unary, not binary—ie, they
act on a single operand (although you
can write lines like a = ~a; or a = !a;).
Also, for reasons that are obvious
when we think about it a little, there
are no compound assignment forms
for the logical AND (&&) and logical
OR (||) operations, so we always need
to write these out explicitly.
Educational? I should say so!
It probably goes without saying (but
I’ll say it anyway) that one of the advantages of subscribing to a magazine
like Practical Electronics is that you
get material like the above. This is like
a canned and distilled version of an
educational course that you’d normally
pay good money for. It’s just one more
service I provide. You’re welcome.
Next time
I ended my last column saying, “…
despite previous broken promises, we
really will add the eight push-button
switches to our console’s front panel”.
Although I didn’t actually find the
time to wire these little rascals up, I
have indeed attached them to my front
panel, as shown in Photo 3, which
means I can’t be accused of “prevaricating around the bush”, as Wallace
might say. Still, more on that soon!
As always, if you have any thoughts
you’d care to share on anything you’ve
read here, please feel free to email me
PE
at max<at>clivemaxfield.com
Practical Electronics | January | 2026
|