Skip to content

Instantly share code, notes, and snippets.

@davay42
Created March 6, 2025 04:42
Show Gist options
  • Save davay42/013df7a7869431bdf1fafb803977f6e2 to your computer and use it in GitHub Desktop.
Save davay42/013df7a7869431bdf1fafb803977f6e2 to your computer and use it in GitHub Desktop.
/*
* ESP32 Counter with OLED Display and Encoder
*
* Hardware required:
* - ESP32 development board
* - SH1106 128x64 OLED Display (I2C)
* - Rotary Encoder with push button
* - 2 additional buttons
*
* Wiring:
* ESP32 Component
* ------------------------------------
* GPIO16 (RX2) Encoder Push
* GPIO17 Encoder A
* GPIO18 Encoder B
* GPIO25 BACK Button
* GPIO26 CONFIRM Button
* GPIO21 (SDA) OLED SDA
* GPIO22 (SCL) OLED SCL
* 3.3V VCC (OLED, Encoder, Buttons)
* GND GND (All components)
*
* Functionality:
* 1. Encoder rotation changes counter value
* 2. Any button press (encoder push, BACK, or CONFIRM) resets counter to 0
* 3. Display shows current value (divided by 2 for smoother counting)
* 4. Serial monitor shows detailed counter updates
*/
#include <Arduino.h>
#include <Wire.h>
#include <U8g2lib.h>
// Pin definitions
const uint8_t ENC_PUSH = 16; // Encoder push button
const uint8_t ENC_A = 17; // Encoder signal A
const uint8_t ENC_B = 18; // Encoder signal B
const uint8_t BTN_BACK = 25; // Back button
const uint8_t BTN_CONFIRM = 26; // Confirm button
// Global variables
volatile int32_t encoderValue = 0;
volatile uint8_t lastEncA = HIGH;
volatile uint8_t lastEncB = HIGH;
int lastEncPush = HIGH;
int lastBackBtn = HIGH;
int lastConfirmBtn = HIGH;
// Initialize OLED display
U8G2_SH1106_128X64_NONAME_F_HW_I2C display(U8G2_R0, U8X8_PIN_NONE);
// Encoder interrupt service routine
void IRAM_ATTR encoderISR() {
uint8_t a = digitalRead(ENC_A);
uint8_t b = digitalRead(ENC_B);
if (a != lastEncA) {
lastEncA = a;
if (a != b) {
encoderValue++;
} else {
encoderValue--;
}
}
}
// Display update function
void updateDisplay(int32_t value) {
display.clearBuffer();
char str[10];
sprintf(str, "%d", value / 2);
display.drawStr(10, 35, str);
display.sendBuffer();
}
void setup() {
// Initialize serial communication
Serial.begin(115200);
Serial.println("ESP32 Counter Example Starting...");
// Configure pins
pinMode(ENC_PUSH, INPUT_PULLUP);
pinMode(ENC_A, INPUT_PULLUP);
pinMode(ENC_B, INPUT_PULLUP);
pinMode(BTN_BACK, INPUT_PULLUP);
pinMode(BTN_CONFIRM, INPUT_PULLUP);
// Initialize display
display.begin();
display.setFont(u8g2_font_ncenB14_tr);
updateDisplay(0);
// Attach encoder interrupt
attachInterrupt(digitalPinToInterrupt(ENC_A), encoderISR, CHANGE);
Serial.println("Setup complete. Rotate encoder or press any button.");
}
void loop() {
static int32_t lastDisplayedValue = 0;
// Update display if value changed
if (encoderValue != lastDisplayedValue) {
Serial.printf("Encoder value: %d (displayed: %d)\n", encoderValue, encoderValue / 2);
updateDisplay(encoderValue);
lastDisplayedValue = encoderValue;
}
// Read all buttons
int encPush = digitalRead(ENC_PUSH);
int backBtn = digitalRead(BTN_BACK);
int confirmBtn = digitalRead(BTN_CONFIRM);
// Check for button presses and reset counter
if ((encPush != lastEncPush && encPush == LOW) ||
(backBtn != lastBackBtn && backBtn == LOW) ||
(confirmBtn != lastConfirmBtn && confirmBtn == LOW)) {
encoderValue = 0;
updateDisplay(encoderValue);
Serial.println("Counter reset by button press");
}
// Update button states
lastEncPush = encPush;
lastBackBtn = backBtn;
lastConfirmBtn = confirmBtn;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment