Improve Rotary Encoder Logic
This commit is contained in:
parent
e023814626
commit
654bd8bdf6
1 changed files with 67 additions and 59 deletions
124
src/bin/main.rs
124
src/bin/main.rs
|
|
@ -7,7 +7,7 @@ use embassy_executor::Spawner;
|
||||||
use embassy_futures::select::{Either, select};
|
use embassy_futures::select::{Either, select};
|
||||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||||
use embassy_sync::channel::{Channel, Sender};
|
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::clock::CpuClock;
|
||||||
use esp_hal::gpio::{Input, InputConfig, Pull};
|
use esp_hal::gpio::{Input, InputConfig, Pull};
|
||||||
use esp_hal::peripherals::GPIO;
|
use esp_hal::peripherals::GPIO;
|
||||||
|
|
@ -116,7 +116,7 @@ async fn main(spawner: Spawner) {
|
||||||
// .unwrap();
|
// .unwrap();
|
||||||
//
|
//
|
||||||
|
|
||||||
let cnt = 4;
|
let cnt = 12;
|
||||||
|
|
||||||
led_strip
|
led_strip
|
||||||
.write((0..cnt).map(|it| {
|
.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
|
// 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<Instant>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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> {
|
struct RotaryEncoderConfig<'a, 'b> {
|
||||||
clk: Input<'a>,
|
clk: Input<'a>,
|
||||||
ot: Input<'b>,
|
ot: Input<'b>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
enum RotaryState {
|
struct RotaryState {
|
||||||
Clk,
|
clk: bool,
|
||||||
Ot,
|
ot: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum RotaryDirection {
|
||||||
|
Cw,
|
||||||
|
Ccw,
|
||||||
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn listen_rotary_encoder(
|
async fn listen_rotary_encoder(
|
||||||
mut config: RotaryEncoderConfig<'static, 'static>,
|
mut config: RotaryEncoderConfig<'static, 'static>,
|
||||||
|
|
@ -180,51 +160,79 @@ async fn listen_rotary_encoder(
|
||||||
) {
|
) {
|
||||||
info!("Waiting for rotary.");
|
info!("Waiting for rotary.");
|
||||||
|
|
||||||
let mut state: Option<RotaryState> = None;
|
let mut state = RotaryState {
|
||||||
|
clk: false,
|
||||||
|
ot: false,
|
||||||
|
};
|
||||||
|
|
||||||
let mut clk_input = Throttler::new(config.clk, Duration::from_millis(50));
|
let mut cw_count = 0;
|
||||||
let mut ot_input = Throttler::new(config.ot, Duration::from_millis(50));
|
let mut ccw_count = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let clk = async {
|
let clk = async {
|
||||||
clk_input.wait_for().await;
|
config.clk.wait_for_any_edge().await;
|
||||||
};
|
};
|
||||||
|
|
||||||
let ot = async {
|
let ot = async {
|
||||||
ot_input.wait_for().await;
|
config.ot.wait_for_any_edge().await;
|
||||||
};
|
};
|
||||||
|
|
||||||
let next_state = match select(clk, ot).await {
|
select(clk, ot).await;
|
||||||
Either::First(_) => (RotaryState::Clk),
|
|
||||||
Either::Second(_) => (RotaryState::Ot),
|
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) {
|
((false, false), (true, false)) => Some(RotaryDirection::Cw),
|
||||||
(None, RotaryState::Ot) => {
|
((true, false), (true, true)) => Some(RotaryDirection::Cw),
|
||||||
if clk_input.input.is_high() {
|
((true, true), (false, true)) => Some(RotaryDirection::Cw),
|
||||||
state = Some(RotaryState::Ot);
|
((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;
|
||||||
}
|
}
|
||||||
|
Some(RotaryDirection::Ccw) => {
|
||||||
|
ccw_count += 1;
|
||||||
}
|
}
|
||||||
(None, RotaryState::Clk) => {
|
None => {}
|
||||||
if ot_input.input.is_high() {
|
|
||||||
state = Some(RotaryState::Clk);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
(Some(RotaryState::Clk), RotaryState::Ot) => {
|
if (state.clk, state.ot) == (true, true) {
|
||||||
info!("Clk -> Ot");
|
if (cw_count - 1) > ccw_count {
|
||||||
state = None;
|
info!("CW");
|
||||||
|
info!("Direction {cw_count} {ccw_count}");
|
||||||
|
cw_count = 0;
|
||||||
|
ccw_count = 0;
|
||||||
channel.send(1).await;
|
channel.send(1).await;
|
||||||
}
|
}
|
||||||
(Some(RotaryState::Ot), RotaryState::Clk) => {
|
if (ccw_count - 1) > cw_count {
|
||||||
info!("Ot -> Clk");
|
info!("CCW");
|
||||||
state = None;
|
info!("Direction {cw_count} {ccw_count}");
|
||||||
|
cw_count = 0;
|
||||||
|
ccw_count = 0;
|
||||||
channel.send(-1).await;
|
channel.send(-1).await;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(Some(RotaryState::Ot), RotaryState::Ot)
|
state = new_state;
|
||||||
| (Some(RotaryState::Clk), RotaryState::Clk) => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue