I wasn't sure where to post this but it seems to me like a programming issue so here it goes.
I have a quadrature incremental encoder wired to my Arduino Uno. I am reading my encoder based on code from Quadrature Encoder too Fast for Arduino (with Solution) – Dr Rainer Hessmer
The code works...kind of... It seems to be skipping pulses or the interrupt is cause issues when writing to the LCD. I'm not sure if the issue lies in the if statement where I only write to the LCD when the value changes? Thanks
Below is my entire program.
/* PINS
* Rs: Pin 4
* EN: Pin 5
* D4: Pin 6
* D5: Pin 7
* D6: Pin 8
* D7: Pin 9
* EncoderA: Pin 2
* EncoderB: Pin 12
* Button: Pin 3
* LED: Pin 11
* Detector: Pin A0
*/
//Include the LCD, Interrupt and digitalWriteFast Libraries
#include "Arduino.h"
#include <LiquidCrystal.h>
#include <digitalWriteFast.h>
//Set Pins/Interrupts
//Initialize an LCD object
LiquidCrystal lcd(4,5,6,7,8,9);
//Encoder Pins
#define c_EncoderInterrupt 0
#define c_EncoderPinA 2
#define c_EncoderPinB 12
//IR Pins
int infraredPin = 0; //Analog Pin 0
//Button Pins
#define zeroButtonInterrupt 1 //Digital Pin 3
//LED Pins
int ledPin = 11;
//Create Custom Characters
byte tare[8] = {
B11111,
B10001,
B11011,
B11011,
B11011,
B11011,
B11011,
B11111,
};
byte notare[8] = {
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
};
//Variable Initialization
//Quadrature Encoder
#define EncoderIsReversed
volatile boolean _EncoderBSet;
volatile long _EncoderTicks = 0;
//Distance Variables
double Distance = 0;
double LastDistance = 0;
float TicksPerInch = 10.0;
volatile long ZeroTicks = 0;
//IR Variables
double infraredRead = 0;
double ADCscale = 1.046875; //Reference Voltage/1024*1000 [mV]
//Zero Variables
volatile long ZeroIR = 0;
volatile boolean zeroed = false;
void setup()
{
analogReference(INTERNAL); //Set AREF to 1.1 [Volts]
//Attach Interrupts
attachInterrupt(c_EncoderInterrupt, HandleMotorInterruptA, RISING);
attachInterrupt(zeroButtonInterrupt, flip, RISING); //Attach Interrupt
//Set LED Pin
pinMode(ledPin, OUTPUT);
// Quadrature Encoders Pin Initialization
pinMode(c_EncoderPinA, INPUT); // sets pin A as input
digitalWrite(c_EncoderPinA, LOW); // turn on pullup resistors
pinMode(c_EncoderPinB, INPUT); // sets pin B as input
digitalWrite(c_EncoderPinB, LOW); // turn on pullup resistors
//Begin the LCD interface
lcd.begin(16,2);
//Create Custom Characters
lcd.createChar(0, tare);
lcd.createChar(1, notare);
//Print LCD constants
lcd.setCursor(0,0);
//lcd.setCursor(15,0);
lcd.print("IR = mV ");
lcd.print((char)0); //Print Untorn Character
lcd.setCursor(0,1);
lcd.print("Dist = in");
}
void loop()
{
Distance = (_EncoderTicks - ZeroTicks)/TicksPerInch; // Calculate Distance Traveled minus zero value
if (Distance != LastDistance) // Only write distance to LCD if it has changed
{
//Clear Distance output
lcd.setCursor(7,1);
lcd.print(" "); //Clear LCD Distance Output
lcd.setCursor(7,1);
lcd.print(Distance); //Print Distance to LCD
LastDistance = Distance;
}
infraredRead = analogRead(infraredPin); //Read Analog Pin0
lcd.setCursor(5,0);
lcd.print(" "); //Clear LCD Voltage output
lcd.setCursor(5,0);
lcd.print((infraredRead - ZeroIR)*ADCscale); //Print IR output to LCD and convert to mV
delay(200); //Delay LCD update so User can read output
}
// Interrupt service routine for quadrature encoder
void HandleMotorInterruptA()
{
// Test transition; since the interrupt will only fire on 'rising' we don't need to read pin A
_EncoderBSet = digitalReadFast(c_EncoderPinB); // read the input pin
// and adjust counter + if A leads B
#ifdef EncoderIsReversed
_EncoderTicks -= _EncoderBSet ? -1 : +1;
#else
_EncoderTicks += _EncoderBSet ? -1 : +1;
#endif
}
void flip()
{
zeroed ^= 0x01; //flip button state
if (zeroed) //Write zero character to LCD
{
ZeroIR = analogRead(infraredPin);
ZeroTicks = _EncoderTicks;
digitalWrite(ledPin, HIGH);
lcd.setCursor(15,0);
lcd.print((char)1);
}
else
{
ZeroIR = 0;
ZeroTicks = 0;
digitalWrite(ledPin, LOW);
lcd.setCursor(15,0);
lcd.print((char)0);
}
}