This is only a preview of the March 2023 issue of Practical Electronics. You can view 0 of the 72 pages in the full issue. Articles in this series:
|
Max’s Cool Beans
By Max the Magnificent
Arduino Bootcamp – Part 3
I
I like things to be logical. One
of the reasons I enjoy playing with
microcontroller units (MCUs) like
the Arduino is because the way they
work inside is based on logical functions and the programs we run on them
behave in a logical manner (on a good
day… if we’re lucky).
would be mega-cool to be performing the
experiments in these columns on an Arduino Uno we’d actually built ourselves.
Great Scottish bagpipes!
left everything ‘as is’ from our previous
experiments, the green power LED on
the right-hand side of the breadboard
should light up. Also, the last program
we loaded into the Arduino should start
randomly lighting the segments on the
7-segment display.
AREF
GND
13
12
~11
~10
~9
8
7
~6
~5
4
~3
2
TX-1
RX-0
Speaking of bagpipes (we weren’t, but
we are now), let’s pretend we are in a
marching band, in which case it’s important to ensure we’re all marching in
I also enjoy mulling over logical conunToo much power!
step to the same drumbeat.
drums. For example, did you ever see the
We’re not going to go through the calculaAs you may recall, in Part 1 of this
1986 fantasy film Labyrinth? This movie is
tion to determine the minimum value of
mega-miniseries (PE, January 2023), we
full of riddles and puzzles, including one
an LED’s current-limiting resistor again
plugged a single green light-emitting
involving two doors, each with a guard.
because – as we discussed in Part 2 – you
diode (LED) into our breadboard, along
One door leads to where we want to go
should have this documented in your logwith a 100Ω current-limiting resistor. We
while the other leads to certain death. We
book. Suffice it to say, our green LED’s
use this LED (a) because we love LEDs
can pose a single question to just one of
forward-voltage drop (VF) is specified
and (b) to provide a visual indication
the guards to help us determine which
as being 3V and its maximum forward
that power is reaching the breadboard.
door we wish to use. The problem is, alcurrent (IF) is 20mA. Based on this, we
In Part 2 (PE, February 2023), we
though we know one guard always tells
decided to use a 100Ω resistor (Fig.1).
plugged a single-digit common-caththe truth and the other always lies, we
This value is reflected in the resistor’s
ode 7-segment display into our breaddon’t know which is which. So, what
brown-black-brown colour bands (Fig.2).
board, connected 150Ω current-limiting
question should we ask? (The answer
Using the maximum current isn’t a
resistors to each of this device’s anode
is at the end of this column.)
problem per se, except for the fact that
terminals, and connected the other side
the LED may be a tad too bright for our
of those resistors to some of the Arduiviewing pleasure. On the other hand,
Roll your own
no Uno’s digital input/output (I/O) pins,
it’s not good practice to drive an elecBy some strange quirk of fate, shortly after
which we configured to act as outputs.
tronic component at any of its maximum
I commenced penning this piece, my old
A circuit diagram reflecting the currated values. For example, LEDs tend to
chum Alvin Brown sent me a link to a
rent state of play is shown in Fig.1. This
dim with age and this dimming is exreview on the Tom’s Hardware website
is obviously an abstraction that reflects
acerbated if we constantly run them at
(https://bit.ly/3WbawFo). You can only
much-simplified views of our real-world
their maximum rated current value. In
imagine my surprise and delight to disArduino and 7-segment display. Differthis situation, we might want to double
cover that this review features a Build
ent people will draw these diagrams
Your Own Arduino Uno Kit. (In addiin different ways, but the gist will
tion to the Uno itself, the kit includes an
We’ll discuss this later
always be the same. It’s important
Audio Synthesiser ‘shield’ (a board that
for you to learn how to parse this
plugs on top of the Arduino) that you can
A
F
sort of diagram and wrap your brain
build and use to make sounds or music.
around the underlying functionality
If you are just starting out with microconB
G
it’s intended to convey.
trollers (which would explain your barely
A more ‘real-world’ depiction of our
controlled excitement at the thought of
E
DP
breadboard’s layout and wiring – inreading this column), you might want to
cluding the connections between the
leave building your own Arduino for later.
breadboard and the Arduino Uno –
On the other hand, you must agree that it
D
C
is illustrated in Fig.2. Take
a moment to compare and
Arduino
7-Segment Display
contrast the different views
150Ω
E
5V
A
1
7
of the design provided by
D
2
6
a
F
B
C
these two representations
4
5
DP
G
5
and make sure that every4
k
B
6 E
GND 5V
3
C
thing makes sense.
A
7
2
From
F
100Ω
D
Before
we
proceed,
con9
DIGITAL IN/OUT (PWM ~)
9
Arduino
G
10
3 8
GND 8
nect the USB cable powering your Arduino. Assuming your host computer is Fig.2. Actual layout and wiring (Arduino shown
Fig.1. Circuit diagram showing the current state of play. powered up and you’ve in blue).
DP
Practical Electronics | March | 2023
61
Experiments
from Part 1
Experiments
from Part 3
5V
a
220Ω
a
a
k
k
k
220Ω
D6
a
D6
D10
a
D10
330Ω
k
k
a
330Ω
GND
k
(a)
(b)
(c)
(d)
Fig.3. Experiments with individually
packaged LEDs.
the resistance to 200Ω, thereby halving
the current to 10mA. Unfortunately, the
closest value I have in my variety pack
of resistors is 220Ω (with colour bands of
red-red-brown), but ‘that’s close enough
for government work,’ as they say.
You might wish to experiment further
by gradually increasing or decreasing
the resistor value until you achieve a
brightness that pleases your eye (don’t
go lower than 100Ω, or you will end up
with a dead LED). If you do decide to
perform this experiment, remember to
keep track of the results in your logbook.
In the case of our 7-segment display,
since each of this display’s red LEDs has
a VF of 2V and an IF of 20mA, we decided to use 150Ω resistor values on its
anode terminals (Fig.1). These resistors
have brown-green-brown colour bands
(Fig.2). Based on our discussions above,
we could decide to double the values of
these resistors to 300Ω. In this case, the
closest value I have is 330Ω (with colour
bands of orange-orange-brown).
We will use a 330Ω resistor with the
individual red LED we are going to experiment with in a moment. In the case
of our 7-segment display, however, for
reasons that will be made clear in the
fullness of time, we are going to stick
with our existing 150Ω current-limiting resistors.
One LED (how sad)
Before we return to experimenting with
our 7-segment display, let’s take a little
diversion that will help increase our understanding of what’s happening inside
the Arduino.
Remember that an LED will turn on
and light up if its anode (a) terminal is
at a more positive potential than its cathode (k) terminal (this assumes that the
potential difference is greater than the
LED’s VF value, of course).
In Part 1, we created our own version
of the standard Arduino Blink program
(‘sketch’ in the vernacular of the Arduino community). As part of this, we
configured the Arduino’s digital input/
output (I/0) pin 6 to act as an output. We
62
then used this output to drive the anode
terminal of an LED whose cathode terminal was connected to GND (0V) via a
current-limiting resistor (Fig.3a).
In the most current version of this program, we commence with three #define
statements – you can access this program, file CB-Mar23-01.txt, and all the
others mentioned here from the March
2023 page of the PE website at: https://
bit.ly/pe-downloads
#define PIN_LED
#define LED_ON
#define LED_OFF
6
HIGH
LOW
Later, in the body of the program, we use
these definitions in calls to the Arduino’s digitalWrite() function to turn
our LED on for 100ms and off for 900ms,
thereby providing a 1/10th-second flash
once each second.
// Turn the LED on
digitalWrite(PIN_LED, LED_ON);
delay(100);
// Turn the LED off
digitalWrite(PIN_LED, LED_OFF);
delay(900);
When we compile our source code into
the machine code that will run on the
Arduino, the preprocessor will replace
any instances of PIN_LED, LED_ON,
and LED_OFF with 6, HIGH, and LOW,
respectively. In the case of an Arduino
Uno, when they are presented to the outside world, HIGH equates to 5V and LOW
equates to 0V.
In a variation of this experiment, we
used the same output to drive the cathode terminal of an LED whose anode
terminal was connected to 5V via a
current-limiting resistor (Fig.3b). As
part of this, we modified our LED_ON
and LED_OFF definitions as follows
(file CB-Mar23-02.txt):
#define LED_ON
LOW
#define LED_OFF HIGH
Had we not performed this modification, instead sticking with our original
version of the program, then the LED in
Fig.3b would have been on for 9/10th of
a second and off for 1/10th of a second.
also connected to the Arduino’s digital I/O
pin 10. The reason we are using pin 10 in
this case is that we’re already using pins 2
through 9 to drive our 7-segment display.
So, what do you think will happen if
the Arduino drives a LOW or a HIGH on
pin 10. While you are pondering this
question, let’s take a moment to note
that the circuit in Fig.3d is functionally
equivalent to that in Fig.3c. The only
reason for showing Fig.3d is to remind
ourselves that (in a series circuit) the ordering of an LED and its current-limiting
resistor doesn’t matter.
Returning to our question. If there’s a
LOW (0V) on pin 10, then the green LED
will have 5V on its anode and 0V on its
cathode, so it will start conducting and
light up. Meanwhile, the red LED will
have 0V on both its anode and cathode,
which means it will do nothing at all.
Contrariwise, if the Arduino drives
a HIGH (5V) on pin 10, then the green
LED will have 5V on its anode and 5V
on its cathode, which means it won’t do
anything. By comparison, the red LED
will have 5V on its anode and 0V on its
cathode, which means it will start conducting and light up.
Unplug the USB cable from your Arduino, and then implement the circuit
from Fig.3c in an unused area of your
breadboard. However, in the case of the
jumper wire connected to the centre point
between the two LEDs, let’s not connect
that to pin 10 on the Arduino just yet. Instead, let’s leave it as a flying lead (Fig.4).
The reason for keeping this as a flying
lead is because – as we discussed in Part
2 – we can make our lives a lot easier by
making sure our hardware is working as
planned before we start trying to drive
it with our software.
Once you’ve wired this circuit up,
plug the USB cable back into the Arduino. Once again, our original green LED
will light up and we will see the random
lighting of the segments on the 7-segment
display. In the case of our two new LEDs,
since their combined forward-voltage
drop as specified in their data sheets
is 5V (3V for the green LED plus 2V for
the red LED), these LEDs should both
be turned off. In the real world, however, their forward voltage drops may be
Two LEDs (twice the fun)
Now look at Fig.3c. In this case, we have
a green LED whose anode is connected
to 5V via its current-limiting resistor. We
also have a red LED whose cathode is
connected to 0V via its current-limiting
resistor. Observe that, in this case, we are
using our new 220Ω and 330Ω resistor
values as discussed earlier in this column.
The green LED’s cathode is connected
to the red LED’s anode, and this point is
Fig.4. Two LEDs is twice the fun.
Practical Electronics | March | 2023
Let’s create an updated version of our early Blink program to drive our red-green
LED combo. In the past, we associated definitions of LED_ON
and LED_OFF with HIGH and
LOW (or LOW and HIGH) respectively, but these definitions
no longer cut the mustard, as
it were. We need to employ
more meaningful definitions,
as shown in Listing 1 (see also
file CB-Mar23-03.txt).
Observe that we’ve changed
our PIN_LED definition to be
associated with pin 10 on the
Arduino. Also, we are now
associating RED_ON_GREEN_
OFF and RED_OFF_GREEN_ON
with HIGH and LOW, respecListing 1. Using definitions more suited to our red/green tively. Although our new definitions are a tad more verbose
LED combo.
(perhaps ‘robust’ would be a
better word), they make it easy for people
less than stated on their datasheets, in
to understand the tasks this program is
which case both LEDs may light up to
intended to accomplish.
some extent.
Use the Arduino’s IDE to capture this
If you plug the free end of the flying
code, click the Verify icon (or use the
lead into one of the holes on the breadSketch > Verify/Compile command) to
board’s 5V rail (the one with the red
make sure things are as they should be,
line), the green LED should turn off and
then click the Upload icon (or use the
the red LED should light up. If you now
Sketch > Upload command) to upload
unplug the flying lead from the 5V rail
the resulting machine code into the Arand plug it into one of the holes on the
duino and feast your orbs on your flashbreadboard’s 0V rail (the one with the
ing LEDs.
blue line), the green LED should light up
and the red LED should turn off.
Just for giggles and grins, unplug the
Layers of abstraction
flying lead from the breadboard’s 0V
I don’t know about you, but I always
rail and plug it into the hole indicated
like to have an idea as to what’s going
by the red circle in Fig.2 (the one anon ‘under the bonnet’ as we say in the
notated with the words ‘We’ll discuss
UK (or ‘under the hood’ in the vernacuthis later’). Observe that our new red
lar of the US). There’s a huge amount to
LED will now flash in time with the ‘A’
wrap our brains around here, but a racing
segment on our 7-segment display (the
version is as follows.
new green LED will be in the opposite
It’s common to hear computer boffins
state to the red LED). Congratulations!
say that digital computers like our ArduYou’ve just created a basic logic probe
ino microcontroller are based on 0s and
– see: https://bit.ly/3YJbIl6
1s (‘zeros and ones’), but what does this
really mean? Well, at the interface where
the microcontroller meets the real world
HIGH or LOW?
in the form of its digital I/O pins, we are
Now, unplug the flying lead from the 0V
working with real voltages, such as 0V
rail and connect it to pin 10 on the Arand 5V in the case of an Arduino Uno.
duino. At this time, as discussed above,
Everything else is an abstraction inboth of our new LEDs should either be
tended to make our lives easier. For exoff (if their combined forward voltage
ample, we use 0 and 1 as abstractions for
drops are greater than or equal to 5V)
0V and 5V, respectively. Similarly, we
or dimly illuminated (if their combined
use LOW and HIGH as abstractions of 0
voltage drops are less than 5V).
and 1, and we use definitions like RED_
This is what we’ve been seeing when
OFF_GREEN_ON and RED_ON_GREEN_OFF
the end of our flying lead isn’t connected
as abstractions of LOW and HIGH.
to anything, but we just connected it to
But why do we use 0 and 1 in the first
pin 10 on our Arduino. What gives? Well,
place? Well, let’s start with the fact that a
as we discussed in Part 1, when a microdigital quantity is one that can be reprecontroller is first powered up, all its pins
sented as being in one of a finite number
are set to be inputs by default. This means
of states. The simplest digital systems
that, as far as what used to be our ‘flying
employ only two states, which we might
lead’ is concerned, it’s not currently being
refer to as 0 and 1, UP and DOWN, IN
driven by anything, which is the same as
and OUT, OFF and ON, and so on.
it not being connected to anything.
Practical Electronics | March | 2023
Next, let’s note that sometime around
the 1850s, a British mathematician called
George Boole established a new mathematical field known as symbolic logic,
which we now know as Boolean algebra. Unfortunately, outside mathematical circles, no one really cared.
In the early part of the 20th century, inventors started to create electrical circuits
based on switching elements that could
perform simple arithmetic functions and/
or execute sequences of operations to
control things like industrial machinery.
These switching elements included regular switches, electromagnetic switches in
the form of relays, and electronic switches in the form of vacuum tubes. However,
there was a limit to the complexity of the
systems those inventors could achieve because they didn’t have appropriate mathematical tools at their disposal.
In the late 1930s, a graduate student at
MIT called Claude Shannon submitted a
master’s thesis that revolutionised electronics. In this thesis, Shannon showed
that Boolean algebra offered an ideal
technique for representing the logical
operation of digital systems. Shannon
had realised that the Boolean concepts
of false and true could be mapped onto
the binary digits 0 and 1, and that both
could be easily implemented by means
of electronic circuits.
Most materials are conductors, insulators, or something in-between. A special
class of materials called ‘semiconductors’ can be persuaded to exhibit both
conducting and insulating properties;
silicon is one such material. The first
transistor was made in 1947 from another
semiconductor material called ‘germanium’ and these were made commercially
available in the early 1950s. In the case
of digital computers, we think of transistors as acting like switches. Today’s transistors can be very small (we can build
billions of them on a silicon chip) and
very fast (they can be activated and deactivated billions of times a second). Also,
the output from one transistor can drive
the inputs of other transistors.
We can connect small groups of transistors together to form simple logical
building blocks that can detect the difference between two voltage values and
can present the results of their operations
in terms of these voltages. These simple
building blocks can be connected to create
larger logical functions, which can themselves be connected to realise sophisticated systems such as digital computers.
Rather than think in terms of two actual
voltages, we prefer to abstract things and
talk in terms of 0s and 1s.
When we write a program for an Arduino, we can make use of built-in functions like digitalWrite(), which writes
a value to one of the Arduino’s digital
input/output (I/O) pins. This function
63
accepts two integer
5V
5V
arguments (think
parameters): the
first is the number
D10
D10
Arduino
Arduino
of the pin we wish
Uno
Uno
to control and the
second is the value
we wish to output,
0V
0V
where this value
digitalWrite (10, 0)
digitalWrite (10, 1)
can be a 0 or a 1. If
we wanted to write
Fig.5. Visualising how the digitalWrite()
0 or 1 values to pin
function performs its magic.
10, for example, we
could do so as follows:
digitalWrite(10,0);
digitalWrite(10,1);
As we’ve already discussed, these 0 and 1 values will appear on
the Arduino Uno’s pin as 0V and 5V, respectively. One way to
visualise how this works is illustrated in Fig.5.
In the same way, we can make a single transistor behave like a
simple switch, we can use a couple of transistors to implement
the equivalent of a single-pole, double-throw (SPDT) switch. By
means of our digitalWrite() commands, we can cause this
switch to connect the output pin to the 0V or 5V rails inside the
Arduino, thereby presenting these values to the outside world.
The creators of the Arduino decided that, rather than use 0 and
1, it would be easier for beginners to work with the keywords LOW
and HIGH. The only problem is that the C/C++ programming languages used by the Arduino’s integrated development environment (IDE) don’t support these keywords.
Based on what we’ve already learned, we could define these
keywords ourselves as follows:
#define LOW 0
#define HIGH 1
Listing 2. Using a for() loop to pulse the LEDs 6 times.
As we will come to realise, this opens the door to a wide
range of possibilities. For example, if we wish to write a 0
to pin 6, we could do so using:
digitalWrite(6, false);
Although they decided to employ a slightly different approach,
this is essentially what the folks who set up the Arduino IDE did
behind the scenes.
If you are interested in learning more about all of this, I’ve
penned and posted a frankly fulsome column for your delectation and delight – see: https://bit.ly/3GacoZv
True or false?
As we previously noted, the Arduino IDE supports a combination
of the C/C++ programming languages. Some computer languages
support the bool and/or boolean data types, which are used to
represent the Boolean concepts of false and true. Unfortunately, C
doesn’t natively support either of these types (sad face). Fortunately, C++ does support the bool data type (happy face). And, just to
add to the fun and frivolity, the Arduino IDE supports both types.
A variable of type bool (or boolean) can be assigned values
of true and false. We will be running into these values a lot
in the not-so-distant future. Before we do, however, it’s worth
noting that the bool data type is essentially an alias of the int
(integer) data type that’s restricted to having values of 0 (false)
and 1 (true). Furthermore, the boolean data type is essentially
an alias of the bool data type.
Once again, based on what we’ve already learned, we could
define these keywords ourselves as follows:
#define false 0
#define true 1
And, once again, although they decided to employ a slightly different approach, this is essentially what the folks who set up the
Arduino IDE did behind the scenes.
64
Alternatively, if we wish to write a 1 to pin 6, we could
do so using:
digitalWrite(6, true);
Similarly, if we declare a variable as being of type bool
(or boolean), in addition to assigning it values of false
and true, we can also assign it values of 0 and 1 and LOW
and HIGH.
For() better or worse
There are three types of loop control statements in C/C++.
These statements can be used to perform the same group
of actions multiple times. One of them is the for() statement, which we introduced in Part 2. Just to remind ourselves, the general form of this statement is as follows:
for (initialize; condition; update)
{
// Do stuff
}
Suppose we wish to quickly pulse (flash) our red-green LED
combo six times, wait a second, and then do it all again. We
could achieve this using a for() statement as illustrated
in Listing 2 (see also file CB-Mar23-04.txt).
We won’t go through this code in detail because we’ve
seen variations of all these statements before. However,
one point worth noting is that, in this example, we’ve declared our loop control variable, iPul, outside the for()
Practical Electronics | March | 2023
statement. As you may recall, my preference is to declare this
as part of the for() statement as shown in red below:
for (int iPul = 0; ...
The rationale for declaring this variable as part of the for()
statement is this limits the scope (ie, the visible range) of the
variable to the loop. And the reason for our declaring it outside the for() statement in this example is that it will help
us wrap our brains around what’s happening when we compare what we are doing here with the other loop control statements, which we will look at in a moment.
It’s the condition portion of the for() statement that’s of
interest to us here. In this case, we used iPul < NUM_FLASH
(that is, ‘iPul is less than NUM_FLASH’), where we previously
defined NUM_FLASH (‘the number of flashes’) as being 6. This
condition will evaluate to a Boolean value of true (if iPul is
indeed less than NUM_FLASH) or false (if iPul is greater than
or equal to NUM_FLASH). The body of the loop will be executed so long as the condition returns true, and the loop will be
terminated as soon as the condition returns false.
In this case, our loop will execute six times for iPul = 0, 1,
2, 3, 4, and 5, and it will terminate as soon as iPul reaches 6.
Enter this program into your Arduino IDE and click the Verify
icon to check you haven’t made any mistakes. Next, click the
Upload icon to upload the machine code version of this program into your Arduino and count the number of flashes to
check that all is as we expect.
As a point of interest, try changing your for() loop’s initialise statement to int iPul = 1 and its condition statement
to iPul <= NUM_PULSES (that is, ‘iPul is less than or equal
to NUM_FLASH’). In this case, our loop will execute six times
for iPul = 1, 2, 3, 4, 5, and 6, and it will terminate as soon as
iPul reaches 7.
While() we’re here
In addition to the for(), there are two more loop control
statements in C/C++. The first is the while(), in which a
condition is checked before executing the body of the loop.
Once again, the body of the loop will only be executed if the
condition returns a Boolean value of true, otherwise the loop
will be terminated.
while (someCondition)
{
// Do stuff
}
The second is the do-while() in which a condition is checked
after executing the body of the loop. In this case, the body of
the loop will always be executed at least one time, after which
it will continue to be executed only so long as the condition
returns true.
do
{
// Do stuff
} while (someCondition);
Let’s create, contrast, and compare two programs using these
different approaches to flash our red-green LED combo six
times, as shown in Listing 3 (see also files CB-Mar23-05.txt
and CB-Mar23-06.txt).
In both of these examples, we increment the loop counter
iPul at the end of the loop (previously, we did this as the
update portion of the for() statement itself). Remember that
iPul++ is the same as saying iPul = iPul + 1.
With respect to the examples shown here, there doesn’t really
seem to be much to choose between these loop control forms.
Practical Electronics | March | 2023
NEW!
5-year collection
2017-2021
All 60 issues from Jan 2017
to Dec 2021 for just £44.95
PDF files ready for
immediate download
See page 6 for further details and
other great back-issue offers.
Purchase and download at:
www.electronpublishing.com
However, sometimes it is critical to evaluate the condition prior
to executing the loop, in which case we could choose to use
the while() loop. On other occasions, as we will soon see,
it is advantageous to execute the loop before evaluating the
condition, in which case the do-while() is the way to go.
There’s a condition
Thus far, we’ve considered only simple conditions involving
the relational operators < (‘less than’) and <= (‘less than or
equal to’). There are two more relational operators, > (‘greater than’) and >= (‘greater than or equal to’). Also, there are
two equality operators, == (‘equal to’) and != (‘not equal to’).
Furthermore, we can create more complex expressions using
the && (‘logical AND’) and || (‘logical OR’) operators. For example, assume that a, b, c and d have all been declared as
being of type int and assigned values, we could have a condition looking something like the following:
(a > b) && (c <= d)
This condition will return true only if a is greater than b AND
c is less than or equal to d, otherwise it will return false.
All of the operators mentioned here are summarised in Fig.6.
Who takes precedence?
When we were kids studying math at school, we were taught
the convention that multiplication and division are performed
before addition and subtraction. This means, for example, that
we evaluate the result of the expression 2 + 2 × 3 as being 8
rather than 12. We say that the multiplication and division
operators have ‘higher precedence’ than the addition and subtraction operators.
If we wanted to, we could emphasise the conventional precedence in the preceding calculation using parentheses, eg,
2 + (2 × 3). Alternatively, we could force a different precedence, eg, (2 + 2) × 3.
Similarly, in the context of computer programming languages like C/C++, the term ‘precedence of operators’ refers
65
Listing 3. Using while() and do-while() loops to pulse the LEDs 6 times: (left) while() loop; (right) do-while() loop.
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 relational, equality, and logical
operators discussed above.
Well, that all seems pretty simple, doesn’t it? So, assuming
once again that a, b, c and d have all been declared as being of
type int and assigned values, how would you expect the condition a + 6 > b / 2 && c * 3 < d – 5 to be evaluated?
Suffice it to say that many a programmer (both inexperienced and experienced) has been bitten by an unexpected
precedence problem. For myself, I prefer to employ copious
quantities of parentheses to make clear to future users and to
the compiler just what I wish to occur, which means I would
capture the aforementioned condition as ((a + 6) > (b /
2)) && ((c * 3) < (d – 5)) (you can call me an old fuddy-duddy if you will, but at least my code works as planned).
If you wish to learn more about this topic, you’ll be delighted to discover that it is documented in excruciating detail on
Wikipedia at: https://bit.ly/3GdcG1M
Type
Relational
Equality
Logical
Operator Description
Example
<
Less than
a < b
<=
Less than or equal to
a <= b
>
Greater than
a > b
>=
Greater than or equal to
b >= b
==
Equal to
a == b
!=
Not equal to
a != b
&&
Logical AND
a && b
||
Logical OR
a || b
Fig.6. Table of Boolean operators available
in C/C++ for use with the Arduino.
66
A long pause
Now it’s time to put
some of the things
we’ve learned in this
column to use with
our 7-segment display. As you may
recall, the final
program we created in our previous
column randomly lit
the segments on the display. The original version of this program is shown in Listing 4a (file CB-Mar23-07.txt). As you’ll
see, I’ve added a few blank lines to aid in our comparison with
an updated version of the program, as reflected in Listing 4b
(file CB-Mar23-08.txt).
Let’s start with our original program. As a reminder, the
Arduino pins used to drive our segments are defined in the
PinsSegs[] array on Lines 5 and 6. There are eight elements
in this array, numbered from 0 to 7. This is why we generate
a random number with a value between 0 and 7 on Line 24.
Upload the original program into your Arduino and carefully
observe what happens on the 7-segment display. As promised,
all eight segments (including the decimal point) light up in a
random fashion. If we look closely, however, we will see that
some of the segments randomly stay lit longer than others.
The reason for this is that, when we generate a random number
on Line 24, we don’t check to see if this new number is different to the previous number. If the values are the same, then the
current segment will remain lit longer than if the values are different. What we want to do is force the values to be different.
Now consider the new version of the program in Listing
4b. The first change occurs on Line 8 where we declare an
integer variable called OldSeg (‘old segment’) and assign it
a value of –1.
Observe that, since OldSeg is declared outside of any of the
functions, it is a global variable whose scope is the whole program. This means it can be seen and modified by any of the
functions. It also means that whatever value it contains will be
retained irrespective of which function is being executed (or
not, as the case might be) at any particular time. Furthermore,
as was noted in the previous column, my personal preference
is to use initial uppercase letters to indicate global variables
and initial lowercase letters to reflect local variables.
Practical Electronics | March | 2023
Listing 4. Using a do-while() loop to ensure a different random number: (left) original program; (right) updated program.
Part 3 is for you to think about what seg(not equal) to the
ments we need to activate to represent
old value, this conthe digits 0 through 9. Have you been
dition
will
return
LEDs (assorted colours)
https://amzn.to/3E7VAQE
thinking about this? Good. Hold that
false
and
the
loop
Resistors (assorted values)
https://amzn.to/3O4RvBt
thought because this is what we will be
will
terminate.
Solderless breadboard
https://amzn.to/3O2L3e8
doing in Part 4.
As soon as we are
Multicore jumper wires (male-male) https://amzn.to/3O4hnxk
Meanwhile, the answer to the question
out of the loop, baskComponents (from Part 2)
posed at the beginning of this column
ing in the confident
7-segment display(s)
https://amzn.to/3Afm8yu
is that we can ask either of the guards:
glow of knowing we
‘Which door will the other guard say is
have a new segment
the one that will take us where we wish
that is different to
to go?’ Both guards will respond with
the old one, we copy this new value
The reason we assign OldSeg a value
the same door, which is the one we don’t
into OldSeg in Line 27 for use the next
of –1 is because we know this is differwant to use.
time we wish to generate a new segment.
ent to any of the random numbers we
I was just wondering if it would be
Upload this new version of the prowill be generating in the range 0 to 7. We
possible to represent this riddle and its
gram into your Arduino and observe that
could, of course, use any value other than
possible outcomes in the form of a truth
all of the randomly selected segments
0 through 7, but –1 is a common choice
table, but I’m exhausted after writing this
now remain illuminated for the same
in this sort of thing.
column, so I’ll leave that to you (please
amount of time.
The cunning part comes in Lines 22
feel free to email me with your solution).
to 25 where we use a do-while() loop
Until next time, as always, I welcome
to control the generation of our random
What’s next?
your insightful comments, perspicacious
number. The way this loop is set up is that
We closed last month’s column by saying:
questions, and sagacious suggestions.
we will keep on generating new random
‘What would be useful while we wait for
numbers as long as the condition evaluates as true, which
will be the case if the newly genCool bean Max Maxfield (Hawaiian shirt, on the right) is emperor of all he
erated segment value stored in
surveys at CliveMaxfield.com – the go-to site for the latest and greatest
iSeg is the same as the old segin technological geekdom.
ment value stored in OldSeg. As
Comments or questions? Email Max at: max<at>CliveMaxfield.com
soon as the new value is different
Components (from Part 1)
Practical Electronics | March | 2023
67
|