In Part I of this project, we jumpered a series of buttons to a voltage divider that we connected to the Nano. Along the way, we discussed the basics of what resistors are and what their values mean. In the conclusion of the project, we’ll answer the very important question “what can I do with that?” as we dive into the code.
If you need a refresher in prior lessons in the series, you can get them all HERE
Here is the code we used to test the breadboard in the last lesson:
int voltageInput = A0;
void setup() {
pinMode(voltageInput, INPUT);
Serial.begin(115200);
}
void loop() {
Serial.println(analogRead(voltageInput));
delay(100);
}
- We start by declaring a variable for pin A0, which is where we read the voltage of the circuit.
- Next, in our setup function, we set our variable to INPUT and set the bit rate we’ll use to communicate with the Nano.
- In the Loop, we print the value of our variable and delay 1/10th of a second before the next iteration.
When you connect your Nano via USB, launch Arduino IDE, open the Serial Monitor, then press a button, you’ll see that each of the buttons gives a different value. If you press two buttons in combination, it gives a different value that the two buttons give when not combined. We’re going to take advantage of that by mapping out the max values returned for each button or from some combination of buttons in order to map out the 26 letters of the English alphabet.
Important: this value is not the actual value of the voltage. The analogRead function displays a value between 0 and 1023. In order to determine what the actual voltage of the circuit is, since we’re working with a 5v circuit, you divide 5 volts by 1024 in order to get the actual voltage of your circuit. We don’t need to do that for this exercise – we just care that there is a measurable distinction for our project. When you’re working with 3 button combinations, if you get a value that is too close, try a different combination – example, I changed combination 1-2-5 into 1-3-6
Copy this chart into Notepad:
A = Button1 =
B = Button2 =
C = Button3 =
D = Button4 =
E = Button5 =
F = Button6 =
G = Button1 – Button2 =
H = Button1 – Button3 =
I = Button1 – Button4 =
J = Button1 – Button5 =
K = Button1 – Button6 =
L = Button2 – Button3 =
M = Button2 – Button4 =
N = Button2 – Button5 =
O = Button2 – Button6 =
P = Button3 – Button4 =
Q = Button3 – Button5 =
R = Button3 – Button6 =
S = Button4 – Button5 =
T = Button4 – Button6 =
U = Button5 – Button6 =
V = Button1 – Button2 – Button3 =
W = Button1 – Button2 – Button4 =
X = Button1 – Button2 – Button5 =
Y = Button1 – Button2 – Button6 =
Z = Button1 – Button3 – Button4 =
Assuming that button 1 is at the bottom of the breadboard and button 6 is nearest your Nano at the top, fill out the chart with the values you retrieve from Serial Monitor for each button or combination.
If you’re having trouble following the values, increase the value of the delay in your code from 100 to 1000. If you get wildly fluctuating values when you press your button, disconnect the Nano from USB and re-seat your resistors, making sure that each leg is firmly inserted into its tie-point.
The variance between minimum and maximum shouldn’t be more than 2-3 units. There’s always a variation – even if you use two resistors with the same rating, there are variations due to quality control and uncontrollable factors – in fact, part of the color coding system of resistors includes a percentage value for the variance possible.
Important: When you’re using a combination of buttons, press them simultaneously in order to get an accurate reading. Also, if your max value for a button or combination of buttons is within 2 units of any other max value (of a button or combination of buttons), try changing to a different resistor – you’ve got an assortment of them in your kit! Some of the unit values in Serial Monitor will be close, since be prepared. For example, I swapped the 1k resistor on button 6 with a 1M resistor in order to get greater differentiation throughout my list.
Finally, make a note of what the LOWEST value displayed is when NO button is pressed, as we’ll use this in the code to decide if we’re calling our function. Call it Lowest Max Value
The resistor values themselves don’t matter for this exercise, it is the differences in your results that you care about. Here are the values I ended up with:
My Lowest Max Value here is 512 and the Max value for any button/button combination is 492. Keep this in mind when we’re writing our function.
We’re going to detour here and talk about re-usability of our code. Whether you’re writing a calculation, a set of instructions for manipulating a variable, or just a set of recurring lines of code over and over, you should offload that into a function.
Why?
- Reduce software defects – debug the function once and it is correct each time it is called.
- Save time – you’re not rewriting the same code over and over, you write it once and call it as needed.
- Makes your code more readable – if your code is easy to understand, it is easy to modify, upgrade, or support
Code reuse makes professional software developers more productive, more profitable, and reduces their stress levels for the reasons above and many more. Any time you can bring a professional practice into your hobby, your results will improve and your skills will increase. Even if there was no concrete benefit other than “doing it like the big boys do,” that would make code re-use worth doing.
Don’t worry, though, this is till going to be a VERY simple program, well within a beginner’s comprehension!
The simplest method of code re-usability is a function… so let’s write a function.
A function is just a defined group of code, a section or segment, which contains the instructions for a specific task. The task can be as simple as outputting data to your screen or as complicated as you need it to be. The key, though, is that you call the function when you want to execute the given task, rather than writing the same code over and over again.
When you write a function, you “Declare” it, outside of any other function. In the declaration line, you start with the return type, which indicates the kind of return your function will provide – a number a string, or whatever. In our case, we’ll use the VOID keyword, meaning that we will not return any information at all. Next, you supply the name of the function, which is what we’ll use to call the code from other parts of the sketch. Finally, we define any arguments required to use the function – in other words, what parameters or variables have to pass along with the function in order for it to work properly?
Start by adding a new variable declaration, like line 2 – we’re adding an array of string by declaring a char variable. There are different ways to do this, but what we’re doing here is declaring an array 2 characters long. We’re only using one character for our program, the second character is the null character that terminates the string. If you want more characters, add 1 to your max number of characters to include this!
Next, change your loop code:
We check the current analog input value to determine if we want to call our function or not. I arbitrarily selected 505 as the value to execute – my highest “max” value was from button 6, at 492, and my “Lowest Max Value,” from no button at all, was 512. 502 splits the difference. If the value is less than 502, then we call the function (printTheLetter).
Under the LOOP function, add this code:
As promised, that’s really simple! I took the values I recorded above and ordered them from the lowest to the highest. I kept the letter assignments for each button or combo, as that’s entirely arbitrary. All that matters is that there are 26 distinct values to assign.
First, on line 14, we set a default value of S for the printLetter variable (which we initialized but did not set on line 2). If none of the if statements are true, then the letter S is what will display.
We started with the lowest max value, 11, and set the value of printLetter to a specific letter. Continuing through the code, if the value is higher, we continue to replace that letter in favor of a new letter, until we either reach a condition that is false (voltageInput is no longer higher than the value we are evaluating) or we’ve progressed through all of the evaluations and set the value to “F.” The last line of the function prints the value of printLetter to the Serial Monitor.
You’ll need to change the values I show here to the ones you recorded above, but that’s not hard. This is a very simple example of a function, but, moving forward, we’ll make extensive use of functions in many ways. A lot of our functions will work with converting data – from metric values to imperial, working with strings, rounding decimals, and so on – but the basic concept will always remain the same. Write the function once and then call it as needed, rather than writing it over and over again.
In the next post, I’ll show you a new electronic component and show you a more advanced function and illustrate how to call it multiple times as needed (and where it makes sense to do so), to help expand your understanding of re-usability!
SmarterHome.club is the website for our Facebook community, The Smarter Home Club – which is an umbrella for all kinds of smart home technologies – home automation, security, custom electronics, weather stations, alternative energy, you name it. DIY focused.
If you’re interested in joining the Smarter Home Club’s Facebook group, please follow this link: