#![no_std]
#![deny(missing_debug_implementations)]
#![deny(missing_docs)]
#![deny(warnings)]
#![deny(trivial_casts)]
#![deny(trivial_numeric_casts)]
#![deny(unsafe_code)]
#![deny(unstable_features)]
#![deny(unused_import_braces)]
#![deny(unused_qualifications)]
extern crate embedded_hal as hal;
use core::marker::PhantomData;
use hal::digital::OutputPin;
use hal::blocking::delay::DelayUs;
static STEP_DIVISION: [u8; 8] = [1,2,4,8,16,32,64,128];
#[derive(Debug)]
pub struct MotorDriver<D, DIR, STEP, CHIP>
where
D: DelayUs<u32>,
DIR: OutputPin,
STEP: OutputPin,
CHIP: Params,
{
delay: D,
dir_pin: DIR,
step_pin: STEP,
_chip: PhantomData<CHIP>,
number_of_steps: u16,
step_division: u8,
step_interval: u32,
}
impl<D, DIR, STEP, CHIP> MotorDriver<D, DIR, STEP, CHIP>
where
D: DelayUs<u32>,
DIR: OutputPin,
STEP: OutputPin,
CHIP: Params,
{
pub fn set_speed(&mut self, rpm: f32) {
self.step_interval =
(60000000f32 / self.number_of_steps as f32 / rpm / self.step_division as f32) as u32;
}
pub fn move_instant(&mut self, steps_to_move: u64) {
let steps_to_move = steps_to_move * self.step_division as u64;
(0..steps_to_move).for_each(|_| self.step(None));
}
pub fn move_smooth(&mut self,
steps_to_move: u64,
steps_acc: u64,
steps_dec: u64) {
let steps_to_move = (steps_to_move - steps_acc - steps_dec) * self.step_division as u64;
let steps_acc = steps_acc * self.step_division as u64;
let steps_dec = steps_dec * self.step_division as u64;
(1..=steps_acc).for_each(|i| self.step(Some((i, steps_acc))));
(0..steps_to_move).for_each(|_| self.step(None));
(1..=steps_dec).rev().for_each(|i| self.step(Some((i, steps_dec))));
}
pub fn set_direction(&mut self, clock_work: bool) {
if clock_work {
self.dir_pin.set_low();
} else {
self.dir_pin.set_high();
}
}
fn step(&mut self, s: Option<(u64, u64)>) {
self.step_pin.set_high();
let mut step_interval = self.step_interval;
if let Some((s1, s2)) = s {
let r1: f64 = s1 as f64 / s2 as f64;
let r2: f64 = 0.1 + 0.2*r1 + 2.2*r1*r1 - 1.5*r1*r1*r1;
step_interval = (self.step_interval as f64 / r2) as u32;
}
self.delay.delay_us(CHIP::STEP_MIN_TIME);
self.step_pin.set_low();
let rest = if step_interval > CHIP::STEP_MIN_TIME {
step_interval - CHIP::STEP_MIN_TIME
} else {
CHIP::STEP_MIN_TIME
};
self.delay.delay_us(rest);
}
fn new(delay: D,
mut dir_pin: DIR,
mut step_pin: STEP,
number_of_steps: u16,
step_division: u8,
rpm: f32) -> Self {
dir_pin.set_high();
step_pin.set_low();
MotorDriver {
delay,
dir_pin,
step_pin,
_chip: PhantomData,
number_of_steps,
step_division,
step_interval: (60000000f32 / number_of_steps as f32
/ rpm / step_division as f32) as u32,
}
}
}
pub trait Params {
const STEP_MIN_TIME: u32;
}
macro_rules! driver {
($name:ident, $time:expr) => {
#[allow(non_camel_case_types)]
#[derive(Debug)]
struct $name;
impl Params for $name {
const STEP_MIN_TIME: u32 = $time;
}
impl<D, DIR, STEP> MotorDriver<D, DIR, STEP, $name>
where
D: DelayUs<u32>,
DIR: OutputPin,
STEP: OutputPin
{
pub fn $name(delay: D,
dir_pin: DIR,
step_pin: STEP,
number_of_steps: u16,
mut step_division: u8,
rpm: f32) -> Self {
if !STEP_DIVISION.contains(&step_division) {
step_division = 1;
}
Self::new(delay, dir_pin, step_pin, number_of_steps, step_division, rpm)
}
}
};
}
driver!(a4988, 1);
driver!(drv8825, 2);
driver!(drv8834, 2);
driver!(drv8880, 1);