Release 2017.10.22 / Update 2018.9.25

Using rotary encoder part 3 : “Dual Encoder”

I have been struggled in part 1 and part 2 to read rotary encoder precisely. In this article, I wrote a new sketch for encoder combining those two wisdom.

I called it “Dual Encoder”.

Purpose of this sketch are,

  • dual encoder reading
  • using ‘timer interrupt’ to read, not ‘attachinterrupt’
  • works on click-type and non-click-type

As a result of trial and error to solve the problem in the previous sketch, I think the accuracy was moderately improved. Especially, I have a satisfaction for use of non-click-type.

Yet, there are chattering still on reading and it may disturb main task. And counting for click-type may goes wrong sometimes.

So, the sketch of part 1 maybe better for the people who don’t care to use attachinterrupt.

I couldn’t make it as library because lack of my skill and time. Please use this sketch as your own project by rewrite or add code. Sorry.


The parts necessary to try this sketch are:

  • ArduinoUNO
  • Rotary encoder ×2
  • (if you have)128*64 OLED

Needed encoders are normal type which has 3 pins, phase1 and phase2 and GND. I recommend you to use non-click-type as in part 2.

Study about u8glib and OLED here.

Or, you don’t have to prepare it if Serial Monitor is enough for you.


Write the sketch to Arduino by download project file or copy & paste from the code down below.

Download – 「Dual encoder ver 1.0


Timer interrupt

This sketch uses “MsTimer2” library to read encoder. So get it in your IDE if you haven’t imported yet.

Or you could use another timer library if you rewrite it directly.

Port registers

This time, I used ‘Port registers’ not ‘digitalRead’ because it is more efficient.

So you can’t change pins easily. And it won’t work on Arduino which has different port number.

Please make it change by yourself if you need modify.

“PIN# & _BV(#)” are the pin setting.

Ref ) Port of ArduinoUNO

By the way, the pins defining for pinMode needs to be changed too.

How to use Dual Encoder

Basically, simply use ENC_COUNT(#) function. You can use it anywhere you want after staring timer interrupt.

Read part 1 and part 2 if you want to know how “Dual Encoder” works.

Inefficient update on the sketch is caused of u8glib. Change the define value of ‘OLED_DRAW’ to 0 if you want to kill it. And check the values on Serial Monitor.

Functions of ‘Dual Encoder’

void SET_ENC_RES (byte encoder num, bool resolution);

This set the resolution of the rotary encoder to use. There is no return value.

If you set ‘resolution’ to 1, it works as click-type.

encoder num Designation of encoder number. The first encoder is (0), the second one is (1).
resolution Specification of resolution
0(false) Non-click type
1(true) Click type

If you want to the first encoder as click type,

SET_ENC_RES(0, true);

You don’t need to use this function if you use non-click type encoder. Default of this sketch is use of non-click type.

boolean ENC_CHECK (); / ENC_CHECK (byte encoder num);

This function is for check whether the encoder is counted or not. If there has change, it returns 1(true) otherwise 0(false).

encoder num Designation of encoder number. The first encoder is (0), the second one is (1).

In case of ENC_CHECK (), it returns true if there is increase / decrease from any encoder.

On the other hand, ENC_CHECK(#) returns true when the specifed one has changes.

The difference-value of ENC_COUNT() is updated if you call it. So use this function when you don’t want to update the value.

The return value of this function is reset after call “ENC_COUNT(#);”.

int ENC_COUNT (byte encoder num);

This function returns difference-value of encoder count from previous call.

encoder num Designation of encoder number. The first encoder is (0), the second one is (1).

Use this function like this. If you want count of the first encoder,

val += ENC_COUNT(0);

On this sketch, you may feel it slow because of u8glib. But the actual count of the encoder would be accurate, if it won’t catch chatterings.

The return value of “ENC_CHECK();” function is reset after call this.

void ENC_RESET()

There are ‘enc_count[]’ variable on the sketch to read continuous count of each encoder. This function reset the variables. This variable is set as int type. But it may overflows in case. Avoid the case by using this function.

reference) range of ‘int’ -32,768 ~ 32,768



It specify the number of encoders.

Reduce value if you use single encoder, because it reduces the load too. Don’t forget rewrite defines of pins.


As you know from part 2, this sketch use “gauging” to avoid chattering. This is the value.

You can’t set this value over 255.


This value is interval time of timer interrupt (ms).

If you reduce the value, accuracy of encoder reading is raised. But it may cause to worse response of whole sketch. Opposite, raising the value solves the problem although give up accuracy of encoder reading.


This is repeat times of “gauging” on one time of timer interrupt. This value also affects to the response of whole task.

You can’t set this value over 255.


ENC_TOLERANCE / TIMER_INTVAL / ENC_REPEAT, balance of those values affects accuracy of encoder reading and response of the sketch. Find proper value balance in your project.


Although the purpose of this sketch is use two encoder, you can add more encoder by little rewrite.

I tried use four encoder.

But this affects timer interrupt duration. So be careful.

This is example when you want to add third encoder.

pin define

port resister

The new encoder number will be (2).

int val += ENC_COUNT(2);


Although there may be no such projects that handle multiple rotary encoders in many cases. But I think this sketch will work well even if a single encoder.

Reference Site

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.