просмотров 59 802

USB volume control by encoder and AVR MCU

I’ve been wanting to connect to my CarPC volume control made by the incremental rotary encoder and plug in usb port. By turning the encoder to the left — the volume must decrease to the right — should be increased. Click down the encoder knob — mute volume.

An incremental rotary encoder provides cyclical outputs (only) when the encoder is rotated. They can be either mechanical or optical. The mechanical type requires debouncing and is typically used as digital potentiometers on equipment including consumer devices. Most modern home and car stereos use mechanical rotary encoders for volume control.

They employ two outputs called A & B, which are called quadrature outputs, as they are 90 degrees out of phase.

The state diagram:

Coding for
clockwise rotation
Phase A B
1 0 0
2 0 1
3 1 1
4 1 0
Coding for
counter-clockwise rotation
Phase A B
1 1 0
2 1 1
3 0 1
4 0 0

Two square waves in quadrature (clockwise rotation).

The two output wave forms are 90 degrees out of phase, which is all that the quadrature term means. These signals are decoded to produce a count up pulse or a count down pulse. For decoding in software, the A & B outputs are read by software, either via an interrupt on any edge or polling, and the above table is used to decode the direction. For example, if the last value was 00 and the current value is 01, the device has moved one half step in the clockwise direction. The mechanical types would be debounced first by requiring that the same (valid) value be read a certain number of times before recognizing a state change.

On encoders with detents there are different ways to switch states. In some, both A and B are always open circuit at the detents, and an entire 00 → 00 switching cycle occurs while transitioning from one detent to the next. Others have detents of alternating 00 and 11 value, with staggered switching times during the transition between detents.

If the encoder is turning too fast, an invalid transition may occur, such as 00 → 11. There is no way to know which way the encoder turned; if it was 00 → 01 → 11, or 00 → 10 → 11.

If the encoder is turning even faster, a backward count may occur. Example: consider the 00 → 01 → 11 → 10 transition (3 steps forward). If the encoder is turning too fast, the system might read only the 00 and then the 10, which yields a 00 → 10 transition (1 step backward).

To implement the project I used two prototyping boards AVR-USB-MEGA16 &  AVR-USB-TINY45 . 

Макетная плата AVR USB MEGA16    Макетка AVR USB TINY45

Connecting encoders to the prototyping boards is as the present at the circuits.


To make this device is determined by the operating system as consumer control with media keys  was used corresponding USBHidReportDescriptor, taken from descriptor of USB multimedia keyboard, and was written the appropriate code to handle.


ATMega32: FUSE_L = 0xCF, FUSE_H = 0x18, LOCKOPT BYTE: 0x3F.

ATTyny85: FUSE_L = 0xD1, FUSE_H = 0xDD

Examples of firmware are in source codes written by AVR Studio 5.0.

The source codes ver.2. You can increase the rate of change of the volume in the code specifying the variable AdditionalKeyPress.

The source codes ver.3. Solved problem — device is not detected by the OS after a reboot or turn off the computer, if it on MCU ATTyny45(85) without crystal.

14 thoughts on “USB volume control by encoder and AVR MCU

  1. Hello, my name is Marek. I search for a encoder board like you have made to my carpc but I need besides the encoder, about 12 multimedia buttons that I can use in a program like girder. Is it possible to program the other — unused pins from the atmega 16 board to functionality like I need? I program only in bascom… Sorry for my English, I speak only polish, German and English a little bit… Best regards, Marek

      • Basic question:
        as i’ve seen in your Source (main.c) according to the xls-table you posted above:
        » if (LEFT_SPIN == encstate)
        KeyPressed = 0xea;
        else if (RIGHT_SPIN == encstate)
        KeyPressed = 0xe9;

        you’ve chosen HID-ID «0C» (column B) with above keys «EA» and «E9» — correct?
        where could i change the «0C» in your source code (f.e. to «07» a standard keyboard)?

        in «usbconfig.h» i’ve found:
        «#define USB_CFG_VENDOR_ID 0xc0, 0x16»
        is this the correct one?
        Thanks so far!

        (btw, i have to wait for hardware arriving from china to test anything…)

        • Operating system determines the device as consumer control, not keyboard. Therefore you can only use the keys from HID Usage Page «0C» strings 181-189 in xls-table.
          About #define USB_CFG_VENDOR_ID 0xc0, 0x16″
          I used the VID and PID provided by Objective Development for free use (for more see file «USB-IDs-for-free.txt» in usbdrv directory in source code)

          • is it possible to program the board, so like a normal keyboard? If I use the other pins from atmega to the multimedia buttons, I want to use 4 from them like the and down from the keyboard, one must be the ENTER. This means, I want to use the 85-88 and hmmm what is the ENTER Code???

  2. I have made the version with the atmega 16 but it doesn’t work 🙁 the computer can’t recognize the adapter…

    On the schematic I se a 16MHz crystal but in the firmware is a 12MHz. Witch us correct? I have test both but with no luck…

Добавить комментарий