Quadrature Encoder to measure RPM

Hi,

I am currently working on a project using a 360 PPR push pull encoder with Z index/1 per revolution signal, with an Arduino Mega. The encoder is connected to a small turbine rotor and I would like to measure the RPM of the rotor via the use of the Z index signal up to a maximum of 2000 RPM, and display the RPM on an LCD screen. I was thinking about using the 360 PPR signals, but thought this would be out of the capability of the Arduino at 2000 RPM, which is a sampling rate of 12 kHz. But am not sure.

I have tested the code below using the external interrupt capability on the Arduino, using parts of an encoder sketch off the web with a momentary push button initially to see if program worked, and that I could output the pulse count to the LCD screen, based on the rising edge of the push button signal. This worked OK, but when I connected the encoder, I could not pick up one pulse, even when printing the data to screen. This is not with the encoder rotating quickly, just rotating it slowly by hand.

I have tested the wiring on the encoder, and also checked the Z signal with a multi-meter to check that 5V is being obtained when the at the Z index position. But still can’t figure out what is causing the issue, especially when the push button worked. I have tried modifying the delay in the void loop, but that doesn’t make a difference as far as I can tell. I am assuming that this is possible with the current setup, and was just wondering what I am missing, any help would be appreciated. Or is there a better approach. I have looked briefly at quadrature timer chips, but for the once per revolution signal I thought they weren’t appropriate.

Many thanks for any help

Kind Regards

// The pin the encoder is connected
#include <LiquidCrystal.h>
int encoder_in = 3;
LiquidCrystal lcd(26, 24, 29, 27, 25, 23);
// Initialize the counter
volatile unsigned int pulses = 0;

void count() {
  // This function is called by the interrupt
  pulses++;
  lcd.setCursor(0,2);
  lcd.print(pulses);
}

void setup() {
  pinMode(encoder_in, INPUT);
  lcd.begin(20,4);

  attachInterrupt(1, count, RISING);
}

void loop() {

  delay(100); 
}

You should not be doing any I/O in an interrupt routine.

MechEng86:
Hi,

I am currently working on a project using a 360 PPR push pull encoder with Z index/1 per revolution signal, with an Arduino Mega. The encoder is connected to a small turbine rotor and I would like to measure the RPM of the rotor via the use of the Z index signal up to a maximum of 2000 RPM, and display the RPM on an LCD screen. I was thinking about using the 360 PPR signals, but thought this would be out of the capability of the Arduino at 2000 RPM, which is a sampling rate of 12 kHz. But am not sure.

I have tested the code below using the external interrupt capability on the Arduino, using parts of an encoder sketch off the web with a momentary push button initially to see if program worked, and that I could output the pulse count to the LCD screen, based on the rising edge of the push button signal. This worked OK, but when I connected the encoder, I could not pick up one pulse, even when printing the data to screen. This is not with the encoder rotating quickly, just rotating it slowly by hand.

I have tested the wiring on the encoder, and also checked the Z signal with a multi-meter to check that 5V is being obtained when the at the Z index position. But still can’t figure out what is causing the issue, especially when the push button worked. I have tried modifying the delay in the void loop, but that doesn’t make a difference as far as I can tell. I am assuming that this is possible with the current setup, and was just wondering what I am missing, any help would be appreciated. Or is there a better approach. I have looked briefly at quadrature timer chips, but for the once per revolution signal I thought they weren’t appropriate.

Many thanks for any help

Kind Regards

// The pin the encoder is connected

#include <LiquidCrystal.h>
int encoder_in = 3;
LiquidCrystal lcd(26, 24, 29, 27, 25, 23);
// Initialize the counter
volatile unsigned int pulses = 0;

void count() {
 // This function is called by the interrupt
 pulses++;
 lcd.setCursor(0,2);
 lcd.print(pulses);
}

void setup() {
 pinMode(encoder_in, INPUT);
 lcd.begin(20,4);

attachInterrupt(1, count, RISING);
}

void loop() {

delay(100);
}

If the Push Pull Encoder actually generates 0 Volt and 5 Volt PULSES
just like the Push Button then the Encoder should work.

Also, I do not recommend LCD functions inside the interrupt.

Is the Z Index output both: Active High and Active Low? Or does it need a Pull-Up resistor or a Pull-Down resistor?

Can you draw two schematic diagrams: Switch vs Encoder? Is there an example circuit for that specific MODEL Encoder?

Hi aarg/mrsimmitville,

Many thanks for your reply. This is my first attempt with an interrupt and encoder of this type. So will remove the LCD functions from the interrupt loop like you suggest. I will change the order of the program tomorrow and rerun the code and re-post how I get on

I have only been able to check the encoder with a multi-meter, I don't have access to any other instruments to make more accurate checks. Based on what you have said I must be misinterpreting the setup of the encoder

mrsimmitville - I will get the encoder information together and post the manufactuer data sheet also.

Many thanks for your help

As mrsummitville suggests you may need a pull up resistor with the index pulse. Setting pin 3 to INPUT_PULLUP may be strong enough by itself. If you are indeed getting 5V with the index pulse then the following sketch will read rpm. The display separate from the interrupt, and the reading of the counts from the interrupt routine is protected.

volatile unsigned int  count = 0;

unsigned int copyCount = 0;
unsigned int rpm = 0;

unsigned long lastRead = 0;

unsigned long interval = 1000;

void setup()
{
  Serial.begin(115200);
  Serial.println("start...");

  attachInterrupt(1, isrCount, RISING);
  pinMode(3,INPUT_PULLUP);
}

void loop()
{
  if (millis() - lastRead >= interval) //read interrupt count every second
  {
    lastRead  += interval; //millis();
    // disable interrupts,make copy of count,reenable interrupts
    noInterrupts();
    copyCount = count;
    count = 0;
    interrupts();
  
    rpm = copyCount*60;
    Serial.println(rpm);//or lcd output   
  }
}

void isrCount()
{
  count++;
}

MechEng86: I am currently working on a project using a 360 PPR push pull encoder with Z index/1 per revolution signal, with an Arduino Mega. The encoder is connected to a small turbine rotor and I would like to measure the RPM of the rotor via the use of the Z index signal up to a maximum of 2000 RPM, and display the RPM on an LCD screen. I was thinking about using the 360 PPR signals, but thought this would be out of the capability of the Arduino at 2000 RPM, which is a sampling rate of 12 kHz. But am not sure.

12 kHz is not enough for A/B counting of a quadruple rotary encoder. The datasheet "PPR" is for "full steps", but each "full step" is four flank changes (quarter steps). So the sampling frequency should be more than 48 kHz for quarter step A/B counting in your application.

For a "turbine rotor" which is always rotating in the same direction, it is possibly enough to just count the Z index, which will lead to 2000 counts per minute. That's an easy task for an Arduino.

There is nothing to be gained, and arguably something to be lost, by using a high-count encoder to simply measure RPM. Using just the index pulse will give you a better reading with FAR less overhead. Look at the FreqMeasure library. It will do everything for you in about two lines of code, and works very well.

Regards, Ray L.