From 654bd8bdf6a1ec97ff02d5f8e3bf55f6d0e2166c Mon Sep 17 00:00:00 2001 From: Mona Mayrhofer Date: Fri, 27 Jun 2025 20:39:08 +0200 Subject: [PATCH] Improve Rotary Encoder Logic --- src/bin/main.rs | 126 +++++++++++++++++++++++++----------------------- 1 file changed, 67 insertions(+), 59 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 5d9e5ec..66fe8cf 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -7,7 +7,7 @@ use embassy_executor::Spawner; use embassy_futures::select::{Either, select}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::channel::{Channel, Sender}; -use embassy_time::{Duration, Instant, Timer}; +use embassy_time::{Duration, Instant, Timer, WithTimeout}; use esp_hal::clock::CpuClock; use esp_hal::gpio::{Input, InputConfig, Pull}; use esp_hal::peripherals::GPIO; @@ -116,7 +116,7 @@ async fn main(spawner: Spawner) { // .unwrap(); // - let cnt = 4; + let cnt = 12; led_strip .write((0..cnt).map(|it| { @@ -136,43 +136,23 @@ async fn main(spawner: Spawner) { // for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.0.0-beta.0/examples/src/bin } -pub struct Throttler<'a> { - input: Input<'a>, - throttle: Duration, - last_fire: Option, -} - -impl<'a> Throttler<'a> { - pub fn new(input: Input<'a>, throttle: Duration) -> Self { - Self { - input, - throttle, - last_fire: None, - } - } - - pub async fn wait_for(&mut self) { - if let Some(allow_next_fire) = self - .last_fire - .and_then(|last_fire| last_fire.checked_add(self.throttle)) - { - Timer::at(allow_next_fire).await; - } - self.input.wait_for_falling_edge().await; - self.last_fire = Some(Instant::now()); - } -} - struct RotaryEncoderConfig<'a, 'b> { clk: Input<'a>, ot: Input<'b>, } #[derive(Clone, Copy, Debug)] -enum RotaryState { - Clk, - Ot, +struct RotaryState { + clk: bool, + ot: bool, } + +#[derive(Clone, Copy, Debug)] +enum RotaryDirection { + Cw, + Ccw, +} + #[embassy_executor::task] async fn listen_rotary_encoder( mut config: RotaryEncoderConfig<'static, 'static>, @@ -180,51 +160,79 @@ async fn listen_rotary_encoder( ) { info!("Waiting for rotary."); - let mut state: Option = None; + let mut state = RotaryState { + clk: false, + ot: false, + }; - let mut clk_input = Throttler::new(config.clk, Duration::from_millis(50)); - let mut ot_input = Throttler::new(config.ot, Duration::from_millis(50)); + let mut cw_count = 0; + let mut ccw_count = 0; loop { let clk = async { - clk_input.wait_for().await; + config.clk.wait_for_any_edge().await; }; let ot = async { - ot_input.wait_for().await; + config.ot.wait_for_any_edge().await; }; - let next_state = match select(clk, ot).await { - Either::First(_) => (RotaryState::Clk), - Either::Second(_) => (RotaryState::Ot), + select(clk, ot).await; + + let new_state = RotaryState { + clk: config.clk.is_low(), + ot: config.ot.is_low(), }; - //info!("State: {next_state:?}"); + let direction = match ((state.clk, state.ot), (new_state.clk, new_state.ot)) { + ((false, false), (false, false)) => None, + ((false, true), (false, true)) => None, + ((true, false), (true, false)) => None, + ((true, true), (true, true)) => None, - match (state, next_state) { - (None, RotaryState::Ot) => { - if clk_input.input.is_high() { - state = Some(RotaryState::Ot); - } + ((false, false), (true, false)) => Some(RotaryDirection::Cw), + ((true, false), (true, true)) => Some(RotaryDirection::Cw), + ((true, true), (false, true)) => Some(RotaryDirection::Cw), + ((false, true), (false, false)) => Some(RotaryDirection::Cw), + + ((false, false), (false, true)) => Some(RotaryDirection::Ccw), + ((false, true), (true, true)) => Some(RotaryDirection::Ccw), + ((true, true), (true, false)) => Some(RotaryDirection::Ccw), + ((true, false), (false, false)) => Some(RotaryDirection::Ccw), + + ((false, false), (true, true)) => None, //??? + ((false, true), (true, false)) => None, //??? + ((true, false), (false, true)) => None, //??? + ((true, true), (false, false)) => None, //??? + }; + + match direction { + Some(RotaryDirection::Cw) => { + cw_count += 1; } - (None, RotaryState::Clk) => { - if ot_input.input.is_high() { - state = Some(RotaryState::Clk); - } + Some(RotaryDirection::Ccw) => { + ccw_count += 1; } - (Some(RotaryState::Clk), RotaryState::Ot) => { - info!("Clk -> Ot"); - state = None; + None => {} + } + + if (state.clk, state.ot) == (true, true) { + if (cw_count - 1) > ccw_count { + info!("CW"); + info!("Direction {cw_count} {ccw_count}"); + cw_count = 0; + ccw_count = 0; channel.send(1).await; } - (Some(RotaryState::Ot), RotaryState::Clk) => { - info!("Ot -> Clk"); - state = None; + if (ccw_count - 1) > cw_count { + info!("CCW"); + info!("Direction {cw_count} {ccw_count}"); + cw_count = 0; + ccw_count = 0; channel.send(-1).await; } - - (Some(RotaryState::Ot), RotaryState::Ot) - | (Some(RotaryState::Clk), RotaryState::Clk) => {} } + + state = new_state; } }