I'm trying to calculate the coming RPS from rotary encoder. I am trying to get it by checking the status with digitalRead. However, I can not get more than 6 RPS. Any solution? I will be obliged for your help. Following is the code.

float rps;

void setup() {
  DDRC &= ~_BV (1); // pinMode (A1, INPUT);

void loop() {
  static int lastReedState;
  static unsigned long lastTransition;
  int reedState = (PINC & _BV (1)) == 0; // digitalRead (A1);
  // On a rising transition of the reed switch:
  if (reedState == LOW && lastReedState == HIGH) {
    // HIGH LOW measuring the low period
    // Compute time since last valid transition.
    unsigned long now = micros();
    unsigned long revolutionTime = now - lastTransition;
    // measuring the High period
    // Compute the RPS
    rps = 1.00 / (12.00*revolutionTime) *1000000.00;
    // 12 is rotary encoders resolution
    // Remember this transition.
    lastTransition = now;
  // Remember last state.
  lastReedState = reedState;
  • Just asking, what Arduino do you use? Why not using interrupt? – dhimaspw Dec 8 '16 at 6:19
  • I am using Arduino Uno. As the matter of fact I have to read 8 input. in that case interrupts become very complicated. – zalt Dec 8 '16 at 6:45
  • have you tried using multiple PulseIn()? – dhimaspw Dec 8 '16 at 7:37
  • When I use PulseIn(), it will affect other process after a while. Therefore, I avoid using such function. – zalt Dec 8 '16 at 7:45
  • 3
    Your code is so slow because of Serial.println(rps);. You should at least embed this statement inside something like if (millis() - lastTimePrinted >= PRINT_PERIOD) { ... } and not try to print faster than your baud rate (960 bytes/s). – Edgar Bonet Dec 8 '16 at 8:54

For one channel I'd use Input Capture capability on Timer/Counter 1. Without debouncing it'll be pretty easy.

If you want to read 8 inputs simultaneously, you can use Pin Change interrupts and Timer/Counter 1 as a timebase. If you don't use Serial communication, you can use whole PORTD, otherwise you can use for example 4 channels on PORTC and 4 channels on PORTD. But again, debouncing will be little bit challenging.

  • I am wondering If it is possible to use more than one interrupt in either PORTC or PORTD . Because I did in that way and could not get proper result for more than one interrupt per either port. – zalt Dec 8 '16 at 8:36
  • @zalt For Pin Change Interrupts no, there is one Interrupt source for each Port. You have to figure out, which lines were changed. However there is an Arduino library PinChangeInt where you can register callback function for each input. – KIIV Dec 8 '16 at 8:47
  • Implemented with a state machine, quadrature coding does not need debouncing. Bounce can cause invalid states or extra states, but they cancel out. – James Waldby - jwpat7 Dec 8 '16 at 9:08
  • @jwpat7 Right, I've missed it's about rotary encoder(s) and his code looks like he's using something like reed switches. – KIIV Dec 8 '16 at 9:18
  • Ok . So far done for one. I have another question. I make new question. – zalt Dec 9 '16 at 7:20

Consider using code similar to that shown in answers to the following questions: Reading from a KY-040 rotary encoder with Digispark; and Read RC receiver channels using Interrupt instead of PulseIn; and Can external interrupts be OR'd together on the '328 (Uno)?.

The first answer illustrates a fast-operating state machine to handle quadrature-encoded signals, ie rotary-encoder inputs.

The second answer illustrates handling of multiple encoders via a single interrupt routine, using a pair of two pin-change-interrupt (PCI) pins per encoder. The method assumes pins of a pair are in the same port. Most Arduino IO pins are PCI capable; some are not; on some models of Arduinos, some PCI pins aren't brought out to headers, or aren't recognized as PCI by the IDE, as noted in the question Why PJ0 and PJ1 are not reporting as PCINT pins.

The third answer includes code from the first two, and also has a sketch that displays a table of PCI vectors and masks. This table assists in planning pin layouts to reduce ISR overhead. For example, if you have half a dozen encoders, you might attach three of them to six pins on one port (and one vector), and the other three to six pins on another port (and another vector). Or you might put two encoders on each of three ports. The latter method might run, on average, a little faster (eg a microsecond or so per ISR invocation).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.