PART 1 of 2 posts
/* ---------------------------------------
This sketch reads a rotary encoder with interrupts and uses the index track to always
recalibrate the encoder every turn. It solves problems with high resolution
encoders or high speed applications.
Tested 1000 turns @ 3000 RPM with a 500cpr encoder and it counted perfect.
Encoder hooked up with common to GROUND, encoder0PinA (or encoder0PinB) to pin 3,
encoder0PinC (Index Track) to pin 2.
Most of the code here was originally coppied from the arduino playground
(by max wolf and Paul Badger)
and then modified to include a way of using the index track to recalibrate for missed
encoder counts at high speeds or at high resolutions. It uses both interupts on the arduino.
Hope this helps,
-MattB
PROBLEMS - for some reason it misses one tenth of a turn when the counter goes from 0.0 to -0.1.
Maybe someone could fix this?? it is not a huge problem.
Also, I'm not a programmer, if anyone sees ways I can clean up this code please let me know.
--------------------------------------- */
#include <avr/interrupt.h>
#define encoder0PinA 3 //Quadrature Track A
#define encoder0PinB 4 //Quadrature Track B
#define encoder0PinC 2 //Index Track
//encoder variables
volatile unsigned int encoder0Pos = 0; //the encoder position variable.
int start = true; //variable used to indicate the first time the encoder sees the index track.
int turn = 0; //the total turns.
int decimal = 0; //tenths of a turn.
int encoderHome = 0; //used to reset encoder0Pos if any counts are missed during a rotation.
int ccw = false; //which direction the encoder is spinning.
int display = 0; //variable for display data on LCD screen.
void setup(){
//encoder pinModes
pinMode(encoder0PinA, INPUT);
digitalWrite(encoder0PinA, HIGH); // turn on pullup resistor
pinMode(encoder0PinB, INPUT);
digitalWrite(encoder0PinB, HIGH); // turn on pullup resistor
pinMode(encoder0PinC, INPUT);
digitalWrite(encoder0PinC, HIGH); // turn on pullup resistor
attachInterrupt(1, doEncoder, CHANGE); // encoder track A on interrupt 1 - pin 3
attachInterrupt(0, doIndex, RISING); // encoder Index track on interupt 0 - pin 2
beginSerial(19200); //start communications with LCD screen Matrix Orbital LCD0821
Serial.print(254, BYTE); //turn off the cursor on LCD
Serial.print(84, BYTE); //turn off the cursor on LCD
Serial.print(254, BYTE); // turn on the LCD backlight //remove any of these if needed
Serial.print(66, BYTE); // turn on the LCD backlight
Serial.print(0); // turn on the LCD backlight
}
void loop(){
Serial.print(12, BYTE); //clears the LCD screen.
Serial.println ("Turns ="); //print "Turns =" on the LCD screen.
decimal = (encoder0Pos / 50); //500 encoder counts per rev divided by 50 is tenths.
if (turn <= -1){ //if turns goes into negative numbers do some stuff to show negative on the LCD.
display = (abs(turn + 1));
decimal = (9 - decimal); //tenths now counts in the reverse direction when turns is negative.
Serial.print ("-"); //print a negative sign when turns is negative
} else {
display = turn; //if turns is not negative then the display equals the turns
}
Serial.print (display); //show turns on LCD
Serial.print ("."); //print a decimal point after the turns
Serial.print (decimal); //print the tenths of a turn after the decimal point.
delay(20); //delay 20ms so that the LCD screen doesnt flood
}
void doIndex(){ //every time the index track comes around doIndex will run.
if (start == true){ //if this is the first time the index track has come around
encoderHome = encoder0Pos; //the encoder Home position will equal the current encoder position.
start = false; //tell the arduino that start is over
} else {
encoder0Pos = encoderHome; } //if this is not the first time index has come around reset the encoder position
} //so that if any counts are missed because of high speed or too high of resolution
//they do not mess up the total turns.
CONTINUED ON NEXT POST