Go Down

Topic: Problems with Alps Rotary Encoder (Read 3717 times) previous topic - next topic

Zeecue

Hi

I just got my hands on 3 Alps Rotary Encoders, but when i use the different sketches, i need to turn the knop "2 times" before the sketch senses that i turn the knop.
I have wired it up like this.

D to ground
C and E to 5v over a 10k ohm resistor and to pins 2 and 3 on my Seeeduino Mega
The signals on the picture is "homemade" using 2 leds and noticing their behavior.

Code: [Select]
#define encoder0PinA 2
#define encoder0PinB 3

volatile unsigned int encoder0Pos = 0;
unsigned int tmp_Pos = 1;
unsigned int valx;
unsigned int valy;
unsigned int valz;

boolean A_set;
boolean B_set;


void setup() {

 pinMode(encoder0PinA, INPUT);
 pinMode(encoder0PinB, INPUT);

// encoder pin on interrupt 0 (pin 2)
 attachInterrupt(0, doEncoderA, CHANGE);

// encoder pin on interrupt 1 (pin 3)
 attachInterrupt(1, doEncoderB, CHANGE);

 Serial.begin (9600);
}


void loop(){
//Check each second for change in position
 if (tmp_Pos != encoder0Pos) {
   Serial.print("Index:"); Serial.print(encoder0Pos, DEC); Serial.print(", Values: ");
   Serial.print(valx, DEC); Serial.print(", ");
   Serial.print(valy, DEC); Serial.print(", ");
   Serial.print(valz, DEC); Serial.println();
   tmp_Pos = encoder0Pos;
 }
 delay(1000);
}


// Interrupt on A changing state
void doEncoderA(){

 // Low to High transition?
 if (digitalRead(encoder0PinA) == HIGH) {
   A_set = true;
   if (!B_set) {
     encoder0Pos = encoder0Pos + 1;
     valx=analogRead(0);
     valy=analogRead(1);
     valz=analogRead(2);
   }        
 }

 // High-to-low transition?
 if (digitalRead(encoder0PinA) == LOW) {
   A_set = false;
 }

}

// Interrupt on B changing state
void doEncoderB(){

 // Low-to-high transition?
 if (digitalRead(encoder0PinB) == HIGH) {  
   B_set = true;
   if (!A_set) {
     encoder0Pos = encoder0Pos - 1;
   }
 }

 // High-to-low transition?
 if (digitalRead(encoder0PinB) == LOW) {
   B_set = false;
 }
}


Best Regards
Morten

mrmeval

Try this first
http://www.arduino.cc/playground/Main/RotaryEncoders

Read all of it and take notes, the author needs a copy editor. Info is scattered about.

You're using analog, not needed and probably not wanted. All encoders do is use two pulses with one leading the other to determine direction and how fast the pulses are to determine speed.

Interrupts will hammer the Arduino and force it to read that control. You will get better precision but the cost is interrupting your code.


Zeecue

Hi again

I have read the most of the site about encoders, and tried all the sketches, the one i got to work the best is the one i posted.
Maybe someone could show me some code, that dont use analog in, but just digital.

I want to use the encoders for volume and skip number functions on a car pc, so the arduino just need to have a couple of buttons mounted and maybe a couple relays, so it should have enough power to do that, and i dont think interupts will be a bad thing when it only need to do these things.

brtech

You copied the code without understanding what it does.  You can just delete the analog read commands.  The guy that wrote the code needed them for his application, but you don't.

When you say that you have to turn the knob two times to get an output, do you mean you have to make two complete turns of the encoder, or just 2/24's (or however many pulses per revolution the encoder you have does)?

The code only prints once per second if it detects motion.  Let it print the 0, wait, and turn the knob a little, then wait.  What happens?

Zeecue

Hi, and thank you for the good answer.

The encoder has 30 "detents" and i need to turn it over 2 "detents" before the sketch recognises that i turn the knop, i have tried to change the delay from 1000ms, to 10ms, and slowly turning the knop, it still does the same.

brtech

Well, I had an aha moment on this one.

Perhaps I wasn't understanding what the symptom is.

I originally understood it to be that when you first turn in on, it prints position=0.  You rotate through detent 1, nothing.  Rotate through detent 2, nothing.  Rotate through detent 3, position=1.  Rotate through detent 4, position=2.  It works from then on, each detent, you get one count.

If that is it, there is some initialization problem that I can't spot, although there is a slight problem with A_set and B_set.  You should initialize them in setup().  Right after pinMode(encoder0PinB, INPUT); add
Code: [Select]

  A_set=digitalRead(encoder0PinA);
  B_set=digitalRead(encoder0PinB);


That, however, would only cause the first detent to not be detected sometimes.

BUT

Maybe what you are trying to tell us is that every other detent is ignored, so you get a count on the first detent, not on the second, count on the third, none on the fourth, and so forth.  Is that what you are seeing?

If that's it, then you are getting what the second sketch in the playground article addresses: the encoder really is designed to increment on both the low to high and high to low transitions.  The code is easily fixed to do this.  In the bottom of doEncoderA(), after A_set=false; add:
Code: [Select]

   if (B_set) encoder0Pos = encoder0Pos + 1;


and similarly, in doEncoderB, after B_set=false; add:
Code: [Select]

   if (A_set) encoder0Pos = encoder0Pos - 1;


Note the absence of the bang.  On the low to high transition, you want the other signal to be low to count.  On the high to low transition, you want the other input to be high.  

One minor point on this code.  I believe the
Code: [Select]

if(digitalRead(encoder0PinA) == LOW) {

can be replaced with
Code: [Select]

else {


Although it works with the original, there is no need to read the pin again.  If it is not HIGH, then it is LOW.

   

Go Up