Rotary encoder question - Page 1
Forum section: electronics / general

author: shebu18
author_rank: Frequent Contributor
timestamp: June 30, 2012, 08:29:18 pm
content: Hello all,I have bought some rotary encoders from TME, ED16112O. They do not use the normal grey code. If i rotate them CW i get initial state 00 then 11, 10, then 00 again. CCW it is the exact opposite. I connect the middle pin to GND and the other 2 to 5V.I have tried it with arduino, got some results using interrupts but i had some misses of rotations.Can you give me some advice on the code? Thank you.Code:int pina=2;int pinb=3;volatile int x=0;volatile int trigger=0;void setup(){pinMode(pina, INPUT);pinMode(pinb, INPUT);attachInterrupt(0, count, RISING);Serial.begin(9600);}void loop(){Serial.println(trigger);}void count(){if(digitalRead(pinb)==HIGH){x=2;};if(digitalRead(pinb)==digitalRead(pina)){trigger--;}else{trigger++;}}

author: free_electron
author_rank: Super Contributor
timestamp: June 30, 2012, 09:09:01 pm
content: nah. its standard gray code... the common is not the center pin but the right pin for this part.

author: shebu18
author_rank: Frequent Contributor
timestamp: July 01, 2012, 07:19:15 am
content: Thank you for your help. Now i need to find a good code for the encoder.

author: shebu18
author_rank: Frequent Contributor
timestamp: July 01, 2012, 08:17:39 am
content: I changed the pinout but now i fase the problem of not enough interrupt pins on the arduino duemilanove. I have 2 but need 4(for 2 encoders) How can i solve this problem. How did Dave solve this in his code?

author: Psi
author_rank: Super Contributor
timestamp: July 01, 2012, 08:37:48 am
content: I don't know much about Arduinos , but modern AVRs have a PCINTs for pretty much every pin. (Pin Change interrupt).Does the Arduino have this?(Edit: The Arduino Uno looks to use an ATmega16U2 which does have PCINTs)

author: Bored@Work
author_rank: Super Contributor
timestamp: July 01, 2012, 08:44:40 am
content: Should I mention it? Ah well, it will anyhow be ignored, so I keep it short. One does not connect slow turning (aka hand operated) mechanical encoders via interrupts.

author: shebu18
author_rank: Frequent Contributor
timestamp: July 01, 2012, 09:03:43 am
content: Quote from: Psi on July 01, 2012, 08:37:48 amHerehttp://arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdfis the schematic of the arduino uno or duemilanove, they use the smae atmega328 chip. It has only INT0 and INT1(pin 2 and 3).In the 328 datasheet i have seen that there are more pins with int functions, but the arduino does not use them. This is the problem.

author: shebu18
author_rank: Frequent Contributor
timestamp: July 01, 2012, 09:05:15 am
content: Quote from: Bored@Work on July 01, 2012, 08:44:40 amTHen how should i connect them? Teach me.

author: Psi
author_rank: Super Contributor
timestamp: July 01, 2012, 09:10:53 am
content: Quote from: shebu18 on July 01, 2012, 09:03:43 amThat will teach me for skim reading.It has an Atmega16U2 but it's for the USB emulation not the actual processor.Quote from: shebu18 on July 01, 2012, 09:05:15 amYou can sample the pin yourself, say 100 times a second (10ms) on any input pin.Use the hardware timer overflow interrupt to set flags when a specific time expires.Then, in the main code loop area, check the flag,- If it's "set" do the logic to process the new encoder position and reset the flag.- If it's not set, do nothing. Eventually it will be set.I wrote this example code on the wiki a while ago, but it's for an AVR not an Ardiuno. So maybe a little different.http://www.eevblog.com/wiki/index.php?title=Embedded_Programming_Tips_and_Tricks_for_BeginnersScroll down to "Repeating Code Using Timer Overflow Interrupts"

author: johnnyfp
author_rank: Frequent Contributor
timestamp: July 01, 2012, 10:09:54 am
content: Check out this link might help you.http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino/comment-page-1#comments.

author: shebu18
author_rank: Frequent Contributor
timestamp: July 01, 2012, 10:19:29 am
content: I do not have enough C knowledge to understand that code(i am learning it alone at home). I am trying to use the method Psi mentioned. I use timer1 to make a interrupt and read the pin states every 10ms. Now i need to manage the code for knowing in witch direction i am rotating the encoder. I am curios how Dave has done this.Thank you for your help.

author: Psi
author_rank: Super Contributor
timestamp: July 01, 2012, 10:39:15 am
content: This may help toohttp://arduino.cc/playground/Main/RotaryEncodersBasically you pick one of the encoder wires and an edge type (rising or falling), doesn't matter which.Then, when that edge type occurs on that encoder wire you look at the other wire and its state will tell you if the encoder is rotating left or right.To tell if an edge is rising or falling you have to store the previous state in a variable so you can compare it to the current state.

author: shebu18
author_rank: Frequent Contributor
timestamp: July 01, 2012, 11:24:22 am
content: I used this code:Code:int pina=2;int pinb=1;int value;int oldvalue;void setup(){pinMode(pina, INPUT);//digitalWrite(pina, HIGH);attachInterrupt(0, scan, RISING);Serial.begin(9600);}void scan(){value=digitalRead(pinb);if(value != oldvalue){Serial.println("right");}if(value==oldvalue){Serial.println("left");}value=oldvalue;}void loop(){}and i got this:If i turn only right i get sometimes right sometimes left. If i turn left i get the things i get on right turning plus some errors. why do i get those errors and why do i not get only right when i turn right and only left when i turn left?Code:<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>right [len=6]<LF>right [len=6]<LF>right [len=6]<LF>right [len=6]<LF>left [len=5]<LF>right [len=6]<LF>right [len=6]<LF>right [len=6]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>left [len=5]<LF>right [len=6]<LF>right [len=6]<LF>left [len=5]<LF>ht [len=3]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>ight [len=5]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>right [len=6]<LF> [len=1]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>t [len=2]<LF>left [len=5]<LF>ight [len=5]<LF>left [len=5]<LF><LF>right [len=7]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>right [len=6]<LF>ght [len=4]<LF>left [len=5]<LF>ight [len=5]<LF>left [len=5]<LF>right [len=6]<LF>right [len=6]<LF>left [len=5]<LF>ht [len=3]<LF>left [len=5]<LF>t [len=2]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]<LF>t [len=2]<LF>left [len=5]<LF>left [len=5]<LF>left [len=5]<LF>t [len=2]<LF>left [len=5]<LF>right [len=6]<LF>left [len=5]

author: shebu18
author_rank: Frequent Contributor
timestamp: July 01, 2012, 12:09:21 pm
content: I can recommend thishttp://www.buxtronix.net/2011/10/rotary-encoders-done-properly.htmlfor a library and it is nice to add it to the code. It works on pins without or with interrupt and it does not take much space up.LE No debounce circuit is required but no for loop runs. It simply does not start running

author: Psi
author_rank: Super Contributor
timestamp: July 01, 2012, 12:29:23 pm
content: You maybe getting some switch bounce. (Where the contacts bounce back and forward before they settle).Google "rotary encoder hardware debounce"Also you have a bug in the code. You want to set oldvalue = value; but you have it the other way around.The way you have it oldvalue never gets set to anything.EDIT: Actually, looking at your code, you're using an external hardware interrupt for one of the connections.The hardware interrupt pins do rise/fall detection themselves, so you don't need any of that oldvalue stuff at all.(It's only needed when you're trying to work out rise/fall yourself in software)Try this scan function instead.void scan(){value=digitalRead(pinb);if(value == HIGH){Serial.println("right");}if(value == LOW){Serial.println("left");}}(i may have left/right reversed)

author: shebu18
author_rank: Frequent Contributor
timestamp: July 01, 2012, 05:25:17 pm
content: it work kind of. I need to debounce it in hardware. I can use the code i found an i do not need the hardware debounce. I am only curios if the loop works if no for loop works. Theoretically i do no need any for or while loop in my psu code.

author: Psi
author_rank: Super Contributor
timestamp: July 02, 2012, 03:01:59 am
content: You shouldn't do any delay loops, use the hardware timer to set variables like flags instead.

author: shebu18
author_rank: Frequent Contributor
timestamp: July 02, 2012, 04:36:48 am
content: Could you give me a example? Thank you.

author: shebu18
author_rank: Frequent Contributor
timestamp: October 19, 2012, 04:59:57 pm
content: Dave, how did you do the rotary encoder on your PSU?I want an increase or decrease of 1 on an click. Using a library found i get almost 4 steps decreased or incresed on one click. THe library is very precise, but not suited for my needs. I will try to write my one.

author: andersm
author_rank: Super Contributor
timestamp: October 19, 2012, 06:19:58 pm
content: Divide the library-provided position by 4? The quadrature encoder pins have four state transitions per "count", so by using each transition you can get 4 times the resolution. Obviously not so useful if you are using encoders with detents ("clicks"), but much better for eg. emulating a potentiometer.

author: AndreasF
author_rank: Frequent Contributor
timestamp: October 19, 2012, 06:26:28 pm
content: The last line of your scan() function is the wrong way around: you want to update the "oldvalue" variable (you had it reversed), therefore:Code:...oldvalue = value;}...That should do it.Edit: Oops, just saw that Psi already mentioned the oldvalue/value issue (and that it's actually not necessary), so please ignore me.