One of the many projects I’m working on requires rotary encoders communicating with a drawing program running on a computer. As always, I’d prefer to do this as cheaply as possible and since I’m working with the ATtiny a lot lately, I thought I’d try it on that.
EDIT 2: Below is mostly stuff that doesn’t work. I’ve written a new post that actually works here.
EDIT 1: I stumbled across this post and it’s several months later and the problem I had was very obvious. The ATmega328 chip that the Arduino uses has two external interrupts which are used by the buildr code. However, the ATtiny only has one external interrupt. So I don’t know why it kinda worked some of the time, but I know why it didn’t work.
I’m using this rotary encoder from sparkfun. It’s got a red/green led as well as a pushbutton, but I’m only using the rotary encoding part. After connecting the rotary encoder to my arduino to make sure it worked, I hooked it up to the ATtiny and used Software Serial on the ATtiny to communicate the value to my computer through the Arduino. Below is a picture of my setup. Notice that I’ve cleaned up the breadboard a bit. Also notice that the rotary encoded is at an angle because the pins are too short to fit into the breadboard normally. This shouldn’t be a problem when I actually mount it to perfboard, but it makes breadboarding tricky. The middle pin on the encoder is connected to ground and the other two are connected to the ATtiny pins 0 and 1. If you later realize that your encoder value is moving the the opposite direction of the way are turning it, just switch these wires.
Almost all rotary encoders output quadrature which is a two bit version of ‘gray code’. This bildr tutorial does a better job explaining it than I can so I will refer you there, but basically the encoder has three pins. The middle is attached to ground and the other two are connected to the Arduino or ATtiny. These two pins are either low or high and since there are two, there are four states that can be represented (00,01,10,11). The states always appear in the same order so you know when you go from one to the other which direction you moved.
I ran into a few problems using the code in the bildr tutorial and had to made a few changes. The bildr tutorial used interrupts to calculate the amount the encoder had turned. This worked fine when I used it on the Arduino but had problems when used on the ATtiny. I can’t for the life of me figure out why. The ATtiny is operating at slightly slower speed (8MHz as opposed to 16MHz) but should be more than enough when all it’s doing is checking an encoder. The first thing I suspected was that the Software Serial was causing problems. So I took it out and used an led to represent the turning. Still didn’t fix it. I originally had the software serial tx pin as digital pin 2 on the ATtiny. I thought maybe this was causing problems so I moved it to pin 4. It started to work better but not near as well as when it was on the arduino. The next thing I tried was changing the bildr code since it declared variables every time it went through the ISR (Interrupt Service Routine) loop. I moved the declarations outside the loop but that didn’t help anything. The final thing I did was to get rid of the interrupts and just have it check the status of the encoder pins every time it went through the loop. After this it worked perfectly, even when I moved the Software Serial back to pin 2. So I still don’t know what the problem was, but I know it works this way. The only real downside for me is that you can’t use any kind of delay in the loop because it may miss part of the encoder turn. Below is this code. If anybody can tell me what my problem was or has had similar experiences, please leave me a comment.
#include <SoftwareSerial.h> SoftwareSerial mySerial(3,4); // rx,tx volatile int lastEncoded = 0; volatile long encoderValue = 0; long lastencoderValue = 0; int lastMSB = 0; int lastLSB = 0; int MSB; int LSB; int encoded; int sum; void setup() { mySerial.begin(9600); pinMode(0, INPUT); pinMode(1, INPUT); digitalWrite(0, HIGH); digitalWrite(1, HIGH); void loop() { mySerial.println(encoderValue); MSB = digitalRead(0); //MSB = most significant bit LSB = digitalRead(1); //LSB = least significant bit encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++; if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --; lastEncoded = encoded; //store this value for next time }
Thank’s for this post.
I need multiple encoders to talk with one arduino, so you helped me 🙂
Here’s my post with slightly modified code: http://www.hackit.pl/2017/04/multiple-encoders-with-atmega.html
Alos I found mistakes: no “}” in setup and unused lastMSb and lastMSB variables.