Welcome back to the Digilent Blog!
When working with microcontrollers, it’s pretty straightforward to have your system board “listen” for an input that you would give it and have it do some sort of action to show that it noticed your input, such as pressing a button to light up an LED. Listening to a set of inputs and then comparing them to a predetermined set, like in the Simon Says game, is a little more involved but definitely doable. But what if we did not compare to any internal values and the system board has no idea how many inputs we might provide? This is a common situation in things like four function calculators; it has no idea how big the numbers will be, nor when we might press the = sign or + sign. The microcontroller can compensate for this, at least in my design, by performing what is known as active listening.
So what is active listening (in terms of an electronic system)? This is where the system board continually checks if a certain condition has been met, or in the case of a four function calculator, continually checks to see if a button is being pressed. This continual checking is known as polling and is a pretty efficient listening method if you are not concerned with potentially not receiving the input for a few microseconds (over a 1000 times faster than a chameleons tongue catching a bug) or the larger power draw as your system board is continually working to check the status of the inputs. In terms of a calculator, I’m not concerned about noticing a button being pressed immediately or about the power draw since I have my chipKIT™ uC32 powered from my computer’s USB port.
Essentially, this boils down to that it’s pretty straightforward to receive a “random” input by polling (however, please leave a comment if you have any questions). But after we get this input, which will translate to a ‘logic high’ voltage signal, how do we then merge this signal into both a number that we are typing and a single character to display?
What I ended up doing for my calculator was creating a switch-case statement that looks at which button on the PmodKYPD was pressed and gives another function the character that represents that particular button. The received character can then be immediately printed to the PmodOLED screen in the appropriate location depending on if it is one of the ‘operator’ characters such as the ‘+’ or ‘=’ signs or if it is a number character. When the pressed button is a number character, its decimal value is added to the number we were originally typing out. However, this raises an important question. How would the microcontroller ‘know’ what the decimal value of a character is? One way to do this is through typecasting. This is a technique where you can designate how you want the system board to interpret a particular data type, such as interpreting a character as an integer.
For example, if we wanted to type the number ’37’ we would first press the ‘3’ button on the keypad to get our ‘3’ character. According to the ASCII Table, the character ‘3’ corresponds to the decimal number 51, meaning if we subtracted a decimal value of 48 from our ‘3’ character, we would get the character corresponding to the decimal value of 3 (‘ETX’). We can then typecast this character as an integer (to get our decimal value of 3) and add it to ten times our pre-existing number value, which in this case is a zero, giving us a value of 3.
Then we would press the ‘7’ button to get the ‘7’ character and subtract a decimal value of 48 to get the character with the decimal value of 7. We then typecast this new character as an integer and add it to ten times our pre-existing number value, a 3 turned into a 30, to give us a new value of 37.
Naturally, calculators (even four-function calculators) do more than just allow you to type numbers onto a screen; they also allow you to do some basic math without forcing you to remember how to do long division. In terms of our calculator, the system board just needs to keep track of the first value that we put in and the second value that we entered and perform the appropriate operation, like adding or dividing, based on another switch-case statement. The tricky bit comes when writing a function to print out our answer on the screen since we have to individually convert every number (and the decimal point if there is one) into the correct character. Otherwise the number 78 would print as the character ‘N’, which isn’t terribly helpful in terms of math.
One way to accomplish this is to slowly divide your number by larger and larger increments of 10 (starting from 1) and wait to see how many of these increments it takes to get your calculated number to a single digit. This lets you know how many digits long your number is. You can then start at that largest division value to get your first (and largest) digit and turn it into the appropriate ASCII char value by adding 0x30 (decimal value of 48 in hexadecimal) and then displaying it on the screen. You can then find your second largest digit by dividing by the next smallest factor of 10 and then subtracting anything “tens place” and larger from it to be left with just the single digit number.
Once you have gone through and displayed your digits you could also, if you so desired, check for any decimal points. Here, we would need our initially calculated value to be a double so that any decimal points would exist in the first place. We can then subtract from our calculated value its “typecasted” integer version to leave us with just the decimal points. With just the decimal points, we can then multiply them by factors of 10 to get our single digit values, remembering to subtract off the higher numbers after we start multiplying by 100 or greater.
In terms of practicality, you might be wondering how you could make sure that you keep everything looking neat and pretty on the display since there is a lot of background manipulation involved. The answer to this is to place limits on how big the numbers can be and how much of them will be shown on the display. A signed integer (can be positive or negative) on a chipKIT processor is only able to be as large as +- 2,147,483,647. With this in mind, it would be a good idea to keep the input numbers within the range of +- 1,000,000,000 where anything larger produces (as per your screen output) an overflow error forcing the user to work with smaller numbers if they want the calculator to keep working correctly.
The code that I used to create this setup can be found here.
What cool projects would you want to try out with a combination of Pmods?