Rotary Encoder Library

Hey Guys,

So the project I'm working on calls for the use of a rotary encoder, so I decided to write a library to do the decoding.
My library uses an interrupt on timer2 to poll the pins and decode the signals.
At the moment it only supports one encoder, but I hope to add the possibility for more encoders in the future.

Here is the library.

Here's an example of using it:

#include "Encoder.h"

const int encoderPin_A = 8;
const int encoderPin_B = 9;

int counter = 0;

void setup()
{
  Serial.begin(9600);
  encoder_begin(encoderPin_A, encoderPin_B); // Start the decoder
}

void loop()
{
  int dir = encoder_data(); // Check for rotation
  
  if(dir == 1)       // If its forward...
  {
    counter++;       // Increment the counter
    Serial.println(counter);
  }
  
  else if(dir == -1) // If its backward...
  {
    counter--;       // Decrement the counter
    Serial.println(counter);
  }
}

And I have a small explanation of it here.

Hopefully it will be useful for somebody.

yes like my i was looking for something like this small and easy to use
i want to connect a I2C and read a couples of this encoder

Update: Support for multiple encoders.

I added support for up to 5 rotary encoders to the library. I've probably done it in the lease efficient way possible, but I have no experience with classes in C++, so I wrote it all in C.

Here is the full explanation.

And here is the library itself.

Were you aware of the Encoder library I published?

http://www.pjrc.com/teensy/td_libs_Encoder.html

It might be nice to change your library's name slightly, so it can be used along side this long-established library without the .h files conflicting.

Ah, sorry Paul, I didn't know about your library.

I'll change the name of the files.

Thanks for making that change. It's good to have names that are different enough for the compiler to not have conflicts when both are installed. Calling it "V2" might imply it's a newer version of the same library, but that's a minor issue. I'd personally prefer you used a more distinctive name, but that's really your call.

Your library uses a different approach that could be really nice for people using boards with a very limited number of interrupt pins, like Arduino Uno. Would be nice if the name somehow made that difference and its advantages clear.

Regarding the library, if you're willing to consider another idea, you might make it a C++ class? That's the normal way almost all Arduino libraries are structured. The object constructor could automatically assign the "_encNum", perhaps using an array or bitmask of which ones are already in use? You'd make _encNum a private or protected class member, so there would be no need to pass it on every function call.

If you add a 32 bit counter, you could even give your C++ object the same read() and write() functions my library has. Then people could use it as a drop-in replacement. They could #include both libraries in the same project and use your library for some encoders and mine for others. All they'd do to change which encoders use which library is change the object name where the instance is created.

Again, sorry about the naming :blush: hopefully the new names make a bit more sense.

I have very little experience with C++, as I've only ever used C really. I think I should learn C++ properly, so I can take advantage of some of its features like you said.

Also, that's a really good idea! I'll take a good look at your library and try to make the two libraries integrable.

C++ has a lot of complex features, but for just making this an object, you can probably use almost any Arduino library as a guide.

The Encoder library I published has a lot of tricky optimizations, so it's probably not the best one to look at for an example. Libraries like Stepper or Servo are probably good ones to use for an example.

Hello Paul,

First thanks for this excellent library.

In my project, I'd need to declare an encoder dynamically. I mean, declare the encoder first, and assign pins in a second time after reading a sort of config file.
is there a way to modify your library, creating a kind of "assign" function to dynamically declare the pins number instead of passing the values at declaration?

Thank you,

Michael.

iznogoud320:
In my project, I'd need to declare an encoder dynamically. I mean, declare the encoder first, and assign pins in a second time after reading a sort of config file.
is there a way to modify your library, creating a kind of "assign" function to dynamically declare the pins number instead of passing the values at declaration?

In theory, you should be able to create instances of the library with "new". But in practice, it doesn't work. There's some sort of bug. Details here:

Fixing this is on my to-do list, but currently I'm working on many much higher priority tasks. If you'd like an update when I work on this bug, please subscribe to that thread. That's where I'll post any updates about a fix.

Ok, Paul, thanks a lot for your fast answer.

Looking forward for this mod :wink:

Michael.

It says there that SoftwareSerial is very likely to cause problems. I'm using GSM Shield on my circuit via hardware serial and Serial LCD via software serial. My microcontroller is an Arduino Uno clone. I'm about to use a rotary encoder to measure soil movement in a mountain. What problems would I be facing? Does it have something to do with my LCD displaying incorrectly? Can I turn off the interrupt whenever the Serial LCD comes up in the code? Any suggestions? Thank you in advance :slight_smile:

SoftwareSerial disables interrupts while sending or receiving a byte. For example, at 9600 baud, 8N1 format, a byte takes 1.04 ms. During that time, the Encoder library can't recognize any changes on the encoder pins.

The pin interrupt hardware will save the fact that the pin changed, so as long as only 1 change happens during that time, it will be picked up later. But 2 missed changes can cause incorrect counting.

With hardware serial, interrupts are disabled for only a few microseconds, instead of over 1000 us, so even fairly fast movement on encoders can be properly tracked while serial data flows.

I'm about to use a rotary encoder to measure soil movement in a mountain.

How?

What problems would I be facing?

That depends on how fast the rotary encoder is turning, and what the rest of the code is doing.

Does it have something to do with my LCD displaying incorrectly?

Yes. No. Maybe. The answer depends on what the undefined it is.

Can I turn off the interrupt whenever the Serial LCD comes up in the code?

You can get anything you like at Alice's Restaurant. You can, similarly, do anything you like in your code. Whether it makes sense, or not, is a different story.

Any suggestions?

Well, now that you mention it, posting your code would be useful. Posting well defined questions might be, too.

The other possibility is my AltSoftSerial library.

http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html

It does not disable interrupts for the entire byte, so it will interfere much less with Encoder. However, AltSoftSerial depends on Timer1, so it's incompatible with any other libraries that need Timer1.

The other other possibility (if my AltSoftSerial library doesn't solve the interrupt latency conflicts) would be using a different Arduino compatible board which has an available hardware serial port. Since I'm the creator of Teensy (full disclosure), of course I'd recommend using a Teensy. All of them have a free serial port. Teensy 3.1 has 3 hardware serial ports, yet it's very affordable.

I believe Arduino Leonardo, Micro, Mega and Due also have extra serial ports.

But since you said you were already using an Uno clone, I'm guessing buying a more capable board is not an option?

I'm also curious, did you buy a cheap clone? Not even a single penny goes to support the Arduino project, nor 3rd party developers, who write the libraries you're using, like Encoder and AltSoftSerial (I'm the author of both, and I can tell you both Encoder and AltSoftSerial development was funded through sales of Teensy boards). The people who make those extremely cheap clones don't develop any software or libraries. They usually don't answer any technical questions. They usually don't even host a forum for questions, instead sending their customers to get support here, from those of us who are funded by sales of the name brand boards.

The extra cost of those boards pays for all this software and library development and resolving of technical issues. I hope anyone reading this will keep that in mind when considering cheap no-name clones.

Thank you Mr. Paul Stoffregen for your quick reply. Wow. I salute you. Well I'm from the Philippines and I only have a few options when it comes to choosing boards.

As to PaulS(arcasm), yeah. I definitely deserve that. I'm sorry coz I'm in a rush to finish this project and I'm new to arduino. I don't even know if it'll actually work. But thank you coz you actually helped me a lot by answering in the forums and yeah it's really difficult to answer unspecific questions like mine so I really appreciate what you're doing. Again, I'm sorry.