Interrupts and LCD issues.

My encoder tick counter looses it’s accuracy when I introduce a lcd.print call.

In the “//STill Moving” section of my code, when I un-comment the lcd.print call, the encoder returns results that are two high by around 20%. I should be able to turn my encoder 1 turn and get 1440 ticks, but is counting 1500 + ticks. If I take the lcd.print calls out in this section of my code, all works right.

Can the lcd calls be keeping the interrupt code from processing correctly? I would think it would count less ticks, but is always more? Any ideas?

Thanks!

/*
*Quadrature Decoder 
*/
#include "Arduino.h"
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <digitalWriteFast.h>  // library for high performance reads and writes by jrraines
                               // see http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1267553811/0
                               // and http://code.google.com/p/digitalwritefast/

// It turns out that the regular digitalRead() calls are too slow and bring the arduino down when
// I use them in the interrupt routines while the motor runs at full speed.

// Quadrature encoders
// Left encoder
#define c_EncoderInterruptA 0
#define c_EncoderInterruptB 1
#define c_EncoderPinA 2
#define c_EncoderPinB 3
//#define EncoderIsReversed

volatile bool _EncoderASet;
volatile bool _EncoderBSet;
volatile bool _EncoderAPrev;
volatile bool _EncoderBPrev;
volatile long _EncoderTicks = 0;
long deltaTicks = 0;

// initialize the library with the numbers of the interface pins
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display

long l_lastPrint;

long _pauseTime = 1500;
long _StartTime = 0;
volatile long _LastEncoderTicks;
bool _isMoving = false;
long _lastMoveTime;


void setup()
{
  Serial.begin(9600);

  // Quadrature encoders
  // Left encoder
  pinMode(c_EncoderPinA, INPUT_PULLUP);      // sets pin A as input
 // digitalWrite(c_EncoderPinA, LOW);  // turn on pullup resistors
  pinMode(c_EncoderPinB, INPUT_PULLUP);      // sets pin B as input
 // digitalWrite(c_EncoderPinB, LOW);  // turn on pullup resistors
  attachInterrupt(c_EncoderInterruptA, HandleLeftMotorInterruptA, CHANGE);
  attachInterrupt(c_EncoderInterruptB, HandleLeftMotorInterruptB, CHANGE);
  l_lastPrint = millis();
  _LastEncoderTicks = _EncoderTicks;
  lcd.init(); //initialize the lcd
  lcd.backlight(); //open the backlight 
  lcd.setCursor(0,0);
  lcd.print("Length: ");

  
  
}

void loop()
{ 
   delay(10);
   deltaTicks = abs(_LastEncoderTicks - _EncoderTicks);


//Start Moving
if (deltaTicks > 1 && _isMoving == false)
{    
     _LastEncoderTicks = _EncoderTicks;
     _isMoving = true;
     //Serial.print(_LastEncoderTicks - _EncoderTicks);
     _lastMoveTime = millis();
     Serial.print("Moving\n");
}

//STill Moving
if (deltaTicks > 1 &&  _isMoving ==true )
{    
  _lastMoveTime = millis();
    //lcd.setCursor(7,0);
    //lcd.print("Moving: ");
    //lcd.print((float(_EncoderTicks)/1440.0)*6.0,3);
    //lcd.print("               ");
}


//Stop Moving
if ((deltaTicks < 1) && (_isMoving == true) && millis() - _lastMoveTime > 3000 )
{     
      _LastEncoderTicks = _EncoderTicks;
      _isMoving = false;
    Serial.print((float(_EncoderTicks)/1440.0)*6.0,3);
    Serial.print("  Stopped\n");
    lcd.setCursor(0,0);
    lcd.print("LengthF: ");
    lcd.print((float(_EncoderTicks)/1440.0)*6.0,3);
    lcd.print("               ");
    _EncoderTicks = 0;
}
_LastEncoderTicks = _EncoderTicks;




// Output to serial for debug  
 if (millis() - l_lastPrint > 1000) 
 {
    //Serial.print(millis() - l_lastPrint);
    l_lastPrint = millis();
    Serial.print("Encoder Ticks: ");
    Serial.print(_EncoderTicks);
    Serial.print("  Revolutions: ");
    Serial.print(_EncoderTicks/1440.00);//4000 Counts Per Revolution
    Serial.print("\n"); 
  }  //endifM
}


// Interrupt service routines for the left motor's quadrature encoder
void HandleLeftMotorInterruptA(){
  _EncoderBSet = digitalReadFast(c_EncoderPinB);
  _EncoderASet = digitalReadFast(c_EncoderPinA);
  
  _EncoderTicks+=ParseEncoder();
  
  _EncoderAPrev = _EncoderASet;
  _EncoderBPrev = _EncoderBSet;
}

// Interrupt service routines for the right motor's quadrature encoder
void HandleLeftMotorInterruptB(){
  // Test transition;
  _EncoderBSet = digitalReadFast(c_EncoderPinB);
  _EncoderASet = digitalReadFast(c_EncoderPinA);
  
  _EncoderTicks+=ParseEncoder();
  
  _EncoderAPrev = _EncoderASet;
  _EncoderBPrev = _EncoderBSet;
}

int ParseEncoder(){
  if(_EncoderAPrev && _EncoderBPrev){            //pre both hgh
    if(!_EncoderASet && _EncoderBSet) return 1;
    if(_EncoderASet && !_EncoderBSet) return -1;
  }else if(!_EncoderAPrev && _EncoderBPrev){     //pre  A low, B High
    if(!_EncoderASet && !_EncoderBSet) return 1;
    if(_EncoderASet && _EncoderBSet) return -1;
  }else if(!_EncoderAPrev && !_EncoderBPrev){     //pre both low
    if(_EncoderASet && !_EncoderBSet) return 1;
    if(!_EncoderASet && _EncoderBSet) return -1;
  }else if(_EncoderAPrev && !_EncoderBPrev){       //pre A high, b low
    if(_EncoderASet && _EncoderBSet) return 1;
    if(!_EncoderASet && !_EncoderBSet) return -1;
  }
}

Any ideas?

Look at this statement:

    //lcd.print((float(_EncoderTicks)/1440.0)*6.0,3);

_EncoderTicks (I HATE variables that have underscores in the name, especially at the beginning) is a 4 byte variable. What happens if an interrupt occurs while the 4 bytes are being accessed?

Everywhere in loop(), where you access, especially where you modify, a multi-byte variable that an interrupt can change you should disable interrupts before you copy the variable and enable them again afterwords.