• Featured User: kurt


    Open-source hardware project hosting is my passion. I spend most of my free time building neat gadgets or planning what I'll build next. I love building things, and I want to make Open Hardware Hub a place that inspires others to build, ...

    Learn More

  • Updates 2013 February 18

    It's been a while, hasn't it? Well, that's ok because we've got a lot of updates to talk about. Most of these have been effective on the site fora couple weeks now. A few may or may not be active when this article gets posted, but they'll certainly be applied in the ...

    Find Out More

The Knob

Download this project


By: madworm

The problem: an existing project (maxed out in terms of free code-space on the chip) would strongly benefit from having a rotary encoder knob attached to it. The project already has serial comms running, so using that would be the simplest thing. I could of course re-spin the board, but that is more costly. Besides: never change a running system. The solution: add another microcontroller to the mix. Reading one quadrature encoder is easily done with little code, so one of the smaller ATtiny chips will do it just fine. 2k of FLASH should be plenty to hold the decoding routine + a bit-banged serial transmitter.

Download project description w/o images
Download project description w/ images


Download all project files

Bill of Materials

Qty Part # Description Schematic ID Source
1 65b50ddfb4529fc6726eacbf067bf172f0038baa ATTINY25-20SU AVR MCU, 2K FLASH, 128B RAM, SOIC8 IC1 Source
1 0b20fc8fdf51da89c4c3f2ee30694af0103bd7d8 EN12-HS22AF30 Mechanical Encoder Rotary Incremental Flat 1.4oz.in Straight Gray Digital Square Wave 24PPR Through Hole PC Pins ENC1 Source
1 C757af23c873e54dac3a19265864662dd2b4d00f 0805ZG475ZAT2A CAPACITOR, 4.7 UF, 10V, 0805, Y5V C1 Source
1 Ef08efdd199592222839c7f9c86ffa912d3ae6fa SML-310YTT86 SML-310 Series Yellow 0603 6.3 mcd Clear 2.1 V LED Surface Mount D1 Source
1 72c9148d03561cc1b553016a94cc6b4b457c40a6 ERJ-3EKF1002V RESISTOR, 0603, 0.1W, 1%, 10K R7 Source
6 5c350aa3e43f48306fe83b21a54097acc6634c98 ERJ-3EKF1001V RESISTOR, 0603, 0.1W, 1%, 1K R1-R6 Source
loading total from bomfire.com...

Download BOM w/o images
Download BOM w/ images


1. Reading the encoder

A quadrature encoder has exactly four states, which are determined by the 2 output signals A and B. These states may be called: (00,01,10,11). The signals A and B are 90° out of phase, shifted with respect to each other. Ideally only one signal can change at any given time, never both. That way one can determine which one changes first (A before B, B before A), which carries the information about direction of rotation.

You can use an edge-triggered interrupt to do it, but that requires absolutely clean edges. No switch bouncing tolerated. Otherwise the cpu load would surge. We don’t want that. This is also not about reading a high-frequency signal, so the polling approach is sufficient. We also don’t care about sleep modes, so there’s no need for interrupts to wake up the micro.

As it happens, there is already a timer interrupt running at 1kHz, which provides ‘time’ and ‘delay’ functionality (recycled code from another project). Reading and evaluating the encoder state is simple enough, so we just plug that into the system-ticker routine.

By comparing the current vs. the previous encoder state, one can determine if a step has been made and in which direction. This assumes that every step is recognized. If steps are skipped, there are disambiguities and it can’t be determined for sure what has happened. Time to increase the polling frequency. But for a hand-turned knob with just 24 ticks per revolution this extremely unlikely.

A typical time-sequence of states may look like this:

… - 11 - 01 - [ 00 - 10 - 11 - 01 ] - 00 - 10 - …

Going from left to right could be clockwise rotation, right to left anti-clockwise rotation.

The state names (00,01…) also match the bits that are set or unset in the GPIO input register of the microcontroller. One way to make the decision of what step has taken place is to use a lot of if-statements, but that is a lot of text to write. A simpler way is to create a truth-table of sorts (array), with elements of {+1, 0, -1}, representing the step-direction. The bit-values of the encoder states (previous and current) are joined into one byte, which will become the index of the array. If a combination indicates a valid step forwards, the associated array-element will be ‘+1’. A negative step will of course be represented by ‘-1’. No change or any invalid combination (e.g. from 00 to 11) will get a ‘0’.

The main loop checks for a changed encoder state (flag is set by the interrupt), and processes the data - i.e. send out a status-byte via serial. Done.

Quadrature_encoder Terminal

2. Volume control for your computer

If you run linux with KDE4, or a system that uses dbus well enough, you can quite easily use a little perl script to grab data from the serial port and control the volume of a music player, e.g. Amarok. To find out what functions to call, start your player and use ‘qdbusviewer’ to see what methods are available. The demo-code provides a short guide how to go on from there. You want to build a streaming radio client with an old router? Why not add a real volume knob? Console music players might be able to listen to serial commands too. ‘MOC’ (music on console) might be a good candidate.

Download steps w/o images
Download steps w/ images


7 - Added a video.
6 - Changed the title.
5 -
4 - Added the 'volume control' step.
3 - Added an image showing terminal output.
2 -
1 - Initial project release
Add revision

blog comments powered by Disqus