Silicon ChipMax’s Cool Beans - April 2023 SILICON CHIP
  1. Outer Front Cover
  2. Contents
  3. Subscriptions: PE Subscription
  4. Subscriptions
  5. Back Issues: Hare & Forbes Machineryhouse
  6. Publisher's Letter: Power!
  7. Feature: AI, Robots, Horticulture and Agriculture by Max the Magnificent
  8. Feature: The Fox Report by Barry Fox
  9. Feature: Net Work by Alan Winstanley
  10. Project: 500 WATTS POWER AMPLIFIER PART 1 by JOHN CLARKE
  11. Feature: Capacitor Discharge Welder by PHIL PROSSER
  12. Project: Amplififier Clipping Indicator by John Clarke
  13. Project: Three low-noise HF-UHF Amplififiers by Jim Rowe
  14. Feature: Circuit Surgery by Ian Bell
  15. Feature: AUDIO OUT by Jake Rothman
  16. Feature: Max’s Cool Beans by Max the Magnificent
  17. PCB Order Form
  18. Advertising Index

This is only a preview of the April 2023 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 Arduino Bootcamp – Part 4 H ello there – how’s your day going? I’m having an awesome time (thanks for asking). One of the great things about writing for PE is receiving emails from readers around the world saying how wonderful I am. Actually, if the truth be told, these messages are usually focused on my columns, but I’m reading between the lines, as it were. For example, I just heard from retired computer studies teacher Tom Boyd, who describes himself as ‘a computer addict since when programming was done with paper tape.’ As Tom noted, ‘The internet is all well and good, but a properly produced product like Practical Electronics is so much better!’ Tom went on to say, ‘I am a long-time Arduino evangelist and I love what you’re doing with your Arduino Bootcamp articles to get more people started.’ Of particular interest to us here, Tom introduced me to his website, which contains a cornucopia of Arduino-related goodies, projects, and ‘How To’ guides: https://bit.ly/3WFTQp4 Ooh! Shiny! Let’s kickoff with a little pizazz. After all, who deserves it more than us? Assuming you’ve still got your 7-segment display wired up the way we left things in our previous column (PE, March 2023), then download file CB-Apr23-06.txt – all the files mentioned in this column are available from the April 2023 page of the PE website at: https://bit.ly/pe-downloads Now, launch your Arduino integrated development environment (IDE). Use the File > New Sketch command to create a new program, then use the File > Save As command to save this file with a name of your own choosing (the name HelloCount would work if you happen to find yourself filename challenged). Next, we want to delete the existing contents of this file and replace it with the contents of our CB-Apr23-06.txt file. If any of this is new to you, all you need do is open the CB-Apr23-06.txt file with your text editor and use the editor’s Edit > Select All command followed by the Edit > Copy command to select and copy the contents of the file to your computer’s Practical Electronics | April | 2023 clipboard. Now, place your cursor in the Arduino IDE window and use its Edit > Select All command followed by its Edit > Paste command to select its existing contents and overwrite them by pasting the contents of the clipboard into the IDE. Before you do anything else, use the IDE’s File > Save command to save your updated program contents. Now, make sure your Arduino Uno is connected to your host computer via its USB cable, then use the IDE’s Sketch > Upload command to load the program into your Arduino and run it. You should see the 7-segment display present a cheery ‘HELLO’ greeting, after which it will start to count from 0 to 9 repeatedly. The rest of this column will walk us through the various elements we’ve brought together to make this program perform its magic. We all count! As Mickey Mouse famously said, ‘Arithmetic is being able to count up to twenty without taking off your shoes,’ and who amongst our number (no pun intended) would argue with logic like that? Speaking of numbers, since ancient peoples counted using their fingers, and given that we are equipped with ten fingers (including thumbs), the number system with which we are most familiar is decimal (a.k.a. ‘denary’). As decimal has ten digits (0, 1, 2, 3, 4, 5, 6, 7, 8, 9), it’s said to be base-10 or radix-10. Decimal is a place-value number system, which means the value of a digit depends on the digit itself and its location (place) within the number. If we visualise the digits as being presented in columns, then each column has a ‘weight’ associated with it, where these weights are powers of ten. Starting with the right-hand digit, which is known as the least-significant digit (LSD), these weights are 100 = 1, 101 = 10, 102 = 10 × 10 = 100, 103 = 10 × 10 × 10 = 1000, and so on. Each digit forming a decimal number is multiplied by its column’s weight and the results are summed to give the total value of that number. For example, we understand 6174, which is known as Kaprekar’s constant after the Indian mathematician Dattatreya Kaprekar, to be: (6 x 1000) + (1 x 100) + (7 x 10) + (4 x 1). Suppose we wish to count in decimal. Starting with 0 in the first column, we keep incrementing (adding 1 to) our first column until we reach 9, at which point we’ve exhausted all of our digits. Thus, the next time we add 1, we reset the first column to 0 and increment the next column to 1, thereby resulting in 10. Similarly, when we reach 99, we set the first two columns to 0 and increment the third column, resulting in 100, and so it goes… for ever. I’m reasonably sure you’re saying to yourself, ‘Good grief! All of this is painfully obvious,’ but hold onto your hat because we are setting the scene for the horrors delights that are to come. Take a number! As we discussed in Part 3 (PE, March 2023), we can use transistors to create simple logical building blocks that can detect the difference between two voltage values and present the results of their operations in terms of the same two voltages. These building blocks can be connected to create larger functions, which can themselves be connected to realise sophisticated systems like computers – see my column, Arduino 0s and 1s, LOW and HIGH, False and True and Other Stuff at: https://bit.ly/3DeMQsl Rather than think in terms of voltages, we prefer to think in terms of 0s and 1s. This leads us to the binary number system, which is said to be base-2 or radix-2. A binary digit, which is known as a ‘bit,’ can assume only two values: 0 or 1. Like decimal, binary is a place value system. In this case, however, the column weights are powers of two. Starting with the right-hand bit, which is known as the least-significant bit (LSB), these weights are: 20 = 1, 21 = 2, 22 = 2 × 2 = 4, 23 = 2 × 2 × 2 = 8, and so on. As before, each bit forming a binary number is multiplied by its column’s weight and the results are summed to give the total value of that number. For example, we understand 1100 in binary to be: (1 × 8) + (1 × 4) + (0 × 2) + (0 × 1) = 12 in decimal. Counting in binary is easy-peasy lemon squeezy (Fig.1). As with decimal, we start with 0 in the LSB. Actually, we start with 59 Binary 3 2 1 0 2 2 2 2 Decimal Fig.1. Binary vs decimal. 0s in all of the bits. This is as good a time as ever to note that we usually write binary 0100 4 numbers with leading 0101 5 0s, which serves to in0110 6 dicate the size of the 0111 7 1000 8 bus, field, or memory 1001 9 location being used 1010 10 to represent and/or 1011 11 store the value. For 1100 12 example, 0101 tells us 1101 13 1110 14 we are working with 1111 15 a 4-bit binary number whose current value is 5 in decimal. By comparison, 00000101 indicates we are working with an 8-bit binary number whose current value is, once again, 5 in decimal. So, when counting with a 4-bit binary number, we start with 0000 (0 in decimal). In this case, as soon as we’ve added 1 to the LSB to give 0001 (1 in decimal), we’ve already exhausted all of our digits. Thus, the next time we wish add 1, we reset the first column to 0 and increment the next column to 1, thereby resulting in 10 (2 in decimal). Similarly, when we reach 11 (3 in decimal), we set the first two columns to 0 and increment the third column, resulting in 100 (4 in decimal), and so it goes. 0000 0 0001 0010 0011 1 2 3 Fancy a nybble? As we previously noted, a binary digit, which is called a bit, can adopt only two values: 0 and 1. It doesn’t take long to realise that there’s a limit to what we can accomplish with a single bit. The solution is to gather groups of bits together, and to then use these groups to represent things like numbers or characters. Some grouping sizes are more common than others. One very common grouping is eight bits, which is known as a ‘byte’. This term, which is a deliberate respelling of ‘bite’ to avoid accidental mutation to ‘bit’, was coined by the GermanAmerican computer scientist Werner Buchholz in 1956. Another common grouping is four bits, which is known as a ‘nybble’ (or ‘nybl’ or ‘nibble’). The fact that two nybbles make a byte is considered to be the height of BCD 8421 BCD 2421 Excess-3 Decimal 0000 0001 0000 0001 0011 0100 0 1 0010 0011 0010 0011 0101 0110 2 3 0100 0101 0100 1011 0111 1000 4 5 0110 0111 1100 1101 1001 1010 6 7 1000 1001 1110 1111 1011 1100 8 9 Fig.2. Three flavors of binary-coded decimal (BCD). 60 humour by computer scientists, which goes some way to explain why they don’t get invited to parties. Binary-coded decimal (BCD) Unfortunately, we now have something of a dichotomy when it comes to number systems. On the one hand (no pun intended), we have people who prefer to work in decimal (base-10). On the other grasping appendage, we have computers, which prefer to perform their magic using binary (base-2). One solution is to employ a class of binary encodings of decimal numbers that we collectively call binary-coded decimal (BCD). Since four bits can represent 24 = 2 × 2 × 2 × 2 = 16 different combinations of 0s and 1s, it takes only four bits to encode (map) our ten decimal values, leaving six combinations unused. In fact, there are a variety of mapping possibilities, three of which (BCD 8421, BCD 2421, and Excess-3) are illustrated in Fig.2. The form of BCD with which most people are familiar is formally known as BCD 8421, where the numbers refer to the weights of the four columns. In fact, this form is so common that if you say BCD, everyone will assume you are talking about BCD 8421. As we see, these are the same weights as for the natural binary number scheme we presented in Fig.1 (ie, 23, 22, 21 and 20, which equate to 8, 4, 2, and 1, respectively). We use the term ‘natural’ in this context because it follows the general counting method employed in decimal and other place-value numbering systems. For this reason, BCD 8421 may also be referred to as Natural BCD (NBCD) or Simple BCD (SBCD). BCD 8421 is said to be a ‘weighted code’ because each of its columns has a weight associated with it. Similarly, BCD 2421 is also a weighted code, although in this case the weight of the most-significant bit (MSB) is 21 = 2. By comparison, Excess3, which is generated by adding 0011 (3 in decimal) to the encodings used in BCD 8421 is not a weighted code because it isn’t possible to assign weights to the columns in such a way that they add up to their corresponding decimal values. For the remainder of our discussions, and for our experiments, we will be employing BCD 8421. Before we proceed, however, can you spot anything interesting with respect to BCD 2421 and Excess-3 (some characteristic they share with each other but not with BCD 8421)? The answer is given at the end of this column. Fig.3. A 302109000 BCD thumbwheel switch (Source: C&K) so comfortable using decimal, it seemed to make sense to implement computers as decimal machines. What this means is that computers like the ENIAC, IBM NORC, and UNIVAC Solid State 80 represented and manipulated numbers and addresses in decimal without converting them to pure binary equivalents. It didn’t take long before computer scientists started to recognise the inherent advantages associated with binary machines. Having said this, BCD continues to be used much more than you might expect. One example is to allow operators in industrial facilities to easily specify decimal values using BCD thumbwheel switches, such as the 302109000 from C&K shown in Fig.3 – see: https://bit.ly/3RaO0uY Rotating the thumbwheel on the front causes the corresponding BCD 8421 code to be presented on four terminals at the rear. By mounting groups of these switches together, users can specify larger numerical values. Another way in which BCD is used today is to drive 7-segment light-emitting diode (LED)-based displays like the one we are currently using in our experiments (Fig.4). What a character! Before we proceed further, we need to decide which segment combinations we wish to use to represent the numbers 0 Then and now When people first started to build electromechanical and electronic digital computers in the 1940s, binary techniques were not widely understood. Since people were Fig.4. Single-digit 7-segment display. Practical Electronics | April | 2023 F E A G D B C Fig.5. Segments used to represent 0 through 9. 5V 5V E D C DP B 150Ω 7-Segment Display E 1 A reason we’ve shown greyed-out 0 values associated with the DP column in the truth table in Fig.7 is to match what we are going to discuss in a moment. Software BCD decoders We will be using hardware BCD decoders in future columns when we start to G employ multiple 7-segment digits in Arduino 6 E C our projects. For the moment, however, A A 7 F F D we are going to implement a pseudo9 G G 10 GND 3 8 BCD decoder in software. We are currently using Arduino pins 0V 2, 3, 5, 6, 7, 9, 8 and 4 to drive display Fig.6. Using 8 pins to drive a 7-segment display. segments A, B, C, D, E, F, G, and DP, respectively (Fig.6). A word of warning… don’t do what I just did, which is through 9 (Fig.5). Although this seems to mistakenly used the numbers from the strange, there is no standard for this sort 7-segment display in my pin array so that of thing by any relevant entity, such as my program didn’t work. It took me ages the IEC, IEEE, or ISO, which means we to figure it out and caused me some conare obliged to come up with our own. sternation... eventually driving me to exFor example, we are using segments B claim ‘Oh Dear’ (or words to that effect). and C to represent the number 1, which In Part 3, we experimented with a redis the most common scenario, but there green LED combo, but we won’t be needis nothing to stop us using segments E ing that anymore, so you can remove those and F if we wish. Similarly, we’ve incomponents from your breadboard. All cluded segment A in our representation we expect to see on the breadboard now of 6 and segment D in our representation are our main power LED, our 7-segment of 9, while some may consider the use display, and any associated current-limof these segments in these cases to be iting resistors. superfluous to requirements. Our current breadboard layout, including connections to our Arduino Uno, was Hardware BCD decoders shown in Part 3. If you don’t happen to So, why have I been waffling on about have that issue close to hand (for shame!), BCD? Well, we are currently using eight you can download a copy of this layout of our Arduino Uno’s digital output pins (file CB-Apr23-01.pdf). to drive our single-digit common cathIn our previous programs, we defined ode 7-segment display (Fig.6). SEG_ON as being HIGH and SEG_OFF as Suppose we were pin-limited, and we being LOW. Bearing this in mind, if we couldn’t afford to dedicate eight pins to wished to display the number 5, for exthis task. One solution would be to purample, we could do so using the followchase a BCD-to-7-segment decoder inteing statements: grated circuit (IC). We could drive this decoder using just four of our Arduino’s digitalWrite(2, SEG_ON); // A pins, leaving the decoder to control the digitalWrite(3, SEG_OFF); // B segments on the display (Fig.7). digitalWrite(5, SEG_ON); // C We should note that a decoder of this digitalWrite(6, SEG_ON); // D type doesn’t drive the display’s decimal digitalWrite(7, SEG_OFF); // E point (DP) segment, which would require digitalWrite(9, SEG_ON); // F its own control. This is because only one digitalWrite(8, SEG_ON); // G decimal point is typically required when digitalWrite(4, SEG_OFF); // DP using a group of such displays. The only 7 6 5 4 3 2 9 8 D 2 C 4 DP 5 B F B DP 7-Segment Display From Arduino A B BCD8 BCD4 BCD2 BCD1 BCD 8421 Decoder C A F D G E F G B E C D DP Fig.7. Using a BCD-to-7-segment decoder IC. Practical Electronics | April | 2023 BCD In 8 4 2 1 7-Segment Out Display A B C D E F G DP 0 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 0 0 0 0 1 1 0 1 1 0 1 0 1 1 1 1 0 0 1 0 0 1 1 0 0 1 1 0 1 0 1 1 0 1 1 0 1 0 1 1 1 1 1 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 1 1 0 1 0 0 0 1 0 1 0 1 1 0 0 1 1 1 1 0 0 0 1 0 0 1 0 1 2 3 4 5 6 7 8 9 Eeek! That’s eight lines of code, which means we would require 80 lines to cover all 10 of our digits. And that’s just the beginning. Suffice it to say that using this approach to control our display would not be pretty, efficient or fun. As an alternative, the approach we are going to use is to create a pseudo-BCD decoder in the form of a look-up table. Do you recall earlier in this column where we noted that a common 8-bit grouping is called a byte? Well, the Arduino environment supports a byte data type (the equivalent generic C/C++ data type would be unsigned char). This data type can represent unsigned (positive) integers in the range 0 to 255 in decimal, 00000000 to 11111111 in binary, or 00 to FF in hexadecimal, which is a number system we have yet to introduce. We will discuss hexadecimal in Part 5. For now, we indicate hexadecimal values in C/C++ by prefixing them with ‘0x’. We can assign positive integer values (eg, 42) and hexadecimal values (eg, 0x2A) to variables of the byte data type. Also, unlike regular C/C++ environments, we can assign 8-bit binary values prefixed by the letter ‘B’ (eg, B00101010). Assuming we’ve defined NUM_DIGITS to be 10, this allows us to create our look-up table as follows (remember that anything to the right of // is understood by the compiler to be a comment): byte DigitSegs[NUM_DIGITS] = { // ABCDEFGDP B11111100, // 0 B01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B10111110, // 6 B11100000, // 7 B11111110, // 8 B11110110 // 9 }; Compare these bit patterns to those illustrated in Fig.7. In particular, observe that we’ve included the 0s associated with the DP segment. We were obliged to do this to fully pack our 8-bit byte fields, even though we don’t plan on using the DP segment at the moment. Bare bones The way I usually set about building a new application is to spend a little time thinking about what I want to do and then creating a skeleton program. In this case, we want a program that will display our decimal digits for one second at a time, but we also want to be able to vary the order in which the digits will be displayed (you’ll see what I mean by this a little later). 61 The reason we’re doing things this way will become clear as we proceed. In addition to our DigitSegs[] look-up table, we also declare an integer variable called DigitToDisplay to which we assign a value of –1. The reason for using this –1 value was introduced in Part 3, and we discuss it again later in this column. This would be a great time for us (well, you) to enter the contents of Listing 1 into your Arduino IDE. Once you’ve done so, it’s a good idea to click the Verify icon (or use the Sketch > Verify/Compile command) to make sure our skeleton program compiles without errors. It’s a lot easier to sort any problems out now before we add more code to confuse the issue. Fleshing things out Listing 1. Skeleton program. My first step would be to create the bare bones program shown in Listing 1. As usual, we start with some of the definitions we’ll be using (we may add to these later). From Part 3, we know that NUM_SEGS defines the number of segments in the display as being 8. We’ve added NUM_DIGITS to define the number of digits we wish to display as being 10. We’re going to use the ON_TIME definition to display the current digit for one second. And I’d like to think that the ALL_SEGS_OFF definition is self-explanatory. Observe the PinsSegs[] array declaration. We use this to assign the Arduino pins we’re going to use to drive the eight segments in our 7-segment display (remember that DP is considered to be a segment). If you compare this to our programs from Part 3, you’ll see that we’ve reversed the order of the pin assignments. This time, we’re starting with pin 4, which drives the DP segment, and we’re ending with pin 2, which drives the A segment. 62 Now we’re going to flesh things out a little. Let’s start by summarising what we know about functions. The simplest definition is that a function is a group of statements that perform a task. We’ve already had some experience with these little scamps in the form of the mandatory setup() and loop() Listing 2. Fleshing things out a little. functions, which the Arduino’s IDE automatically inserts into our programs. We’ve also noted that the for calls to a function versus the decIDE includes a wealth of built-in funclaration of that function. tions, such as the pinMode(), digiIn previous columns, I’ve used the talWrite() and delay() functions term ‘argument’ and qualified this by we’ve employed in previous programs. saying ‘think parameter,’ but now it’s Now we’re going to create two functions time to delve a little deeper. When we of our own. We’ll call these functions declare a function, part of this declaGetNewDigit() and DisplayNewDigration is a comma-separated list of pait(), as illustrated in Listing 2. rameters in parentheses. In the case of Before we consider the code with which our DisplaySegs() function, for exwe’re going to populate these functions, ample, we have one parameter of type there are several points that are worthy byte called theseSegs. of note. Let’s start with the fact that, in By comparison, when we call a funcaddition to using an initial capital letter tion, like our call to DisplaySegs() for my global variable names, I also use from within our loop() function, we an initial capital letter for my function pass in a comma-separated list of argunames because I think of them as being ments in parentheses. In this case, we global entities (we can’t do anything are passing in a single argument of type about the names of the Arduino IDE’s byte called charSegs. built-in functions). Of course, if a function is declared Remember that C/C++ doesn’t care with an empty parameter list, then, about our use of whitespace characwhen we call it, we will pass in an ters. Having said this, when I declare empty argument list (in both cases we a function, I include a space between keep the parentheses). the name and its parentheses, like GetAs I mentioned in a previous column NewDigit (), for example. By com(PE, October 2020): ‘In the real world, parison, when I call a function from a lot of people use the terms paramelsewhere in the program, I omit this eters and arguments interchangeably. space, like GetNewDigit(), for examSo long as the person you are talkple. The reason for doing this is that ing to understands the message you it facilitates using the editor to search are trying to convey, then there’s ‘no Practical Electronics | April | 2023 harm, no foul,’ as they say. The problem comes when you are talking with professional programmers who will take great delight in painstakingly instructing you in the error of your ways. Personally, I don’t care to give the little rascals the satisfaction.’ Have you ever wondered why the setup() and loop() function declarations are prefixed by the void keyword (similarly for our new DisplaySegs() function)? Well, in the same way that we specify a data type when we declare a variable, we also specify a data type when we declare a function. In the case of functions that don’t return any values, we use void as a data type that represents no data. Now consider our new GetNewDigit() function. Instead of void, we’ve declared this as being of type int. This allows us to use the function to return an integer value by means of a return statement located at the end of the function (I’m simplifying things a little, but the gist is there). Now look at the DigitToDisplay = GetNewDigit() statement in our loop() function. What this says is that whatever value is returned from the GetNewDigit() function call will be assigned to our DigitToDisplay variable. I know that this can all seem to be a little overwhelming at first, but it won’t take long before it’s second nature to you. I should also point out that some of the code we are using here is a little ‘clunky,’ but we’re doing things this way to provide us with examples to talk about. Apart from the contents of our new functions, the rest of the program is complete. The setup() function, which – because of the way the Arduino’s IDE does things – will be executed only one time, uses a for() loop to declare the pins we want to drive our display as being of type OUTPUT (we introduced for() loops in Part 2 and Part 3). The setup() function also calls our DisplaySegs() function to turn all the display’s segments off. Contrariwise, because of the way the Arduino’s IDE does things, the loop() function will be executed over and over. This function calls our GetNewDigit() function, which we will use to generate the next digit we wish to display. We use this returned value as an index into our DigitSegs[] array to retrieve the entry associated with the digit we wish to display. We then pass this value into our DisplaySegs() function, whose job it will be to turn the appropriate segments On and Off. Before we proceed, this would be a good time to add these new statements to your program and then verify that this fleshed-out version compiles without errors. if (someCondition) { // Do stuff } We discussed conditions and the concepts of true and false in toe-curling detail in Part 3. In this case, if the evaluation of someCondition returns true, then we will execute the statements inside the curly brackets. Alternatively, if the test returns false, we will skip everything inside the curly brackets and move onto the next statement. A slightly more sophisticated version of this statement includes an else clause as follows: if (someCondition) { // Do stuff } else { // Do other stuff } Once again, if the evaluation of someCondition returns true, then we will execute the statements inside the curly brackets associated with the if. Alternatively, if the test returns false, then we will skip everything inside the curly brackets associated with the if, and instead execute the statements inside the curly brackets associated with the else. But wait, there’s more, because we can also associate a new if with an else as follows: if (someCondition) { // Do stuff } else if (anotherCondition) { // Do other stuff } We can keep on adding more else-if constructs and we can end everything with a final else if we so desire. If there’s only one statement inside any of the pairs of curly brackets, then we can omit that pair of brackets and just use the statement on its own. For example: Questions, questions We are now poised to use a new form of control statement called if(), which essentially asks a question. The simplest form of this statement is as follows: AND (a) a & b (b) (c) OR y a XOR | b if (someCondition) DisplaySegs(AllSegsOff); y a y ^ b a b y a b y a b y 0 0 1 1 0 1 0 1 0 0 0 1 0 0 1 1 0 1 0 1 0 1 1 1 0 0 1 1 0 1 0 1 0 1 1 0 Having said this, I strongly recommend that you always use a pair of curly brackets, even if they currently embrace only a single statement. There are two reasons for this. First, they make it easier to read and understand your code. Second, they prevent your introducing errors if you add more statements later, which is often the case when you are debugging a program and trying to determine why it’s not doing what you expect it to do. A 1 0 1 0 1 1 0 0 A 1 0 1 0 1 1 0 0 A 1 0 1 0 1 1 0 0 The &, | and ^ bitwise operators B 1 1 0 0 1 0 1 0 B 1 1 0 0 1 0 1 0 B 1 1 0 0 1 0 1 0 As we’ve previously noted, computers are constructed out of simple logical building blocks. These are often called primitive gates, primitives, logic gates, or gates. The reason for the ‘gate’ moniker is that, in the same way a wooden gate can allow or prevent the passage of a person or an animal through an opening, so a logic gate can allow or prevent the passage of signals. & Y 1 0 0 0 1 0 0 0 | Y 1 1 1 0 1 1 1 0 ^ Y 0 1 1 0 0 1 1 0 Fig.8. AND, OR and XOR functions: (a) Logic gate symbols, (b) Truth tables and (c) Examples of bitwise operators applied to two 8-bit bytes. Practical Electronics | April | 2023 63 A[7] B[7] A[1] B[1] A[0] B[0] Gate[7] Gate[1] Gate[0] Y[7] Y[1] Y[0] Fig.9. How the bitwise operators are realised in logic gates. Three of the most common gates are the AND, OR, and XOR (Fig.8). These gates accept bit-size values on their inputs and generate bit-sized values on their outputs. If you want to know how these little rapscallions can be constructed out of transistors, this topic is discussed in excruciating exhilarating detail in my book Bebop to the Boolean Boogie – see: https://amzn.to/3X0rF4i The symbols for these gates are shown in Fig.8a. Their corresponding truth tables are presented in Fig.8b. Observe that the output from the AND gate is 1 (true) only when both of its inputs are 1, otherwise the output is (0) false. By comparison, the output from the OR gate is 1 if either of its inputs are 1. Although we rarely do so, the OR gate is more properly referred to as an ‘inclusive OR’ because the output being 1 includes the case where both the inputs are 1. By comparison, with an exclusive OR (XOR) gate, the output being 1 excludes the case where both the inputs are 1. In Part 3 of this epic saga, we introduced the conditional operators && (AND) and || (OR). The reason we call these conditional operators is that we use them as part of condition statements. For example, assuming a, b, c, and d to be integer variables, we could have a condition like (a > b) && (c < d), which we can think of as ‘a is greater than b AND c is less than d.’ The output of this condition will only return true if both sub-conditions are true. Similarly, we could have a condition like (a > b) || (c < d), which we can think of as ‘a is greater than b OR c is less than d.’ The output of this condition will return true if either of the sub-conditions are true. Now, this is where we take tentative steps into new territory because we can also use &, | and ^ as bitwise operators. The easiest way to visualise what this means is to assume that we’ve declared three variables of type byte called A, B and Y. Now, suppose we use the bitwise operators in a program as follows: Y = A & B; // Bitwise AND Y = A | B; // Bitwise OR Y = A ^ B; // Bitwise XOR Since we are using bitwise operators on variables of type byte, and since bytes contain eight bits, this is equivalent to 64 feeding our A and B values into eight 2-input gates. The processor will perform the selected operation between each bit forming A and the corresponding bit forming B (Fig.9). In the case of the & operator the gates will be AND gates, in the case of the | operator they will be OR gates, and in the case of the ^ operator they will be XOR gates. This is the way the central processing unit (CPU) in our microcontroller implements these operators; that is, by using real, physical logic gates. Suppose we previously assigned binary values of 10101100 and 11001010 to variables A and B, respectively. In this case, the results from using the bitwise operators will be as illustrated in Fig.8c. These operators work with byte variables (which are always unsigned), char variables (signed or unsigned), and int variables (short, regular, long; signed or unsigned), the only rule being that all the variables (input and output) must be of the same type. Using masks One thing the bitwise operators can be used for is creating and applying masks. Suppose we have a variable of type byte called A, but we don’t know its contents. Now suppose we want to determine the contents of the least-significant four bits of A. We could extract these bits using a bitwise & as follows: Y = A & B00001111; In this case, the binary value 00001111 is our mask. Remind yourself of the way an AND gate works (Fig.8a). The result of this operation will be to clear the mostsignificant four bits of Y to 0; meanwhile, the least-significant four bits of Y will end up as a copy of the least-significant four bits of A. Remember that the bits forming an 8-bit byte are numbered from 0 (on the right) to 7 (on the left). Now suppose we want to force bit 2 (ie, the third bit) of A to 0 while leaving the other bits as-is. We could do so using a bitwise & as follows: A = A & B11111011; Contrariwise, suppose we wish to force bit 6 of A to 1 while leaving the other bits as-is. We could do so using a bitwise | as follows: A = A | B01000000; This is another point where things start to get interesting. Suppose we wish to perform some action if bit 3 of A is 0. We could achieve this using an if() statement with the following condition: if ( (A & B00001000) == 0)… In this case, the result from the bitwise & is temporary in nature. That is, it’s not assigned to anything; it is used only as part of the test. The 0s in bits 0, 1, 2, 4, 5, 6, and 7 of our B00001000 value will force these bits in the temporary result to 0. Meanwhile, the 1 in bit 3 of our B00001000 value will allow whatever 0 or 1 is in the corresponding bit in A to appear in the temporary result, and it is this value that will be compared to 0. I have a trick question. Suppose we wish to perform some action if bit 3 of A is 1. Look at the previous statement. Is your knee-jerk reaction to replace the == 0 with == 1? It’s not that easy, I’m afraid, because a 1 in bit 3 is 00001000 in binary, which is equivalent to 8 in decimal. But turn that frown upside down into a smile, because we can achieve the desired effect using the following statement: if ( (A & B00001000) != 0)… So, as opposed to thinking about this as ‘Is the result one?’ we instead think ‘Is the result non-zero?’ If you wish to dive deeper into the mysteries of masks, you will probably not be overly surprised to discover I’ve written a column on this very topic – see: https://bit.ly/3Yd3UaS The << and >> shift operators The C/C++ programming languages support two bitwise shift operators: the leftshift << and the right-shift >>. These operators require two operands – the first is the variable or value to be shifted, and the second (which can be a positive number or a variable of type int containing a positive value) specifies by how many bits the shift will involve. For example (assuming A is a variable of type byte): Y = A << 1; // Shift A left 1 bit Y = A >> 5; // Shift A right 5 bits When a value is shifted left, the mostsignificant (left-hand) bit or bits effectively ‘fall off the end.’ Meanwhile, 0 values are shifted into the newly vacated right-hand bit or bits. This is known as a ‘logical shift’ and is true for both signed and unsigned values. Similarly, when a value is shifted right, the least-significant (right-hand) bit or bits effectively ‘fall off the end.’ If the data being shifted is an unsigned char or int data type (the byte data type is unsigned by default), then the result is a logical shift, and 0 values will be shifted into the newly vacated left-hand bits (we’ll leave what happens when performing shift-right operations on signed data types as a topic for another day). Not surprising, shifting left or right by 0 bits has no effect. One interesting nugget of knowledge is the fact that shifting left Practical Electronics | April | 2023 Start 0 0 1 1 0 1 1 1 Start 0 0 0 0 0 0 0 1 iSeg = 0 << 1 0 1 1 0 1 1 1 0 << 1 0 0 0 0 0 0 1 0 iSeg = 1 >> 1 0 0 1 1 0 1 1 1 << 1 0 0 0 0 0 1 0 0 iSeg = 2 << 2 1 1 0 1 1 1 0 0 << 1 0 0 0 0 1 0 0 0 iSeg = 3 << 1 1 0 1 1 1 0 0 0 << 1 0 0 0 1 0 0 0 0 iSeg = 4 >> 4 0 0 0 0 1 0 1 1 << 1 0 0 1 0 0 0 0 0 iSeg = 5 << 6 1 1 0 0 0 0 0 0 << 1 0 1 0 0 0 0 0 0 iSeg = 6 >> 3 0 0 0 1 1 0 0 0 << 1 1 0 0 0 0 0 0 0 iSeg = 7 (a) Various shift examples Fig.10. (left) Performing shift operations on an 8-bit byte. Listing 4 (right) Random version of GetNewDigit() (b) Shifting a bit mask by one bit is the same as multiplying by 21 = 2. For example, shifting the value 00000110 (6 in decimal) left by one bit results in 00001100 (12 in decimal). Similarly, shifting left by two bits is the same as multiplying by 22 = 2 × 2 = 4; shifting left by three bits is the same as multiplying by 23 = 2 × 2 × 2 = 8, and so forth. Contrariwise, shifting right by one bit is the same as dividing by 2; shifting right by 2 bits is the same as dividing by 4, and so on. In the not-so-distant past, knowing this sort of thing used to be extremely useful when working with simple, resourcelimited processors like the Arduino Uno – and it can still come in handy on occasion – but today’s compilers are very clever, and they will automatically take full advantage of these tricks without you having to worry about things. The shift operators work with byte variables, char variables (signed or unsigned) and int variables (short, regular, long; signed or unsigned). A series of examples of various shifts performed on a byte variable are illustrated in Fig.10a (read this sequence from top to bottom). Bringing it all together Let’s leave our GetNewDigit() function for the moment and instead focus on our DisplaySegs() function. The way I’ve implemented this employs an if() Listing 3. Displaying the segments. Practical Electronics | April | 2023 statement, the use of a mask, a bitwise & (AND), and a bitwise << (shift left) as shown in Listing 3. As we’ve already discussed, we pass an 8-bit byte into this function. The 0s and 1s in this byte, whose name is theseSegs inside the function, correspond to the segments we want to turn off and on, respectively. We start by declaring a variable called mask of data type byte and assigning it a value of B00000001. The main body of this function involves a for() loop. The first thing we do inside this loop is to use the & operator to perform a bitwise AND between the mask and theseSegs, then we use an if() to compare the result to 0. If there’s a 0 in theseSegs in the same bit position as the 1 in mask, then the result of this comparison will be true, in which case we turn the corresponding segment Off, otherwise we fall through to the else clause and turn the segment On. The final statement in our for() loop shifts our mask one bit to the left. The way the values in the mask correspond to the values in our iSeg index variable is illustrated in Fig.10b. Consider the way the 1 value slides through our mask from right to left, thereby testing the segments in the order DP, G, F, E, D, C, B, A. It now becomes apparent why we reversed the order of the Arduino pins driving the 7-segment display in our PinsSegs[] array declaration, because this makes things match up just the way we want them to. Add this code to your DisplaySegs() function and upload the program into your Arduino. If you run into any problems that you can’t resolve, you can download my version (file CB-Apr23-02.txt). Observe that the 7-segment display presents only the number 6. This isn’t too surprising since all our GetNewDigit() function currently does is return the number 6. Now it’s time to become more adventurous and start displaying all the numbers from 0 to 9 (I’m too young for all this excitement). Tossing a coin Can you cast your mind back to Part 2 (PE, February 2023) when we created a program to randomly turn On and Off the segments in our 7-segment display? The problem was that we didn’t include a test to see if the new random number was the same as the previous random number. This meant that, every now and then, a segment stayed on for some multiple of the expected time. In Part 3 (PE, March 2023), we implemented a solution that involved repeatedly generating new random numbers until we determined that the new value was different to the old value. Now, I want you to see if you can add the code to our GetNewDigit() function to do something similar. This time, however, we want to randomly present numbers between 0 and 9 on the 7-segment display. Before reading further, try to do this on your own, and then compare your solution to mine, as shown in Listing 4 (file CB-Apr23-03.txt). Now we remember why we initialised our global DigitToDisplay variable to have a value of –1. We did this to guarantee that the first time we generate a new value, that value will be different to our old (–1) value. Count on me The next thing I want you to do is to modify the contents of our GetNewDigit() function in such a way that our program repeatedly counts from 0 to 9. Once again, try to do this on your own first, and then compare your solution to the two versions I came up with, as shown in Listings 5a and 5b. Let’s start with my first version, as shown in Listing 5a (file CB-Apr23-04. txt). Once again, remember that, when our program starts, our global DigitToDisplay variable has been initialised to have a value of –1. Happily, this isn’t a problem because the first thing we do is add 1 to this value, which means we will start off displaying the value 0. 65 Listing 5. Two ways of counting 0 to 9: (a) (left) With test, (b) (right) With modulo operator. The problem occurs when we reach 9. Adding 1 will give us a value of 10, which we can’t replicate on our single-digit 7-segment display. We could perform a test to see if tmpDigit == 10. In fact, this is what we do do (if you see what I mean), except we replace the explicit 10 value with NUM_DIGITS, which we previously defined as being equal to 10. (We do this to future-proof our program in case we add any more digits in the future, or in Part 5, whichever comes first.) If you’ve been paying attention, you will be squirming in your seat saying, ‘You rotter!’ You say this because, when talking about if() tests earlier, I said, ‘I strongly recommend that you always use a pair of curly brackets, even if they currently embrace only a single statement,’ but on Line 59 of Listing 5a I’m flouting my own rule. The thing is, this is an unwritten rule (the best kind to apply to oneself in my experience). Always remember the adage, ‘Rules are for the obedience of fools and the guidance of the Fig.11. The segments associated with the ‘HELLO’ characters. wise.’ In this case, breaking the rule made it easier for us to compare Listings 5a and 5b. Speaking of which, I dislike having to employ tests to get around end conditions, like reaching 10 in this example. As an alternative, we can implement the solution shown in Listing 5b (file CB-Apr23-05.txt). In this case, after incrementing our DigitToDisplay value, we use the modulo % operator to divide the result by NUM_DIGITS, which is 10. The modulo operator returns the remainder from an integer division. After a few moments thought, we realise that that 0 % 10 = 0, 1 % 10 = 1, 2 % 10 = 2, and so forth up to 9 % 10 = 9. However, 10 % 10 = 0, which brings us back to where we started (I feel a small ‘Tra-la’ is in order). Hello there! Do you remember when we ran the program at the beginning of this column, and it started by bidding us a cheery ‘HELLO’? When you think about it, since we can control all of the segments on our display, we can use them to create characters other than the numbers 0 through 9. For example, ‘H’, ‘E’, ‘L’, and ‘O’ (Fig.11). Just for giggles and grins, see if you can take our previous program and modify it to display the ‘HELLO’ message before it starts counting. As before, try to do this on your own first, and then compare your solution to mine, as shown in Listing 6 (file CB-Apr23-06.txt). Note that this augments our existing code – it doesn’t replace it. I started off by adding some new definitions as follows: #define NUM_HELLO_CHARS 5 #define ON_TIME 1000 #define OFF_TIME 150 #define PAUSE_TIME 1000 Listing 6. Adding the code to bid a cheery hello. 66 As shown in Listing 6, I also declared an array called HelloSegs[] to define the segments I wish to use to display my message. Next, I modified my setup() function to display this message. The reason for putting this code in the setup() function is that we wish to display the message only one time. The question you should be asking is why we need to turn all the segments off for the OFF_TIME (150 milliseconds) after displaying each character. The reason is that, if we didn’t do Practical Electronics | April | 2023 0 at the start of our count sequence. Online resources For the purposes of this series, I’m going to assume that you are already familiar with fundamental concepts like voltage, current and resistance. If not, you might want to start by perusing and pondering a short series of articles I penned on these very topics – see: https://bit.ly/3EguiJh Similarly, I’ll assume you are no stranger to solderless breadboards. Having said this, even if you’ve used these little scamps before, there are some aspects to them that can trap the unwary, so may I suggest you feast your orbs on a column I wrote just for you – see: https://bit.ly/3NZ70uF Last, but not least, you will find a treasure trove of resources at the Arduino.cc website, including example programs and reference documentation. LEDs (assorted colours) https://amzn.to/3E7VAQE Resistors (assorted values) https://amzn.to/3O4RvBt Solderless breadboard https://amzn.to/3O2L3e8 Multicore jumper wires (male-male) https://amzn.to/3O4hnxk Next time ‘HELLO’ is just one of the words that we can display. Components (from Part 2) While we are wait7-segment display(s) https://amzn.to/3Afm8yu ing for the next exciting installment of this mega-mini8, the complementary value to 2 is (9 series, try to think of other characters – 2) = 7, and so forth. and symbols and messages we could Now, pick two complementary numcreate (but don’t cheat by looking on bers, let’s say 2 and 7. Their correspondthe internet!). ing Excess-3 codes are 0101 and 1010, Last, but certainly not least, we still respectively. What this means is that have the question we posed earlier in we can generate the complement of an this column, which was ‘What differExcess-3 code (or a BCD 2421 code) by entiates BCD 2421 and Excess-3 from simply inverting all its bits, which was BCD 8421.’ The answer is that BCD a very useful trick in the early days of 2421 and Excess-3 are known as ‘selfcomputing. If you want to learn more complementing codes’. What does this about BCD, bounce over to my column mean? Well, in decimal, the compleMysteries of the Ancients: Binary Coded mentary value of a number n between Decimal (BCD) (https://bit.ly/3wwnUsx). 0 and 9 is (9 – n). Thus, the compleUntil next time – cunningly titled Part mentary value to 0 is (9 – 0) = 9, the 5 – have a good one! complementary value to 1 is (9 – 1) = this, we wouldn’t be able to distinguish between the two ‘L’ characters. This also explains why we add a delay of PAUSE_TIME (1000 milliseconds = 1 second) after displaying the final letter in our message. If we didn’t do this, it would be hard to distinguish between the letter ‘O’ in ‘HELLO’ and the number 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 BACK ISSUES Practical Electronics Practical Electronics Components (from Part 1) Practical Electronics Practical Electronics Practical Electronics Practical Electronics Practical Electronics Practical Electronics The UK’s premier electronics and computing maker magazine The UK’s premier electronics and computing maker magazine The UK’s premier electronics and computing maker magazine The UK’s premier electronics and computing maker magazine The UK’s premier electronics and computing maker magazine The UK’s premier electronics and computing maker magazine The UK’s premier electronics and computing maker magazine Circuit Surgery Exploring op amp exponential amplifiers Make it with Micromite Circuit Surgery Audio Out PE Analogue Vocoder: Driver Amplifier design Using and interfacing the Exploring op amp versatile iButton input offsets Audio Out Vocoder: Driver Amplifier build KickStart Using the I2C bus Make it with Micromite Circuit Surgery Using and interfacing Exploring the the versatile iButton LM35 temp sensor Audio Out C void interrupt(void) { if (intcon & 4) { clear_bit(intcon, 2); FCM_INTERRUPT_TMR o(); Hex :040000008A01122837 :08000800F000F00S030 EF10000 :10001000040EF2000A0 EF300BA110A122928352 86C :2000200D928FE28073 Flowcode WIN!High-current Microchip WLR089 Xplained Pro Evaluation Kit Battery Balancer Wind turbine Small-scale garden set-up Electronic Building Blocks Circuit Surgery Building a budget Distortion and electronic stethoscope distortion circuits Audio Out Designing a practical de-thump circuit Make it with Micromite Circuit Surgery Code for an iButton-based Simulating distortion Electronic Door Lockand distortion circuits Audio Out Using transformers in audio electronics Make it with Micromite Circuit Surgery Installing MMBASIC on Using a distortion and Raspberry Pi Pico distortion circuits void interrupt(void) { if (intcon & 4) { clear_bit(intcon, 2); FCM_INTERRUPT_TMR o(); Assembly movlw D′7′ bsf STATUS, RP0 bcf STATUS, RP1 movwf _adcon1 movlw D′192′ movwf _option_reg Flowcode Programming Hex :040000008A01122837 :08000800F000F00S030 EF10000 :10001000040EF2000A0 EF300BA110A122928352 86C :2000200D928FE28073 Techno Talk – Should we be worried? Net Work – Electricity generation and streaming radio <at>practicalelec WIN! Microchip SAM E54 Curiosity Ultra Development Board High-current Battery Balancer Hex :040000008A01122837 :08000800F000F00S030 EF10000 :10001000040EF2000A0 EF300BA110A122928352 86C :2000200D928FE28073 Full-wave Universal Motor Speed Controller PLUS! Feb 2022 £5.49 Techno Talk – Go eco, get ethical! PLUS! 01 practicalelectronics www.electronpublishing.com movlw D′7′ bsf STATUS, RP0 bcf STATUS, RP1 movwf _adcon1 movlw D′192′ movwf _option_reg PLUS! Jan 2022 £5.49 WIN! Explorer 8 Development Kit from Microchip Assembly Learn Flowcode Programming: PIC, Arduino and 16x2 LCD Battery Monitor Logger 9 772632 573023 Digital FX Unit 8/14/20-pin PIC Introducing the Programming Helper Raspberry Pi Pico WIN! WIN C void interrupt(void) { if (intcon & 4) { clear_bit(intcon, 2); FCM_INTERRUPT_TMR o(); 02 Fox Report – Another fine mess: moving to Windows 11 Net Work – Scanners, eVTOLs and the latest from space 9 772632 573023 practicalelectronics www.electronpublishing.com <at>practicalelec BACK ISSUES – ONLY £5.95 £5.95 per issue for UK incl p&p n £8.95 Europe Air Mail n £9.95 ROW Air Mail We can supply back issues of PE/EPE by post. We stock magazines back to 2006, except for the following: 2006 Jan, Feb, Mar, Apr, May, Jul 2007 Jun, Jul, Aug 2008 Aug, Nov, Dec 2009 Jan, Mar, Apr 2010 May, Jun, Jul, Aug, Oct, Nov 2011 Jan 2014 Jan 2018 Jan, Nov, Dec 2019 Jan, Feb, Apr, May, Jun Issues from Jan 1999 are available on CD-ROM / DVD-ROM If we do not have a a paper version of a particular issue, then a PDF can be supplied for the same price. Your email address must be included on your order. Please make sure all components are still available before Practical Electronics | 2023issue. commencing any project from| aApril back-dated KickStart PLUS! Introduction to linear actuators Single-Chip Silicon Labs FM/AM/SW Digital Radio Receiver PLUS! Apr 2022 £5.49 May 2022 £5.49 Jun 2022 £5.49 9 772632 573023 9 772632 573023 Techno Talk – From nano to bio 04 Cool Beans – Simple filtering with software Net Work – UK gigafactories, Rolls-Royce electric planes practicalelectronics www.electronpublishing.com <at>practicalelec Techno Talk – Positivity follows gloom 05 Cool Beans – Amazing Analogue AI and a handy PSU Net Work – Google Lens plus energy and space news practicalelectronics www.electronpublishing.com <at>practicalelec practicalelectronics www.electronpublishing.com <at>practicalelec Microchip SAM V71 Xplained Ultra Evaluation Kit Multi-purpose Battery Manager Controlling a linear actuator Techno Talk – Mixed Menu 06 Cool Beans – Choosing servos and a little competition Net Work – NFC and the rise of mobile payments MMBASIC + RPi Pico + display = PicoMite Backpack! WIN! Simple MIDI Toot toot! Music Model Railway Level Keyboard Crossing with moving barriers, flashing Advanced GPS Computer: lights and bell! Advanced GPS Computer construction and use 9 772632 573023 Make it with Micromite Exploring DACs and microcontrollers WIN! Microchip SAM C21 Xplained Pro Evaluation Kit Digital FX Unit WIN! Microchip MPLAB ICD 4 In-Circuit Debugger WIN! Flowcode C 192kHz, 24-bit Learn <at>practicalelec Soothing Electronic Wind Chimes Assembly movlw D′7 D′7′ bsf STATUS, RP0 bcf STATUS, RP1 movwf _adcon1 movlw D′192′ movwf _option_reg SuperCodec: Balanced Input and Attenuator Techno Talk – Communing with nature Fox Report – Power as free as the wind Net Work –EVs, upgrading to Windows 11 and space tech www.electronpublishing.com Audio Out Vocoder final assembly Completing our impressive Analogue Vocoder Mastering AC meters MiniHeart Heartbeat SimulatorBuild this handy Arduino-based power supply Learn Flowcode Programming PLUS! Make it with Micromite Circuit Surgery Build an iButton-based Exploring the Electronic Door Lock Royer oscillator WIN! WIN Flowcode Vintage Battery Radio Li-ion Power Supply Mastering switch debounce 64-key MIDI Matrix Microchip MPLAB Starter Kit for Digital Power PIC18F Development Board: using displays Cool Beans Vocoder: Audio PSU WIN! WIN! Retro gaming with Nano Pong! Flowcode Digital Clock Design Flowcode C void interrupt(void) { if (intcon & 4) { clear_bit(intcon, 2); FCM_INTERRUPT_TMR o(); Assembly movlw D′7′ bsf STATUS, RP0 bcf STATUS, RP1 movwf _adcon1 movlw D′192′ movwf _option_reg PLUS! Jul 2022 £5.49 Hex :040000008A01122837 :08000800F000F00S030 EF10000 :10001000040EF2000A0 EF300BA110A122928352 86C :2000200D928FE28073 Techno Talk – Time for a total rethink? 07 Cool Beans – Touch-sensitive robots and using servos Net Work – The irresistible rise of automotive electronics 9 772632 573023 practicalelectronics www.electronpublishing.com <at>practicalelec Aug 2022 £5.49 08 9 772632 573023 practicalelectronics ORDER FORM – BACK ISSUES  Back issues required (month / year) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Address . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tel: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  I enclose cheque/PO to the value of £ . . . . . . . . . . . .  Please charge my Visa/Mastercard £ . . . . . . . . . . . . . . . Card No . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Valid From . . . . . . . . . . . . . Card Expiry Date . . . . . . . . . . . . . Card Security Code . . . . . . . . . . (Last three digits on or under the signature strip) SEND TO: Practical Electronics, Electron Publishing Limited 113 Lynwood Drive, Merley, Wimborne, Dorset BH21 1UU Tel: 01202 880299 Email: stewart.kearn<at>wimborne.co.uk On-line Shop: www.electronpublishing.com Payments must be in £ sterling – cheque must be drawn on a UK bank and made payable to ‘Practical Electronics’. 67 All items normally posted within seven days of receipt of order. Copy this form if you do not wish to cut your issue.