Silicon ChipMax’s Cool Beans - February 2021 SILICON CHIP
  1. Outer Front Cover
  2. Contents
  3. Subscriptions: PE Subscription
  4. Subscriptions: PicoLog Cloud
  5. Back Issues: PICOLOG
  6. Publisher's Letter
  7. Feature: The Fox Report by Barry Fox
  8. Feature: Techno Talk by Mark Nelson
  9. Feature: Net Work by Alan Winstanley
  10. Project: Remote Monitoring Station by Tim Blythman
  11. Project: Low-distortion DDS Signal Generator by Phil Prosser
  12. Project: INDOOR 'POOR AIR QUALITY' MONITOR by Geoff Graham
  13. Project: USB Logic Analysers by Jim Rowe
  14. Feature: AUDIO OUT
  15. Feature: Circuit Surgery by Ian Bell
  16. Feature: Make it with Micromite
  17. Feature: Practically Speaking by Jake Rothman
  18. Feature: Max’s Cool Beans by Max the Magnificent
  19. Feature: Electronic Building Blocks by Julian Edgar
  20. PCB Order Form
  21. Advertising Index

This is only a preview of the February 2021 issue of Practical Electronics.

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

Articles in this series:
  • (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)
Max’s Cool Beans By Max the Magnificent Flashing LEDs and drooling engineers – Part 12 I must admit to feeling a tad smug as I pen these words, because I just received an email from a devoted PE reader called David Humrich (a.k.a., ‘The LED Baron’) who hails from Down Under. As part of this antipodean communication, David was kind enough to say, ‘I just received the November issue of PE. I particularly enjoyed reading your ‘drip plus splash’ fun. I must confess that I start reading the magazine from the back so that I find your columns sooner!’ ‘You’re making me blush,’ I thought. ‘Don’t stop,’ I thought. Suffice it to say that, as a result of David’s message, I’m currently bouncing around with a great big smile on my face. Wait until I tell my mother that we’ve finally found someone who (intentionally) reads my columns! Prognostication procrastination If I have one failing (and I’m not admitting to anything, you understand), it’s that I’m easily distra… SQUIRREL!!! As a result, many of my hobby projects take years to come to fruition because something else appears on the scene to attract my attention (‘Ooh, shiny!’). In the case of my Pedagogical and Phantasmagorical Inamorata Prognostication Engine, for example, I’ve probably been dabbling around with this for close to 15 years at the time of writing. Some of my friends are prone to making unkind remarks, even going so far as to cast aspersions (which is something I would never do because my throwing arm isn’t what it used to be) and telling me that I shouldn’t commence any new projects until I finish some of the existing ones. Sometimes my lack of progress R ac ing pix el 5 6 7 P lodding pix el B ac kground pix els 3 makes me feel sad but – for reasons I shall shortly explain – now I don’t feel so bad. On a trip to England to visit my mother in 2018, I went to see an exhibition of Leonardo da Vinci’s work, which was being presented in downtown Sheffield. All I can say is that the man was a genius. I’m currently reading his biography by Walter Isaacson (https://amzn. to/33D0PGR) who – as always – does a brilliant job. Previously, I read Walter’s biographies on Steve Jobs and Einstein. Regarding the former, I think he was a brilliant guy who I wouldn’t have liked very much. Regarding the latter, even though we didn’t get into the math, it wasn’t until I read this book that I fully comprehended just how impressive an achievement Einstein’s theory of General Relativity truly was (and still is, for that matter). The point is that, reading this biography on Leonardo, I discovered we share a lot in common. It goes without saying (although I’ll say it anyway) that both us are renowned for our ready wit, dapper dress, and sporty sense of style. Furthermore, I learned that the little rascal left unfinished many more things than he actually completed. He was constantly making sketches with the intention of turning them into pictures, and ceaselessly taking notes with the purpose of writing treatises, but before he got around to actually doing something, he became preoccupied with something else. Now, I’m certainly not comparing myself with Leonardo da Vinci (I’m happy to leave such comparisons to my dear old mom, who would doubtless opine that Leonardo came in a distant second), but – still and all – it’s nice to know that I’m not the only one who... SQUIRREL!!! The final countdown I currently have the words and tune to The Final Countdown rattling around in 2 my head. This song, which was released by the Swedish rock band Europe in 1986, reached number one in 25 countries. I couldn’t help myself; I just took a break to listen to it on YouTube (https://youtu. be/NNiTxUEnmKI). This trip down memory lane was triggered by thoughts of the scene toward the end of the 1987 American science fiction action movie Predator, which starred Arnold Schwarzenegger. I’m thinking of the part where Dutch (Arnold) disables the alien’s cloaking device and then crushes the short-tempered creature under a trap’s counterweight, thereby making it a very unhappy alien indeed. In response, laughing maniacally, the beast activates a self-destruct device, whose countdown sequence is presented as a series of rotating symbols on an alienarm-mounted display. I was thinking we might implement something similar on the NeoPixel rings flaunted by the Prognostication Engine, as discussed in my previous column (PE, January 2021). Since the engine sports a Big Red Button (‘Do not press!’), our countdown sequence could be associated with the activation of this button. Of course, we’ve got only a single ring to play with on our prototype, but that will provide a starting point. I’m thinking of implementing what I’m calling a ‘plodding pixel’ and a ‘racing pixel’ (Fig.1). Remember that the pixel numbers shown here are the way we decided we wanted to visualise and manipulate things, with pixel 0 in the ‘south-west’ position and the pixel numbers increasing in a clockwise direction. The actual pixel numbers on the physical ring are completely different, so we employ a simple cross-reference operation using an array of integers called RingXref[] to translate from our ideal world into the real world (see last month’s column and code for more details). T im e 1 0 1 2 1 5 1 4 1 3 Fig.1. Countdown pixels. 60 ( a) R ac ing pix el approac hes plodding pix el ( b) B um p & pause ( c ) Off we go again Fig.2. First-pass countdown sequence Practical Electronics | February | 2021 The idea is that the racing pixel proceeds in a clockwise direction (Fig.2a) until it reaches the plodding pixel, at which point it ‘bumps’ the plodding pixel over into the next clockwise spot (Fig.2b). We then pause for a short time before the racing pixel sets off again (Fig.2c). In an earlier column (PE, October 2020), we noted that it’s a good idea to make our code and functions as simple and as general-purpose as possible. As part of this, the way I’ve written the sketch (program) for this particular effect is that we define four colours – one for the background pixels (eg, white), one for the racing pixel (eg, yellow), one for the plodding pixel (eg, red), and one we use when the racing pixel bumps into the plodding pixel (eg, orange). Doing things this way allows us to experiment with different scenarios quickly and easily, as illustrated in the video I just took (https://bit.ly/3gXpueJ). When it comes to the code itself, we’ve done things a little differently this time (the full sketch is presented in file CB-Feb21-01.txt – which is available on the February 2021 page of the PE website, and also the PE general downloads page: https://bit.ly/3oouhbl). For example, let’s consider our bump colour (the one we use when the racing pixel crashes into the plodding pixel). Based on our most recent programs (PE, January 2021), we know that we are going to use our GetGammaCorrectedColor() function to correct the gamma value of our initial colour (COLOR_ BUMP_PIXEL, in this example). Next, we are going to use our ModifyBrightness() function to control the intensity of this colour as defined by our BRIGHTNESS constant. Previously, we might have broken this sequence out into a number of discrete steps, as follows: tmpColor = GetGammaCorrectedColor(COLOR_BUMP_PIXEL); tmpColor = ModifyBrightness(tmpColor, BRIGHTNESS); ColorBumpPixel = tmpColor; We implemented things this way in order to make what we were doing easier to understand, but now it’s time to ‘take off the training wheels’ (well, just one wheel to start with) and make things a tad more concise, as follows: ColorBumpPixel = ModifyBrightness(GetGammaCorrectedColor(COLOR_ BUMP_PIXEL), BRIGHTNESS); I know this sort of thing can appear a little scary at first, but it’s really not as bad as it seems. We can think of this as being like the layers of an onion. First, let’s start at the outside and work our way in. As we see, we are assigning the value returned from our ModifyBrightness() function to our ColorBumpPixel variable. Now, our ModifyBrightness() function requires two arguments – a colour to be modified and the amount by which it should be modified (the difference between arguments and parameters was discussed in my Tips and Tricks column in the October 2020 issue of PE). In the case of the first argument, as opposed to specifying a colour directly, we are using the colour value returned from our GetGammaCorrectedColor() function. Now, that wasn’t too bad, was it? Another way to look at this is to think about how the C/ C++ compiler sees things, which is to start by looking at the inner layers of the onion and working its way out. In this case, it will first determine the return value from our GetGammaCorrectedColor() function and subsequently use this as the first argument to our ModifyBrightness() function. Another thing we are going to do is define two global integer variables called PtrPloddingPixel and PtrRacingPixel, and we are going to use these to ‘point’ to the relevant pixels Practical Electronics | February | 2021 (you’ll see what I mean in a minute). In the case of the racing pixel, we want to turn the new (next) pixel on and the old (last) pixel off, then update our PtrRacingPixel variable to point at the next pixel, pause for a short delay, and then do the whole thing again until our racing pixel bumps into our plodding pixel. In my previous column, we introduced a way of determining the number of the old pixel using the % modulo operator so as to get around the boundary conditions when we transition from pixel 15 back to pixel 0 (or from 0 to 15 if our racing pixel were travelling in an anticlockwise direction). We could use a similar trick this time, but instead we’re going to employ a slightly different technique. You may recall that we introduced the concepts of typedef (type definitions), enum (enumerated types), and struct (structures) in my Tips and Tricks column in the December 2020 issue of PE. In this case, we’ll start by declaring a struct called NextLastPair and then declare an array of these elements called PixelPtrs. typedef struct { int next; int last; } NextLastPair; NextLastPair PixelPtrs[NUM_NEOS]; Remember that the number of pixels in our ring, represented by NUM_NEOS, is 16. The idea is that, for any element in this array, which we will assume corresponds to the current pixel of interest, the next value will be the number of the adjacent pixel in the clockwise direction, while the last value will be the number of the adjacent pixel in the anticlockwise direction. The clever part is when we initialise this array in our setup() function, as shown below. This initialisation is based on the same modulo operator tricks we introduced in my previous column. for (int iNeos = 0; iNeos < NUM_NEOS; iNeos++) { PixelPtrs[iNeos].next = (iNeos + 1) % NUM_NEOS; PixelPtrs[iNeos].last = (iNeos + (NUM_NEOS - 1)) % NUM_NEOS; } I know this can be a little demanding on the little gray cells, so I’ve generated the results for you to peruse and ponder (Fig.3). In the case of the next values, for each value of iNeos, we add 1 and then divide the result by 16 iN eos + 1 % 1 6 iN eos + 1 5 % 1 6 (NUM_NEOS) using 0 1 1 0 1 5 1 5 the modulo opera1 2 2 1 1 6 0 tor to give us the re2 3 3 2 1 7 1 mainder, which – by 4 2 3 4 3 1 8 4 5 5 4 1 9 3 the magic of maths 6 4 5 6 5 2 0 – is the number 6 7 7 6 2 1 5 we want. Similar7 8 8 7 2 2 6 ly, in the case of 8 9 9 8 2 3 7 9 1 0 1 0 9 2 4 8 the l a s t values, 1 1 9 1 0 1 1 1 0 2 5 for each value of 1 1 1 2 1 2 1 1 2 6 1 0 iNeos, we add 15 1 3 1 3 2 7 1 1 1 2 1 2 (NUM_NEOS - 1) 1 4 1 4 2 8 1 2 1 3 1 3 and again divide 1 4 1 5 1 5 1 4 2 9 1 3 1 5 1 6 0 1 5 3 0 1 4 the result by 16 ( a) T he nex t v alues ( a) T he last v alues (NUM_NEOS) using the modulo operator to give us the Fig.3. Generating the next and last values. 61 remainder, which – once again – provides us with the value we require. The rest is easy-peasy. All we have to do in our main loop() function is to cycle around turning the racing and plodding pixels on and off as required, including (possibly) changing the colour of the plodding pixel when the racing pixel bumps into it. Once again, you can see all of this code in file CB-Feb21-01.txt, which you can access from the February 2021 page of the PE website. Of course, our experiments here covered a single ring. The Prognostication Engine has five such rings, which opens the door to many more possibilities. For example, every time the first (least-significant) ring experiences a ‘bump,’ this could increment the racing pixel on the next ring, and so on up the chain. My head is buzzing with ideas here, but I’m afraid they will have to wait their turn because – you guessed it – SQUIRREL!!! But where’s the GOL? I fear I’ve let you down and led you astray. At the close of my previous column, I made mention of the fact that in this month’s column we would be using our 12×12 ping pong-ball array to implement a version of Conway’s famous Game of Life (GOL) (https://bit.ly/pe-jan21-cgol). Sad to relate, I got sidetracked by the countdown sequence discussed above, so I’m afraid that we will have to leave the GOL until next time (I hang my head in shame). Until then, as always, I (really do) welcome your comments, questions, and suggestions. Want to build your own amazing array? All the details are in previous Cool Beans columns, starting in March 2020. Cool bean Max Maxfield (Hawaiian shirt, on the right) is emperor of all he surveys at CliveMaxfield.com – the go-to site for the latest and greatest in technological geekdom. Comments or questions? Email Max at: max<at>CliveMaxfield.com Max’s Cool Beans cunning coding tips and tricks T he late great Stephen Hawkins (RIP) wrote a ripping yarn called God Created the Integers: The Mathematical Breakthroughs That Changed History (https://amzn.to/3lKfV3e). It’s sitting on the bookshelf here in my office. One day I intend to read it. The reason this book just sprung into my mind is that a lot of things in C/C++ programming in general, and programming for the Arduino in particular, are, at their most fundamental level, integers in one form or another. Are you high? Let’s consider the pin levels LOW and HIGH, for example. If we’ve defined a pin as a digital output, we might assign it a value of LOW or HIGH as follows: digitalWrite(PinA, LOW); digitalWrite(PinB, HIGH); In the real world, assuming an Arduino Uno, these will appear on the pin as values of 0V and 5V, respectively. But did you know that we can achieve exactly the same effect using 0 and 1? For example: digitalWrite(PinA, 0); digitalWrite(PinB, 1); How can this be? Well, if the truth were told, behind the scenes (‘Pay no attention to that man behind the curtain’), the little scamps who created the Arduino used something like #define statements to equate the keywords LOW with 0 and HIGH with 1. 62 Knowing this tidbit of trivia opens the door to a lot of things when we come to think about it. For example, consider the following snippet of code: int tmpValue; tmpValue = digitalRead(PinA); if (tmpValue == HIGH) { // Do some stuff } We now know that we could replace HIGH with 1, or with the result of an integer expression, or with the integer value returned from a function, or... the list goes on. We all have truths As Pontius Pilate famously says (or sings) in the 1970 rock opera Jesus Christ Superstar, with music by Andrew Lloyd Webber and lyrics by Tim Rice: ‘But what is truth? Is truth unchanging law? We both have truths – are mine the same as yours?’ I know what he means and, in a moment, you will too. Way back in the 1850s, a largely self-taught English mathematician, philosopher, and logician called George Boole (1815-1864) developed a form of mathematics that we now call Boolean algebra. Bool’s intention was to use mathematical techniques to represent and test logical and philosophical arguments. Sad to relate, the significance of his work was Practical Electronics | February | 2021 not fully appreciated until the late 1930s, when a graduate student at MIT, Claude Shannon, revolutionized electronics by submitting a master’s thesis showing how Boolean algebra offered an ideal way for representing the logical operation of digital systems. In the case of the Arduino, we have a data type called bool (or boolean). Variables declared using this type can be assigned values of false or true. Suppose we declare a Boolean variable called tmpBool and assign it a value of true or false. Later, we might perform some tests like: if (tmpBool == true) { // Do some stuff } if (tmpBool == false) { // Do some stuff } Note that the way I’m writing this code – as opposed to using an if else construct – is to illustrate a point. Also, as a point of interest, we could make the expressions above more concise and achieve exactly the same effect by writing them as follows: if (tmpBool) { // Do some stuff } if (!tmpBool) { // Do some stuff } The statements encompassed by the if() statement will only execute if the condition returns a true (ie, non-zero) value. For example, suppose we have something like the following: if (tmpInt == 6) { // Do some stuff } If tmpInt does contain a value of 6, then the condition will return a value of true (1) and the statements associated with the if() will execute; otherwise, the condition will return a value of false (0), which will prevent the statements associated with the if() from executing. The reason I mention this here is that a common mistake is to use a single ‘=’ (assignment) rather than a double ‘==’ (comparison); for example: if (tmpInt = 6) { // Do some stuff } In this case, the compiler will first evaluate the expression and assign a value of 6 to tmpInt (which is going to mess up the rest of the program). Since the processor will see the end result of the ‘comparison’ as being 6, it will treat this a being true (non-zero), and subsequently execute the statements associated with the if(). We will continue to consider the ramifications of all this in my next Tips and Tricks column. In the meantime, as always, please feel free to reach out to me with comments, questions or suggestions. In the latter example, we understand !tmpBool to mean ‘Not tmpBool.’ It’s all about the integers Under the hood, as it were, the C/C++ compiler – and hence the Arduino – tends to treat Boolean operations as though the variables were integers. Let’s start with the false value, which equates to 0. Based on this, many people think that the true value equates to 1. This is true as far as it goes (no pun intended), but in fact any non-zero integer is considered to be true, so 1, 2, 6, 10, 100… are all true in the Boolean sense. In turn, assuming we’ve declared an integer variable called tmpInt and a Boolean variable called tmpBool, this allows us to do things like: Your best bet since MAPLIN Chock-a-Block with Stock Visit: www.cricklewoodelectronics.com Or phone our friendly knowledgeable staff on 020 8452 0161 Components • Audio • Video • Connectors • Cables Arduino • Test Equipment etc, etc tmpBool = true; tmpInt = tmpBool; tmpInt = false; tmpInt = 6; tmpBool = tmpInt; tmpBool = 12; Obviously, this is nonsense code, but it serves to give us an idea what we can do. Now, let’s return to consider an if() statement as follows: if (condition) { // More statements } Practical Electronics | February | 2021 Visit our Shop, Call or Buy online at: www.cricklewoodelectronics.com 020 8452 0161 Visit our shop at: 40-42 Cricklewood Broadway London NW2 3ET 63