Silicon ChipMax’s Cool Beans - November 2020 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: The Christmas Tree that grows! by Tim Blythman
  11. Back Issues: LFSR Random Number Generator Using Logic ICs by Tim Blythman
  12. Project: USB Digital and SPI Interface Board by Tim Blythman
  13. Project: HIGH-POWER 45V/8A VARIABLE LINEAR SUPPLY by Tim Blythman
  14. Feature: P955H PIC Training Circuit by Peter Brunning
  15. Project: Five-way LCD Panel Meter / USB Display by Tim Blythman
  16. Feature: Pedal Power Station! by Julian Edgar
  17. Feature: Make it with Micromite by Phil Boyce
  18. Feature: Circuit Surgery by Ian Bell
  19. Feature: Practically Speaking by Jake Rothman
  20. Feature: Max’s Cool Beans by Max the Magnificent
  21. Feature: AUDIO OUT by Jake Rothman
  22. PCB Order Form: DIRECT BOOK SERVICE
  23. Advertising Index

This is only a preview of the November 2020 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 9 W ell hello there! On the off chance you are newly arrived at this party, our current discussions pertain to one of my hobby projects – a 12×12 array of ping pong balls, each equipped with a WS2818based tricolour LED in the form of an Adafruit NeoPixel. In the last-but-one Cool Beans column (PE, September 2020), we commenced a set of ‘drip’ experiments. We started by visualising the array as lying flat on the floor with individual drips of virtual water falling onto it from above. Each drip lit its associated pixel (ping pong ball) with white light. The way we implemented our original algorithm, each drip appeared in a random location, turned hard on, and then turned hard off again. The duration of each drip was random, as was the inter-drip delay (ie, the delay between adjacent drips). Next, we decided to light our drips with random colours, which we selected from a palette comprising three primary colours (red green and blue), three secondary colours (yellow, cyan, and magenta), and six tertiary colours (flush orange, chartreuse, spring green, azure, electric indigo, and rose). In my previous Cool Beans column, (PE, October 2020), we created some jolly useful functions that allow us to fade from one colour value to another. If you’ve only just started subscribing to PE, then you’ll doubtless be delighted to discover that the back issues containing the aforementioned columns are available for purchase via the magazine’s Digital Downloader page (https://bit.ly/3eC7hjS). More colour! So, the current state of play is that each time a random virtual drip drops, as it were, we fade from black to a randomly selected colour, hold for a short time, and then fade back down again (Fig.1a). Hmmm. On the one hand, this isn’t too shabby. On the other hand, are we the sort of men and women (and boys and girls) who can be satiated with a single saturated colour? ‘No!’ I cry, ‘A thousand times no!’ As a first pass, let’s pluck the low-hanging fruit and simply select a second colour at random. The idea is that we will fade from black to our first colour, then fade from our first B la c k B la c k B la c k B la c k B la c k B la c k F a d e F a d e F a d e F a d e F a d e F a d e C o lo u r C o lo u r 1 C o lo u r 1 C o lo u r 1 C o lo u r 1 C o lo u r 1 F a d e F a d e F a d e F a d e F a d e F a d e B la c k C o lo u r 2 C o lo u r 2 C o lo u r 2 C o lo u r 2 C o lo u r 2 F a d e F a d e F a d e F a d e F a d e B la c k B la c k C o lo u r 3 C o lo u r 3 C o lo u r 3 F a d e F a d e F a d e B la c k B la c k B la c k // Get drip colors iColor = random(0, NUM_WHEEL_COLORS); dripColorOne = ColorWheel[iColor]; iColor = random(0, NUM_WHEEL_COLORS); dripColorTwo = ColorWheel[iColor]; Later, after we’ve determined the values of any delays we wish to use, we add an extra call to our CrossFade() function as follows: // Fade from black to first drip color, then hold CrossFade(iNeo, COLOR_BLACK, dripColorOne, FADE_UP_TIME, dripOnDelay); // Fade from first drip color to second drip color, then hold CrossFade(iNeo, dripColorOne, dripColorTwo, CROSSFADE_TIME, dripOnDelay); // Fade from second drip color to black, then wait CrossFade(iNeo, dripColorTwo, COLOR_BLACK, FADE_DOWN_TIME, interDripDelay); For your delectation and delight, I’ve created a video showing this latest incarnation of our drip sketch in action – you can see it at: https://bit.ly/2G8i2ig Now, one problem with generating the second colour (a) Single colour as a random value is that we could end up with the same colour as the first, which would be a tad boring. We could, (b) Second colour (random) of course, get around this by tweaking our code to ensure (c) Second colour that the second colour is different to the first. Still and (complementary) all, as they say, generating the second colour as a random (d) Second and third colours value seems to lack a certain creative cunning and exhib(split complementary) its a scarcity of subtle sophistication. Perhaps we could (e) Second and third colours (triadic) adopt a more scientific approach. (f) Second and third colours (analogous) In all of these examples, this was the initial randomly selected colour Fig.1. Summary of the effects implemented by our current batch of ping-pong ball array sketches. 58 colour to our second, then fade from our second back to black (Fig.1b). As usual, it would probably be a good idea if you were to download a copy of this sketch (program) in order to follow along with my cogitations and ruminations (file CB-Nov20-01.txt – it and the other files associated with this article, are available on the November 2020 page of the PE website). If you compare this program to our original single random colour version, you will see that the way we’ve built our code means the modifications are minimal. All these changes occur in our DropDrip() function. First, we randomly generate two drip colours rather than one: Complementary combinations In the visual arts, the term ‘colour theory’ refers to a body of practical guidance to colour mixing and the visual effects associated with specific colour combinations. For example, complementary colours are any two colours that Practical Electronics | November | 2020 0 1 1 1 2 1 0 9 3 4 8 7 ( a ) C o m p le m e n ta r y ( b ) S p lit C o m p le m e n ta r y ( c ) T r ia d ic Fig.2. Colour theory and colour combinations. ( d ) A n a lo g o u s 6 5 Fig.3. Index numbers used for colours. are directly opposite each other on the colour wheel, thereby providing maximum contrast. In the traditional RYB colour model, examples of complementary colours would be redgreen, yellow-purple, and blue-orange. Modern colour theory uses either the CMY subtractive colour model or the RGB additive colour model, in which case examples of complementary pairs are red-cyan, green-magenta, and blue-yellow (Fig.2a). The high contrast of complementary colours creates a lively look, but they can be jarring to the eye, so you might want to think twice before daubing every room in your house with complementary colour combinations. The overall operation of our new sketch is depicted in Fig.1c, but how are we to determine the complementary counterpart to our initial randomly generated colour? Well, as you may recall, when we introduced the concept of the colour wheel in an earlier column (PE, September 2020), we annotated each of our colours with a number from 0 to 11 (Fig.3). These are the numbers we are using in our sketches to index (point to) the colours in our colour wheel. I don’t know about you, but I think this next bit is really rather clever (in this case, you can follow along by downloading file CB-Nov20-02.txt). In particular, take a look at the following lines of code from the DropDrip() function and compare these to their equivalents in our previous sketch shown earlier. Since our colour wheel contains only 12 colours indexed from 0 to 11, this would be problematic, to say the least. The solution is to use the % (modulo) operator, which returns the integer remainder from an integer division. This explains the % NUM_WHEEL_COLORS (which equates to % 12) portion of our algorithm, which ensures we only ever end up with index values between 0 and 11 for our second colour. Once again, I’ve created an eye-catching video showing this complementary colour incarnation of our drip sketch in action (https://bit.ly/3lzUDqa). // Get drip colors iColor = random(0, NUM_WHEEL_COLORS); dripColorOne = ColorWheel[iColor]; // Get drip colors iColor = random(0, NUM_WHEEL_COLORS); dripColorOne = ColorWheel[iColor]; iColorTmp = (iColor + (NUM_WHEEL_COLORS / 2)) % NUM_WHEEL_COLORS; dripColorTwo = ColorWheel[iColorTmp]; iColorTmp = (iColor + (NUM_WHEEL_COLORS / 2) 1) % NUM_WHEEL_COLORS; dripColorTwo = ColorWheel[iColorTmp]; Observe that we generate the first colour as a random value as before. Since we know our colour wheel contains 12 colours (we defined this in our sketch as NUM_WHEEL_COLORS), we therefore understand that we need to add half this value (ie, 6) to the index value of our first colour to generate the index value of its complement, which will be our second colour. In the case of our current sketches, we could, of course, simply use (iColor + 6) for this portion of our algorithm. The reason we used (iColor + (NUM_WHEEL_COLORS / 2)) is to ‘future proof’ our code in case we were to decide to increase the size of our colour wheel at some stage in the future. (Yes, I know, a pretty cunning move.) Now, the (iColor + (NUM_WHEEL_COLORS / 2)) portion of the calculation would work ‘as is’ so long as the index value of the first colour was between 0 and 5, because this would result in an index value for the second colour between 6 and 11. But what happens if the index value of the first colour is between 6 and 11? In this case, we would end up with an index value for the second colour between 12 and 17. iColorTmp = (iColor + (NUM_WHEEL_COLORS / 2) + 1) % NUM_WHEEL_COLORS; dripColorThree = ColorWheel[iColorTmp]; Practical Electronics | November | 2020 A cornucopia of colour combinations Now we are really going to up our game because we are going to move to using three colours for each drip. We’ll start with a split complementary implementation as illustrated in Fig.1d and Fig.2b. As we see, this is a variation of the original complementary scheme. In this case, in addition to the base colour, we use the two colours either side of the base colour’s complement. Let’s start by considering how we are going to generate our three colours. As we see below, we commence by generating the first colour as a random value as before, and then we generate our split complementary values by tweaking the algorithm we used to generate our complementary value (you can follow along by downloading file CB-Nov20-03.txt). The next part is where we fade from colour to colour, which simply requires us to add one more call to our CrossFade() function as illustrated below: // Fade from black to first drip color, then hold CrossFade(iNeo, COLOR_BLACK, dripColorOne, FADE_UP_TIME, dripOnDelay); // Fade from first drip color to second drip color, then hold CrossFade(iNeo, dripColorOne, dripColorTwo, CROSSFADE_TIME, dripOnDelay); // Fade from second drip color to third drip color, then hold 59 N o d r ip D r ip fa d e s o n D r ip fa d e s o ff ( a ) R u d im e n ta r y d r ip e ffe c t ( a ) O n e d r ip a t a tim e N o d r ip D r ip fa d e s o n S p la s h fa d e s o n D r ip fa d e s o ff S p la s h fa d e s o ff ( b ) A u g m e n tin g e a c h d r ip w ith a n a s s o c ia te d s p la s h ( b ) M u ltip le d r ip s a t th e s a m e tim e Fig.4. Single versus multiple drips. Fig.5. Basic drip effect compared to a ‘drip plus splash’ effect. CrossFade(iNeo, dripColorTwo, dripColorThree, CROSSFADE_TIME, dripOnDelay); // Fade from third drip color to black, then wait CrossFade(iNeo, dripColorThree, COLOR_BLACK, FADE_DOWN_TIME, interDripDelay); Just for giggles and grins, I also experimented with triadic colour combinations, as depicted in Fig.1e and Fig.2c; followed by analogous colour combinations, as depicted in Fig.1f and Fig.2d. Naturally, the code for these can be downloaded: files CB-Nov20-04.txt and CB-Nov20-05.txt, respectively. Furthermore, you can view videos of these split complementary, triadic, and analogous incarnations on my Cool Beans YouTube Channel (https://bit.ly/3kBgdJD). As an aside, the reasons for our experiments with the various colour combinations discussed above goes far beyond our simple drip sketches. There are all sorts of fun things we might wish to display on our ping-pong ball array in the future. For example, I’m planning on implementing a version of Conway’s Game of Life (https://bit.ly/3fQdhqz) – and knowing how these colour combinations work may well prove to be invaluable to those efforts. We demand more drips! I think it’s fair to say that everything we’ve done thus far has been pretty exciting, but we could do better. Until now, for example, we’ve implemented only a single virtual drip at a time (Fig.4a). Suppose we decide to allow multiple drips to occur at the same time (Fig.4b)? Obviously, we could simply pick a random group of pixels and fade them all on and all off at the same time, and then repeat this action with another random group of pixels, but where would the fun be in that? Apart from anything else, this approach would fall far short of representing randomly occurring drips. What we want is to allow multiple drips to be active at the same time, but for their start and end times to be randomly determined such that they overlap in interesting and unpredictable ways. We might even decide to augment our drips with a ‘splash’ (or ‘puddle’) effect. For example, neglecting the colour-tocolour fades we discussed earlier, the way in which our current drips work is that they essentially fade on and then fade off again (Fig.5a). By comparison, suppose that, following the initial drip, our virtual water droplet splashes out into the pixels north, south, east, and west of our original pixel. There are all sorts of things we could play with here, such as having the fading up of the splash pixels overlap the fading down of 60 the initial drip pixel. We might also decide to experiment with making the colour of the splash pixels analogous to the colour of their parent drip pixel. I don’t know about you, but I, for one, can’t wait! I’m sorry for the delay Sad to say, the way in which we’ve been implementing things thus far will prove to be rather limiting. Consider the following interpretation of the main loop() function used in the Arduino’s classic ‘Blink’ sketch. In this case, we are cycling around turning the LED on and off at a frequency of 1Hz (one cycle per second). void loop() { digitalWrite(PinLed, HIGH); delay(500); digitalWrite(PinLed, LOW); delay(500); } Observe the use of the delay() function. This is of a type known as a ‘blocking function,’ because it prevents (or blocks) anything else from happening while it meanders along through life twiddling its metaphorical thumbs. When you come to think about it, all of our existing sketches have simply been enhanced versions of this Blink approach. Yes, we’ve implemented random drip lengths and random times between drips, but these have all been accomplished by means of the delay() function. And, yes, we’ve added fades, but these simply involved a series of incremental colour changes separated by calls to the delay() function. The thing is, we’ve managed to ‘get by’ when playing with individual drips, but we would find it extremely difficult (if not impossible) to handle multiple simultaneous random drips using our current code architecture. Next time… I’ll leave you for the moment to ponder how we might move to implement things like multiple drips and drips that splash. In my next column, we will ‘Dump the Delay’ and adopt a new way of creating our sketches that will allow us to realise all of these wondrous effects. …but wait, there’s more! Hold onto your hats because this is ‘hot off the press’ as I pen these words. With regard to my Tips and Tricks columns, one of the most important suggestions I have if you wish to learn anything is to conceive a project you want to create Practical Electronics | November | 2020 or implement and then find out how to make it happen. In the case of learning a computer programming language, for example, while it’s obviously a jolly good idea to read reference books on that language, working out how to code a real-world project is an extremely efficacious way to wrap one’s brain around the nitty-gritty details. The reason I mention this here is that my chum, Ted Fried, who is an FPGA designer at Apple, suggested that it would be a great idea to have a competition. Ted’s proposal was that if you (yes you) were to create a program to run on my 12 × 12 ping pong ball array, you could email that program to me for me to run it on my array and post a video of it running on YouTube. Eventually, when we have enough videos, we could all vote to decide which programs provide the coolest and/or most interesting and/or most spectacular effects. The only problem with Ted’s idea is that you really need an array of your own to develop your program, which sort of defeats the object of the exercise. But turn that frown upside down into a smile because we’ve come up with a cunning plan (indeed, it is a plan ‘as cunning as a fox what used to be Professor of Cunning at Oxford University,’ as Edmund Blackadder once famously said). In a nutshell, my chums at Alorium Technology (https:// bit.ly/30Za3MA) have created a special simulator for us. This little beauty allows you to simulate your ping pong ball array program on your host computer. All you have to do is replace the #include <Adafruit_NeoPixel.h> statement with #include <NeoPixel_Simulator.h> – the rest of the program stays ‘as-is’ – pretty cool, eh? Wnat to build your own amazing array? All the details are in previous Cool Beans columns, starting in March 2020. Naturally, I’ve written a column explaining how all of this works in excruciating detail (https://bit.ly/3h2mvkf). Also, for your delectation and delight, I’ve created a short video showing the same program running on the real array and on the simulator (you can view it Cool bean Max Maxfield (Hawaiian shirt, on the right) is emperor here: https://bit.ly/2E4ULgm). of all he surveys at CliveMaxfield.com – the go-to site for the So, set to with gusto and abandon (and latest and greatest in technological geekdom. aplomb, of course). I cannot wait to see the cunning creations you come up with. Comments or questions? Email Max at: max<at>CliveMaxfield.com Until then, have a good one! Max’s Cool Beans cunning coding tips and tricks I n an earlier Tips and Tricks column (PE, September 2020), we talked about how the integers we use in our sketches (programs) come in different sizes (8-, 16-, 32-, 64-bits) and flavors (signed and unsigned). In my previous Tips and Tricks column (PE, October 2020), we discussed the concept of casting; that is, explicitly promoting a smaller integer to a larger version, or demoting a larger integer to a smaller form. As part of my Cool Beans column in that same issue, we introduced a function called GetBlue(), whose purpose was to accept a 32-bit unsigned integer as a parameter and return the least-significant 8 bits as follows: uint8_t GetBlue (uint32_t tmpColor) { return (uint8_t) (tmpColor & 0xFF); } Practical Electronics | November | 2020 We also noted the fact that, in this case, both the cast and the mask operations were unnecessary (the main reason for using them here is to make our intent clear to anyone who has to understand and maintain this program in the future), and that we could actually write this function as follows: uint8_t GetBlue (uint32_t tmpColor) { return tmpColor; } I made the comment: ‘You may rest assured that the compiler’s optimisation know-how should enable it to recognise any operations that are superfluous to requirements and remove them.’ Well, if you ever find yourself wondering how your C/ C++ code will be converted into assembly language on its way to machine code, there’s a wonderful free tool called Compiler 61 Explorer you can use. For example, a comparison of the two versions of our function above shows that they return identical assembly code (https://bit.ly/2P5GemJ). A cunning algorithm I must admit that I’m quite proud of this one. In a Tips and Tricks column from long, long ago, relatively speaking (PE, May 2020), we were talking about the for() statement, which we noted could be abstracted as follows: for (initialization; condition; modification) { // More statements go here } ‘Initialisation’ is where we initialise our control variable(s), ‘condition’ is where we perform a test, and ‘modification’ is where we increment or decrement our control variable(s). Note that the way I said this indicates the possibility of having multiple initialisation and modification variables. Generally speaking, beginners think of a for() statement as looking something like the following: for (i = 0; i < 10; i++) { // More statements go here } In reality, however, both the initialisation and modification sections can comprise multiple comma-separated elements looking something like the following: for (i = 0, j = 10; i < 10; i++, j--) { // More statements go here } Observe that we can only have a single condition, although this could have multiple parts, such as ( (i < 10) && (j > 0) ), although this would be superfluous to requirements in this particular example. The reason I’m waffling on about this here is that I just implemented a cunning algorithm using a for() loop of this ilk, and I thought it might be instructive to share it with you. A rainbow of colours I was starting to get worried with regard to my Cool Beans columns that you might think we were only ever going to light a single pixel at a time on our 12 × 12 array. Thus, I whipped up an interesting little sketch based on Adafruit’s classic Rainbow algorithm. As a starting point, we present the dynamically changing rainbow using the 12 columns forming the array. For each cycle, we first generate the 12 colours and store them in a 12-element array called RainbowColors[], after which we call a function called LoadRainbowColors() to load these colours into the array. The key portion of this function is as follows: for (int xInd = 0; xInd < NUM_COLS; xInd++) { for (int yInd = 0; yInd < NUM_ROWS; yInd++) { iNeo = GetNeoNum(xInd, yInd); Neos.setPixelColor(iNeo, RainbowColors[xInd]); } } In this case we use two nested for() loops, each of which employs a single initialisation and modification variable. 62 You can peruse the complete sketch if you wish (file CBNov20-06.txt – available on the November 2020 page of the PE website) and also watch a video of it in action on the array (https://bit.ly/310Df5D). Next, I decided that I wished to present the rainbow on the array’s diagonals. Let’s think about this for a moment (maybe you could sketch things out on a piece of paper). If we had a 2 × 2 array, we would have three diagonals; a 3 × 3 array would give us five diagonals; a 4 × 4 array would have seven diagonals, and so on. The bottom line is that the number of diagonals in a square array is equal to the number of rows plus the number of columns minus one. Thus, in the case of our 12 × 12 array, we have 12 + 12 – 1 = 23 diagonals. This means that, for each cycle, we now need to generate 23 colours and store them in a 23-element array called RainbowColors[], after which we call a modified version of our LoadRainbowColors() function to load these colours into the array. The key portion of this modified function is as follows: for (int xInd = xStart, yInd = yStart; xInd <= xEnd; xInd++, yInd--) { iNeo = GetNeoNum(xInd, yInd); Neos.setPixelColor(iNeo, RainbowColors[iDiag]); } Observe that, in this case, we are using a single for() loop that employs two initialisation variables and two modification variables. Once again, you can ponder the complete sketch for this if you wish (file CB-Nov20-07.txt), and also watch a video of it in action (https://bit.ly/2DXZsbZ). Your best bet since MAPLIN Chock-a-Block with Stock Visit: www.cricklewoodelectronics.com O r p h o n e o u r f r i e n d l y kn o w l e d g e a b l e st a f f o n 0 2 0 8 4 5 2 0 1 6 1 Components • Audio • Video • Connectors • Cables Arduino • Test Equipment etc, etc Vi s i t our Sh op , C a ll or B uy on li n e a t : w w w . c r i c k lew oodelec t r on i c s . c om 0 2 0 8 4 5 2 0 1 6 1 Vi s i t our s h op a t : 4 0 - 4 2 C r i c k lew ood B r oa dw a y L on don NW 2 3 E T Practical Electronics | November | 2020