How to Code double click and long press with a rotary encoder

I want to be able to double click and long press the rotary encoder to do different tasks how would I be able to do this?

#include <HID-Project.h>
#include <Encoder.h>
#define inputCLK 1
#define inputDT 2
#define inputSW 3

int currentStateCLK;
int previousStateCLK; 

void setup() { 
	pinMode (inputCLK,INPUT);
	pinMode (inputDT,INPUT);
	pinMode(inputSW, INPUT_PULLUP);

	Serial.begin (4000);
	Consumer.begin();
	Keyboard.begin();

	// Read the initial state of inputCLK
	// Assign to previousStateCLK variable
	previousStateCLK = digitalRead(inputCLK);

} 



void loop() { 
	// Read the current state of inputCLK
	currentStateCLK = digitalRead(inputCLK);

	// If the previous and the current state of the inputCLK are different then a pulse has occured
	if (currentStateCLK != previousStateCLK){ 
		// If the inputDT state is different than the inputCLK state then 
		// the encoder is rotating counterclockwise
		if (digitalRead(inputDT) != currentStateCLK) { 
			rotateRight();
		} else {
			rotateLeft();
		}
	} 
	// Update previousStateCLK with the current state
	previousStateCLK = currentStateCLK; 

  if (!digitalRead(inputSW)){
    Consumer.write(MEDIA_PLAY_PAUSE);
    delay(300);
  }
      
}

void rotateRight() {
	// Increase the volume.
	Consumer.write(MEDIA_VOLUME_UP);  
}

void rotateLeft() {
	// Decrease the volume.
	Consumer.write(MEDIA_VOLUME_DOWN);
}


Use the encoder button (inputSW) with the IDE examples for special button handling. Don't forget the pullup resistors!

The OneButton library does support this out of the box

here is an example on how to use that

click to see the code
#include "OneButton.h"
const byte rotarySwitchPin = 4;
OneButton rotarySwitch(rotarySwitchPin);

void singleClick() {
  Serial.println("SINGLE CLICK");
}

void doubleClick() {
  Serial.println("DOUBLE CLICK");
}

void longClickStart() {
  Serial.println("LONG CLICK START");
}

void longClickOngoing() {
  Serial.println("ONGOING LONG CLICK");
}

void longPressStop() {
  Serial.println("LONG CLICK STOP");
}

void setup() {
  pinMode(rotarySwitchPin, INPUT_PULLUP); // necesary on some boards as OneButton does this in the constructor which might be undone during init phase
  Serial.begin(115200);
  rotarySwitch.attachClick(singleClick);
  rotarySwitch.attachDoubleClick(doubleClick);
  rotarySwitch.attachLongPressStart(longClickStart);
  rotarySwitch.setLongPressIntervalMs(100); // will call the ongoing callback every 100ms 
  rotarySwitch.attachDuringLongPress(longClickOngoing);
  rotarySwitch.attachLongPressStop(longPressStop);
}

void loop() {
  rotarySwitch.tick();
  // you can do other stuff here
}

or edited code based on @noiasca input's below

#include "OneButton.h"
const byte rotarySwitchPin = 4;
OneButton rotarySwitch(rotarySwitchPin);

void singleClick() {
  Serial.println("SINGLE CLICK");
}

void doubleClick() {
  Serial.println("DOUBLE CLICK");
}

void longClickStart() {
  Serial.println("LONG CLICK START");
}

void longClickOngoing() {
  Serial.println("ONGOING LONG CLICK");
}

void longPressStop() {
  Serial.println("LONG CLICK STOP");
}

void setup() {
  rotarySwitch.setup(rotarySwitchPin, INPUT_PULLUP, true); // <== new features to make sure the pullup is activated on every board. Not necessary on a UNO
  Serial.begin(115200);
  rotarySwitch.attachClick(singleClick);
  rotarySwitch.attachDoubleClick(doubleClick);
  rotarySwitch.attachLongPressStart(longClickStart);
  rotarySwitch.setLongPressIntervalMs(100); // will call the ongoing callback every 100ms 
  rotarySwitch.attachDuringLongPress(longClickOngoing);
  rotarySwitch.attachLongPressStop(longPressStop);
}

void loop() {
  rotarySwitch.tick();
  // you can do other stuff here
}

1 Like

@J-M-L
your userprofile doesn't provide an easy access to send you a PM, hence public:

regarding

pinMode(rotarySwitchPin, INPUT_PULLUP); // necesary on some boards as OneButton 

check the .setup() member function of OneButton - and use the "new way" how to initialize the object and assign the pins in setup:

I know indeed (I was part of the discussion that lead to the addition).
You are right, if Wokwi updated the library then that's what I should have used (I was just lazy in the wokwi and copied / paste an old demo code I had and to be fair, on a UNO it's not an issue).

EDIT: ➜ I updated the wokwi and it works fine

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.