Rotary encoder help

I had a quick go at reading a rotary encoder that I pulled out of a cheap mouse, with the center pin at +3v and the 2 outer pins to ext0 and ext1. Using the following python code, I can’t seem to read the inputs correctly.

# Welcome to Python on Pokitto!
from umachine import *
import upygame as upg
import umachine as pok

# Setup the screen.
screen = upg.display.set_mode()

pin0 = Pin( Pin.EXT0, Pin.IN )
pin1 = Pin( Pin.EXT1, Pin.IN )

olda = 0
a=0
b=0
x=0

while True:

    a = pin0.value()
    b = pin1.value()

    if olda != a:
        if b == 1:
            x+=1
        else:
            x-=1
 
    olda = a
 
    # Render screen
    screen.fill(0)
    
    pok.draw_text(0, 14, str(a), 1)
    pok.draw_text(0, 21, str(b), 1)
    pok.draw_text(x, 35, "=", 1)
    upg.display.flip()

I expected the inputs to be something like the following - 00,10,11,01,00,10,11,01 etc. however I’m only getting 00,10,11,00,10,11. It seems to be missing part of the rotation.

Has anyone doe this sort of thing before? Any clues as to if I’m reading the inputs correctly or not?

I have coded rotary encoders from scratch. I am a bit of an expert.

2 words: state machine

Without a state machine, you will never get it to work reliably

EDIT

Turns out I had it wired wrong, it’s working fine :slight_smile:

I know a little about them from a few years ago when I had to emulate one to fix an N64 joystick (internally they aren’t joysticks, but spring loaded rotary encoders, like a self centring mouse)

Is there a speed issue reading pins? I’m only getting 44fps with the following code, which has the knock-on effect of not reading the encoder fast enough. If I turn it nice and slow, everything is fine, but turn it quickely and it misses reads.

# Welcome to Python on Pokitto!
from umachine import *
import upygame as upg
import umachine as pok

# Setup the screen.
screen = upg.display.set_mode()

pin0 = Pin( Pin.EXT0, Pin.IN )
pin1 = Pin( Pin.EXT1, Pin.IN )

a=0
b=0
c=0
oldc= 0
x=0

while True:

    oldc = c
    a = pin0.value()
    b = pin1.value()
    c = a | (b * 2)
    
    if oldc != c:
        if c == 0:
            if oldc == 2:
                x-=1
            if oldc == 1:
                x+=1
        if c == 1:
            if oldc == 0:
                x-=1
            if oldc == 3:
                x+=1
        if c == 2:
            if oldc == 3:
                x-=1
            if oldc == 0:
                x+=1
        if c == 3:
            if oldc == 1:
                x-=1
            if oldc == 2:
                x+=1


    # Render screen
    screen.fill(0)
    
    pok.draw_text(0, 14, str(a), 1)
    pok.draw_text(0, 21, str(b), 1)
    pok.draw_text(x, 38, "=", 1)

    upg.display.flip()

You do not have to clear the screen, that is done automatically.

Do you need to draw on every round? What if you just collect the values to the list and draw and flip e.g. every 10th frame?

Which brings us back to the state machine. Plz believe me, unless you intend to poll like crazy, only the state machine can make it 100% reliable