hi
i am trying to use a Incremental Optical Rotary Encoder with 600 ppr to get an rpm on a moter
iam using the arduino due
this code works from RPM 0 to about 800 but when the RPM is higher then 800 it does not work it give 0 as the encoder Value and the RPM can anyone look at this code and find out why it is doing this
thanks
jim
//pin2 = A-channal(Green) pin3 = B-channal(White)
int encoderPin1 = 2;
int encoderPin2 = 3;
//encoader variables
volatile long lastEncoded = 0;
volatile long encoderValue = 0;
volatile long lastencoderValue = 0;
volatile long lastMSB = 0;
// variables RPM
int rpm = 0 ;
void setup() {
Serial.begin (115200);
//encoader pins
pinMode(encoderPin1, INPUT);
pinMode(encoderPin2, INPUT);
//pullup resistors
digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
digitalWrite(encoderPin2, HIGH); //turn pullup resistor on
//on interrupt 0=pin 2 1=pin 3
attachInterrupt(2, updateEncoder, CHANGE);
attachInterrupt(3, updateEncoder, CHANGE);
}
void loop(){
// print RPM
rpm = ((encoderValue *60)/2400) ;
Serial.print("RPM-----------");
Serial.println(rpm);
Serial.println(encoderValue);
encoderValue=0;
// 1 second delay
delay(1000);
}
// encoader interrupt
void updateEncoder(){
int MSB = digitalRead(encoderPin1); //MSB = most significant bit
int LSB = digitalRead(encoderPin2); //LSB = least significant bit
int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value
if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;
lastEncoded = encoded; //store this value for next time
}
600 ppr at 800 rpm is 480000 interrupts per second; that may be beyond what your arduino is capabale of doing, at least using the normal Arduino functions like digitalRead(). If 800 works, and you only need to handle 1000 as the max, you might look at using direct digital IO or finding a digitalReadFast() library. Otherwise you might need to throw extra hardware at the problem, and/or consider a different method.
Edit: oops. My calculations were interrupts per minute... I always seem to forget that factor when dealing with RPM, vs everything else that is timed in seconds. (OTOH, there's probably more than one interrupt per encoder "tick"?)
One would hope that had if (s)he wanted position information, it would have been mentioned. My experience suggests that once you're above a couple of revs/sec, position is not the question. Remember that positional accuracy is a fractional thing, a fractional of one revolution. If one is intent on using the wrong tool, at least find a way to filter out the first 599 pulses, after all, for measuring rpm it's only every 600th pulse that matters.
Before the pedants jump in with the usual rhetoric, look at a simple bit of math. 1000rpm is 16 - 2/3 revs/sec. At 600ppr, that's 10,000 pulses per second. That's a period (time between pulses) of 100us. The resolution of micros() is 4us. So, if you measure pulse timing at 100us, rpm = 1000. If however, you measure 104us, rpm = 962. At 96us, rpm = 1042. How accurate is that?
The same measurement using a hall effect sensor or some other device intended for measuring revolutions, 1000 rpm has a revolutional period of 60ms, that's 60,000us. If you measure 60,004, rpm = 999.93. In fact to get the same 'lack-of-accuracy' the timing would need to be out by approximately +/- 2,300us.
jimlathe board is a DUE, and a DUE has 2 hardware quadrature decoder. With this board, the right way to measure speed of a quadrature encoder is certainely not with digitalread() function....
See this thread, reply #55 for a working example sketch with a quadrature encoder of 1024 ppr (= 4 * 1024 edges per revolution) up to 3500 RPM: