Rotary encoder - skip grey values?

I have a rotary encoder and using a Feather 32u4 board, I send strings to an iOS app (using BLE uArt). If I try to send too quickly, the string gets combined for the send. For instance for each event I send either "+1_", "-1_", or "b"... b is for button press. Combined = something like "+1_+1_+1_".

The problem is that I get values for each detent and also between the detents.

Since I can get combined values, I can't just ignore every other message. Is there a way to code my sketch to have the values between detents ignored? I can't use a different encoder as another team has chosen it for development and I am running prototypes with their encoder. I am a very basic sketch author at this point.

The problem is almost surely in the code you haven't posted.

And, the datasheet for the encoder that you haven't posted.

Here is the code that reads the encoder. I don't have the sketch with me that has the Feather uArt stuff in it, but even with this simple code, I get 2 values per detent. Using uArt if I twist quickly, I can get multiples values that get packed together for the send to iOS (hence I can't just ignore every other event from the encoder).

I do not have a data sheet for the encoder. I was told from someone who scoped it that it generates a value for each detent and also between each detent. I want to ignore the in-between detent values.

int outputA = A2;
 int outputB = A1;
 int button = A3;
 int counter = 0; 
 int aState;
 int aLastState; 
 int buttonState;
 int lastButtonState;
  
 void setup() { 
   pinMode (outputA,INPUT);
   pinMode (outputB,INPUT);
   pinMode (button,INPUT);
   
   Serial.begin (9600);
   
   aLastState = digitalRead(outputA);        // Reads the initial state of the outputA
   lastButtonState = digitalRead(button);    // Reads the initial state of the button
 } 
 
 void loop() { 
   aState = digitalRead(outputA);            // Reads the "current" state of the outputA
   buttonState = digitalRead(button);        // Reads the "current" state of the button
   
   // If the previous and the current state of the outputA are different, that means a Pulse has occured
   if (aState != aLastState){     
     // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
     if (digitalRead(outputB) != aState) { 
       counter ++;
       Serial.print(1);
     } else {
       counter --;
       Serial.print(-1);
     }
     //Serial.print("Position: ");
     //Serial.println(counter);
   } 

   // check for a button press
   if (buttonState == HIGH) {
    if (lastButtonState == LOW) { // but only send the serial message if the button was just pressed (debounce)
     Serial.print("B");
    }
    lastButtonState = HIGH;
   }
   else {
    lastButtonState = LOW;
   }
   
   aLastState = aState; // Updates the previous state of the outputA with the current state
 }

Check out: Buxtronix: Rotary encoders, done properly

You can either adapt that code to your project or try a library I've written that uses the technique and adds features. It's interrupt driven, so you'd need to move the encoder to pins that support interrupts: GitHub - gfvalvo/NewEncoder: Rotary Encoder Library

Thank you very kindly. Will check these out and hopefully it solves my dilemma.

You might try changing this line:

if (aState != aLastState){

to:

if ((aState != aLastState) && (aState == HIGH)) {

That would let you count only the LOW-to-HIGH transitions on the A pin, which should happen once per detent.

I'm assuming your encoder has an equal number of "pulses" as detents per revolution, and therefore goes through a full cycle on both pins between detents. That type will always come to rest at a detent with both switched open. But your code is written for the other type of encoder, which has half as many pulses as detents. Of course I'm guessing here, but that seems to be the explanation. Your code counts every transition of A, and you get two transitions between detents - HIGH-to-LOW, and LOW-to-HIGH. So just count the LOW-to-HIGH transitions, and you should get one "tick" per detent, which is what you want.

If you were getting a tick only every other detent, the code and the encoder type would be mismatched in the opposite way.

Most encoders can be ordered in either type. The datasheet will show the part numbers that correspond to the available pulse and detent options.

ShermanP:
You might try changing this line:

if (aState != aLastState){

to:

if ((aState != aLastState) && (aState == HIGH)) {

That would let you count only the LOW-to-HIGH transitions on the A pin, which should happen once per detent.

I'm assuming your encoder has an equal number of "pulses" as detents per revolution, and therefore goes through a full cycle on both pins between detents.

You are probably correct in your guess about what type of encoder this is (although OP can't produce a datasheet or part number). So, a better solution is to process a complete quadrature cycle (which occurs ever detent) before updating the internal count. The library link I posted above can handle either type of encoder. You specify the type in either the constructor or configure() method.

I agree that Ben Buxton's state-table method gives the best performance of all, at least the best of anything I've seen. But it works with polling too if the polling rate is appropriate - about 2ms works well for me.

True. That's a nice alternative if you're shy of interrupt-enabled pins on your board, especially because of the inherit debouncing of the algorithm requiring no additional delays. Should be more then adequate if the encoder is just a control knob being turned by a human.