Go Down

Topic: rotary encoder limiting (Read 4228 times) previous topic - next topic

thereyouare

How to limit the newposition between 0 to 4?

I don't want it to count bigger than 4 and count smaller than 0

Code: [Select]

#include <Encoder.h>


Encoder myEnc(5, 6);


void setup() {
  pinMode(9, OUTPUT);
    pinMode(10, OUTPUT);
      pinMode(11, OUTPUT);
        pinMode(12, OUTPUT);
  Serial.begin(9600);
  Serial.println("Basic Encoder Test:");
}

long oldPosition  = -999;

void loop() {
  long newPosition = myEnc.read();
  if (newPosition != oldPosition) {
    oldPosition = newPosition;


   if (newPosition ==1)

{
  digitalWrite(9,LOW);
digitalWrite(10,LOW);
digitalWrite(11,LOW);
digitalWrite(12,HIGH);


}
if (newPosition ==2)
{
  digitalWrite(9,LOW);
digitalWrite(10,LOW);
digitalWrite(11,HIGH);
digitalWrite(12,LOW);


}
if (newPosition ==3)
{
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
digitalWrite(11,LOW);
digitalWrite(12,LOW);

}

if (newPosition ==4)
{
digitalWrite(9,HIGH);
digitalWrite(10,LOW);
digitalWrite(11,LOW);
digitalWrite(12,LOW);

}

  }
}

jremington

#1
Jan 07, 2014, 12:50 am Last Edit: Jan 07, 2014, 04:11 am by jremington Reason: 1
if counting forwards, use
if (newPosition > 4) newPosition = 0;

if counting backwards, use
if (newPosition < 0) newPosition = 4;

thereyouare

#2
Jan 07, 2014, 09:12 am Last Edit: Jan 07, 2014, 11:35 am by thereyouare Reason: 1
Thanks but still having a problem.I have used this.
Code: [Select]
if (newPosition > 4) newPosition = 4;

if counting backwards, use
if (newPosition < 0) newPosition = 0;


It doesn't print bigger than 4 but it counts.When I turn the knob 10 steps forward,in serial monitor arduino prints  "1,2,3,4,4,4,4,4,4,4"   .It's OK.But from that position ,when I turn the knob 10 steps backward,arduino prints "4,4,4,4,4,4,4,3,2,1." instead of  "4,3,2,1,0,0,0,0,0,0".

How to resume counting if it is bigger than 4 or smaller than 0?

elac

Try this:
Code: [Select]
/* interrupt routine for Rotary Encoders


The average rotary encoder has three pins, seen from front: A C B
Clockwise rotation A(on)->B(on)->A(off)->B(off)
CounterCW rotation B(on)->A(on)->B(off)->A(off)

and may be a push switch with another two pins, pulled low at pin 8 in this case


*/

// usually the rotary encoders three pins have the ground pin in the middle
enum PinAssignments {
  encoderPinA = 2,   // right (labeled DT on our decoder, yellow wire)
  encoderPinB = 3,   // left (labeled CLK on our decoder, green wire)
  clearButton = 8    // switch (labeled SW on our decoder, orange wire)
                // connect the +5v and gnd appropriately
};

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

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

int pressCount = 0;

void setup() {

  pinMode(encoderPinA, INPUT_PULLUP); // new method of enabling pullups
  pinMode(encoderPinB, INPUT_PULLUP);
  pinMode(clearButton, INPUT_PULLUP);
  pinMode(9, OUTPUT);
  pinMode(13, OUTPUT);
  // turn on pullup resistors (old method)
  //digitalWrite(encoderPinA, HIGH);
  // digitalWrite(encoderPinB, HIGH);
  // digitalWrite(clearButton, HIGH);

  // 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);  // 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("Index:");
    Serial.println(encoderPos, DEC);
    lastReportedPos = encoderPos;
  }
  if (digitalRead(clearButton) == LOW )  {
    /*delay(300);
     pressCount ++;
     //Reset count if over max mode number
     if(pressCount > 2)
     {
     pressCount = 0;
     }
     switch (pressCount) {

     case 0:
     digitalWrite(13, LOW);
     break;
     case 1:
     analogWrite(9,25);
     break;
     case 2:
     analogWrite(9,0);
     digitalWrite(13, HIGH);
     break;

     }*/
    encoderPos = 0;
  }
  switch (encoderPos) {

    case 0:
      digitalWrite(9, LOW);
      digitalWrite(13, LOW);
      break;

    case 1:
      digitalWrite(9, LOW);
      digitalWrite(13, HIGH);
      break;

    case 2:
      digitalWrite(13, LOW);
      digitalWrite(9, HIGH);
      break;
    case 3:
      digitalWrite(13, LOW);
      digitalWrite(9, HIGH);
      break;
  }

}



// 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 != 5)
    {
      encoderPos += 1;
    }
    if ( A_set && !B_set && encoderPos == 5)
    {
      encoderPos = 0;
    }

    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 == 0)
    {
      encoderPos = 5;
    }
    if ( B_set && !A_set )
    {
      encoderPos -= 1;
    }

    rotating = false;
  }
}

Works well for limiting encoder, sketch is set for a limit of 4.
Check on serial monitor.
It's all about the skills

3dprinter

#4
Jan 08, 2014, 09:15 pm Last Edit: Jan 08, 2014, 09:53 pm by Msquare Reason: 1
I always get nervous when people who have not mastered the intricacies of the "%" operator (modulus) and are sensible enough to use a nice library which hides some complications are given long code to do interrupts.

Try
Code: [Select]

for ( int i = 0; i<20; i++ )
Serial.print(i%5) ;
To get rid of negative numbers use the abs() function

3dprinter

Oh, I forgot, if you did want to have a ceiling/floor type functionality use the constrain() function
Code: [Select]
Serial.print(constrain(i,0,4));

You question about "Limiting it between 0 and 4" is a ambigious.

jremington

Quote
"4,4,4,4,4,4,4,3,2,1." instead of  "4,3,2,1,0,0,0,0,0,0".
How to resume counting if it is bigger than 4 or smaller than 0?

Evidently, the library code is incrementing some variable other than newPosition, then returning the result. To fix that you will have to modify the original library code. Find the place where the position variable is incremented or decremented in response to each impulse from the encoder. That is where you want to impose limits on the position. For example, if the code has something like
Code: [Select]

  position++;

you can add a line as follows:
Code: [Select]

  position++;
  (if position>4) position = 4;


Similarly for the decrement.

thereyouare


Try this:
Code: [Select]
/* interrupt routine for Rotary Encoders


The average rotary encoder has three pins, seen from front: A C B
Clockwise rotation A(on)->B(on)->A(off)->B(off)
CounterCW rotation B(on)->A(on)->B(off)->A(off)

and may be a push switch with another two pins, pulled low at pin 8 in this case


*/

// usually the rotary encoders three pins have the ground pin in the middle
enum PinAssignments {
  encoderPinA = 2,   // right (labeled DT on our decoder, yellow wire)
  encoderPinB = 3,   // left (labeled CLK on our decoder, green wire)
  clearButton = 8    // switch (labeled SW on our decoder, orange wire)
                // connect the +5v and gnd appropriately
};

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

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

int pressCount = 0;

void setup() {

  pinMode(encoderPinA, INPUT_PULLUP); // new method of enabling pullups
  pinMode(encoderPinB, INPUT_PULLUP);
  pinMode(clearButton, INPUT_PULLUP);
  pinMode(9, OUTPUT);
  pinMode(13, OUTPUT);
  // turn on pullup resistors (old method)
  //digitalWrite(encoderPinA, HIGH);
  // digitalWrite(encoderPinB, HIGH);
  // digitalWrite(clearButton, HIGH);

  // 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);  // 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("Index:");
    Serial.println(encoderPos, DEC);
    lastReportedPos = encoderPos;
  }
  if (digitalRead(clearButton) == LOW )  {
    /*delay(300);
     pressCount ++;
     //Reset count if over max mode number
     if(pressCount > 2)
     {
     pressCount = 0;
     }
     switch (pressCount) {

     case 0:
     digitalWrite(13, LOW);
     break;
     case 1:
     analogWrite(9,25);
     break;
     case 2:
     analogWrite(9,0);
     digitalWrite(13, HIGH);
     break;

     }*/
    encoderPos = 0;
  }
  switch (encoderPos) {

    case 0:
      digitalWrite(9, LOW);
      digitalWrite(13, LOW);
      break;

    case 1:
      digitalWrite(9, LOW);
      digitalWrite(13, HIGH);
      break;

    case 2:
      digitalWrite(13, LOW);
      digitalWrite(9, HIGH);
      break;
    case 3:
      digitalWrite(13, LOW);
      digitalWrite(9, HIGH);
      break;
  }

}



// 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 != 5)
    {
      encoderPos += 1;
    }
    if ( A_set && !B_set && encoderPos == 5)
    {
      encoderPos = 0;
    }

    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 == 0)
    {
      encoderPos = 5;
    }
    if ( B_set && !A_set )
    {
      encoderPos -= 1;
    }

    rotating = false;
  }
}

Works well for limiting encoder, sketch is set for a limit of 4.
Check on serial monitor.



This script  resets counter to 0 if it is bigger than 4.It isn't what I want  but  a little modification it works like a charm.

Code: [Select]
/* interrupt routine for Rotary Encoders


The average rotary encoder has three pins, seen from front: A C B
Clockwise rotation A(on)->B(on)->A(off)->B(off)
CounterCW rotation B(on)->A(on)->B(off)->A(off)

and may be a push switch with another two pins, pulled low at pin 8 in this case


*/

// usually the rotary encoders three pins have the ground pin in the middle
enum PinAssignments {
  encoderPinA = 3,   // right (labeled DT on our decoder, yellow wire)
  encoderPinB = 2,   // left (labeled CLK on our decoder, green wire)
  clearButton = 12    // switch (labeled SW on our decoder, orange wire)
                // connect the +5v and gnd appropriately
};

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

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

int pressCount = 0;

void setup() {

  pinMode(encoderPinA, INPUT_PULLUP); // new method of enabling pullups
  pinMode(encoderPinB, INPUT_PULLUP);
  pinMode(clearButton, INPUT_PULLUP);
  pinMode(4, OUTPUT);
  pinMode(A2, OUTPUT);
    pinMode(A3, OUTPUT);

  // turn on pullup resistors (old method)
  //digitalWrite(encoderPinA, HIGH);
  // digitalWrite(encoderPinB, HIGH);
  // digitalWrite(clearButton, HIGH);

  // 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);  // 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("Index:");
    Serial.println(encoderPos, DEC);
    lastReportedPos = encoderPos;
  }
  if (digitalRead(clearButton) == HIGH )  {
    /*delay(300);
     pressCount ++;
     //Reset count if over max mode number
     if(pressCount > 2)
     {
     pressCount = 0;
     }
     switch (pressCount) {

     case 0:
     digitalWrite(13, LOW);
     break;
     case 1:
     analogWrite(9,25);
     break;
     case 2:
     analogWrite(9,0);
     digitalWrite(13, HIGH);
     break;

     }*/
    encoderPos = 0;
  }
  switch (encoderPos) {

    case 0:
         digitalWrite(4, HIGH);
      digitalWrite(A2, LOW);
      digitalWrite(A3, LOW);
      break;

    case 1:
     
       digitalWrite(4, HIGH);
      digitalWrite(A2, LOW);
      digitalWrite(A3, LOW);
      break;

    case 2:
      digitalWrite(4, LOW);
      digitalWrite(A2, HIGH);
      digitalWrite(A3, LOW);
      break;
    case 3:
      digitalWrite(4, LOW);
      digitalWrite(A2, LOW);
      digitalWrite(A3, HIGH);
      break;
  }

}



// 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 != 5)
    {
      encoderPos += 1;
    }
    if ( A_set && !B_set && encoderPos == 5)
    {
      encoderPos = 4;
    }

    rotating = false;  // no more debouncing until loop() hits again
  }
}
void doEncoderB() {
  // debounce
  if ( rotating ) delay (1);  // wait a little until the bouncing is done
  // Test transition, did things really change?
  if ( digitalRead(encoderPinB) != B_set ) { // debounce once more
    B_set = !B_set;
    // adjust counter + if A leads B
    if ( !A_set && B_set && encoderPos != 0)
    {
      encoderPos -= 1;
    }
    if (!A_set && B_set && encoderPos == 0)
    {
      encoderPos = 1;
    }

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

}


Thank you very much. :)

Jaxon_Shredda

I managed this with the following code:


Code: [Select]
void loop() {
 
 long newPosition = myEnc.read();

 while(newPosition != oldPosition) { // only do stuff if something changed

   if (newPosition > oldPosition) {  // one of two options, up or down, pick one
     relativePosition += 1;          // it went up
   }
   else {
       relativePosition -= 1;        // it went down
   }
   if (relativePosition > 7)  {      // did we reach our + limit? - Could use a variable here
      relativePosition -= 1;         // reset the position to just one before our limit
   }
   if (relativePosition < -7) {      // did we reach our - limit? - Could also use a variable here
      relativePosition += 1;         // reset the position to just one before our limit
   }

   oldPosition = newPosition;
   Serial.println(relativePosition);
 }  
}

Jaxon_Shredda

Cleaned it up a bit more:

Code: [Select]
/* Input Encoder Limiting Example
*/
 
#include <Encoder.h>

Encoder myEnc(2, 3);                          // Sets input pins on input encoder
int tickLimit = 10;                           // Maximum we want to go with the input encoder in either direction
long oldPosition  = 0;                        // Referance for manual encoder positioning comparisons
long relativePosition = 0;                    // Pointer for ticks that fall in the tickLimit window

void setup() {
}

void loop() {

  long newPosition = myEnc.read();            // Get the current position of the manual encoder

  while (newPosition != oldPosition) {        // only adjust output if input changed

    if (newPosition > oldPosition) {          // one of two options, up or down, pick one
      if (relativePosition != tickLimit)  {   // did we reach our positive tick limit?
        relativePosition += 1;                // it went up so bump the relative position up by one tick
      }
    }
    else {
      if (relativePosition != -tickLimit) {   // did we reach our negative tick limit?
        relativePosition -= 1;                // it went down so bump the relative position down by one tick
      }
    }
    oldPosition = newPosition;                // Reset the oldPosition referance
  }
}

Go Up