Go Down

Topic: Trying to get one encoder to act like two (Read 199 times) previous topic - next topic

Qhergt1987

I'm trying to get one encoder to act like two when the button is held down and knob turned.   
When button released and knob turned, I want  one value to change, and when button held down and knob turned I want a second value to be changed.     Right now both are changing at once and I think that is being caused by the SW pin om the encoder going to ground each time the knob is turned.   
Is there a way to do this?   

Here's the code.
Code: [Select]


#include <Encoder.h>
Encoder knobLeft(5, 6);
Encoder knobRight(7, 8);
int buttonPin = 2;
void setup() {
  Serial.begin(9600);
  Serial.println("three Knobs Encoder Test:");
}

long positionLeft  = -999;
long positionRight = -999;

void loop() {
  long newLeft, newRight, two, three;
  newLeft = (knobLeft.read() / 4 * 10);
  newRight = (knobRight.read() / 4);
  Two = constrain(newRight, 0, 360);
  Three = (newLeft * 0.01); 
while (digitalRead(buttonPin) == LOW) {
 newLeft = qnh;
}
  if (newLeft != positionLeft || newRight != positionRight) {
    Serial.print("one = ");
    Serial.print(newLeft);
     Serial.print(", two= ");
    Serial.print(qnh), 2;
    Serial.print(", three= ");
    Serial.print(head);
    Serial.println();
    positionLeft = newLeft;
    positionRight = newRight;
  }
  // if a character is sent from the serial monitor,
  // reset both back to zero.
  if (Serial.available()) {
    Serial.read();
    Serial.println("Reset both knobs to zero");
    knobLeft.write(0);
    knobRight.write(0);
  }
}


Grumpy_Mike

How is this single encoder wired?
Your code has two encoders defined but if you have wired pin 5 to 7 and 6 to 8 then the results you get are to be expected.

The problem is the use of the Encoder library, you will have to change the code in that to look at the push button and see what counter to increment.

However the big problem is that reading encoders depends on knowing the last state of the encoder and if you use the same physical encoder then that last state is wrong when you change over so I don't think your trick will work anyway.

Delta_G

However the big problem is that reading encoders depends on knowing the last state of the encoder and if you use the same physical encoder then that last state is wrong when you change over so I don't think your trick will work anyway.
You would have to code it such that if the state of the button has changed (state change example) since the last change in the encoder (in the interrupt if it's interrupt driven) then you don't increment on the first pulse you just record a new last state.   It would necessitate dropping the first pulse on every switch, but I don't think there is any other way. 
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

Qhergt1987

I have two encoders wired in.   They both work great togeather and one at a time.  The issue occurs if I hold button down and turn. 

  Is there a way to get a 3rd encoder to work on the uno?
Or would I be better off using an Attiny with a 3rd encoder  linked to the uno to provide that value?

Delta_G

Is there a way to get a 3rd encoder to work on the uno?
Yes.  I wrote some code for a 1284P that reads two encoders on spinning motors using pin change interrupts.  It could easily be extended to three encoders on an UNO if you can use 6 pins on the same port.  Give me a minute to look it up. 
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

Delta_G

#5
Aug 23, 2019, 06:45 am Last Edit: Aug 23, 2019, 06:55 am by Delta_G
This wouldn't be exactly what you need.  It obviously makes reverences to my robot and not whatever you're doing.  But you should be able to see how I wrote the ISR to quickly figure out which encoder fired and in which direction. 

It does require that all of the encoders be set up on the same port.  On the UNO that pretty much limits you to PortD on pins 2 through 7 (unless you don't use Serial and want to use 0 and 1), or PortB on pins 8 through 13.  But no combinations of the two. 

Code: [Select]
#define LEFT_INT_MASK 0x80
#define LEFT_B_MASK 0x40
#define RIGHT_INT_MASK 0x20
#define RIGHT_B_MASK 0x10

volatile uint8_t lastPortRead = 0;

volatile int32_t leftCounter = 0;
volatile int32_t rightCounter = 0;


ISR(PCINT2_vect){

uint8_t portRead = PINC;

uint8_t whoFired = portRead ^ lastPortRead;
uint8_t pinsDiff = portRead ^ (portRead << 1); // Will have bits 5 or 7 set if pins on right motor or left motor are diff.  Cleared if same.

if (whoFired & LEFT_INT_MASK) {
boolean forw = false;
if (pinsDiff & LEFT_INT_MASK) {
leftCounter++;
forw = true;
} else {
leftCounter--;
}
}
if (whoFired & RIGHT_INT_MASK) {
boolean forw = false;
if (pinsDiff & RIGHT_INT_MASK) {
rightCounter++;
forw = true;
} else {
rightCounter--;
}
}

lastPortRead = portRead;
}


void setupPCint(){

PCICR = PCICR | (1 << PCIE2);   //  Turn on pin change interrupt 2
PCIFR = (1 << PCIF2);   // Clear any pending interrupt flag for pin change interrupt 2
PCMSK2 = (1 << PCINT23) | (1 << PCINT21);  // Set interrupts for pins 21 and 23 at bits 5 and 7.  Bits 4 and 6 will be the other pins.

}


int32_t getLeftMotorCount(){
int32_t retval = 0;
// Disable interrupt
cli();
retval = leftCounter;
sei();
return retval;
}

int32_t getRightMotorCount(){
int32_t retval = 0;
// Disable interrupt
cli();
retval = rightCounter;
sei();
return retval;
}



If you're having trouble following the port reads, it's mimicking the same idea as  this code where we determine the direction by seeing which pin is leading.
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

Qhergt1987

This wouldn't be exactly what you need.  It obviously makes reverences to my robot and not whatever you're doing.  But you should be able to see how I wrote the ISR to quickly figure out which encoder fired and in which direction. 

It does require that all of the encoders be set up on the same port.  On the UNO that pretty much limits you to PortD on pins 2 through 7 (unless you don't use Serial and want to use 0 and 1), or PortB on pins 8 through 13.  But no combinations of the two. 

Code: [Select]
#define LEFT_INT_MASK 0x80
#define LEFT_B_MASK 0x40
#define RIGHT_INT_MASK 0x20
#define RIGHT_B_MASK 0x10

volatile uint8_t lastPortRead = 0;

volatile int32_t leftCounter = 0;
volatile int32_t rightCounter = 0;


ISR(PCINT2_vect){

uint8_t portRead = PINC;

uint8_t whoFired = portRead ^ lastPortRead;
uint8_t pinsDiff = portRead ^ (portRead << 1); // Will have bits 5 or 7 set if pins on right motor or left motor are diff.  Cleared if same.

if (whoFired & LEFT_INT_MASK) {
boolean forw = false;
if (pinsDiff & LEFT_INT_MASK) {
leftCounter++;
forw = true;
} else {
leftCounter--;
}
}
if (whoFired & RIGHT_INT_MASK) {
boolean forw = false;
if (pinsDiff & RIGHT_INT_MASK) {
rightCounter++;
forw = true;
} else {
rightCounter--;
}
}

lastPortRead = portRead;
}


void setupPCint(){

PCICR = PCICR | (1 << PCIE2);   //  Turn on pin change interrupt 2
PCIFR = (1 << PCIF2);   // Clear any pending interrupt flag for pin change interrupt 2
PCMSK2 = (1 << PCINT23) | (1 << PCINT21);  // Set interrupts for pins 21 and 23 at bits 5 and 7.  Bits 4 and 6 will be the other pins.

}


int32_t getLeftMotorCount(){
int32_t retval = 0;
// Disable interrupt
cli();
retval = leftCounter;
sei();
return retval;
}

int32_t getRightMotorCount(){
int32_t retval = 0;
// Disable interrupt
cli();
retval = rightCounter;
sei();
return retval;
}

Basically I'll have to create a "Center Counter" for a 3rd encoder? 

Delta_G

Basically I'll have to create a "Center Counter" for a 3rd encoder? 
Yeah, something like that.
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

dougp

Basically I'll have to create a "Center Counter" for a 3rd encoder?  
I'm trying to get one encoder to act like two when the button is held down and knob turned.   
When button released and knob turned, I want  one value to change, and when button held down and knob turned I want a second value to be changed.
So, is the idea to have one physical encoder for three different values?
Everything we call real is made of things that cannot be regarded as real.  If quantum mechanics hasn't profoundly shocked you, you haven't understood it yet. - Niels Bohr

No private consultations undertaken!

Qhergt1987

Yes,
Or just have 3 seperate encoders. 
I tried modifying the two encoder example from the encoder.h library but that didnt work. 

dougp



Why not use the debounced pushbutton to cycle a counter through 0-1-2-0-1-2...  

if(counter == zero) valueA is manipulated,
if(counter == one) valueB is manipulated,
and so on.

A minimal visual feedback would be some LEDs to show which counter is active.
Everything we call real is made of things that cannot be regarded as real.  If quantum mechanics hasn't profoundly shocked you, you haven't understood it yet. - Niels Bohr

No private consultations undertaken!

Qhergt1987


Qhergt1987

Would prefer to have 3 seperate encoders at least.   

Go Up