stepper-motor
Arduino library to accurately control a stepper motor
stepper_motor.cpp
1 #include <Arduino.h>
2 
3 #include "stepper_motor.h"
4 
5 // Sequence used to turn the stepper motor one step
6 const PROGMEM uint8_t STEP_SEQUENCE[] = {
7  0b00000001,
8  0b00000011,
9  0b00000010,
10  0b00000110,
11  0b00000100,
12  0b00001100,
13  0b00001000,
14  0b00001001,
15 };
16 
17 StepperMotor::Driver::Driver(std::initializer_list<uint8_t> pins) {
18  size_t i = 0;
19  for(uint8_t pin : pins) {
20  if(i >= 4) break;
21  this->pins[i++] = pin;
22  pinMode(pin, OUTPUT);
23  }
24 }
25 
26 void StepperMotor::Driver::turn(int16_t degree) {
27  if(degree < 0) {
28  uint8_t rotations = -degree / 360;
29  degree = -degree % 360;
30 
31  for(uint16_t steps = 0; steps < rotations * steps_per_rotation; ++steps) {
32  stepBackward();
33  }
34  turnTo(((int16_t)current_degree_position - degree + 360) % 360);
35  } else {
36  uint8_t rotations = degree / 360;
37  degree = degree % 360;
38 
39  for(uint16_t steps = 0; steps < rotations * steps_per_rotation; ++steps) {
40  stepForward();
41  }
42  turnTo(((int16_t)current_degree_position + degree) % 360);
43  }
44 }
45 
46 void StepperMotor::Driver::turnTo(uint16_t target_angle) {
47  target_angle = target_angle % 360;
48  uint16_t target_step_position = ((uint32_t)target_angle * steps_per_rotation / 360) % steps_per_rotation;
49 
50  while(target_step_position != current_step_position) {
51  if(current_step_position > target_step_position && current_step_position - target_step_position < steps_per_rotation / 2 ||
52  current_step_position < target_step_position && target_step_position - current_step_position > steps_per_rotation / 2) {
53  stepBackward();
54  } else {
55  stepForward();
56  }
57  }
58 
59  current_degree_position = target_angle;
60  resetPins();
61 }
62 
64  steps_per_rotation = steps;
65 }
66 
67 void StepperMotor::Driver::setWaiter(void (*waiter)(unsigned int)) {
68  this->waiter = waiter;
69 }
70 
71 
72 void StepperMotor::Driver::stepForward() {
73  current_step_position = (current_step_position + 1) % steps_per_rotation;
74  for(size_t i = 0; i < 8; ++i) {
75  executeStep(pgm_read_byte_near(STEP_SEQUENCE + i));
76  waiter(800);
77  }
78 }
79 
80 void StepperMotor::Driver::stepBackward() {
81  current_step_position = (current_step_position + steps_per_rotation - 1) % steps_per_rotation;
82  for(size_t i = 0; i < 8; ++i) {
83  executeStep(pgm_read_byte_near(STEP_SEQUENCE + (7 - i)));
84  waiter(800);
85  }
86 }
87 
88 void StepperMotor::Driver::executeStep(uint8_t step) {
89  size_t j = 0;
90  for(uint8_t pin : pins) {
91  digitalWrite(pin, (step & 1 << j++) != 0);
92  }
93 }
94 
95 void StepperMotor::Driver::resetPins() {
96  for(uint8_t pin : pins) {
97  digitalWrite(pin, false);
98  }
99 }
Driver(std::initializer_list< uint8_t > pins)
Create a new driver instance using the given pins.
void turn(int16_t degree)
Relative turn.
void turnTo(uint16_t target_angle)
Absolute turn.
void setStepsPerRotation(uint16_t steps)
Set the steps needed for one complete rotation.
void setWaiter(void(*waiter)(unsigned int))
Set a custom waiter.