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;

// ------------------------------------------------------------------
// ------------------------------------------------------------------

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;

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

  lcd.init();                      // initialize the lcd


  // 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);


// ------------------------------------------------------------------
// ------------------------------------------------------------------
void loop() {

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

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


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

  • 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 '19 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 '19 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 '19 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 '19 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 '20 at 6:18

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, privacy policy and cookie policy