Silicon ChipMax’s Cool Beans - August 2025 SILICON CHIP
  1. Contents
  2. Publisher's Letter: Environmental concerns with semiconductor manufacturing
  3. Subscriptions
  4. Feature: Techno Talk by Max the Magnificent
  5. Project: The Micromite Explore-40 by Tim Blythman
  6. Feature: MIPI I3C by Andrew Levido
  7. Back Issues
  8. Project: 8-Channel Learning IR Remote Receiver by John Clarke
  9. Feature: Circuit Surgery by Ian Bell
  10. Feature: Audio Out by Jake Rothman
  11. Project: FlexiDice by Tim Blythman
  12. Feature: Max’s Cool Beans by Max the Magnificent
  13. Feature: The Fox Report by Barry Fox
  14. Project: 180-230V DC Motor Speed Controller, part two by John Clarke
  15. Feature: Precision Electronics, part eight by Andrew Levido
  16. PartShop
  17. Market Centre
  18. Advertising Index
  19. Back Issues

This is only a preview of the August 2025 issue of Practical Electronics.

You can view 0 of the 80 pages in the full issue.

Articles in this series:
  • Techno Talk (February 2020)
  • Techno Talk (February 2020)
  • Techno Talk (March 2020)
  • Techno Talk (March 2020)
  • (April 2020)
  • (April 2020)
  • Techno Talk (May 2020)
  • Techno Talk (May 2020)
  • Techno Talk (June 2020)
  • Techno Talk (June 2020)
  • Techno Talk (July 2020)
  • Techno Talk (July 2020)
  • Techno Talk (August 2020)
  • Techno Talk (August 2020)
  • Techno Talk (September 2020)
  • Techno Talk (September 2020)
  • Techno Talk (October 2020)
  • Techno Talk (October 2020)
  • (November 2020)
  • (November 2020)
  • Techno Talk (December 2020)
  • Techno Talk (December 2020)
  • Techno Talk (January 2021)
  • Techno Talk (January 2021)
  • Techno Talk (February 2021)
  • Techno Talk (February 2021)
  • Techno Talk (March 2021)
  • Techno Talk (March 2021)
  • Techno Talk (April 2021)
  • Techno Talk (April 2021)
  • Techno Talk (May 2021)
  • Techno Talk (May 2021)
  • Techno Talk (June 2021)
  • Techno Talk (June 2021)
  • Techno Talk (July 2021)
  • Techno Talk (July 2021)
  • Techno Talk (August 2021)
  • Techno Talk (August 2021)
  • Techno Talk (September 2021)
  • Techno Talk (September 2021)
  • Techno Talk (October 2021)
  • Techno Talk (October 2021)
  • Techno Talk (November 2021)
  • Techno Talk (November 2021)
  • Techno Talk (December 2021)
  • Techno Talk (December 2021)
  • Communing with nature (January 2022)
  • Communing with nature (January 2022)
  • Should we be worried? (February 2022)
  • Should we be worried? (February 2022)
  • How resilient is your lifeline? (March 2022)
  • How resilient is your lifeline? (March 2022)
  • Go eco, get ethical! (April 2022)
  • Go eco, get ethical! (April 2022)
  • From nano to bio (May 2022)
  • From nano to bio (May 2022)
  • Positivity follows the gloom (June 2022)
  • Positivity follows the gloom (June 2022)
  • Mixed menu (July 2022)
  • Mixed menu (July 2022)
  • Time for a total rethink? (August 2022)
  • Time for a total rethink? (August 2022)
  • What’s in a name? (September 2022)
  • What’s in a name? (September 2022)
  • Forget leaves on the line! (October 2022)
  • Forget leaves on the line! (October 2022)
  • Giant Boost for Batteries (December 2022)
  • Giant Boost for Batteries (December 2022)
  • Raudive Voices Revisited (January 2023)
  • Raudive Voices Revisited (January 2023)
  • A thousand words (February 2023)
  • A thousand words (February 2023)
  • It’s handover time (March 2023)
  • It’s handover time (March 2023)
  • AI, Robots, Horticulture and Agriculture (April 2023)
  • AI, Robots, Horticulture and Agriculture (April 2023)
  • Prophecy can be perplexing (May 2023)
  • Prophecy can be perplexing (May 2023)
  • Technology comes in different shapes and sizes (June 2023)
  • Technology comes in different shapes and sizes (June 2023)
  • AI and robots – what could possibly go wrong? (July 2023)
  • AI and robots – what could possibly go wrong? (July 2023)
  • How long until we’re all out of work? (August 2023)
  • How long until we’re all out of work? (August 2023)
  • We both have truths, are mine the same as yours? (September 2023)
  • We both have truths, are mine the same as yours? (September 2023)
  • Holy Spheres, Batman! (October 2023)
  • Holy Spheres, Batman! (October 2023)
  • Where’s my pneumatic car? (November 2023)
  • Where’s my pneumatic car? (November 2023)
  • Good grief! (December 2023)
  • Good grief! (December 2023)
  • Cheeky chiplets (January 2024)
  • Cheeky chiplets (January 2024)
  • Cheeky chiplets (February 2024)
  • Cheeky chiplets (February 2024)
  • The Wibbly-Wobbly World of Quantum (March 2024)
  • The Wibbly-Wobbly World of Quantum (March 2024)
  • Techno Talk - Wait! What? Really? (April 2024)
  • Techno Talk - Wait! What? Really? (April 2024)
  • Techno Talk - One step closer to a dystopian abyss? (May 2024)
  • Techno Talk - One step closer to a dystopian abyss? (May 2024)
  • Techno Talk - Program that! (June 2024)
  • Techno Talk - Program that! (June 2024)
  • Techno Talk (July 2024)
  • Techno Talk (July 2024)
  • Techno Talk - That makes so much sense! (August 2024)
  • Techno Talk - That makes so much sense! (August 2024)
  • Techno Talk - I don’t want to be a Norbert... (September 2024)
  • Techno Talk - I don’t want to be a Norbert... (September 2024)
  • Techno Talk - Sticking the landing (October 2024)
  • Techno Talk - Sticking the landing (October 2024)
  • Techno Talk (November 2024)
  • Techno Talk (November 2024)
  • Techno Talk (December 2024)
  • Techno Talk (December 2024)
  • Techno Talk (January 2025)
  • Techno Talk (January 2025)
  • Techno Talk (February 2025)
  • Techno Talk (February 2025)
  • Techno Talk (March 2025)
  • Techno Talk (March 2025)
  • Techno Talk (April 2025)
  • Techno Talk (April 2025)
  • Techno Talk (May 2025)
  • Techno Talk (May 2025)
  • Techno Talk (June 2025)
  • Techno Talk (June 2025)
  • Techno Talk (July 2025)
  • Techno Talk (July 2025)
  • Techno Talk (August 2025)
  • Techno Talk (August 2025)
  • Audio Out (September 2025)
  • Audio Out (September 2025)
Articles in this series:
  • Circuit Surgery (April 2024)
  • STEWART OF READING (April 2024)
  • Circuit Surgery (April 2024)
  • STEWART OF READING (April 2024)
  • Circuit Surgery (May 2024)
  • Circuit Surgery (May 2024)
  • Circuit Surgery (June 2024)
  • Circuit Surgery (June 2024)
  • Circuit Surgery (July 2024)
  • Circuit Surgery (July 2024)
  • Circuit Surgery (August 2024)
  • Circuit Surgery (August 2024)
  • Circuit Surgery (September 2024)
  • Circuit Surgery (September 2024)
  • Circuit Surgery (October 2024)
  • Circuit Surgery (October 2024)
  • Circuit Surgery (November 2024)
  • Circuit Surgery (November 2024)
  • Circuit Surgery (December 2024)
  • Circuit Surgery (December 2024)
  • Circuit Surgery (January 2025)
  • Circuit Surgery (January 2025)
  • Circuit Surgery (February 2025)
  • Circuit Surgery (February 2025)
  • Circuit Surgery (March 2025)
  • Circuit Surgery (March 2025)
  • Circuit Surgery (April 2025)
  • Circuit Surgery (April 2025)
  • Circuit Surgery (May 2025)
  • Circuit Surgery (May 2025)
  • Circuit Surgery (June 2025)
  • Circuit Surgery (June 2025)
  • Circuit Surgery (July 2025)
  • Circuit Surgery (July 2025)
  • Circuit Surgery (August 2025)
  • Circuit Surgery (August 2025)
  • Circuit Surgery (September 2025)
  • Circuit Surgery (September 2025)
Articles in this series:
  • Audio Out (January 2024)
  • Audio Out (January 2024)
  • Audio Out (February 2024)
  • Audio Out (February 2024)
  • AUDIO OUT (April 2024)
  • AUDIO OUT (April 2024)
  • Audio Out (May 2024)
  • Audio Out (May 2024)
  • Audio Out (June 2024)
  • Audio Out (June 2024)
  • Audio Out (July 2024)
  • Audio Out (July 2024)
  • Audio Out (August 2024)
  • Audio Out (August 2024)
  • Audio Out (September 2024)
  • Audio Out (September 2024)
  • Audio Out (October 2024)
  • Audio Out (October 2024)
  • Audio Out (March 2025)
  • Audio Out (March 2025)
  • Audio Out (April 2025)
  • Audio Out (April 2025)
  • Audio Out (May 2025)
  • Audio Out (May 2025)
  • Audio Out (June 2025)
  • Audio Out (June 2025)
  • Audio Out (July 2025)
  • Audio Out (July 2025)
  • Audio Out (August 2025)
  • Audio Out (August 2025)
Articles in this series:
  • Max’s Cool Beans (January 2025)
  • Max’s Cool Beans (January 2025)
  • Max’s Cool Beans (February 2025)
  • Max’s Cool Beans (February 2025)
  • Max’s Cool Beans (March 2025)
  • Max’s Cool Beans (March 2025)
  • Max’s Cool Beans (April 2025)
  • Max’s Cool Beans (April 2025)
  • Max’s Cool Beans (May 2025)
  • Max’s Cool Beans (May 2025)
  • Max’s Cool Beans (June 2025)
  • Max’s Cool Beans (June 2025)
  • Max’s Cool Beans (July 2025)
  • Max’s Cool Beans (July 2025)
  • Max’s Cool Beans (August 2025)
  • Max’s Cool Beans (August 2025)
  • Max’s Cool Beans (September 2025)
  • Max’s Cool Beans (September 2025)
Articles in this series:
  • The Fox Report (July 2024)
  • The Fox Report (July 2024)
  • The Fox Report (September 2024)
  • The Fox Report (September 2024)
  • The Fox Report (October 2024)
  • The Fox Report (October 2024)
  • The Fox Report (November 2024)
  • The Fox Report (November 2024)
  • The Fox Report (December 2024)
  • The Fox Report (December 2024)
  • The Fox Report (January 2025)
  • The Fox Report (January 2025)
  • The Fox Report (February 2025)
  • The Fox Report (February 2025)
  • The Fox Report (March 2025)
  • The Fox Report (March 2025)
  • The Fox Report (April 2025)
  • The Fox Report (April 2025)
  • The Fox Report (May 2025)
  • The Fox Report (May 2025)
  • The Fox Report (July 2025)
  • The Fox Report (July 2025)
  • The Fox Report (August 2025)
  • The Fox Report (August 2025)
  • The Fox Report (September 2025)
  • The Fox Report (September 2025)
Items relevant to "180-230V DC Motor Speed Controller, part two":
  • 180-230V DC Motor Speed Controller PCB [11104241] (AUD $15.00)
  • 180-230V DC Motor Speed Controller PCB pattern (PDF download) [11104241] (Free)
  • 180-230V DC Motor Speed Controller lid panel artwork and drilling templates (Free)
Articles in this series:
  • 180-230V DC Motor Speed Controller (July 2024)
  • 180-230V DC Motor Speed Controller (July 2024)
  • 180-230V DC Motor Speed Controller Part 2 (August 2024)
  • 180-230V DC Motor Speed Controller Part 2 (August 2024)
  • 180-230V DC Motor Speed Controller (July 2025)
  • 180-230V DC Motor Speed Controller (July 2025)
  • 180-230V DC Motor Speed Controller, part two (August 2025)
  • 180-230V DC Motor Speed Controller, part two (August 2025)
Articles in this series:
  • Precision Electronics, Part 1 (November 2024)
  • Precision Electronics, Part 1 (November 2024)
  • Precision Electronics, Part 2 (December 2024)
  • Precision Electronics, Part 2 (December 2024)
  • Precision Electronics, Part 3 (January 2025)
  • Precision Electronics, part one (January 2025)
  • Precision Electronics, part one (January 2025)
  • Precision Electronics, Part 3 (January 2025)
  • Precision Electronics, part two (February 2025)
  • Precision Electronics, Part 4 (February 2025)
  • Precision Electronics, Part 4 (February 2025)
  • Precision Electronics, part two (February 2025)
  • Precision Electronics, part three (March 2025)
  • Precision Electronics, part three (March 2025)
  • Precision Electronics, Part 5 (March 2025)
  • Precision Electronics, Part 5 (March 2025)
  • Precision Electronics, Part 6 (April 2025)
  • Precision Electronics, Part 6 (April 2025)
  • Precision Electronics, part four (April 2025)
  • Precision Electronics, part four (April 2025)
  • Precision Electronics, Part 7: ADCs (May 2025)
  • Precision Electronics, part five (May 2025)
  • Precision Electronics, Part 7: ADCs (May 2025)
  • Precision Electronics, part five (May 2025)
  • Precision Electronics, Part 8: Voltage References (June 2025)
  • Precision Electronics, part six (June 2025)
  • Precision Electronics, part six (June 2025)
  • Precision Electronics, Part 8: Voltage References (June 2025)
  • Precision Electronics, Part 9 - System Design (July 2025)
  • Precision Electronics, Part 9 - System Design (July 2025)
  • Precision Electronics, part seven (July 2025)
  • Precision Electronics, part seven (July 2025)
  • Precision Electronics, part eight (August 2025)
  • Precision Electronics, part eight (August 2025)
Max’s Cool Beans By Max the Magnificent Weird & Wonderful Arduino Projects Part 8: in which we handle switches like heroes A s usual, I have a cornucopia of cool concepts to convey, and I’m struggling to decide where to start. Now that I think about it, I recently came across some interesting nuggets of knowledge regarding the expression of integer values in different bases, so let’s kick off there. 2B or not 2B Currently, in the standard C programming language, integer values, such as literals and constants, can be written using either decimal or hexadecimal notation; other bases, such as binary, are not supported by default. Decimal values are expressed as standard numbers written without any prefix. For example: int x = 42; By comparison, hexadecimal values are prefixed with 0x or 0X (I prefer the former). For example, the hexadecimal equivalent of 42 in decimal could be expressed as follows: int y = 0x2A; In the case of the C++ programming language, the 2014 release (known as C++14) introduced support for binary int z = 0b101010; As fate would have it, the Arduino’s integrated development environment (IDE) uses a combination of C and C++. As a result, the current version of the IDE supports decimal, hexadecimal and binary notations. Don’t get bitten by a byte The original C language featured four integer data types: char, short, int and long. We’ve discussed these before. They can all be modified with the signed or unsigned keywords. The short, int and long types are signed by default; that is, signed is implied if this keyword is omitted. In contrast, the char type is special. It’s always eight bits (one byte) in size, but it may be signed or unsigned by default, depending on the compiler being used. As you can imagine, this has resulted in countless problems when programs are ported from one machine (and its compiler) to another. When the Arduino was launched in 2005, its creators aimed to make SRCLR SRCLK b 1 16 VCC c 2 15 a d 3 14 SER SER e 4 13 OE RCLK f 5 12 RCLK g 6 11 SRCLK h 7 10 SRCLR GND 8 9 h’ (a) Package values that are prefixed with 0b or 0B (I prefer the former). This means that the binary equivalent of 42 in decimal can be expressed as follows: 0 1 2 3 4 5 6 7 h’ 0 1 2 3 4 5 6 7 OE Connection No connection a b c d e f (b) Block diagram Fig.1: the 8-bit 74HC595 SIPO shift register IC configuration. 54 Shift register g h Output register things easy for beginners to grasp. As part of this, they added a new integer data type called byte, which is an unsigned 8-bit integer that can hold values in the range 0 to 255 in decimal. In reality, ‘under the hood’, byte is an alias for unsigned char (or, more technically, uint8_t). The Arduino’s documentation also states that we can use binary values in the form Bxxxxxxxx (only uppercase ‘B’ is allowed). I must admit that I always wondered why we are obliged to specify exactly eight bits. For example, if we wish to specify a 6-bit binary value of 101010, then using an 8-bit B00101010 (with two leading zeros) will work, while using a 6-bit B101010 (without the leading zeros) will cause the compiler to ‘throw a wobbly’ (flag an error). It turns out that, to support this capability (‘under the hood’ once again), the Arduino’s cunning creators include a suite of definitions like the following: #define B00000000 0 #define B00000001 1 #define B00000010 2 #define B00000011 3 … #define B11111110 254 #define B11111111 255 So, when working with the Arduino, you can use the byte data type along with Bxxxxxxxx values if you wish. However, if you want to make your programs portable or if you plan on using other microcontrollers (and their compilers) in the future, stick to the fixed-width data types (int8_t, uint8_t, int16t, uint16_t etc) and the 0b prefix for binary values. Setting the scene As you may recall, as part of our general experiments in the January 2025 Practical Electronics | August | 2025 Practical Electronics | August | 2025 Bouncy, bouncy In our June 2025 SRCLR SRCLR column, we added To shift From SRCLK three momentary register SRCLK Switches pushbutton switches RCLK RCLK to our breadboard and used them to directly drive the 74HC595’s SRCLR, SRCLK, and RCLK inputs. Almost immediately, we ran DIGITAL I/O (PWM ~) into switch bounce problems. Arduino As we discussed at Fig.2: debouncing switches with the Arduino. that time, when we activate or deactivate an electrome- I’ve stated 6ms is that several years ago, chanical switch, it rarely executes a one of my friends, an acknowledged single, clean transition. Instead, it can expert in embedded system design, bounce up to 100+ times over a period performed extensive tests on a wide variety of switches, finding an averas long as six milliseconds (6ms). Switch bounce isn’t a concern if age bounce time of around 2ms, and a we’re doing something simple, such maximum bounce time of around 6ms. As we discussed in last month’s as using a switch to control LED(s), because the bounces are faster than we can column how, in less critical deployperceive. However, it can cause prob- ments, such as those in consumer eleclems when using the switch to drive tronics, designers often assume that high-speed digital logic, such as our worst-case bounce durations are as shift register or the input to a micro- low as 1ms, depending on the switch type and the application. controller, because each bounce can Does pressing a button on your be perceived as a legitimate switchremote control sometimes cause your ing event. In our case, pressing the SRCLK TV to jump multiple channels? Now switch caused the shift register to be you know why! In the case of embedded systems clocked multiple times. There are various methods for de- and microcontroller applications, debouncing signals from switches, with signers typically assume a worst-case both hardware and software techniques. bounce durations of 10ms. Meanwhile, The solution we adopted was to feed designers of mission-critical and safethe outputs from the switches into our ty-critical systems tend to be conservaArduino, debounce the switches in tive, so they assume worst-case bounce durations of 20ms. software, and then feed the debounced In my own debounce solutions, I versions to the shift register (Fig.2). We began by treating each switch in- assume the actual real-world bounce dependently. Every time we pressed the duration to be no more than 6ms, but I SRCLR or SRCLK switches to modify usually design to accommodate longer the contents of the shift register, we bounce durations ‘just in case’. had to press the RCLK switch to copy these contents into the output register. But what about… There are many shortfalls in our curTo prevent our switch-pressing finger from becoming fatigued, we modi- rent ‘cheap and cheerful’ switch hanfied our code to automatically add an dling solution. Let’s start with the lowRCLK pulse following an SRCLR or hanging fruit. As we’ve discussed in SRCLK event. previous columns, the 74HC595 doesn’t You can download a copy of the contain any special initialisation logic. latest and greatest version of our cur- This means it can power up containrent switch debounce code and see ing a random collection of 0s and 1s. the current state of our breadboard in Thus far, we’ve addressed this conthe files named CB-aug25-code-01.txt cern by commencing every experiment and CB-aug25-brd-01.pdf, respectively. by hand-clearing the device. The great As usual, all files mentioned in this thing about having the Arduino in the column are available as part of the circuit is that we can tweak our setup() August 2025 download package from function to do this for us. the PE website at https://pemag.au/ Another problem with our current link/ac6f code is that it assumes that all the pushbutton switches will be in their They bounce how long?! inactive states when power is first apSwitch bounce is a contentious topic. plied to the system. In the real world, Many references state that the bouncing it’s not beyond the bounds of imaginalasts no longer than 1ms. The reason tion that the user may press and hold ~10 ~9 8 7 ~6 ~5 4 ~3 2 TX-1 RX-0 column, we populated a breadboard with an eight-segment light-emitting diode (LED) bar graph display, along with current-limiting resistors. At that time, we drove all the display segments directly using eight of our Arduino Uno R3 microcontroller’s digital input/output (I/O) pins. Later, in the June 2025 issue, we added an eight-bit serial-in, parallelout (SIPO) shift register in the form of a 74HC595 integrated circuit (IC). We are using a breadboard-friendly dualin-line package (DIP) version, as illustrated in Fig.1(a). As per its data sheet (https://pemag. au/link/ac1o), the eight primary outputs from this device are named a to h (or QA to QH). However, we can also think of them as being numbered 0 to 7. We moved to using these signals to drive the segments on our display. In last month’s column, we utilised our 74HC595 with a 2-input XNOR function (which we created using a 2-input XOR and a NOT gate) to implement a linear feedback shift register (LFSR), which generates a pseudorandom sequence of values. We will return to this in next month’s column; for now, we have other fish to fry. As illustrated in Fig.1(b), the 74HC595 actually contains two 8-bit registers: the shift register itself and an output register. In addition to the SER (serial data) input, this device has four control signals. However, we are currently using only three of these because we are connecting the OE (output enable) input to ground, permanently enabling the outputs. Regarding the remaining control signals, the active-low SRCLR (shift register clear) input, which is level-­ sensitive, clears all the shift register bits to 0. By comparison, a rising edge (a 0-to-1 transition) on the positiveedge-triggered SRCLK (shift register clock) input performs a 1-bit shift on the current contents of the shift register. As part of this, the value being presented to the SER input is copied into bit 0; the original contents of bit 0 are copied into bit 1; the original contents of bit 1 are copied into bit 2, and so on. We can visualise the original contents of bit 7 as conceptually ‘falling off the end’. Once we’ve changed the contents of the shift register via its SRCLR or SRCLK inputs, we need to apply a rising edge (a 0-to-1 transition) to the positive-edge-triggered RCLK (output register clock) input. This causes the current contents of the shift register to be copied into the output register, thereby making them visible to the outside world. 55 one or more switches prior to powering up the system, so it behooves us to take that into account. Mission-critical and safety-critical systems must be as foolproof as possible. Of course, we should never forget what the late, great Douglas Adams wrote about this: “A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools.” As a counterpoint to this, when I give a lecture on embedded systems, one of the points I usually make is, “Half of the safety systems we build into a system are there to tell us when the user has turned the other half off.” We have multiple options here. For example, on power-up, in our setup() function, we could have the Arduino to read the current states of the switches and write these values to our shift register. Another possibility – one we might consider using in the retro game console we are building – would be to enter a special configuration mode if we detect that one of our switches is active when the system is powered on. And another alternative would be to simply wait for all the switches to be in (or return to) their inactive states before proceeding to the main body of the program. Sad to relate, though, that we still haven’t addressed the main problem, which is that… We live in a beautiful noisy world When we introduced our initial switch debounce solution in the June 2025 issue, I wrote, “In an ideal world, starting from the switch being in its inactive state, the Arduino would detect the leading edge of the activation and cause its output to the shift register (SR) to respond immediately.” This is essentially how we implemented things. However, I also coyly noted that, “This approach may not be quite as ideal as we might suppose.” Consider our current approach, as illustrated in Fig.3(a). As soon as we see the first edge of what we assume to be the start of a switch transition on the SRCLK signal from the switch, we generate a pulse on the SRCLK signal to the shift register (we follow this with a pulse on the RCLK signal to the shift register, but we aren’t showing that here to keep things simple). If you examine our code, you’ll see that we then use a delay(10) statement to wait 10 milliseconds, thereby allowing any bouncing to occur before we return to checking the switch. 10ms is a nice round number, and it’s greater than the 6ms worst-case bouncing 56 we might expect to see. Bounce The delay() SRCLK function is blockfrom SW ing, which leaves 10ms SRCLK the Arduino twidto SR dling its metaphorical thumbs; that (a) Trigger on first edge in a noise-free world is, it prevents us from doing anyNoise Bounce thing useful, such SRCLK as reading new from SW values from the Arduino’s inputs, SRCLK performing comto SR putations, and (b) Trigger on first edge in a noisy world driving new values to its outputs. The Arduino Noise Bounce Uno R3 we are SRCLK using in these exfrom SW > 6ms periments runs at 16MHz (16 milSRCLK lion clock cycles to SR per second). This (c) Trigger > 6ms after last bounce means that doing nothing for 10ms Fig.3: strategies for addressing noisy digital signals. equates to 160,000 clock cycles that could be employed days) before someone presses the switch. to do something useful. So, what we’re going to do, as ilHowever, the real problem with our existing solution is that it doesn’t ac- lustrated in Fig.3(c), is wait until the count for noise in the form of electro- signals from our switches have been magnetic interference (EMI). This can steady for more than 6ms following originate from natural sources, such the last bounce (thereby ensuring that as lightning, or human-made sources, we’ve really and truly stopped bouncing) before taking any action. This also including radio transmitters or motors means that brief pulses from EMI or switching on and off. With our program responding to the other sources of electrical noise will first active edge on the SRCLK signal, be ignored. consider what would happen if noise were present on this signal, as depict- Tortuous terminology Before we proceed, there’s someed in Fig.3(b). That’s right, our current code would ‘jump the gun’, as it were. thing else that deserves mention. The This would be, ahem, unfortunate if SRCLK input to our shift register is desomeone were using this code as part scribed as “edge-triggered” because all of something like a missile launch the action occurs at an edge or transition. In this case, we’re talking about control system. To be honest, EMI is probably not positive edges in the form of 0-to-1 something we need to worry about transitions. By comparison, the SRCLR input to in the case of our home-based experiments, but it is a significant concern our shift register is said to be “levelin mission-critical and safety-critical triggered” (or “level-sensitive”) because applications such as industrial automa- it’s the active level of this signal that’s tion, medical devices, and aerospace. important. In the case of our shift regAnd, of course, one of our goals in ister, if the SRCLR input is low state, these columns is to learn and apply the SRCLK input will have no effect ‘best practices’, enabling the knowl- on the register’s contents. A ‘synchronous system’ is a digital edge gained to be deployed in realsystem in which a shared clock signal world applications. It may be worth reminding our- coordinates all operations. This signal, selves that the timing relationships typically in the form of a square(ish) in the waveforms depicted in our il- wave, provides a regular timing referlustrations, such as Fig.3, are not to ence, and all changes in the system’s scale. For example, we might take a state occur in sync with the clock’s coffee break or go for a long walk be- edges. In our case, even though we’re using tween adjacent presses of our SRCLK switch, which means the noise could a hand-pressed switch to instigate our occur seconds, minutes, hours (even clock signal, this input still defines Practical Electronics | August | 2025 Inactive Noise Active Bounce Inactive Noise Bounce SRCLK from SW Edge-triggered If we decide that we want to do something on the inactive edge SRCLK to SR > 6ms > 6ms RCLK to SR SRCLR from SW Level-sensitive If we decide that we want to do something when it goes inactive SRCLR to SR > 6ms > 6ms RCLK to SR Fig.4: our newer and more flexible method for handling signals from bouncing switch contacts. the synchronous domain of the shift register. That is, whatever happens only on a clock edge is synchronous to that edge, even if the clock is erratic or driven by a human. Meanwhile, the SRCLR input, being level-sensitive and immediate, is said to be ‘asynchronous’ to that clock domain. That is, it takes effect independently of the clock. Switch handling revisited Our original switch-handling implementation primarily focused on what would happen when our switches were pressed, but we didn’t spend much time worrying about what to do when they were released. This wasn’t a problem in this case, but some systems may require us to support different actions when our switches are pressed and released. Bearing all this in mind, let’s create a solution capable of handling all the cases illustrated in Fig.4. For this portion of our discussions, let’s assume our control signals power up in their inactive states. Let’s start with the SRCLK signal coming from the switch. Our routine will ignore any noise on this signal, responding only to an active edge when we know the signal has stopped bouncing (ie, it is stable for more than 6ms). At this point, it will first apply a positive-going pulse to the SRCLK signal feeding the shift register, followed by a positive-going pulse on the RCLK signal feeding the shift register. Additionally, we will design our routine to allow us to perform actions on this signal’s inactive edge if needed in the future. Practical Electronics | August | 2025 Next, consider the SRCLR signal coming from the switch. In our original code, we used this to first apply a negative-going pulse to the SRCLR signal feeding the shift register, followed by a positive-going pulse on the RCLK signal feeding the shift register. We could follow the same approach in our new routine. However, since I want to demonstrate alternative ways of doing things, I’ve decided that we will treat the SRCLR signal feeding the shift register as a debounced version of the SRCLR signal coming from the switch. Counters vs shift registers Let’s take a step back and contemplate things at a high level of abstraction. What we really want is a single solution that can be used to debounce any of our switches, regardless of whether we wish their signals to operate in an edge-triggered or level-sensitive manner. Our solution should be capable of handling both positive and negative edges, as well as both activelow and active-high signals. As part of this, we will monitor the signals from our switches, wait for them to transition from one state to another, then wait for 16ms after the final bounce before performing any actions. Why 16ms? Well, it’s significantly longer than the worst-case 6ms of expected switch bounce; it sits comfortably between the 10ms commonly used in embedded systems and the 20ms typical for mission- and safetycritical applications; and it integrates well with our implementation strategy, as discussed below. A very common software technique is to use a loop that executes periodically (say, once every millisecond) in conjunction with a counter. Suppose a signal from a switch starts off low. In this case, all we need to do is wait for it to be continuously high for 16ms. One way to achieve this is to initialise our counter with a value of 16. Every time our loop executes, we will check the state of the switch. If it’s high, we decrement the contents of the counter; if it’s low, we reload the counter with a value of 16. When the counter reaches 0, we know that the signal has been steadily high for 16ms. Once we know the signal has transitioned to a stable high level, we can perform any required actions, then start waiting for it to transition low again. Once again, we will initialise our counter with a value of 16. Once again, every time our loop executes, we will check the state of the switch. In this case, if it’s low, we decrement the contents of the counter; if it’s high, we reload the counter with a value of 16. When the counter reaches 0, we know that the signal has remained steadily low for 16ms. Another approach involves utilising a software shift register; this is what we will do. We will use a 16-bit (twobyte) variable to store the recent ‘history’ of our shift register, where these 16 bits correspond to 16 readings over 16ms (ie, one per millisecond). Suppose the signal from our switch starts off low. We can initialise our shift register with 0x0000 in hexadecimal (which is equivalent to sixteen 0s in binary). Every time our loop executes, 57 If all 1s WFO sary actions and then transitions the switch to its WFO state. JR If not all 1s Names of states If not all 0s WFZ WFO = WAITING_FOR_ONES JR = JUST_RISEN WFZ = WAITING_FOR_ZEROS JF = JUST_FALLEN Names of functions JF UpdateSwitches() ProcessSwitches() If all 0s Fig.5: a state machine view of our switch handling solution. we shift the register one bit to the left and then insert the current value (low = 0, high = 1) from the switch into the least significant bit. When the shift register contains 0xFFFF (which is equivalent to sixteen 1s in binary), we know that the signal has been steadily high for 16ms. Once this happens, we can perform any required actions, then start waiting for it to transition back to all zeroes. In this case, we know the shift register already contains all 1s, so no initialisation is required. As before, every time our loop executes, we shift the register one bit to the left and then insert the current 0 or 1 value from the switch into the least significant bit. When the shift register contains 0x0000, we know that the signal has been steadily low for 16ms. Did you see that? You may be thinking that 22ms – the sum of our 6ms worst-case bounce scenario and our 16ms delay after the final bounce – is a long time to wait for something to occur after we press a switch. It’s true that the human perception of delay in response to pressing a button can be surprisingly sensitive. However, there’s a practical threshold below which most people won’t consciously notice a delay. A delay under 10ms is typically imperceptible to humans. A delay of 10-30ms may be slightly noticeable to very sensitive users, especially in contexts that require fast feedback (eg, gamers or musicians), but it generally still feels instantaneous. A delay of 30-100ms becomes noticeable to the average person, who may describe the system as feeling “laggy” or “slow to respond”. Most users will perceive any delay greater than 100ms, feeling the system is “sluggish” or “unresponsive”. So, as a rule of thumb, we should aim to keep any button-to-action delays under 50ms. However, don’t take my word for any of this, as this is a test 58 you can easily perform for yourself using your Arduino, pushbuttons and LEDs. Getting into a state As previously discussed, we will employ a software-based switch debounce approach, using a shift register as part of our overall switch-­ handling solution. The easiest way to implement our switch handling scheme is as a state machine (Fig.5). Each of our switches will have a corresponding state machine, and each state machine will have four states: WFO (waiting for ones), JR (just risen), WFZ (waiting for zeros), and JF (just fallen). If the signal from a switch starts off at 0 when the system is powered up, we will load its corresponding shift register with 0x0000 and initialise its state machine to the WFO state. Contrariwise, if the signal from a switch starts off at 1, we will load its shift register with 0xFFFF and initialise its state machine to the WFZ state. Every time we cycle around our 1ms loop thereafter, we will call two functions. First, we will call the UpdateSwitches() function, followed by the ProcessSwitches() function. For each switch, the Update­ Switches() function shifts that switch’s register one bit to the left and adds the current state of the switch to the least-significant bit of the register. Next, it performs a test. If the switch is currently in its WFO state and the shift register contains all 1s, it will transition to the JR state. Alternatively, if the switch is currently in its WFZ state and the shift register contains all 0s, it will transition to the JF state. Now, this is the clever bit (well, I think so). For each switch, the ProcessSwitches() function checks to see if it’s in its JR state, in which case it performs any necessary actions and then transitions the switch to its WFZ state, or if it’s in its JF state, in which case it performs any neces- Consider the code Remembering that I’m a rough-andtough hardware design engineer (not a weedy software weenie), I must admit that I’m rather proud of this solution, which you can peruse and ponder in the file named CB-aug25code-02.txt. I won’t wear out my welcome by walking through this code line by line. Instead, we’ll just hit some of the highlights. First, we define a constant called TICK and assign it a value of 1; this will control our 1ms loop. We also create a bunch of definitions for the names of our control signals, the names of our state machine’s states, and the values we will use to preload and compare our switch-related shift registers (ALL_ZEROS is defined as 0x0000, while ALL_ONES is defined as 0xFFFF). The first part that’s a little different from what we’ve seen before occurs on line 30, as illustrated in Listing 2(a). Remember that we are using the convention that the listing number (2 in this case) corresponds to the numerical part of the matching code file name (“02” here). This code snippet defines a new type that combines two related pieces of data: swData (switch data), which will serve as our 16-bit shift register, and swState (switch state), where we will store the current state of the switch. The name of this structure is SwStuff. We will use this new type to store the data associated with our state machines. As a reminder, we introduced the concepts of struct (short for “structure”) and typedef (short for “type definition”) in our Coding Tips and Tricks discussions in the December 2020 issue. Later, on line 47, we declare an array of type SwStuff called Switches[], as illustrated in Listing 2(b). In this case, NUM_SIGNALS (the number of control signals, which corresponds to the number of switches) has been defined as 3, but this can be easily changed to accommodate more or fewer switches. Now let’s consider the setup() function. After configuring input and output pins and setting the signals to the shift register to their inactive states, we clear the shift register by pulsing its SRCLR signal, followed by its RCLK signal. Next, we initialise the state machines associated with the switches by loading the shift register and setting the state for each switch. We then wait until all the switches are Practical Electronics | August | 2025 Listing 2(a): defining a new type. Listing 2(b): using our new type. Mad max, ready to power up the Arduino! I know we’ve wandered a little off the beaten path, but we are still working toward building our retro games console, as seen in Photo 1. Of particular interest here are the eight pushbutton switches mounted on the front panel: four white direction control switches and four coloured action control switches. Each of our games will use these switches in different ways, and our latest-andgreatest switch-handling solution can be easily enhanced to address this. Listing 2(c): the main loop() function. Next time in their inactive states. If any of the switches are in their active states, we flash the Arduino’s onboard LED (the one attached to pin 13) until they are returned to their inactive states. You can test that this works by pressing one or more of the switches while the Arduino is powered up. The loop() function is easy peasy lemon squeezy, as illustrated in Listing 2(c). The Arduino’s millis() function returns the number of milliseconds since our program started running. In this case, TimeThen is a global variable that we use to remember the last time an action was performed, while timeNow is a local variable that stores the current time. In a nutshell, once every millisecond, we first call the Update­S witches() function and then call the ProcessSwitches() function. The great thing about this is how things are separated out. The Update­Switches() function treats each switch identically. It’s only the Process­ Switches() function that is required to handle any switch-specific actions. We’ve already discussed what these functions do, so I’ll leave it to you to review the code to see how everything plays together. I suggest that you peruse and ponder the program while comparing it to the actions depicted in Figs. 4 and 5. Please feel Practical Electronics | August | 2025 free to email me if you’ve got any questions (my address is at the end of this column). Lastly, load this code into your Arduino and ensure that your LFSR continues to function as before, secure in the knowledge that everything will continue to work in the noisiest of noisy environments. Consider the console You may be thinking that we’ve put a lot of effort into our new switch handling solution, not least that the old one was ‘good enough for government work’, as they say. Still, there’s a r e a s o n behind our madness. Give me strength! Once again, we’ve run out of time. There’s so much to do and so little time. I’m too young for all this excitement! In our next column, we will begin by addressing the homework problems posed in last month’s column. After that, we will wire up our game console switches and apply our new switch handling code to these little scamps. Meanwhile, if you have any thoughts that you’d care to share on anything you’ve read here, please feel free to drop me an email at max<at> clivemaxfield.com. And, as always, PE have a good one! Photo 1: an early version of our retro games console (Photograph by Joe Farr). 59