//*!
// * Example of enabling and handling pin change interrupts
// *
// * In this example we can get an interrupt when pin 3 or 2 changes
// * and use that to move a stepper motor.
// *
// */
#![no_std]
#![no_main]
#![feature(abi_avr_interrupt)]
use panic_halt as _;
use core::sync::atomic::{AtomicBool, Ordering};
static PIN_CHANGED: AtomicBool = AtomicBool::new(false);
//This function is called on change of pin 3 & 2
#[avr_device::interrupt(atmega328p)]
#[allow(non_snake_case)]
fn PCINT2() {
PIN_CHANGED.store(true, Ordering::SeqCst);
}
#[arduino_hal::entry]
fn main() -> ! {
let dp = arduino_hal::Peripherals::take().unwrap();
let pins = arduino_hal::pins!(dp);
//Pins used to drive the stepper motor
let mut dir_pin = pins.d4.into_output();
let mut step_pin = pins.d5.into_output();
//Rotary encoder attached on these pins
let rotary_pins = [
pins.d2.into_floating_input().downgrade(), //CLK
pins.d3.into_floating_input().downgrade(), //DT
];
// Enable the PCINT2 pin change interrupt
dp.EXINT.pcicr.write(|w| unsafe { w.bits(0b100) });
// Enable pin change interrupts on PCINT19 & PCINT18 which is pin PD3 / PD2
dp.EXINT.pcmsk2.write(|w| w.bits(0b1100));
//From this point on an interrupt can happen
unsafe { avr_device::interrupt::enable() };
loop {
if rotate(&PIN_CHANGED) {
//Check which direction the rotary encoder was turned
if rotary_pins[0].is_low() && rotary_pins[1].is_high() {
dir_pin.set_high(); //clockwise
} else if rotary_pins[0].is_high() && rotary_pins[1].is_low() {
dir_pin.set_low(); //counter clockwise
}
//Move the stepper motor
for _ in 0..=19 {
step_pin.set_high();
arduino_hal::delay_us(2000);
step_pin.set_low();
arduino_hal::delay_us(2000);
}
}
}
}
fn rotate(flag: &AtomicBool) -> bool {
avr_device::interrupt::free(|_cs| {
if flag.load(Ordering::SeqCst) {
flag.store(false, Ordering::SeqCst);
true
} else {
false
}
})
}