Pages: [1]   Go Down
Author Topic: Rotary Encoder Tutorial port to Arduino Uno  (Read 2587 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 47
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm using this tutorial to try to program my Arduino Uno to read a rotary encoder: http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino

The difference is he is on a Atmega168 platform where the Uno is Atmega328. I have the A side of my encoder in A5 and the B side in A4, but have tried them reversed too. I've adjusted the code thusly:

#define ENC_A A5
#define ENC_B A4
#define ENC_PORT PINC

I haven't made any changes in the read_encoder function though. I suspect the hex values should be different?

At this poing I get the following output:

Starting
Counter value: 0
Counter value: 1

Then nothing else, no matter how I turn the knob. Any suggestions? Thanks,

David


Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8975
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
old_AB |= ( ENC_PORT & 0x03 );  //add current state

One thing they forgot to mention is that the two pins MUST be the bottom two bits of the port.

Your choices are:
PIND 0,1 (Serial port, probably not a good choice)
PINB 8,9  (Probably a good choice)
PINC A0,A1  (The pins used in the example)

Alternatively you can select other pairs of adjacent pins with a shift before the mask:

For 2,3 change the code to:
Code:
old_AB |= ( (PIND >> 2) & 0x03 );  //add current state

For 3,4 change to
Code:
old_AB |= ( (PIND >> 3) & 0x03 );  //add current state

For A4,A5 change to:
Code:
old_AB |= ( (PINC >> 4) & 0x03 );  //add current state

Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Newbie
*
Karma: 0
Posts: 47
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks. I've still got dramas though. I've decided to go with A0 and A1. At the moment though I can only ever get the encoder to change values if I'm touching the metal housing with my hand. I'm tried it with 5V common and swapping A and B to see if I've got them right.

Should there be pullup resistors in the circuit(I saw them mentioned in the tutorial, but no details). Also should the common be 5V or GND? Thanks,

David
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8975
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

For an optical encoder you would have four pins:  +5, Ground, A and B.

Is this a mechanical encoder with only three terminals?  In that case you could connect the common to Ground and use pull-up resistors (either the built-in ones or external fro the input pin to +5).  Alternatively you can connect the common to +5 and use pull-dowm resistors from the input pins to Ground.  Without pull-up or pull-down resistors the switches are switching between +5 and floating or Ground and floating.  When left floating the input could read HIGH or LOW randomly.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Newbie
*
Karma: 0
Posts: 47
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yeah it's a mechanical encoder, specifically this one: http://www.sparkfun.com/products/10596

I guess I'm a bit unclear on the idea of pullup and pulldown resistors and the need for them. I don't quite get why I/O lines float, or why it's suggested to use 220k resistors for such purpose in some of the tutorials. Some tutorials don't even seem to use them. Can you point me to a good reference or what I should be looking up? Thanks,

David
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8975
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

http://arduino.cc/it/Tutorial/Button
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As per your suggestion, I was trying to use pins 10 &11 with the following change: "old_AB |= ( (PIND >> 2) & 0x03 );"
 but had no luck. I am still only able to read pin 1 and 2 on all 3 ports, so I was wondering what other change might need to be made?
THanks in advance, this was really helpful thread

Code:

#define ENC_A 10
#define ENC_B 11
#define ENC_PORT PINB

//see the website for changing this
 
void setup()
{
  /* Setup encoder pins as inputs */
  pinMode(ENC_A, INPUT);
  digitalWrite(ENC_A, HIGH);
  pinMode(ENC_B, INPUT);
  digitalWrite(ENC_B, HIGH);
  Serial.begin (115200);
  Serial.println("Start");
}
 
void loop()
{
 static uint8_t counter = 0;      //this variable will be changed by encoder input
 int8_t tmpdata;
 /**/
  tmpdata = read_encoder();
  if( tmpdata ) {
    Serial.print("Counter value: ");
    Serial.println(counter, DEC);
    counter += tmpdata;
  }
}
 
/* returns change in encoder state (-1,0,1) */
int8_t read_encoder()
{
  static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
  static uint8_t old_AB = 0;
  /**/
  old_AB <<= 2;                   //remember previous state
old_AB |= ( (PIND >> 2) & 0x03 );  //add current state
uint8_t new_AB=old_AB >> 4;
  return ( enc_states[( new_AB & 0x0f )]);
}
Logged

Norfolk UK
Offline Offline
Faraday Member
**
Karma: 71
Posts: 2614
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is a excerpt of a program/project that used the sparkfun encoder. Should be easy to convert to your needs.
Code:
//Constants
const int encButton = 5;                         //Rotary Encoder button pin (11)
const int encoder0PinA = 6;                      //Rotary Encoder A pin (12)
const int encoder0PinB = 7;                      //Rotary Encoder B pin (13)
const long debounceDelay = 30;                   //Button debounce time


// Button = pin number to read
int checkButton(int Button) {
  int buttonState = digitalRead(Button);          // Read button
  if (buttonState == HIGH) {                      // If button pressed then wait a bit to allow for debounce
    long Time = millis();
    while ((millis() - Time) < debounceDelay) {   
    }
    buttonState = digitalRead(Button);            // Read button again
    return buttonState;                           // Return button state
  }
  else {                                          //Button not pressed so no need to wait for bebounce
    return LOW;
  }
}

int readEncoder() {
  static int encoder0PinALast = LOW;
  int eDir = 0;
  int n = digitalRead(encoder0PinA);
  if ((encoder0PinALast == LOW) && (n == HIGH)) {
    if (digitalRead(encoder0PinB) == LOW) {
      eDir = -1;
      //Serial.print("-1");
    }
    else {
      eDir = 1;
      //Serial.print("1");
    }
  }
  encoder0PinALast = n;
  //Serial.println(eDir);
  return eDir;
}
Logged


Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Alternatively...

There are more portable ways to do it, particularly in arduino:

Code:
#define PIN_A  5  //encoder pin a
#define PIN_B 6 //encoder pin b

old_AB |= ((digitalRead(PIN_B))?(1<<1):0) | ((digitalRead(PIN_A)?(1<<0):0);  //( ENC_PORT & 0x03 );  //add current state

When you move pins, you just need to redefine them and compile.
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8975
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As per your suggestion, I was trying to use pins 10 &11 with the following change: "old_AB |= ( (PIND >> 2) & 0x03 );" but had no luck.
Code:
#define ENC_PORT PINB

old_AB |= ( (PIND >> 2) & 0x03 );  //add current state

You have to use the PINB register for pins 10 and 11.  Try it this way:
Code:
#define ENC_PORT PINB

old_AB |= ( (ENC_PORT >> 2) & 0x03 );  //add current state
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Pages: [1]   Go Up
Jump to: