"Slippery" rotary encoder

Hi Everyone I wonder if anyone can help on this one.

What this does:
A rotary encoder counter determines the speed of a stepper motor. Every completed loop LoopCounter++. When LoopCounter reaches the number determined by the Encoder Counter (counter) the stepper makes a step. Then LoopCounter=0

My problem:
The rotary "slips"unless I turn the knob sloooowly and in a controlled manner over the clicking of the encoder. As if it would need time between the first and second sensor. Is the loop too long?
By slipping I mean that it goes one up and one down instead of just one up.

Also, the speed control won't work if I omit the line

Serial.println(LoopCounter);

Any clue why that is? (I'm expecting a RTFM here)

Thanks in advance!

This is the full code:

// LOOP counter
int LoopCounter     =0;

// variables for the rotary encoder
int outputA = 3;
int outputB = 2;

// Starting from 100 because of issue with decreasing and increasing
//TODO: see if it is mechanical problem, try with a different rotary
unsigned int counter = 1; 
//current state
int aState;
int aLastState;  


// new bits to control speed in real time ++

int lastChange; // the time of changing pin state
int state = HIGH;


const int buttonPin  = 12;     // the pin that the pushbutton is attached to
const int ledPin     = 13;    // the pin that the LED is attached to
 
int buttonState      = 0;     // current state of the button
int lastButtonState  = 0;     // previous state of the button
int ledState         = 0;     // remember current led state

//declare variables for the motor pins
int motorPin1 = 8;    // Arduino pin 8 to In 1 on the ULN2003
int motorPin2 = 9;    // Arduino pin 9 to In 2 on the ULN2003
int motorPin3 = 10;   // Arduino pin 10 to In 3 on the ULN2003
int motorPin4 = 11;   // Arduino pin 11 to In 4 on the ULN2003
                      // supply power to + and - from Arduino 5vdc and gnd

int motorSpeed = 1250;  // set speed of 28BYJ-48 stepper,

//max frequency is 100hz, so max speed is 1250

int lookup[8] = {B01001, B00001, B00011, B00010, B00110,B00100,B01100, B01000};
 
void setup() {
  { 
   // pins for the encoder
   pinMode (outputA,INPUT);
   pinMode (outputB,INPUT);
   
  // Reads the initial state of the outputA
   aLastState = digitalRead(outputA);   
 } 
  lastChange = millis();  // ledpin state changed NOW
  digitalWrite(ledPin, state);
  
  pinMode(buttonPin, INPUT_PULLUP);  // initialize the button pin as a input
  pinMode(ledPin, OUTPUT);    // initialize the button pin as a output
  //declare the motor pins as outputs
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(motorPin4, OUTPUT);
  Serial.begin(9600);
}
 
void loop() 

{
  // Number of loops since the last step increases of one unit
  LoopCounter++;
// if the counter is above 5000 it goes back to 0 to avoid 
if (counter >= 5000)
       counter = 0 ;
  
aState = digitalRead(outputA); // Reads the "current" state of the outputA
   // 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 ++;
     } else {
       counter --;
     }
     if (counter>=400){
       counter==0;}
     Serial.print("Position: ");
     Serial.println(counter);
     } 
   aLastState = aState; // Updates the previous state of the outputA with the current state

   if (counter >= 400){
    counter == 0;}


 //this IF determines delay time between one step and the next one
 if (LoopCounter >= counter){
  LoopCounter=0; 
  // invert led's state
  state = !state; 
  digitalWrite(ledPin, state);
  // read the pushbutton input pin, did we reach the edge?
  buttonState = digitalRead(buttonPin); 
    // by comparing the buttonState to its previous state 
    if (buttonState != lastButtonState) {
      // change the state of the led when someone pressed the button
      if (buttonState == 1) { 
        if(ledState==1) ledState=0;
        else            ledState=1;         
        }
      }    
    // remember the current state of the button
    lastButtonState = buttonState;

    // turns LED on if the ledState=1 or off if the ledState=0
    if(ledState == 0 && buttonState == LOW)
      clockwise();
     else if(ledState == 1 && buttonState == LOW)
            anticlockwise();
     else if (ledState == 1 && buttonState == HIGH)
            clockwise();  
     else if(ledState == 0 && buttonState == HIGH) 
            anticlockwise();
    }
    

Serial.println(LoopCounter);

}


void clockwise()
{
  for(int i = 0; i < 8; i++) // 8 pulses
  {
    setOutput(i);
    delayMicroseconds(motorSpeed);
  }
}

void anticlockwise()
{
  for(int i = 7; i >= 0; i--) // 8 pulses
  {
    setOutput(i);
    delayMicroseconds(motorSpeed);
  }
}

void setOutput(int out)
{
  digitalWrite(motorPin1, bitRead(lookup[out], 0));
  digitalWrite(motorPin2, bitRead(lookup[out], 1));
  digitalWrite(motorPin3, bitRead(lookup[out], 2));
  digitalWrite(motorPin4, bitRead(lookup[out], 3));
}

First, what type of encoder are you using? Second, you're using a polling method to read the encoder. Is that what you really want to do? To illustrate, suppose a fire detection system has 100 sensors/per floor and it takes 1 second to visit and read each sensor. If you're reading the second floor and a fire breaks out on the first floor in the Empire State building, it's going to be almost 3 hours before you know about it.

Take a look at using interrupts on the encoder and write an ISR for the encoder. It might help with some of the strobe issues you're having.

Hello Econjack,

The fireman example is clear, that's indeed what I thought was happening. I'll look into ISR, thanks for the tip!

These are the encoders I am using:

DO you have an idea why the loop has to be written on the Serial Monitor in order to make the whole thing work?

Thanks!

I'm still trying to figure out what you're trying to do. First, why is counter an unsigned int? While it starts out equal to 1, what happens if it is decremented to 0 and then decremented again? If don't know if that's possible, but that will roll it over to 65,536. Next, look at your code and ask yourself: can counter ever get over 400? Why the second check on counter around line 92? Why the check for counter against 5000, since you have checks against 400 and reset it to 0 if it is? You also have some unnecessary braces in setup(). I'm not sure why the print statement allows it to work, other than it takes some some to execute which may affect the outcome of the digitalRead() calls. Finally, use Ctrl-T to format your code in a more standard format. Your style is difficult for me to read.

Yeah, good points, the code is a little bit of a mess, I will clean it up and format it.

I'll give it a try with ISR, thanks for the tips.

Luca