Example project · Displays & sensors
Encoder menu (big OLED)
A settings page on the 1.5″ 128×128 SH1107, driven by a rotary encoder decoded in MicroPython (gray code on two GPIOs with external pull-ups). Select the encoder and use its Inspector arrows to scroll; click the button to toggle an entry.

What's on the bench
- 3× Resistor
- Battery
- Button
- Encoder
- ESP32-C3
- OLED 1.5″ 128×128
The code
This MicroPython script runs on the emulated board every boot; edit it in the Code tab.
from machine import I2C, Pin import framebuf, time i = I2C(0, scl=Pin(9), sda=Pin(8)) buf = bytearray(2048) fb = framebuf.FrameBuffer(buf, 128, 128, framebuf.MONO_VLSB) for c in b'\xae\x20\xa8\x7f\xd3\x00\xdc\x00\x81\x4f\xad\x8a\xa4\xa6\xaf': i.writeto(0x3d, bytes([0, c])) def show(): for p in range(16): i.writeto(0x3d, bytes([0x00, 0xb0 + p, 0x00, 0x10])) i.writeto(0x3d, b'\x40' + buf[p*128:(p+1)*128]) a = Pin(0, Pin.IN) b = Pin(1, Pin.IN) btn = Pin(5, Pin.IN) items = ['LED strip', 'Fan boost', 'Buzzer', 'Wi-Fi', 'Debug log', 'About'] on = [False] * len(items) sel = 0 CODE = {(0, 0): 0, (1, 0): 1, (1, 1): 2, (0, 1): 3} last = CODE[(a.value(), b.value())] lastbtn = btn.value() def draw(): fb.fill(0) fb.text('Settings', 0, 0) fb.hline(0, 10, 128, 1) for i, name in enumerate(items): y = 18 + i * 14 fb.text('>' if i == sel else ' ', 0, y) fb.text('[x]' if on[i] else '[ ]', 10, y) fb.text(name[:11], 38, y) show() draw() print('MENU') while True: c = CODE[(a.value(), b.value())] if c != last: d = (c - last) % 4 if d == 1: sel = (sel + 1) % len(items) print('SEL', sel) elif d == 3: sel = (sel - 1) % len(items) print('SEL', sel) last = c draw() v = btn.value() if v and not lastbtn: on[sel] = not on[sel] print('TOGGLE', sel, on[sel]) draw() lastbtn = v time.sleep_ms(10)