Silicon ChipMax’s Cool Beans - September 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: ULTRABRITE LED PUSHBIKE LIGHT by Daniel Doyle Nicholas Vinen
  11. Back Issues: LFSR Random Number Generator Using Logic ICs by Tim Blythman
  12. Project: The Micromite Explore-28 by Geoff Graham
  13. Project: Three Stepper Motor Drivers by Jim Rowe
  14. Feature: Cheap and easy compact speaker enclosures by Julian Edgar
  15. Feature: Circuit Surgery by Ian Bell
  16. Feature: Make it with Micromite by Phil Boyce
  17. Feature: Max’s Cool Beans by Max the Magnificent
  18. Feature: PICn’Mix by Mike Hibbett
  19. Feature: AUDIO OUT by Jake Rothman
  20. PCB Order Form
  21. Advertising Index

This is only a preview of the September 2020 issue of Practical Electronics.

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

Articles in this series:
  • Techno Talk (September 2020)
  • Techno Talk (October 2020)
  • (November 2020)
  • Techno Talk (December 2020)
  • Techno Talk (January 2021)
  • Techno Talk (February 2021)
  • Techno Talk (March 2021)
  • Techno Talk (April 2021)
  • Techno Talk (May 2021)
  • Techno Talk (June 2021)
  • Techno Talk (July 2021)
  • Techno Talk (August 2021)
  • Techno Talk (September 2021)
  • Techno Talk (October 2021)
  • Techno Talk (November 2021)
  • Techno Talk (December 2021)
  • Communing with nature (January 2022)
  • Should we be worried? (February 2022)
  • How resilient is your lifeline? (March 2022)
  • Go eco, get ethical! (April 2022)
  • From nano to bio (May 2022)
  • Positivity follows the gloom (June 2022)
  • Mixed menu (July 2022)
  • Time for a total rethink? (August 2022)
  • What’s in a name? (September 2022)
  • Forget leaves on the line! (October 2022)
  • Giant Boost for Batteries (December 2022)
  • Raudive Voices Revisited (January 2023)
  • A thousand words (February 2023)
  • It’s handover time (March 2023)
  • AI, Robots, Horticulture and Agriculture (April 2023)
  • Prophecy can be perplexing (May 2023)
  • Technology comes in different shapes and sizes (June 2023)
  • AI and robots – what could possibly go wrong? (July 2023)
  • How long until we’re all out of work? (August 2023)
  • We both have truths, are mine the same as yours? (September 2023)
  • Holy Spheres, Batman! (October 2023)
  • Where’s my pneumatic car? (November 2023)
  • Good grief! (December 2023)
  • Cheeky chiplets (January 2024)
  • Cheeky chiplets (February 2024)
  • The Wibbly-Wobbly World of Quantum (March 2024)
  • Techno Talk - Wait! What? Really? (April 2024)
  • Techno Talk - One step closer to a dystopian abyss? (May 2024)
  • Techno Talk - Program that! (June 2024)
  • Techno Talk (July 2024)
  • Techno Talk - That makes so much sense! (August 2024)
  • Techno Talk - I don’t want to be a Norbert... (September 2024)
  • Techno Talk - Sticking the landing (October 2024)
  • Techno Talk (November 2024)
  • Techno Talk (December 2024)
  • Techno Talk (January 2025)
  • Techno Talk (February 2025)
  • Techno Talk (March 2025)
  • Techno Talk (April 2025)
  • Techno Talk (May 2025)
  • Techno Talk (June 2025)
Max’s Cool Beans By Max the Magnificent Flashing LEDs and drooling engineers – Part 7 W ell hello there! How nice it is to see you again. It probably won’t surprise you to hear that things have been progressing apace here at Maxfield Manor with regard to my 12 × 12 ping-pong ball array. I should perhaps warn you that we will be leaping from topic to topic with the agility of young mountain goats in this column, so please take a moment to make sure you’re wearing appropriate clothing before we proceed further. Blinded by the light Let’s commence by reminding ourselves that each of our pixels (ping-pong balls) contains a tricolour LED called a NeoPixel. Furthermore, each NeoPixel contains red, green, and blue subpixels, each of which can be driven with 256 different levels from 0 (0x00 in hexadecimal = 0% = fully off) to 255 (0xFF in hexadecimal = 100% = fully on). I don’t know about you, but whenever I’m working on a project like this, questions pop into my mind and I realise that there are all sorts of things I don’t know. For example, suppose we were to light up one of our pixels 100% red. Now suppose we were to light up an adjacent pixel with 100% green and 100% blue, resulting in cyan. Does this mean that the cyan pixel is twice as bright as the red pixel? In turn, does this mean that we should really light the green and blue subpixels at 50% (128 in decimal = 0x80 in hexadecimal) so as to achieve the same brightness as the red pixel? Similarly, if we were to take another pixel that’s adjacent to our original red pixel and light all three sub-pixels to generate white, does this mean that we should really set the red, green, and blue sub-pixels to 33% (85 in decimal = 0x55 in hexadecimal) in order to achieve the same brightness as the red pixel? I thought it might be a good idea to test things out. As you may recall from my previous column (PE, August 2020), our NeoPixels are connected together as a single string numbered from 1 to 144 (there’s also a sacrificial pixel 0, which we’re using as a voltage-level converter, but this plays no part in the visible portion of the display). We’re considering our array to be an (X,Y) matrix with both X (horizontal) and Y (vertical) positions numbered from 0 to That’s what I call a pixel array... and the shirt’s not bad either! 11, and with pixel (0,0) in the bottom left-hand corner. Also, we created a simple function called GetNeoNum(), which accepts X and Y values as arguments and returns the number of the corresponding NeoPixel in the string. As a first test of this brightness/contrast conundrum, I created a simple sketch (program) that fills the outer pixels with 100% white and an inner 4 × 4 square of pixels with 100% red (Fig.1a). Then we drop the surrounding white to 33%. Next, the sketch fills the outer pixels with 100% red and the inner square with 100% white (Fig.1b). Once again, we subsequently drop the white to 33%. We then cycle back to perform the whole sequence over and over again. If you wish, you can download this sketch and peruse and ponder it at your leisure (it’s file CB-Aug20-01.txt – available for download, along with the other three files discussed in this column, on the September 2020 page of the PE website). For your delectation and delight, I’ve also created a short video showing all of this in action (https://bit.ly/2OG9lgg). As an aside, you may recall from an earlier column (PE, July 2020) that the creators of Adafruit’s NeoPixel library provided two ways for us to specify the colour of a pixel. Let’s suppose our string is called Neos and that we want to set the colour associated with pixel 42 to have red, green, and blue colour components of 128, 0, and 255, respectively (these would be 0x80, 0x00, and 0xFF in hexadecimal). If we wish, we can specify the colours individually using a statement like: Neos.setPixelColor(42, 128, 0, 255) (a) Red inner 100% ; White outer 100% < -> 33% (b ) Red outer 100% ; White inner 100% Fig.1. First contrast test. Practical Electronics | September | 2020 < -> 33% Or: Neos.setPixelColor(42, 0x80, 0x00, 0xFF) 53 Neos.setPixelColor(42, 8388863) into here) it’s also exclusive, which means it won’t appear in the result. Another way to look at this is to observe that when this function is called it will return a result between min and (max – 1). where the number is specified in decimal, or: A bit of a drip As an alternative we can specify all three colours together as a single numerical value using a statement like: Neos.setPixelColor(42, 0x8000FF) with the number specified in hexadecimal. Using a single numerical value in hexadecimal makes our lives a lot easier, so that’s what we’ll do. This explains why you will see the colour definitions in my sketches looking something like the following: #define COLOR_WHITE 0xFFFFFFU #define COLOR_BLACK 0x000000U #define COLOR_RED 0xFF0000U #define COLOR_GREEN 0x00FF00U #define COLOR_BLUE 0x0000FFU Note that adding ‘U’ (or ‘u’) characters on the end of these values informs the compiler to regard them as being unsigned (see this month’s Tips and Tricks column for more discussions on the difference between signed and unsigned values). Most of the time this won’t be necessary, but every now and then... Next, I started to wonder if my 4 × 4 centre square was a tad small (16 pixels) in comparison to the surrounding area (128 pixels), so I decided to increase its size to 6 × 6. Fortunately, due to the way I created my original program, all I had to do to generate the new version was to change two definitions: XY_ CENTER_MIN was changed from 4 to 3, while XY_CENTER_MAX was changed from 7 to 8. Once again, you can download this sketch (CB-Aug20-02.txt). And, once again, I’ve created a short video showing all of this in action (https://bit.ly/2OG9lgg). Personally, I think the 33% white looks a bit washed out. My conclusion is that, if we were trying to use our array to represent images or to play extremely low-resolution videos, then we would probably vary the intensity of each sub-pixel to balance everything out. By comparison, in the case of our simple effects, we probably want to make everything as bright as possible, which – happily – is my default position anyway. For our first series of effects, we’re going to imagine that our array is lying flat on the floor and that occasional drips of water – virtual raindrops, if you will – are randomly falling from the sky. Whenever a virtual drip lands on one of our pixels (ping-pong balls), that pixel will light up bright white for a short period of time. You may find it advantageous to download the sketch associated with this effect (file CB-Aug20-03.txt) and reference it in conjunction with these discussions. As you will see, we declare two integer global variables called OldX and OldY, which we will use to keep track of the (X,Y) coordinates of the last pixel that was lit up. We initialise both of these variables with random values between 0 and 11 in our setup() function. Most of this sketch is self-explanatory. The interesting part is where we generate the (X,Y) coordinates associated with a new drip as follows (the +1s associated with the maximum values are there to offset the fact that, as we just discussed, the random() function treats its maximum argument as being exclusive): do { newX = random(MIN_X, (MAX_X + 1)); newY = random(MIN_Y, (MAX_Y + 1)); } while (condition); This loop will be executed at least one time, and it will keep on executing until its condition is met (ie, returns true). But what condition should we use? One alternative would be to say: ((OldX == newX) && (OldY == newY)) To give our effects an ‘organic’ feel, we’re going to be using the C/C++ random() function, which accepts two arguments and returns a random result as follows: In this case, the loop will keep on executing until the new pixel is different from the old pixel, but there’s nothing to prevent the new pixel from being horizontally or vertically adjacent to the old pixel. Personally, I prefer a tad more differentiation, so I opted to swap the && (logical AND) operator for the || (logical OR) operator and use: result = random(min, max); ((OldX == newX) || (OldY == newY)) The min argument is optional. If this value is not specified, it will default to 0. This value is also inclusive, which means it may appear in the result. By comparison, the max argument is required and (for all sorts of reasons we won’t go This means the new pixel cannot be on the same row or column as the old pixel. The only other things to note about this sketch are that we also use the random() function to vary the duration of the flashes associated with each of the drips and the gaps between drips. Also, the last thing we do at the end of each cycle is set the values of OldX and OldY to be the values of newX and newY, respectively. This means that the pixel we just flashed will be considered to be our old pixel the next time we pass through the loop. Do you even need to ask?! Yes, of course I’ve carefully crafted a video showing all of this in action (see: https://bit.ly/2OG9lgg). Feeling random? Red Ma g e n t a Y ellow G reen Y e llo w Cy an Blue (a) Sub tractiv e (ink s, paints, and pig ments) R e d G reen C y a n B lu e (b ) Additiv e (lig ht) Fig.2. Subtractive and additive primary colours. 54 Ma g e n t a Do you believe in colour fairies? When I was a little kid, I had a book that described how the red, yellow, and blue colour fairies spent the night repainting everything, which explained why all of the colours looked so bright and fresh each morning. Practical Electronics | September | 2020 0° Primary Red 330° Tertiary 30° Tertiary FF 00 00 Rose Flush O rang e FF 00 80 FF 80 00 300° Secondary 60° Secondary Mag enta FF 00 FF 11 0 Y ellow 2 10 270° Tertiary Electric Indig o 9 Chartreuse 80 FF 00 4 7 6 Your best bet since MAPLIN Chock-a-Block with Stock 90° Tertiary 3 8 80 00 FF FF FF 00 1 5 240° Primary 120° Primary 00 00 FF 00 FF 00 Blue Visit: www.cricklewoodelectronics.com O r phone our f riendly kn ow ledg eab le staf f on 0 2 0 8 4 5 2 0 16 1 Components • Audio • Video • Connectors • Cables Arduino • Test Equipment etc, etc G reen 210° Tertiary Az ure 00 80 FF 150° Tertiary 180° Secondary Cy an Spring G reen 00 FF 80 00 FF FF Fig.3. The colour wheel we will be using in our experiments. This all made perfect sense to me, especially since I knew from school that the fairies could generate other colours by working together: red and yellow made orange, red and blue made purple, yellow and blue made green, and so forth. Later, my teacher explained that red (R), yellow (Y), and blue (B) were primary colours. What she didn’t say was that this was just one possible set of primaries, because the term ‘primary colours’ simply refers to a small collection of three or more colours that can be combined to form a range of additional hues, shades, tints and tones. For example, printers use cyan (C), magenta (M), and yellow (Y) inks as their primary colours. Furthermore, although it’s possible to mix cyan, magenta, and yellow to form black, printers typically use a special black pigment. We use the letter K to represent this pigment because B could be confused with blue. This explains why we use the term CMYK when we’re talking about printer ink. Now, the thing about inks, paints and pigments is that they are subtractive in nature. One way to think about this is that we start with a white background illuminated with white light. The white background reflects all of the frequencies in the white light. When we start to add our colours, each colour absorbs (subtracts) some of the frequencies from the white light (Fig.2a). Furthermore, when inks, paints, or pigments are mixed together, they each absorb different frequencies. Basically, what we see is what’s left over; that is, what isn’t absorbed. When all of the colours are mixed together, they absorb all of the frequencies leaving us with nothing to see (ie, black). By comparison, light is additive. The set of primary light colours with which we are most familiar are red (R), green (G), and blue (B). One way to think about this is that we start with a black room and add our primary light sources. Red and green add together to form yellow, red and blue add to form magenta, and green and blue add to form cyan. When they are all combined, red, green, and blue are perceived as white. Technicolor drips The reason for our interest in primary colours is that the next version of our drip program is going to illuminate our pixels with randomly selected colours. Since we have red, green, and blue subpixels, each of which can be assigned values from 0 to 255, we have the potential for 256 × 256 × 256 = 16,777,216 (224) different hues, shades, tints and tones. Practical Electronics | September | 2020 V is it o u r S h o p , C a ll o r B u y o n lin e a t: w w w .c r ic k le w o o d e le c tr o n ic s .c o m 0 2 0 8 4 5 2 0 16 1 V is it o u r s h o p a t: 4 0 -4 2 C r ic k le w o o d B r o a d w a y Lo n d o n N W 2 3E T Of course, some of these little rascals are going to be dim and lacklustre but – from our experiments in contrast at the beginning of this column – we know that we want our colours to be as bright and shiny as they can be. One way to represent colours is to use a colour wheel (Fig.3). As we see, our three primary colours (red green and blue) can be combined to form three secondary colours (yellow, cyan, and magenta) and six tertiary colours (with more exotic names: flush orange, chartreuse, spring green, azure, electric indigo, and rose). These 12 colours are the ones we will use in our sketch, which you can download if you wish (CB-Aug20-04.txt). If you compare this sketch to our previous version, you will observe that the only difference is that – as opposed to lighting our pixels with white – for each virtual drip we now use the random() function to select one of our 12 colour options. Once again, I’ve created a video showing all of this in action (https://bit.ly/2OG9lgg). Next time I must admit that I do like the coloured drips featured in our last sketch, but simply turning our pixels hard on and hard off is not very subtle and lacks a little je ne sais quoi. One way in which we can add a soupçon of sophistication is by fading the colour up, holding it steady, and then fading it back down again, so this is what we’ll do in my next column. Until then, have a good one! 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 55 Max’s Cool Beans cunning coding tips and tricks I n my previous tips and tricks column (PE August 2020), we noted that when people are first introduced to the C/C++ programming languages, one of the first data types to which they are introduced is the int, which stands for ‘integer’. We also noted that we may decide to declare our integers as being signed or unsigned: signed int John; unsigned int Jane; A signed int can be used to represent both positive and negative values, while an unsigned int can be used to represent only positive values. Interestingly enough, the C/C++ standards don’t explicitly define the size of an int. All they say is that an int should be a minimum of two bytes (16 bits). In the case of an Arduino Uno with its 8-bit data bus, the size of an int is indeed two bytes; in other computers it can be two bytes, four bytes, or more. A 2-byte (16-bit) variable can be used to represent 216 = 65,526 different patterns of 0s and 1s. In the case of a signed int, these patterns can be used to represent both negative and positive values in the range –32,768 to +32,767. By comparison, in the case of an unsigned int, these patterns can be used to represent only positive values in the range 0 to 65,535. Hey, short stuff! There are also short and long flavours of the int: signed short int Fred; signed long int Bert; unsigned short int Mary; unsigned long int Beth; In the same way we assume a number like 42 to be positive without explicitly writing it as +42, the compiler will assume that an unqualified int is signed, which means we may omit the signed part of the declaration if we wish: int John; short int Fred; long int Bert; Similarly, if we declare something as being of type short or long, the compiler will happily assume that we are talking about integer values, so we may also omit the int part if we wish: int John; short Fred; long Bert; The C/C++ specifications state that the minimum size of a short int is two bytes (16 bits), while the minimum size of a long int is four bytes (32 bits). Fixing the width It can be a tad disconcerting when one first discovers that the size of the different types of integers can vary from one machine to another. The reason behind this is to allow the compiler to make use of its knowledge of the targeted processor’s internal architecture to use optimal data sizes for that particular machine. Things aren’t too bad if you are a hobbyist writing code for only one processer. However, depending on the size of the numbers you are trying to represent, problems may arise if you try to port your code from a machine that supports four-byte integers to one 56 whose integers are only two bytes in size, for example. In order to get around this, we can use the fixed-width integer types that have been available since the v11 release of C++; for example: int8_t Cuthbert; // Unequivocally 8 bits (one byte) uint8_t Clarence; // Indubitably 8 bits (one byte) There are also 16-bit (int16_t and uint16_t), 32-bit (int32_t and uint32_t), and 64-bit (int64_t and uint64_t) equivalents of these fixed-width types. A dangerous thing ‘A little knowledge is a dangerous thing,’ as the old saying goes. Suppose you are writing a program for an Arduino Uno and you know that the counter you are using to control a for() loop will only ever count up to 100. In this case, would you be better off using an int8_t (8 bits) rather than an int (16 bits), thereby saving a byte (8 bits) in memory? For example: for (int8_t i = 0; i < 100; i++) { // Do something cunning here } Generally speaking, the answer is ‘no’. The problem is that using a smaller variable in order to save memory may negatively impact the performance of your program. Unless you are intimately familiar with the workings of your compiler and the internal architecture of your processor, you are best advised to use an int and let the compiler use its detailed knowledge of the processor’s architecture to make optimal decisions for you. Having said this, if you do have specific requirements, then by all means use the appropriate fixed-width types. In the case of the programs for my 12 × 12 ping-pong ball array project, for example, you will observe that I declare all of my colour values as being of type uint32_t (ie, unsigned 32-bit integers). The equivalent would be an unsigned long in the case of the Arduino Uno, but I prefer to be explicit in the case of these declarations. But wait, there’s more! I come from the days where every memory location and every clock cycle were considered to be precious commodities. Computer magazines used to have columns of cunning tricks for doing things like swapping the upper and lower four bits in a byte in the least number of clock cycles or using the smallest number of instructions or consuming the least amount of memory. Some designers of embedded systems are pushing the boundaries of the processors they’ve been instructed to use. In this case, they may decide to use the minimum width and fastest minimum width types that have been supported by C since 1999 (known as C99-compliant compilers); for example: int8_t Bob; // Fixed width signed // 8-bit integer int_least8_t Dan; // Minimum width signed // 8-bit integer int_fast8_t Sam; // Fastest minimum width // signed 8-bit integer Of course, there are unsigned versions of these types, along with 16-, 32-, and 64-bit variants, but I’d advise holding off on using these little scamps until you are 100% sure you are aware of any and all implications. Practical Electronics | September | 2020