Introduction: How to Read Binary/Hex Thumbwheel Switch With an AVR Microcontroller

About: Gian is a computational biologist,maker, author, humorist. He holds degrees in Molecular/Cellular Biology, Biochemistry, Computer Science. He has a collection of 8-bit microcontrollers and a room full of compu…
This instructable will show you how to read the number on a binary pushwheel or thumbwheel switch using LED's or an AVR microcontroller (I'm using an ATmega328p but this can be adapted for any AVR or probably another microcontroller of your choice). Multiple thumbwheel switches can be strung together to make an electronic combination lock, protecting your valuable...um....cookies!

Thumbwheel switches have detent buttons (technically called a "pushwheel") or a wheel that you can push to change a number up or down by one. Inside they have switch logic that encodes the number on the dial as, typically, octal, hex, BCD (Binary Coded Decimal) . This encoding is then sourced to or sank from the external pads where it can be read and displayed (as with LED's), decoded with IC's (e.g. 4029,74HC93,and 74HC590), or hooked into input pins of a microcontroller and further processed.

My favorite local electronics shop had a bin full of ones that looked like old SCSI device ID switches so I grabbed a few to see how they worked. The numbers go from 0 to 15 so I think this would traditionally be called a hex switch, but I'll be referring to them as binary because of the output we're working with. Don't confuse binary with BCD; they are not the same thing. Ok, let's go!

Step 1: Parts List

For this instructable you I am using the following parts:

You Probably Need These

  • A binary pushwheel or thumbwheel switch. These can be had at the major electronics outlets online, or if you're in Colorado, check out J.B. Saunders in Boulder. They have them on the cheap!
  • A solderless breadboard
  • A soldering iron, solder, hookup wire (I used 24 gauge stranded because it's very bendable)
  • An AVR microcontroller
    • I'm using an ATmega328p sitting in a Bare Bones Board from Modern Device
    • I'm using the USB BUB to program the AVR

Optional

  • Four LED's (for illustration of the encoding)
  • Four resisters (for the LED's. I used 200 Ohm that I had already on my bench (I'm lazy2))
Modern Device]
  • Four diodes if you're paranoid about running reverse polarity into the pins of your MCU

Something to write or compile your firmware

Windows

  • WinAVR for Windows AVR development

FreeBSD / Linux (other *NIX variant)

   pkg_add -r avr-gcc  -or-  cd /usr/ports/devel/avr-gcc/ && make install clean   pkg_add -r avr-libc   pkg_add -r avr-gdb

Mac

There are other utilities, like Eclipse, that you may also like to use but this should be a good start.

Now that you know what you need, we'll put it together, but in order to do that you need to know how the binary switch works.....so let's move on to the next step!

Step 2: Binary Switches AndTruth Tables

As I briefly mentioned in the introduction, a binary switch is a switch that encodes it's state in binary. Binary is a method of encoding using two discrete states -- one's and zero's -- to represent other symbols when put together. Each one or zero is called a "bit" and these bits are usually strung together into groups of eight called a "byte." Not all bits in a byte have to be used for encoding, however, and the ASCII character set is a notable example that only uses 7-bits (there is an extended version). The pushwheel switch in this instructable has a range from 0 to 15 and uses four bits to encode the number on the dial.

A Brief Binary Digression

In order to understand how four bits can represent 16 different numbers, we have to know a little about how binary encoding does its job for this switch (and in general).

From the first picture, you should be able to see there are actually five pads coming out from the back of the switch. These are labeled 1, 2, 4, 8, and C. The C is considered a common terminal. That is to say, it's a part of the switching circuitry that is always connected to whatever switches are flipped on in the switch. In my setup, I'll have the "C" pad connected to ground and any current will flow from the open switches and out the C terminal and down to ground. Therefore, the "C" pad doesn't contribute to the bits used in encoding the digit on the front of the dial; this is the sink of current for the switching circuitry inside the thumbwheel switch.

The 1, 2, 4, and 8 pads encode the bits for the number. In binary, the placement and number of 1's and 0's in a byte are used to determine the identity of an individual unit in a character set, or for our purposes, the number selected on the dial. Because we have four bits in our set, the maximum number of unique combination of ones and zeros is 24 = 16. The best way to remember this is to raise the number of possibilities (here we have two possibilities: a 1 or a 0) by the number of bits (here we have four bits: pads 1, 2, 4, and 8). If we were to write out all unique combinations of 1's and 0's in four places it would look like this:

          No 1's      One 1      Two 1's      Three 1's      Four 1's          ------      -----      -------      ---------      --------           0000        0001       0011          0111          1111                       0010       0101          1011                       0100       1001          1101                       1000       0110          1110                                  1010                                  1100

So we have 16 unique possibilities arranging 0's and 1's and, conveniently, this switch's counter goes from 0 to 15. It's nice when a plan comes together. But you may be wondering if there's a pattern for how each of those four bit arrangements (called a Nibble, by the way) represent the numbers. I'm glad you asked.

Remember the 1, 2, 4, and 8 designations for the pads? That's not capricious labeling by the marketing folks. Let's look again at our pattern of numbers. Each bit location has a "place" that can be thought of as it's "power of two" location reading with the least significant bit on the right starting at the 0th bit. That is to say, we use a 0-based index and start counting from zero to one to two, etc, instead of counting in the vernacular where we would start with one. So, 20 = 1, 21 = 2, 22 = 4, and so on. Arranging this from right to left we have something that looks like this for the four-bit pattern 0101 :
                   Place -->  8  4  2  1                              0  1  0  1

To determine what number that "0101" represents, all we need to do is find every place that has a 1 in it and add it's power of two number. In our example, there are ones in the 1 and 4 place. Add 1 + 4 and you get 5, so, the binary number 0101 represents the decimal number 5. Isn't that exciting? Let's try another one, this one a full 8 bits, even though our switch only has four bits. It's good practice and is something you can impress with on your next date.
What is the decimal number that 01101110 represents? Here it is in their places:
                            128 64 32 16  8  4  2  1                              0  1  1  0  1  1  1  0
Find the places that have 1's and add those place numbers together. That would be 64 + 32 + 8 + 4 + 2 = 110. Pretty easy, huh? Knowing this now we are able to take our 4-bit switch and make a matrix of the pin numbers that have a 1 (logical one in digital is a higher voltage than a logical zero, in our case 5V and 0V respectively) against the decimal number they will represent. See the 2nd picture below for a table I made to represent the pads on the switch that would be at a logical 1 depending on the number selected on the front of the dial.

Now we can start building things. Follow me to the next step!

Step 3: Solder the Switch and Test Binary Logic

It's time to put the solder to the pads, as it were, and start building stuff.

Take your hookup wire, strip off about half a centimeter on both ends. It doesn't matter what colors you use or if you use different colors at all, just as long as you don't get your wires confused. You'll kick yourself in the butt trying to debug an error in binary logic when you find out you had pad "2" in the place of pad "4."

Now is a good time to verify or convince yourself that your binary logic is correct. To do this, I took four LED's and four 220 ohm resistors and put them on a breadboard. You can use 180 ohm or even 1k resistors depending on your LED color and forward voltage requirements that will work for you. For your power, you can either use a 5V regulated source (that's that small circuit hanging off of my breadboard in one of the pics) or you can power the board from your Arduino, BBB, etc. The choice is yours.

  • Connect the C wire to 5V (Make a note of this as you'll do the opposite when connecting to your microcontroller).
  • Connect wires 1, 2, 4, 8 to their own resistors followed by the positive side of the LED. That's the long leg, if you're unsure. then connect the other side of the LED to ground.

The circuit should look something like the ones I have below. If you are really unsure, there's a schematic included in the pictures to show the LED test circuit. Also note that I am showing the binary from left to right in the pictures. It doesn't matter whether you hook your wires up in your test circuit from left to right or right to left as long as the wires go to the right LEDs and you can compare them against your truth table to confirm your logic.

Once you are comfortably convinced that the universe is operating exactly as it should you can connect your microcontroller.

Step 4: Connect Your Microcontroller and Load Your Code

Pick four ports on your MCU that are free and configure them as inputs. I chose PD[2..5] in my setup but it doesn't matter which you choose, just be wary of using PD[0..1] if you are planning to use U(S)ART communication as those pins are usually reserved for that. I'm pretty sure Arduino and other clones map pins 0 and 1 to their USB FTDI port, as well. As an optional measure, you may chose to install diodes (in the pictures below the stripe is to the right). Some boards have protection but if you play around with bare AVR chips on boards it's probably not a bad habit. You do these things after you've smelled enough transistors burning.

Once you've made the connections to your input pins it's just a simple matter of reading your pins and processing the data. You could read the pins and light LED's, setup interrupts to handle serial communication, or if you string several of the switches together, you can use them as an electronic lock, testing the pins to see if the correct combination was entered before you grant access to the microcontroller or whatever it happens to be guarding.

Step 5: [Optional] AVR Code Example

Ok Ok I wouldn't leave you hanging. I think you're probably all capable of reading I/O pins, so this isn't meant to insult your intelligence. It's just a brief snippet that I wrote to read the pins and send the data via the USART in the ATmega328p to a serial port on my FreeBSD box.

I don't use Arduino libraries, just pure C so you may have to adjust yours accordingly. There may be a more elegant way of doing this, but this is what i came up with.

#include <avr/io.h>#include <util/delay.h>#include "uart.h"#define SWITCH_M 0b00111100int main(){	USART_init(BAUD_9600);	DDRD 	= 0x00;		// inputs for switches	PORTD  	= 0xFF;	// pullup on PD[2..5] (we have negative logic on switch now)		uint8_t		bcode = 0x00;	for (;;)	{		bcode = (PIND & SWITCH_M);	// bcode = 00xxxx00		bcode = (bcode >> 2);		// bcode = 0000xxxx		bcode |= 0xF0;			// bcode = 1111xxxx			USART_tx(~bcode);		// bcode = 0000xxxx		bcode = 0x00;		_delay_ms(2000);			}	}

Starting with my wheel switch at 0 and cycling up I get the following output:
0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F

I hope you enjoyed this instructable! If you have any questions feel free to contact me here, email, or on our IRC channel on irc.freenode.net #instructables