Silicon ChipMax’s Cool Beans - January 2026 SILICON CHIP
  1. Contents
  2. Publisher's Letter: Hardware requiring an App is a red flag
  3. Subscriptions: ETI Bundles
  4. Feature: Teach-In 2026 by Mike Tooley
  5. Project: High-Bandwidth Differential Probe by Andrew Levido
  6. Feature: Techno Talk by Max the Magnificent
  7. Feature: Max’s Cool Beans by Max the Magnificent
  8. Back Issues
  9. Project: NFC Programmable IR Remote Control Keyfob by Tim Blythman
  10. Feature: Circuit Surgery by Ian Bell
  11. Feature: Audio Out by Jake Rothman
  12. Feature: Generating Power by Unusual Means by Dr David Maddison
  13. Feature: The Fox Report by Barry Fox
  14. Project: Variable Speed Drive Mk2 For Induction Motors, Part 2 by Andrew Levido
  15. PartShop
  16. Advertising Index
  17. Market Centre
  18. Back Issues

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:
  • Teach-In 12.1 (November 2025)
  • Teach-In 2026 (December 2025)
  • Teach-In 2026 (January 2026)
  • Teach-In 2026 (February 2026)
Articles in this series:
  • Techno Talk (February 2020)
  • Techno Talk (March 2020)
  • (April 2020)
  • Techno Talk (May 2020)
  • Techno Talk (June 2020)
  • Techno Talk (July 2020)
  • Techno Talk (August 2020)
  • Techno Talk (September 2020)
  • Techno Talk (October 2020)
  • (November 2020)
  • Techno Talk (December 2020)
  • Techno Talk (January 2021)
  • Techno Talk (February 2021)
  • Techno Talk (March 2021)
  • Techno Talk (April 2021)
  • Techno Talk (May 2021)
  • Techno Talk (June 2021)
  • Techno Talk (July 2021)
  • Techno Talk (August 2021)
  • Techno Talk (September 2021)
  • Techno Talk (October 2021)
  • Techno Talk (November 2021)
  • Techno Talk (December 2021)
  • Communing with nature (January 2022)
  • Should we be worried? (February 2022)
  • How resilient is your lifeline? (March 2022)
  • Go eco, get ethical! (April 2022)
  • From nano to bio (May 2022)
  • Positivity follows the gloom (June 2022)
  • Mixed menu (July 2022)
  • Time for a total rethink? (August 2022)
  • What’s in a name? (September 2022)
  • Forget leaves on the line! (October 2022)
  • Giant Boost for Batteries (December 2022)
  • Raudive Voices Revisited (January 2023)
  • A thousand words (February 2023)
  • It’s handover time (March 2023)
  • AI, Robots, Horticulture and Agriculture (April 2023)
  • Prophecy can be perplexing (May 2023)
  • Technology comes in different shapes and sizes (June 2023)
  • AI and robots – what could possibly go wrong? (July 2023)
  • How long until we’re all out of work? (August 2023)
  • We both have truths, are mine the same as yours? (September 2023)
  • Holy Spheres, Batman! (October 2023)
  • Where’s my pneumatic car? (November 2023)
  • Good grief! (December 2023)
  • Cheeky chiplets (January 2024)
  • Cheeky chiplets (February 2024)
  • The Wibbly-Wobbly World of Quantum (March 2024)
  • Techno Talk - Wait! What? Really? (April 2024)
  • Techno Talk - One step closer to a dystopian abyss? (May 2024)
  • Techno Talk - Program that! (June 2024)
  • Techno Talk (July 2024)
  • Techno Talk - That makes so much sense! (August 2024)
  • Techno Talk - I don’t want to be a Norbert... (September 2024)
  • Techno Talk - Sticking the landing (October 2024)
  • Techno Talk (November 2024)
  • Techno Talk (December 2024)
  • Techno Talk (January 2025)
  • Techno Talk (February 2025)
  • Techno Talk (March 2025)
  • Techno Talk (April 2025)
  • Techno Talk (May 2025)
  • Techno Talk (June 2025)
  • Techno Talk (July 2025)
  • Techno Talk (August 2025)
  • Techno Talk (October 2025)
  • Techno Talk (November 2025)
  • Techno Talk (December 2025)
  • Techno Talk (January 2026)
  • Techno Talk (February 2026)
Articles in this series:
  • Max’s Cool Beans (January 2025)
  • Max’s Cool Beans (February 2025)
  • Max’s Cool Beans (March 2025)
  • Max’s Cool Beans (April 2025)
  • Max’s Cool Beans (May 2025)
  • Max’s Cool Beans (June 2025)
  • Max’s Cool Beans (July 2025)
  • Max’s Cool Beans (August 2025)
  • Max’s Cool Beans (September 2025)
  • Max’s Cool Beans: Weird & Wonderful Arduino Projects (October 2025)
  • Max’s Cool Beans (November 2025)
  • Max’s Cool Beans (December 2025)
  • Max’s Cool Beans (January 2026)
  • Max’s Cool Beans (February 2026)
Articles in this series:
  • STEWART OF READING (April 2024)
  • Circuit Surgery (April 2024)
  • Circuit Surgery (May 2024)
  • Circuit Surgery (June 2024)
  • Circuit Surgery (July 2024)
  • Circuit Surgery (August 2024)
  • Circuit Surgery (September 2024)
  • Circuit Surgery (October 2024)
  • Circuit Surgery (November 2024)
  • Circuit Surgery (December 2024)
  • Circuit Surgery (January 2025)
  • Circuit Surgery (February 2025)
  • Circuit Surgery (March 2025)
  • Circuit Surgery (April 2025)
  • Circuit Surgery (May 2025)
  • Circuit Surgery (June 2025)
  • Circuit Surgery (July 2025)
  • Circuit Surgery (August 2025)
  • Circuit Surgery (September 2025)
  • Circuit Surgery (October 2025)
  • Circuit Surgery (November 2025)
  • Circuit Surgery (December 2025)
  • Circuit Surgery (January 2026)
  • Circuit Surgery (February 2026)
Articles in this series:
  • Audio Out (January 2024)
  • Audio Out (February 2024)
  • AUDIO OUT (April 2024)
  • Audio Out (May 2024)
  • Audio Out (June 2024)
  • Audio Out (July 2024)
  • Audio Out (August 2024)
  • Audio Out (September 2024)
  • Audio Out (October 2024)
  • Audio Out (March 2025)
  • Audio Out (April 2025)
  • Audio Out (May 2025)
  • Audio Out (June 2025)
  • Audio Out (July 2025)
  • Audio Out (August 2025)
  • Audio Out (September 2025)
  • Audio Out (October 2025)
  • Audio Out (November 2025)
  • Audio Out (December 2025)
  • Audio Out (January 2026)
  • Audio Out (February 2026)
Articles in this series:
  • The Fox Report (July 2024)
  • The Fox Report (September 2024)
  • The Fox Report (October 2024)
  • The Fox Report (November 2024)
  • The Fox Report (December 2024)
  • The Fox Report (January 2025)
  • The Fox Report (February 2025)
  • The Fox Report (March 2025)
  • The Fox Report (April 2025)
  • The Fox Report (May 2025)
  • The Fox Report (July 2025)
  • The Fox Report (August 2025)
  • The Fox Report (September 2025)
  • The Fox Report (October 2025)
  • The Fox Report (October 2025)
  • The Fox Report (December 2025)
  • The Fox Report (January 2026)
  • The Fox Report (February 2026)
Items relevant to "Variable Speed Drive Mk2 For Induction Motors, Part 2":
  • Mk2 VSD PCB [11111241 or 9048-02] (AUD $15.00)
  • STM32G030K6T6 programmed for the VSD Mk2 [1111124A] (Programmed Microcontroller, AUD $10.00)
  • Firmware for the VSD Mk2 (Software, Free)
  • VSD Mk2 PCB pattern (PDF download) [11111241] (Free)
  • Mk2 VSD drilling & cutting diagrams (Panel Artwork, Free)
Articles in this series:
  • Variable Speed Drive Mk2, Part 1 (November 2024)
  • Variable Speed Drive Mk2, Part 2 (December 2024)
  • Variable Speed Drive Mk2 for Induction Motors, Part 1 (December 2025)
  • Variable Speed Drive Mk2 For Induction Motors, Part 2 (January 2026)
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