Package: micropython-rotary-encoder
This is an automatic translation, may be incorrect in some places. See sources and examples!Rotary EncoderLibrary for Raspberry Pi Pico microcontroller encoder using MicroPython language.
Library features:Encoder: normal rotation, pressed rotation, fast rotationButton: anti-rattle, hold, click, multiple clicksEncoder button registration is optionalInterrupts are used for registering eventsEvents can be handled in several ways:With asyncio task (recommended)By interrupt timerIndependent function callThe following materials were used to develop the library:LibraryRotary Encoderby Mike TeachmanLibrary (Arduino)EncButton, by AlexGyverMaterialRotary Encoder, by CoderDojoTCCompatibilityMicroPython 1.19.1Raspberry Pi PicoRotary Encoder EC11 (KY-040)On the hardware above the library has been tested and works correctly.
But with small crutches, it can work on other equipment.ATTENTIONYou use this module at your own risk.
My experience in MicroPython programming is the whole 7 days. So there may be nuances that I haven't considered.
If you notice a bug or have suggestions for improvement, write to Issues.ContentsInstallInitializationDocumentationExamplesBugs and feedbackInstallationInstall the library via pip (Thonny -> Manage Packages) by namemicropython-rotary-encoderOr manual installation:Download library from githubtake themicropython_rotary_encoderfolder from the archive.upload to the root of the microcontroller or to thelibfolder.If you want to play around with the logic of the library, then the 2nd installation option is preferable. :)UsageInitializationfrommachineimportPinfrommicropython_rotary_encoderimportRotaryEncoderRP2,RotaryEncoderEvent# create pins for encoder and buttonen_pin_clk=Pin(15,Pin.IN,Pin.PULL_UP)en_pin_dt=Pin(9,Pin.IN,Pin.PULL_UP)en_pin_sw=Pin(8,Pin.IN,Pin.PULL_UP)# create an encoder objectencoder=RotaryEncoderRP2(en_pin_clk,en_pin_dt,en_pin_sw)After initialization, the encoder automatically subscribes to encoder and button pin interrupts.
But encoder event processing must be started manually.Using the uasyncio libraryThis is the best option for most projects.# at the beginning of the file add the import of the uasyncio libraryimportuasyncioasasyncio# ----# Encoder initialization code above ^# ----asyncdefasync_some_other_task():print("async_some_other_task")whileTrue:awaitasyncio.sleep(1)asyncdefmain():awaitasyncio.gather(encoder.async_tick(1),# run encoder event handling every 1msasync_some_other_task(),)asyncio.run(main())With timer interruptsYou can read more about timershereFor Raspberry Pi PicohereBe careful, although this is the easiest option, it is not optimal.
Since encoder events are handled in a timer interrupt, other interrupts will be delayed.# ----# Encoder initialization code above ^# ----encoder.timer_tick(1)# запускаем обработку событий энкодера каждые 1 мсBy manual callEverything is in your hands, but don't forget to call theraw_tick()method every 1 - 5 ms.importutime# ----# Encoder initialization code above ^# ----whileTrue:encoder.raw_tick()# handle encoder eventsutime.sleep_ms(1)# delayDocumentationConstructor parametersParameterTypeDefaultDescriptionpin_clkpinNonePin CLK encoderpin_dtpinNonePin DT encoderpin_swpinNonePin buttonsdebounce_msint50Contact bounce timeoutencoder_stepint1Encoder stephold_msint1000Button hold timeoutstep_msint200Timeout between encoder eventsfast_msint50Timeout between encoder events on holdclick_msint400Timeout between button pressespin_clk,pin_dt- encoder pins, if one of them is not specified, then the library will work only in button mode.pin_sw- optional parameter, if not specified, the library will work only in encoder mode.debounce_ms- contact bounce timeout, protection against false positives of the button.encoder_step- encoder step, this is the number of encoder events before triggering.
For example, if the step is 1, then each encoder event will fire a trigger.
If the step is 2, then the trigger will fire on every second encoder event.
Useful for compensating for encoder chatter.hold_ms- button hold timeout, if the button is held longer than this time, theHELDevent will fire.step_ms- timeout between multiple clicks, if click events occur faster than this time, theMULTIPLE_CLICKevent will fire.fast_ms- timeout between encoder events for fast scrollingTURN_LEFT_FAST | TURN_RIGHT_FAST.click_ms- timeout between clicking and releasing the button for theCLICKevent.СобытияEncoder/button events are passed to callbacks, which can be registered with theon()method.EventParameters passed to callbackTrigger conditionANYevent_id: int, clicks: intDuplicate any eventCLICKNoneThe button was pressed and released inclick_msMULTIPLE_CLICKclicks: intThe button was pressed, released and pressed again withinstep_msHELDNoneButton held longerhold_msRELEASENoneThe button was released afterHELDTURN_LEFTNoneThe encoder has been turned to the leftTURN_LEFT_FASTNoneThe encoder was turned faster thanfast_msTURN_LEFT_HOLDNoneThe encoder was turned to the left and with theTURN_LEFT_FAST_HOLDNoneThe encoder was turned faster thanfast_msand with theTURN_RIGHTNoneThe encoder has been turned to the rightTURN_RIGHT_FASTNoneThe encoder was turned faster thanfast_msTURN_RIGHT_HOLDNoneThe encoder was turned to the right and with the pressed buttonTURN_RIGHT_FAST_HOLDNoneThe encoder was turned faster thanfast_msand with theRegister callbacksTo register callbacks, you need to use theon(event, callback)method, which takes two parameters.event- event, property of theRotaryEncoderEventclass.callback- a function that will be called when the event fires.
The number of arguments to the callback function depends on the event. See table above.# ----# Encoder initialization code above ^# ----# subscribe to encoder eventsdefon_click():print("CLICK")defon_multy_clicks(clicks:int):print(f"CLICK{clicks}times")defon_any(event_id:int,clicks:int):print(f"ANY{event_id}, clicks{clicks}")encoder.on(RotaryEncoderEvent.CLICK,on_click)encoder.on(RotaryEncoderEvent.MULTIPLE_CLICK,on_multy_clicks)encoder.on(RotaryEncoderEvent.ANY,on_any)Unsubscribing from eventsTo unsubscribe from events, you need to use theoff(event, callback)method, which takes two parameters.event- event, property of theRotaryEncoderEventclass.callback- a link to a function that was registered earlier.
For one method call, only one callback from one event is unsubscribed.# ----# Callback registration code above ^# ----# unsubscribe from the encoder eventencoder.off(RotaryEncoderEvent.CLICK,on_click)# example with multiple subscriptionencoder.on(RotaryEncoderEvent.CLICK,on_click)# subscribe firstencoder.on(RotaryEncoderEvent.CLICK,on_click)# subscribe secondencoder.off(RotaryEncoderEvent.CLICK,on_click)# unsubscribe firstUnsubscribe from all eventsTo unsubscribe from all events, you need to use theoff_all()method, which takes two parameters.event- event, property of theRotaryEncoderEventclass.callback- a reference to a function that was registered earlier, if it is not passed, then all listeners of this event will be unsubscribed.# ----# Encoder initialization code above ^# ----defon_click():print("CLICK")defon_click2():print("CLICK2")encoder.on(RotaryEncoderEvent.CLICK,on_click)# subscribe first, with callback on_clickencoder.on(RotaryEncoderEvent.CLICK,on_click2)# subscribe second, with callback on_click2encoder.on(RotaryEncoderEvent.CLICK,on_click)# subscribe third, with callback on_click# unsubscribe from the RotaryEncoderEvent.CLICK event only listeners with the on_click callback functionencoder.off_all(RotaryEncoderEvent.CLICK,on_click)# unsubscribe all `on_click` listeners from event RotaryEncoderEvent.CLICK# unsubscribe from the RotaryEncoderEvent.CLICK event of all listenersencoder.off_all(RotaryEncoderEvent.CLICK)# unsubscribe all listeners from event RotaryEncoderEvent.CLICKExamplesExamples of using the encoder can be found in theexamplesfolder.Bugs and feedbackIf you find bugs, createissue.
The library is open for revision and yourpull requests.