The microcontroller revolution has accelerated the development of tools available to the electronics industry. Multimeters (recently, DMMs) and oscilloscopes (recently, DSOs) have been a staple of electronics workbenches for decades, along with signal generators, frequency counters, and other specialized tools.
All of these tools, however, have generally been made to make measurements of basic quantities — voltage, current, frequency, or perhaps subtler measurements like capacitance or even complex impedance, in the case of LCR meters. The intelligence has always been, ostensibly, with the operator.
Tools like automated component testers are starting to change that. Instead of having to know what a particular component is and find the right instrument or come up with a test procedure, these devices help play detective for you. Connect a mystery component across two or three terminals, lower the latch, press the big blue button that is literally the only control on the unit, and it (usually) tells you what the component is, which terminal is which (if it matters), and even the specs.
For $15 or so, it would be a cool little device if it just did resistors; this kind of form factor can be convenient. But so far, I’ve seen it identify not only resistors, but diodes, FET and BJT transistors, capacitors, inductors, and (unreliably) combinations of two or more of the above, such as diode-plus-resistor combinations.
For components like diodes, it will give a good estimate of the forward voltage drop as well as the capacitance, which is easy to forget about until you wonder why your LED is acting like a capacitor.
…and knowing modern tech, there’s a good chance that it started life as an Arduino project.
New toys are always such fun, especially when you find a replacement for a component that has more features, better specs, and costs half as much.
The Arduino Uno is deservedly popular. It makes introductory embedded system design easy, and has introduced millions to the fun of open-source projects. Generic versions are available for as little as a few dollars, and even the cheap ones generally more-or-less work okay. (Brand-name Arduino Unos cost more, but you’re paying for reliability. They just work.)
The Uno, however, is starting to show its age. It runs at 16MHz, which is adequate for most hobby projects but nothing exceptional. It has a popular-but-still-weird shield scheme, which works only because the Arduino ecosystem is so huge that there’s just about every kind of shield you can imagine and then some. And it’s still relatively expensive, for what it is — connecting it to the outside world still usually requires a computer or at least an expensive and not-very-capable WiFi or Ethernet shield.
The NodeMCU 1.0 solves many of these issues. The NodeMCU is an ESP8266-based, Arduino-compatible dev board. Once you download the USB drivers and Arduino core, it can be programmed with the Arduino IDE. In addition, it’s breadboardable, has onboard WiFi, and costs roughly 1/2 to 1/3 as much as the Uno.
It also has better specs:
Item
Arduino Uno
NodeMCU 1.0
SRAM
2kB
128kB
Flash ROM
32kB
4MB
Clock speed
16MHz
80MHZ/160MHZ
Usable I/O
18
13
It is a 3.3V part, so some designs may need to be modified. (3v3 is really the future of hobby electronics, anyway.)
“To know recursion, you must first know recursion.”
(Original author unknown)
Much of the fun of writing code is learning about all of the various algorithms and techniques that help get the job done. Some of these are relatively straightforward: if (this), then (do that); while (this is true) then (keep doing that), and so on. It’s what makes the magic work.
One of the more interesting techniques is recursion. Analogous to mathematical induction, recursion involves using the function being written in part of its own definition. This sounds not only unintuitive but unsound — but it turns out to be mathematically rigorous.
Computing factorials is a straightforward task that can easily be done either recursively or non-recursively. X factorial, written as X!, is (for integers) the product of all integers from 2 up to X. So, 5! == 5 * 4 * 3 * 2, or 120. (Factorials get large very quickly.)
Writing a FOR loop is one way of computing the factorial (and probably the best way, since recursion doesn’t buy you much here). To implement this, you would simply multiply the integers between 2 and X, inclusive:
int factorial(int num){
int n, result=1;
if(num < 2){return(1);}
for (n=2;n<=num;n++){result *= n;}
return(result);
}
This works well and doesn’t have the overhead associated with recursive calls, so it’s efficient, as well. A recursive approach, while less efficient, is instructive — especially since it’s so concise:
int factRecurs(int num){
if(num < 2){return(1);}
return(num * factRecurs(num-1));
}
int factR(int num){return((num<2) ? 1 : num*factR(num-1));}
That’s it. That’s the algorithm. We tell it how to handle the factorial of 1 (or less), then how to handle N!, given that we know how to compute (N-1)!. It feels like cheating, but it’s sound.
If factRecurs(3) were called, for instance, it would call factRecurs(2), which would call factRecurs(1), which would return a value of 1. factRecurs(2) would then multiply this by 2 and return it to factRecurs(3), which would multiply it by 3 and return the correct answer: 6.
The “Towers of Hanoi” puzzle is probably the best-known “poster child” problem for recursion. There is a nonrecursive formula, but it’s unintuitive.
“Towers of Hanoi” is a puzzle consisting of a stack of discs of increasing diameter, and three piles in which they can be placed. The puzzle starts out with the discs stacked in order from largest to smallest in one pile; the goal is to move them to another pile, by moving only one disc at a time and without ever stacking a larger disc on a smaller one.
The optimal solution, produced by the recursive algorithm, takes 2^N-1 moves for a pile of N discs. (One move with one disc; three moves with two; seven moves with three, etc.) Surprisingly, a pile of any size can be moved according to the rules, given enough time.
The recursive algorithm may not be obvious at first, but once it is understood, it almost feels like cheating — yet it works. The base case is, of course, moving one disc. If our function is called to move one disc from one pile to another, it simply prints out that move. (We could include a move legality check, but as it turns out, we won’t need to.)
The question arises of what to do when presented with more than one disc to move. The recursive Hanoi algorithm’s answer to this is that this is really the same problem we’re trying to solve, so we will just assume we know how to solve it!
The recursive case of moving N discs from A to B goes like this:
* Move N-1 discs from A to C;
* Move one disc from A to B;
* Move N-1 discs from C to B.
It seems too simple to work — somewhat like Douglas Adams’ story of how the Infinite Improbability Drive was created by someone simply figuring out how improbable it would be for one to appear, then giving a Finite Improbability Drive a cup of really hot tea. It shouldn’t work — but it does. (And it’s mathematically correct.)
FreeBASIC is a fun language for playing around with algorithms. You can do a lot with it, but it’s still lightweight enough that a few lines of code are sufficient to start doing what you want.
I recently discovered that FBIDE will work with 64-bit versions of fbc.exe (the FreeBASIC compiler), so even the 32-bit memory limitation is a thing of the past. Arrays and other structures can now be as large as system memory permits.
Every new expansion of capabilities, however, always leads to discoveries of new limitations and questions about how to circumvent those. The next natural limitation I came across was working with graphics files the same size as or larger than the available screen real estate (1920×1080, in my case, less a bit for the window widgets.)
As it turns out, though, FreeBASIC has this covered, as well. All of the graphics routines (pset, line, circle, etc) can work with memory buffers as well as drawing directly to the screen. (After all, the screen buffer is itself just a block of memory.) All you need to do is create an image buffer of the appropriate size using ImageCreate, and then draw to this using the usual commands.
It seemed to me that it would be nice to both draw on the screen and to a scaled-up buffer with a single command, so I wrote some routines to do that. (There’s a file link below the examples.)