In a recent project I've had to employ interrupts to track two different encoder wheels/strips to ensure I know the exact positions of two stepper motors. The encoder strips have fairly high resolution, and change even with very slight movements -- which is perfect for my project.
However, I encounter a problem that I've nailed down to be a conflict between the liquid crystal library and the interrupts themselves. If I have an lcd.print() statement within my loop, or any other call to an lcd method, the values I get for the counts are extraneous. A slight bump to the table sends them out of whack -- they'll count up (or down) 10, 20, 100 steps, very rapidly.
If I remove the lcd method calls, and repeat the experiment. A slight bump to the table still causes a change in the count value, but it's what you would expect from such a vibration: it will go from 0 to -1 back to 0, to -1, and then settle down at 0, as an example.
I presume that the lcd method calls prevent interrupts from within, and somehow the counts stack up in one direction, rather than settling down, going back and forth. Anyone have any insight on how I might solve this problem? I found a few older threads mentioning the calls to "cli()" in wiring.c, but commenting those out did not help.
I'm not sure if there's a better way to keep track of the encoder positions that would avoid the use of interrupts. I worry that if something gets jostled slightly while the code is off doing something else, the program will have no knowledge of this unexpected movement, and will no longer have an accurate idea of how the steppers are positioned.
Here's the code boiled down to bare minimums for debugging:
#include <Wire.h>
#include <LiquidCrystal_SR.h>
//LCD display setup
LiquidCrystal_SR lcd(4, 6, 7);
// | |
// | \-- Clock Pin
// \---- Data/Enable Pin
#define encoderAI 0
#define encoderAQ 1
#define encoderBI 2
#define encoderBQ 3
volatile int countA;
volatile int countB;
int lastVal;
int curVal;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
countA = 0;
pinMode(encoderAI, INPUT);
pinMode(encoderAQ, INPUT);
pinMode(encoderBI, INPUT);
pinMode(encoderBQ, INPUT);
attachInterrupt(2, handleEncoderA, CHANGE);
attachInterrupt(0, handleEncoderB, CHANGE);
}
void loop() {
// put your main code here, to run repeatedly:
curVal = countA;
if (lastVal != curVal) {
Serial.println(countA);
lcd.setCursor(0,0);
lcd.print("This Is A Test");
}
lastVal = countA;
}
void handleEncoderA() {
if(digitalRead(encoderAI) == digitalRead(encoderAQ)) {
countA ++;
} else {
countA --;
}
}
void handleEncoderB() {
if(digitalRead(encoderBI) == digitalRead(encoderBQ)) {
countB ++;
} else {
countB --;
}
}