ENCODERS AND OPTICAL LIMIT SWITCH

I'm working on a mini project that has 2 optical encoders (One for elevation axis & other Traverse axis), initially i was able to use one of the codes suggested in the forums and modify them to give me readings of both encoders; However, my next step is to connect a limit switch (Optical limit switch) to zero the encoder count whenever the switch is activated. If there's anyone who has done a similar project i would appreciate some guidance on this, Or even a code that serves a similar purpose.
P.S For this project i'm using MEGA 2560.
Thanks!

Sounds easy. On each pass through the loop() function, which will, of course, have no blocking code in it, read the limit switches. If any of them have been activated then zero the encoder count and, presumably stop the movement.

Do you know how to read the limit switches ? Try just reading one limit switch to start with and see how you get on.

Unfortunately i have never worked with limit switches, How is the connections & coding done?

Here's my current code: (I'm currently trying on one switch which is attached to the elevation Encoder)

enum PinAssignments {
 encoderPinA = 2,   // right
 encoderPinB = 3,// left
 encoderPinC = 20,
 encoderPinD = 21,
 
 clearButton = 8    // another two pins
};

volatile unsigned int encoderPos = 0;  // a counter for the dial
unsigned int lastReportedPos = 1;   // change management
volatile unsigned int encoderPos2 = 0;  // a counter for the dial
unsigned int lastReportedPos2 = 1;   // change management
static boolean rotating=false;      // debounce management

// interrupt service routine vars
boolean A_set = false;              
boolean B_set = false;
boolean C_set = false;
boolean D_set = false;

void setup() {

 pinMode(encoderPinA, INPUT); 
 pinMode(encoderPinB, INPUT); 
 pinMode(encoderPinC, INPUT); 
 pinMode(encoderPinD, INPUT);
 pinMode(clearButton, INPUT);
// turn on pullup resistors
 digitalWrite(encoderPinA, HIGH);
 digitalWrite(encoderPinB, HIGH);
 digitalWrite(encoderPinC, HIGH);
 digitalWrite(encoderPinD, HIGH);
 digitalWrite(clearButton, HIGH);

// encoder pin to interrupt (pin 2)
 attachInterrupt(digitalPinToInterrupt(encoderPinA), doEncoderA, CHANGE);
// encoder pin to interrupt (pin 3)
 attachInterrupt(digitalPinToInterrupt(encoderPinB), doEncoderB, CHANGE);
// encoder pin to interrupt (pin 20)
 attachInterrupt(digitalPinToInterrupt(encoderPinC), doEncoderC, CHANGE);
// encoder pin to interrupt (pin 21)
 attachInterrupt(digitalPinToInterrupt(encoderPinD), doEncoderD, CHANGE);
 Serial.begin(9600);  // output
}

// main loop, work is done by interrupt service routines, this one only prints stuff
void loop() { 
 rotating = true;  // reset the debouncer

 if (lastReportedPos != encoderPos) {
   Serial.print("TRAVERSE:");
   Serial.println(encoderPos, DEC);
   lastReportedPos = encoderPos;
 }
 if (digitalRead(clearButton) == LOW )  {
   encoderPos = 0;
 }

 
 if (lastReportedPos2 != encoderPos2) {
   Serial.print("ELEVATION:");
   Serial.println(encoderPos2, DEC);
   lastReportedPos2 = encoderPos2;
 }
 if (digitalRead(clearButton) == LOW )  {
   lastReportedPos2 = 0;
 }
}

// Interrupt on A changing state
void doEncoderA(){
 // debounce
 if ( rotating ) delay (1);  // wait a little until the bouncing is done

 // Test transition, did things really change? 
 if( digitalRead(encoderPinA) != A_set ) {  // debounce once more
   A_set = !A_set;

   // adjust counter + if A leads B
   if ( A_set && !B_set ) 
     encoderPos += 1;

   rotating = false;  // no more debouncing until loop() hits again
 }
}

// Interrupt on B changing state, same as A above
void doEncoderB(){
 if ( rotating ) delay (1);
 if( digitalRead(encoderPinB) != B_set ) {
   B_set = !B_set;
   //  adjust counter - 1 if B leads A
   if( B_set && !A_set ) 
     encoderPos -= 1;

   rotating = false;
 }
}
void doEncoderC(){
 // debounce
 if ( rotating ) delay (1);  // wait a little until the bouncing is done

 // Test transition, did things really change? 
 if( digitalRead(encoderPinC) != C_set ) {  // debounce once more
   C_set = !C_set;

   // adjust counter + if A leads B
   if ( C_set && !D_set ) 
     encoderPos2 += 1;

   rotating = false;  // no more debouncing until loop() hits again
 }
}
// Interrupt on B changing state, same as A above
void doEncoderD(){
 if ( rotating ) delay (1);
 if( digitalRead(encoderPinD) != D_set ) {
   D_set = !D_set;
   //  adjust counter - 1 if B leads A
   if( D_set && !C_set ) 
     encoderPos2 -= 1;

   rotating = false;
 }
}

Unfortunately i have never worked with limit switches, How is the connections & coding done?

This example of how to read the state of an input is already in your code. What have you got connected to pin 8 ?

digitalRead(clearButton)

Nothing is connected to pin 8.

i connected the limit switch to 5V, GND and pin 30.

elburjr:
i connected the limit switch to 5V, GND and pin 30.

You need to post the datasheet for the limit switch you are using.

...R

Hi,

Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html
then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks. Tom... :slight_smile:

Thanks for the remark Tom!

Regarding my project, I managed to make it work perfectly!

Here's the final code for others to benefit:

enum PinAssignments {
  encoderPinA = 2,   // right
  encoderPinB = 3,// left
  encoderPinC = 20,
  encoderPinD = 21,
  
  clearButton = 8    // another two pins

};
int limitswitch1 = 7;                                       //input switch1; pin 30
int limitswitch2 = 48;                                       //input switch2; pin 48
int LEDPin = 13;                                            // output,indicator; pin 13
volatile unsigned int encoderPos = 0;  // a counter for the dial
unsigned int lastReportedPos = 1;   // change management
volatile unsigned int encoderPos2 = 0;  // a counter for the dial
unsigned int lastReportedPos2 = 1;   // change management
static boolean rotating=false;      // debounce management

// interrupt service routine vars
boolean A_set = false;              
boolean B_set = false;
boolean C_set = false;
boolean D_set = false;

void setup() {

  pinMode(encoderPinA, INPUT); 
  pinMode(encoderPinB, INPUT); 
  pinMode(encoderPinC, INPUT); 
  pinMode(encoderPinD, INPUT);
  pinMode(limitswitch1, INPUT);
  pinMode(limitswitch2, INPUT);
  pinMode(clearButton, INPUT);
 // turn on pullup resistors
  digitalWrite(encoderPinA, HIGH);
  digitalWrite(encoderPinB, HIGH);
  digitalWrite(encoderPinC, HIGH);
  digitalWrite(encoderPinD, HIGH);
  digitalWrite(clearButton, HIGH);
  digitalWrite(limitswitch1, HIGH);
  digitalWrite(limitswitch2, HIGH);
  
// encoder pin to interrupt (pin 2)
  attachInterrupt(digitalPinToInterrupt(encoderPinA), doEncoderA, CHANGE);
// encoder pin to interrupt (pin 3)
  attachInterrupt(digitalPinToInterrupt(encoderPinB), doEncoderB, CHANGE);
// encoder pin to interrupt (pin 20)
  attachInterrupt(digitalPinToInterrupt(encoderPinC), doEncoderC, CHANGE);
// encoder pin to interrupt (pin 21)
  attachInterrupt(digitalPinToInterrupt(encoderPinD), doEncoderD, CHANGE);
  Serial.begin(9600);  // output

  Serial1.begin (9600);                                     // initialise serial port at 9600 baud rate
  Serial2.begin (9600);     
  pinMode(LEDPin, OUTPUT);                                  //output indicator for limitswitches
  pinMode(limitswitch1, INPUT);                             //input sense for limitswitch1
  pinMode(limitswitch2, INPUT);                             //input sense for limitswitch2
}

// main loop, work is done by interrupt service routines, this one only prints stuff
void loop() { 
  rotating = true;  // reset the debouncer

  if (lastReportedPos != encoderPos) {
    Serial.print("TRAVERSE:");
    Serial.println(encoderPos, DEC);
    lastReportedPos = encoderPos;
  }
  if (digitalRead(clearButton) == LOW )  {
    encoderPos = 0;
  }

  
  if (lastReportedPos2 != encoderPos2) {
    Serial.print("ELEVATION:");
    Serial.println(encoderPos2, DEC);
    lastReportedPos2 = encoderPos2;
  }
  if (digitalRead(clearButton) == LOW )  {
    encoderPos2 = 0;
  }

  
  if (digitalRead(limitswitch1) == HIGH)         //limitswitch1 read 0V; blocked
  {
     encoderPos = 0;                         // Count Zeroing
  }     

  if (digitalRead(limitswitch2) == HIGH)

  { 
	encoderPos2 = 0;
  }
}

// Interrupt on A changing state
void doEncoderA(){
  // debounce
  if ( rotating ) delay (1);  // wait a little until the bouncing is done

  // Test transition, did things really change? 
  if( digitalRead(encoderPinA) != A_set ) {  // debounce once more
    A_set = !A_set;

    // adjust counter + if A leads B
    if ( A_set && !B_set ) 
      encoderPos += 1;

    rotating = false;  // no more debouncing until loop() hits again
  }
}

// Interrupt on B changing state, same as A above
void doEncoderB(){
  if ( rotating ) delay (1);
  if( digitalRead(encoderPinB) != B_set ) {
    B_set = !B_set;
    //  adjust counter - 1 if B leads A
    if( B_set && !A_set ) 
      encoderPos -= 1;

    rotating = false;
  }
}
void doEncoderC(){
  // debounce
  if ( rotating ) delay (1);  // wait a little until the bouncing is done

  // Test transition, did things really change? 
  if( digitalRead(encoderPinC) != C_set ) {  // debounce once more
    C_set = !C_set;

    // adjust counter + if A leads B
    if ( C_set && !D_set ) 
      encoderPos2 += 1;

    rotating = false;  // no more debouncing until loop() hits again
  }
}
// Interrupt on D changing state, same as D above
void doEncoderD(){
  if ( rotating ) delay (1);
  if( digitalRead(encoderPinD) != D_set ) {
    D_set = !D_set;
    //  adjust counter - 1 if D leads C
    if( D_set && !C_set ) 
      encoderPos2 -= 1;

    rotating = false;
  }
}

Some comments :

// interrupt service routine vars
boolean A_set = false;              
boolean B_set = false;
boolean C_set = false;
boolean D_set = false;

Variables whose value is changed within an ISR should be declared volatile

 if ( rotating ) delay (1);  // wait a little until the bouncing is done

delay() does not work within an ISR because interrupts are disabled.

int limitswitch1 = 7;                                       //input switch1; pin 30
int limitswitch2 = 48;                                       //input switch2; pin 48
int LEDPin = 13;                                            // output,indicator; pin 13

Could be declared as const byte to save memory.

  Serial1.begin (9600);                                     // initialise serial port at 9600 baud rate
  Serial2.begin (9600);

Why ?

  pinMode(encoderPinA, INPUT); 
  digitalWrite(encoderPinA, HIGH);
//etc

could bepinMode(encoderPinA, INPUT_PULLUP); Your comment helps but why use two statements when one will do ?

You seem to have only two limit switches but two axes of movement, each with two end points. That seems strange but I don't know exactly what your hardware consists of and what it does.

Thanks for the tips!

Although i have come a long way on my project and i'm almost finalizing it, There seems to be one last obstacle.
My problem now is that on my second encoder (Traverse) i can't seem to hold the variable since i'm guessing there's 2 axis movement on it alone so the count of the encoder keeps increasing on the same axis.

How can i possibly hold the variable so the count doesn't keep increasing ridiculously when going back and forth in 1 axis?

Also here's the current code:

enum PinAssignments {
  encoderPinA = 2,   // right
  encoderPinB = 3,// left
  encoderPinC = 20,
  encoderPinD = 21,
  
  clearButton = 8    // another two pins

};
int limitswitch1 = 7;                                       //input switch1; pin 7
int limitswitch2 = 9;                                       //input switch2; pin 48
int LEDPin = 13;                                            // output,indicator; pin 13
volatile unsigned int encoderPos = 0;  // a counter for the dial
unsigned int lastReportedPos = 1;   // change management
volatile unsigned int encoderPos2 = 0;  // a counter for the dial
unsigned int lastReportedPos2 = 1;   // change management
static boolean rotating=false;      // debounce management

// interrupt service routine vars
boolean A_set = false;              
boolean B_set = false;
boolean C_set = false;
boolean D_set = false;

void setup() {
// Declare pins as INUPT && Turn on pull up resistors
  pinMode(encoderPinA, INPUT_PULLUP); 
  pinMode(encoderPinB, INPUT_PULLUP); 
  pinMode(encoderPinC, INPUT_PULLUP); 
  pinMode(encoderPinD, INPUT_PULLUP);
  pinMode(limitswitch1, INPUT_PULLUP);
  pinMode(limitswitch2, INPUT_PULLUP);
  pinMode(clearButton, INPUT_PULLUP);
  pinMode(LEDPin, OUTPUT); //output indicator for limitswitches
  
// encoder pin to interrupt (pin 2)
  attachInterrupt(digitalPinToInterrupt(encoderPinA), doEncoderA, CHANGE);
// encoder pin to interrupt (pin 3)
  attachInterrupt(digitalPinToInterrupt(encoderPinB), doEncoderB, CHANGE);
// encoder pin to interrupt (pin 20)
  attachInterrupt(digitalPinToInterrupt(encoderPinC), doEncoderC, CHANGE);
// encoder pin to interrupt (pin 21)
  attachInterrupt(digitalPinToInterrupt(encoderPinD), doEncoderD, CHANGE);
  Serial.begin(9600);  // output

}
// main loop, work is done by interrupt service routines, this one only prints stuff
void loop() { 
  rotating = true;  // reset the debouncer

  if (lastReportedPos != encoderPos) {
    Serial.print("TRAVERSE:");
    Serial.println(encoderPos, DEC);
    lastReportedPos = encoderPos;
  }
  if (digitalRead(clearButton) == LOW )  {
    encoderPos = 0;
  }

  if (lastReportedPos2 != encoderPos2) {
    Serial.print("ELEVATION:");
    Serial.println(encoderPos2, DEC);
    lastReportedPos2 = encoderPos2;
  }
  if (digitalRead(clearButton) == LOW )  
  {
    encoderPos2 = 0;        // Elevation Encoder's Count Zeroing
  }

  
  if (digitalRead(limitswitch1) == HIGH)         //limitswitch1 read 0V; blocked
  {
     encoderPos = 0;                         // Traverse Encoder's Count Zeroing
  }     

  if (digitalRead(limitswitch2) == HIGH)
  {
    encoderPos2 = 0;
   }
  
}

// Interrupt on A changing state
void doEncoderA(){
  // debounce
  if ( rotating ) delay (1);  // wait a little until the bouncing is done

  // Test transition, did things really change? 
  if( digitalRead(encoderPinA) != A_set ) {  // debounce once more
    A_set = !A_set;

    // adjust counter + if A leads B
    if ( A_set && !B_set ) 
      encoderPos += 1;

    rotating = false;  // no more debouncing until loop() hits again
  }
}

// Interrupt on B changing state, same as A above
void doEncoderB(){
  if ( rotating ) delay (1);
  if( digitalRead(encoderPinB) != B_set ) {
    B_set = !B_set;
    //  adjust counter - 1 if B leads A
    if( B_set && !A_set ) 
      encoderPos -= 1;

    rotating = false;
  }
}
// Interrupt on D changing state
void doEncoderD(){
  // debounce
  if ( rotating ) delay (1);  // wait a little until the bouncing is done

  // Test transition, did things really change? 
  if( digitalRead(encoderPinD) != D_set ) {  // debounce once more
    D_set = !D_set;

    // adjust counter + if D leads C
    if ( D_set && !C_set ) {
      encoderPos2 += 1;
    }
    rotating = false;  // no more debouncing until loop() hits again
  }
}
// Interrupt on C changing state
void doEncoderC(){
  if ( rotating ) delay (1);
  if( digitalRead(encoderPinC) != C_set ) {
    C_set = !C_set;
    //  adjust counter - 1 if C leads D
    if( C_set && !D_set ) {
      encoderPos2 -= 1;
    }
    rotating = false;
  
}

}