1

This is my first time working with a rotary encoder and interrupts. I am using a Pro Micro which has interrupt pins at pin0 and pin1. The code below works as expected.

My question: do I need to use an interrupt pin for PinB as well, or can I use any digital pin?

It does not seem to work when I choose PinB = 9, for example.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display


// Used for generating interrupts using CLK signal
const int PinA = 0;

// Used for reading DT signal
const int PinB = 1;

// Used for the push button switch
const int PinSW = 8;

// Keep track of last rotary value
int lastCount = 50;

// Updated by the ISR (Interrupt Service Routine)
volatile int virtualPosition = 50;



// ------------------------------------------------------------------
// INTERRUPT     INTERRUPT     INTERRUPT     INTERRUPT     INTERRUPT
// ------------------------------------------------------------------


void isr ()  {
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();

  // If interrupts come faster than 5ms, assume it's a bounce and ignore
  if (interruptTime - lastInterruptTime > 5) {
    if (digitalRead(PinB) == LOW)
    {
      virtualPosition-- ; // Could be -5 or -10
    }
    else {
      virtualPosition++ ; // Could be +5 or +10
    }

    // Restrict value from 0 to +100
    //virtualPosition = min(100, max(0, virtualPosition));


  }
  // Keep track of when we were here last (no more than every 5ms)
  lastInterruptTime = interruptTime;
}

// ------------------------------------------------------------------
// SETUP    SETUP    SETUP    SETUP    SETUP    SETUP    SETUP
// ------------------------------------------------------------------
void setup() {
  // Just whilst we debug, view output on serial monitor
  //  Serial.begin(9600);

  lcd.init();                      // initialize the lcd

  lcd.backlight();

  // Rotary pulses are INPUTs
  pinMode(PinA, INPUT);
  pinMode(PinB, INPUT);

  // Switch is floating so use the in-built PULLUP so we don't need a resistor
  pinMode(PinSW, INPUT_PULLUP);

  // Attach the routine to service the interrupts
  attachInterrupt(digitalPinToInterrupt(PinA), isr, LOW);


}

// ------------------------------------------------------------------
// MAIN LOOP     MAIN LOOP     MAIN LOOP     MAIN LOOP     MAIN LOOP
// ------------------------------------------------------------------
void loop() {

  // Is someone pressing the rotary switch?
  if ((!digitalRead(PinSW))) {
    virtualPosition = 50;
    while (!digitalRead(PinSW))
      delay(10);
    //    Serial.println("Reset");
  }

  // If the current rotary switch position has changed then update everything
  if (virtualPosition != lastCount) {



    lcd.clear();
    lcd.print(virtualPosition);

    // Keep track of this new value
    lastCount = virtualPosition ;
  }

  //delay(100);
}
5
  • think about how the code works now, with just a single interrupt ... then think about what would happen if you had interrupt on both data pins of the encoder ... one thing to note is that you would have twice as many interupts per revolution of the encoder, but they would not be symmerical if you are interrupting on only one edge ... i am assuming that you are using a quadrature encoder
    – jsotola
    Jun 28, 2019 at 15:54
  • attachInterrupt(digitalPinToInterrupt(PinA), isr, LOW); I think you mean FALLING, otherwise the ISR will continuously get called when the pin is LOW, leaving barely any CPU cycles for you main code.
    – Gerben
    Jun 28, 2019 at 16:11
  • Let me rephrase: The code above works perfectly fine as is (yes it could be optimized per @Gerben). It uses a single interrupt on PinA. When I try to assign PinB to any other physical digital pin (other than Pin1), it no longer works. I cannot understand why.
    – user19216
    Jun 28, 2019 at 16:29
  • I don't see why it won't work. There is nothing special about pins 1 and 9. 1 indeed is a interrupt pin, but you don't use that here. Pretty strange.
    – Gerben
    Jun 28, 2019 at 16:39
  • How would I use this as a subroutine instead of a main loop? For example, setting a max val, then running another sub until max val is hit. I'd assume we'd use another input for the break trigger.
    – Matt
    Mar 16, 2020 at 6:18

1 Answer 1

2

Found my error... on the ProMicro, the pins are not arranged 0, 1, 2, 3, 4, 5 etc instead they arranged 1, 0, 2, 3, 4, 5 etc... On the board I misread TXO and RXI as TX0 and RX1 and just didn't notice it on my pinout sheet.... so I had D0 and D1 swapped. All works well now. Learning more everyday! I appreciate your time...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.