rotary-encoder-embedded 0.1.1

A rotary-encoder library built with embedded-hal
Documentation
# rotary-encoder-embedded

A rotary encoder library for embedded rust applications

- https://crates.io/crates/rotary-encoder-embedded

![rotary encoder](https://github.com/ostenning/images/blob/main/rotary-encoder.jpg?raw=true)

## features

- Heapless & no standard library
- 2-bit gray code lookup table implementation
- Implemented with embedded-hal (https://docs.rs/embedded-hal/0.2.7/embedded_hal)
- Experimental support for measuring angular velocity for non-linear control (gated behind the `angular-velocity` feature flag)

## examples

Examples use the `stm32h7xx-hal` crate and are compatible with any project using `embedded-hal`. 
It is recommended to use the `interrupt driven example`.

### simple example

```rust
fn main() -> ! {
    // Configure DT and CLK pins, typically pullup input
    let rotary_dt = gpio_pin_1.into_pull_up_input()
    let rotary_clk = gpio_pin_2.into_pull_up_input();
    // Initialize the rotary encoder
    let mut rotary_encoder = RotaryEncoder::new(
        rotary_dt,
        rotary_clk,
    );
    // Optional, configure sensitivity if needed
    rotary_encoder.set_sensitivity(Sensitivity::Low);
    // Application loop
    loop {
        // Update the encoder, which will compute its direction
        rotary_encoder.update();
        match rotary_encoder.direction() {
            Direction::Clockwise => {
                // Increment some value
            }
            Direction::AntiClockwise => {
                // Decrement some value
            }
            Direction::None => {
                // Do nothing
            }
        }
    }
}
```

### interrupt driven example

Trigger GPIO pin interrupts for both `DT` and `CLK` on both rising and falling edges

```rust
static ROTARY_ENCODER: Mutex<RefCell<Option<RotaryEncoder>>> = Mutex::new(RefCell::new(None));

fn main() -> ! {
    // Configure DT typically as pullup input & interrupt on rising/falling edges
    let mut rotary_dt = rotary_dt.into_pull_up_input();
    rotary_dt.make_interrupt_source(sys_cfg);
    rotary_dt.trigger_on_edge(exti, Edge::RisingFalling);
    rotary_dt.enable_interrupt(exti);
    // Configure CLK typically as pullup input & interrupt on rising/falling edges
    let mut rotary_clk = rotary_clk.into_pull_up_input();
    rotary_clk.make_interrupt_source(sys_cfg);
    rotary_clk.trigger_on_edge(exti, Edge::RisingFalling);
    rotary_clk.enable_interrupt(exti);
    // Initialize Rotary Encoder and safely store in static global
    interrupt::free(|cs| {
        ROTARY_ENCODER.borrow(cs).replace(Some(
            RotaryEncoder::new(
                rotary_dt,
                rotary_clk,
            )
        ));
    });

    loop {}
}
/// Called from the GPIO interrupt vector
fn handle_rotary_interrupt() {
    // Retrieve Rotary Encoder from safely stored static global
    interrupt::free(|cs| {
        if let Some(ref mut rotary_encoder) = ROTARY_ENCODER.borrow(cs).borrow_mut().deref_mut() {
            // Borrow the pins to clear the pending interrupt bit (which varies depending on HAL)
            let mut pins = rotary_encoder.borrow_pins();
            pins.0.clear_interrupt_pending_bit();
            pins.1.clear_interrupt_pending_bit();
            // Update the encoder, which will compute its direction
            rotary_encoder.update();
            match rotary_encoder.direction() {
                Direction::Clockwise => {
                    // Increment some value
                }
                Direction::AntiClockwise => {
                    // Decrement some value
                }
                Direction::None => {
                    // Do nothing
                }
            }
        }
    });
}
```

### angular velocity example

For experimental angular velocity support use the `RotaryEncoderWithVelocity` struct. This functionality is gated behind the `angular-velocity` crate feature flag.

```rust
fn main() -> ! {
    // Configure DT and CLK pins, typically pullup input
    let rotary_dt = gpio_pin_1.into_pull_up_input()
    let rotary_clk = gpio_pin_2.into_pull_up_input();
    // Initialize Rotary Encoder with Velocity functionality
    let mut rotary_encoder = RotaryEncoderWithVelocity::new(
        rotary_dt,
        rotary_clk,
    );
    // Optional settings
    rotary_encoder.set_sensitivity(Sensitivity::Low);
    rotary_encoder.set_velocity_action_ms(5);       // The window of time that the velocity may increase
    rotary_encoder.set_velocity_inc_factor(0.2);    // How quickly the velocity increases over time
    rotary_encoder.set_velocity_dec_factor(0.01);   // How quickly the velocity decreases over time
    // Application loop
    loop {
        // Update the encoder which will compute its direction and velocity
        // As velocity is a function of time, we need the current time
        // current_time should be a monotonously rising time in ms (akin to Arduino's `millis()`)
        rotary_encoder.update(current_time);
        // Get the velocity
        let velocity = rotary_encoder.velocity();
        // Match the direction
        match rotary_encoder.direction() {
            Direction::Clockwise => {
                // Increment some value by some factor multiplied by velocity
            }
            Direction::AntiClockwise => {
                // Decrement some value by some factor multiplied by velocity
            }
            Direction::None => {
                // Do nothing
            }
        }
        // As velocity is a function of time, we need to reduce its value over time
        // This method could also be called from a Timer
        rotary_encoder.decay_velocity();
    }
}
```