Rotary Encoder Problem

Hello, I hope this is the correct place to post this. Couldn't find anywhere that involved the coding of random parts.

Alright so, I'm trying to use a rotary encoder from spark fun. Its pretty straightforward, two outputs (A and B) and a SW output.

//these pins can not be changed 2/3 are special pins
int encoderPin1 = 4;
int encoderPin2 = 3;
int encoderSwitch = 7; 

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

void setup() {
  Serial.begin (9600);

  pinMode(encoderPin1, INPUT);
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on
  digitalWrite(encoderSwitch,HIGH); 
  
  

  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3) 
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);

}

void loop(){
  
if(encoderSwitch > 0)
{
  analogWrite(A0, 255);
}



while(encoderValue  == lastencoderValue)
{
  analogWrite(A3, 255); 
  analogWrite(A4, 0);
  analogWrite(A2,0); 
}
if (encoderValue > lastencoderValue)
{
analogWrite(A4, 255); 
analogWrite(A2, 0);

}
if (encoderValue < lastencoderValue)
{
analogWrite(A2, 255); 
analogWrite(A4, 0); 

}
  
  Serial.println(encoderValue);
  delay(1000); //just here to slow down the output, and show it will work  even during a delay
}

void updateEncoder(){
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int 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
}

I'm trying to verify that my code works with 4 LED's. I have a base LED that lights up when the lastencodervalue is equal to the encoded value, and an Up and Down LED for when the encoder is turned CW or CCW. I also have a switch LED for when the pushbutton is pressed.

Here is my problem(s)

As stated before, I want my LED's to light when they're increasing or decreasing. A problem I'm having is that the LED will light when turned CW (causing the encoded value to go up, viewable via serial monitor), but when I turn the encoder CCW, the up LED only turns off when the count coming out of the A and B get below Zero. (Viewable via serial monitor)

Another problem is the switch. I thought that when the switch is pressed that it would send a high pulse in, so I tried to make a statement that was along the lines of

if (encoderSwitch == HIGH)
{
analogWrite(A0, 255) //supplies 5V to the LED on pin A0 when Pin is pressed
}

But this doesn't yield any results.

Help?

Thank you!

Note all the comments that says

 //these pins can not be changed 2/3 are special pins

And note how you have the pins defined:

int encoderPin1 = 4;
int encoderPin2 = 3;

A and B should be connected to 2 and 3, not 3 and 4.

I wish the 328 had more interrupts. My biggest beef with it. I have a TTL circuit that updates one or more 193 counters so I don't have to use both available interrupts or run a tight loop just to keep up with an encoder and obviously it supports more than one encoder - as many as I care to lay down chips for. That's one reason I want to learn about CPLDs now, to see if I can implement my encoder counter into a CPLD and have it as one chip.

And this applies to your original post? How?

Doc

More interrupts is a common problem.

Look up Pin Change Interrupts.

see
http://arduino.cc/playground/Main/PcInt
and
http://arduino.cc/playground/Main/PinChangeInt

Also it is helpful to search the forum and playground for solutions before posting. Most of the time, someone else has had the same problem, and probably posted a solution.

Here is my problem(s)

As stated before, I want my LED's to light when they're increasing or decreasing. A problem I'm having is that the LED will light when turned CW (causing the encoded value to go up, viewable via serial monitor), but when I turn the encoder CCW, the up LED only turns off when the count coming out of the A and B get below Zero. (Viewable via serial monitor)

You never update the value of lastEncoded, so it is always 0.

Another problem is the switch. I thought that when the switch is pressed that it would send a high pulse in, so I tried to make a statement that was along the lines of

if (encoderSwitch == HIGH)
{
analogWrite(A0, 255) //supplies 5V to the LED on pin A0 when Pin is pressed
}

But this doesn't yield any results.

The variable encoderSwitch is a pin number. To get the actual value you have to do a digitalRead(). Also make sure it's set as an input. I recommend reading some of the examples http://arduino.cc/en/Tutorial/HomePage, and all of the documentation Arduino - Home.

I recently developed code for an incremental rotary encoder based on a state machine.
Code for Arduino is included: Google Code Archive - Long-term storage for Google Code Project Hosting.

Oliver

Here is a test program I wrote a while back to adjust date & time of a DS3231 RTC using the same rotary encoder you have. You should be able to cut out the bit(s) you need.
The main part is readEncoder that returns -1,0,1 depending of encoder direction. The other interesting bit is checkButton that returns button press state.

#include <Wire.h>
#include <RealTimeClockDS3231.h>

//Enumerations
const int eHours = 0;
const int eMinutes = 1;
const int eDay = 2;
const int eMonth = 3;
const int eYear = 4;
const int eDOW = 5;

//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 = 90;                   //Button debounce time
const long adjustDelay = 10000;                  //10 Second Adjust timeout

//Globals
char formatted[] = "0000-00-00 00:00:00x";

void setup() {
  //  Wire.begin();
  pinMode (encoder0PinA,INPUT);
  digitalWrite(encoder0PinA,HIGH);               //Enable pullup resistor
  pinMode (encoder0PinB,INPUT);
  digitalWrite(encoder0PinB,HIGH);               //Enable pullup resistor
  pinMode (encButton,INPUT);                     //Encoder button is set to input
  Serial.begin(9600);
}

void loop() {
  long loopTime = millis();                 //Read timer
  int mainDelay = 1000;                      // Default main loop delay

  while ((millis() - loopTime) < mainDelay) {

    if (checkButton(encButton)){
      while (checkButton(encButton)){             //Wait for button to be released
      };
      delay(100);
      digitalWrite(13, HIGH);   // set the LED on
      //Serial.println("Button On");
      eAdjust();
      //Serial.println("Button Off");
      digitalWrite(13, LOW);   // set the LED on
    }

  }

  RTC.readClock();				 //Read the current date and time
  RTC.getFormatted2k(formatted);
  Serial.println(formatted);
}

// Called from main loop when encoder button pressed
void eAdjust(){
  RTC.readClock();				  //Read the current date and time
  int value = readEncoder();                      //Init encoder readback value and prime encoder sub (result discarded)
  int eMode = eHours;                             //Set mode to eHours
  doDisplay(eMode);                               //Display Hours

  long eTime = millis();			  //Get current CPU time for adjust loop timeout
  while ((millis() - eTime) < adjustDelay) {

    if (checkButton(encButton)){                  //Is encoder button pressed?
      // Mode button pressed
      //Serial.println("Button Pressed");
      while (checkButton(encButton)){             //Wait for button to be released
      };
      delay(100);                                 //Slight delay to allow for button debounce
      //Serial.println("Button Released");
      eMode++;				          //Increment mode
      if (eMode > eDOW){                          //End of modes?
        // Mode cycled past end
        RTC.setSeconds(0);                        //Zero seconds
        RTC.setClock();                           //Set the clock
        //Serial.println("Mode Exit");
        return;                                   //Return
      }
      RTC.getFormatted2k(formatted);
      Serial.println(formatted);
      doDisplay(eMode);		                  //Display the new mode
      eTime = millis();		                  //Reset adjust loop timout
    }

    if (millis() % 10 == 0){                      //Only read every 10mS
      int result = readEncoder();                 //Read encoder. Returns -1,0,1
      //Serial.print("Encoder: ");
      if (!result == 0){			  //Encoder <> 0
        //Encoder wheel was turned
        //Serial.print("Encoder Turned");
        switch (eMode){
        case eHours:                              //Mode eHours
          value = RTC.getHours() + result;        //Read hours and add encoder direction
          RTC.setHours(value % 24);               //Store new hours after legalizing
          break;                                  //No further processing
        case eMinutes:
          value = RTC.getMinutes() + result;
          RTC.setMinutes(value % 60);
          break;
        case eDay:
          value = RTC.getDate() + result;
          RTC.setDate(value % 31);
          break;
        case eMonth:
          value = RTC.getMonth() + result;
          RTC.setMonth(value % 12);
          break;
        case eYear:
          value = RTC.getYear() + result;
          RTC.setYear(value % 99);
          break;
        case eDOW:
          value = RTC.getDayOfWeek() + result;
          RTC.setDayOfWeek(value % 7);
          break;
        default:                                  //What to do if mode unknown
          break;                                  //Nothing
        }
        doDisplay(eMode);                         //Display new mode
        eTime = millis();                         //Reset adjust loop timout
      }
    }
  }
  //Timed out
  //RTC.setClock();
  Serial.println("Timeout");
}

void doDisplay(int Mode){                         //Display relevent data for given mode
  Serial.print("Mode ");
  Serial.print(Mode);
  Serial.print(": ");
  switch (Mode){
  case eHours:
    Serial.println(RTC.getHours());
    break;
  case eMinutes:
    Serial.println(RTC.getMinutes());
    break;
  case eDay:
    Serial.println(RTC.getDate());
    break;
  case eMonth:
    Serial.println(RTC.getMonth());
    break;
  case eYear:
    Serial.println(RTC.getYear());
    break;
  case eDOW:
    Serial.println(RTC.getDayOfWeek());
    break;
  default:
    break;
  }
}	

// 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;
}