Moving a rotary encoder from pro-mini to Mega

Hi,

I'm trying to migrate a project from a pro-mini to a mega.

I have a rotary encoder Rotary Encoder - Illuminated (RGB) - COM-15141 - SparkFun Electronics that works when connected to analogue pins 0 and 1 on the pro-mini.

When I wire it up to the Mega (sticking with analogue pins 0 and 1) it doesn't work (i.e. no output on serial monitor). Here's the code....

/* Rotary encoder read example */
#define ENC_A 14  // Analogue pin 0
#define ENC_B 15  // Analogue pin 1
#define ENC_PORT PINC // The Port C Input Pins register - read only. (Port C is the analogue input pins)
 
// this code from https://www.circuitsathome.com/mcu/programming/reading-rotary-encoder-on-arduino 
// The encoder is this one.https://www.sparkfun.com/products/10982 
// And the datasheet http://cdn.sparkfun.com/datasheets/Components/Switches/EC12PLRGBSDVBF-D-25K-24-24C-6108-6HSPEC.pdf 
 
void setup()
{
  /* Setup encoder pins as inputs */
  pinMode(ENC_A, INPUT);
  digitalWrite(ENC_A, HIGH);   // turns on pull-up resistor on the pin so it won’t dangle in the air when switch is open
  pinMode(ENC_B, INPUT);
  digitalWrite(ENC_B, HIGH);   // turns on pull-up resistor on the pin so it won’t dangle in the air when switch is open
  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 ) {
    // If non-zero, the encoder is either rotating clockwise or counter clockwise
    Serial.print("Counter value: ");
    Serial.println(counter, DEC);
    counter += tmpdata;
  }
  
  // Simulate the microprocessor doing something
  delay(10);
}
 
/* returns change in encoder state (-1,0,1) */
/*
* -1 means clockwise, zero means 'invalid' and +1 means anti-clockwise.
* PREVIOUS CURRENT   RESULT
* A B      A B
* 0 0      0 0       -1 clockwise
*
*/
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}; // This is a static array, the contents should
                                                                      // remain unchanged.
  static uint8_t old_AB = 0;    // This is an 8 bit byte.
  /**/
  old_AB <<= 2;                   // remember previous state - shift each bit two places leftwards.  
                                  // Rightmost bits (bits 0 & 1) will now be set to 0,0. 
                                  // Example, if old_AB was 00000011, it will now be 00001100
  old_AB |= ( ENC_PORT & 0x03 );  // add current state. (Remember, 0x03 = 00000011)
                                  // The first bit "ENC_PORT & 0x03" reads the port to which encoder is connected and sets all but two lower bits to zero
                                  // The 2nd bit, "old_AB |=" ORs the previous state with the new state. The previous state will now be in bits 2 &3, and the
                                  // current state in bits 0 & 1.
                                  
  // Test if anything has changed.                                
  if ( (bitRead(old_AB,3) != bitRead(old_AB,1)) ||     (bitRead(old_AB,2) != bitRead(old_AB,0)))
  {  
    //Serial.print(bitRead(old_AB,3));Serial.print(bitRead(old_AB,2));Serial.print(bitRead(old_AB,1));Serial.print(bitRead(old_AB,0));
    int8_t result=enc_states[( old_AB & 0x0f )];
    if (result == -1)
    {
      Serial.println(" clockwise.");
    }
    else if (result == 1)
    {
      Serial.println(" anti-clockwise.");
    }
    else
    {
      Serial.println(" invalid.");
    }
  } 
                                  
  // Remember, 0x0f = 00001111. Th first bit here "old_AB & 0x0f" simply resets the 
  // first 4 bits to zero, because we're only interested in the current and previous values.
  // The 4 remaining bits, give us a number from 0 to 15, which is used as an index number to return a value from 
  // the enc_states[] array.
  return ( enc_states[( old_AB & 0x0f )]);
}

The code is cribbed off the web somewhere, and despite the fact I'm using, i must admit there are a couple of bits I don't understand.

  1. The code works (on the pro mini) but ENC_A is defined as pin 14 and ENC_B as pin 15 - but the encoder is physically connected to analogue pins 0 & 1.
  2. What is PINC? the comments say it's the input pins register, but what does this mean?
  3. most importantly, why doesn't this work on the Mega?

Thanks

I' using pins 18 and 19 on a Mega2560 Pro Mini in a polling mode using this function:

void setup()
{
    // a bunch of stuff...
   pinMode(PINA, INPUT_PULLUP);
   pinALast = digitalRead(PINA);

   pinMode(PINB, INPUT_PULLUP);
}


/*****
  Purpose: To read the KY-040 rotary encoder. This uses a polling method, so the symbolic
          constants for PIN1 and PINB can be any digital pin

  Paramter list:
    void

  Return value:
    int           it returns 1 (CW) -1 (CCW) 0 (no turn).
                  It also sets a global for the direction
*****/

int ReadEncoder()
{
  // static unsigned char encoder_A_prev = 0;
  aVal = digitalRead(PINA);    // Read encoder pins
  if (aVal != pinALast) {
    pinALast = aVal;
    // if the knob is rotating, we need to determine direction
    // We do that by reading pin B.
    if (digitalRead(PINB) != aVal) {  // Means pin A Changed first - We're Rotating Clockwise
      encoderDirection = CW;
      return encoderDirection;
    } else {// Otherwise B changed first and we're moving CCW
      encoderDirection = CCW;
      return encoderDirection;
    }
  }
  encoderDirection = 0;
  return encoderDirection;
}

The thee variables used in the function are globals defined with the volatile keyword. The function is called within loop(). While perhaps not ideal if you need really fast response times, it works pretty well.

Thanks econjack,

I was hoping to find a solution for my existing code and pinout - for one thing I've already physically built the board with the encoder on it, and I think what I've got ought to work on both mini-pro and mega.

My guess is that since the Mega and pro Mini have different number of pins the line....

#define ENC_PORT PINC // The Port C Input Pins register - read only. (Port C is the analogue input pins)

probably needs changing, have yout tried the A,B or D registers? (if they exist?)

sorry. just speculating, can't offer anything better

On the Mega analog pins 0-7 are on PINF.
Also, change the pin numbers to A0 and A1.
After that it should work.

PINC in the input registor for PORTC which is the analog inputs on the Pro Mini.

The Mega is an utterly different register layout, however (it has a dozen ports or so compared to the
ATmega328's 3 ports)

You have some high speed encoder reading code there which uses direct port access for speed
(its meant for a high resolution motor shaft encoder, not a control knob).

You should find something using digitalRead() instead, then you can say A0 and A1 or whatever for
your input pins.