-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathSwitecX12.cpp
155 lines (138 loc) · 3.46 KB
/
SwitecX12.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
* SwitecX12 Arduino Library
* Guy Carpenter, Clearwater Software - 2017
*
* Licensed under the BSD2 license, see license.txt for details.
*
* All text above must be included in any redistribution.
*/
#include <Arduino.h>
#include "SwitecX12.h"
// This table defines the acceleration curve.
// 1st value is the speed step, 2nd value is delay in microseconds
// 1st value in each row must be > 1st value in subsequent row
// 1st value in last row should be == maxVel, must be <= maxVel
static unsigned short defaultAccelTable[][2] = {
{ 20, 800},
{ 50, 400},
{ 100, 200},
{ 150, 150},
{ 300, 90}
};
const int stepPulseMicrosec = 1;
const int resetStepMicrosec = 300;
#define DEFAULT_ACCEL_TABLE_SIZE (sizeof(defaultAccelTable)/sizeof(*defaultAccelTable))
SwitecX12::SwitecX12(unsigned int steps, unsigned char pinStep, unsigned char pinDir)
{
this->steps = steps;
this->pinStep = pinStep;
this->pinDir = pinDir;
pinMode(pinStep, OUTPUT);
pinMode(pinDir, OUTPUT);
digitalWrite(pinStep, LOW);
digitalWrite(pinDir, LOW);
dir = 0;
vel = 0;
stopped = true;
currentStep = 0;
targetStep = 0;
accelTable = defaultAccelTable;
maxVel = defaultAccelTable[DEFAULT_ACCEL_TABLE_SIZE-1][0]; // last value in table.
}
void SwitecX12::step(int dir)
{
digitalWrite(pinDir, dir > 0 ? LOW : HIGH);
digitalWrite(13, vel == maxVel ? HIGH : LOW);
digitalWrite(pinStep, HIGH);
delayMicroseconds(stepPulseMicrosec);
digitalWrite(pinStep, LOW);
currentStep += dir;
}
void SwitecX12::stepTo(int position)
{
int count;
int dir;
if (position > currentStep) {
dir = 1;
count = position - currentStep;
} else {
dir = -1;
count = currentStep - position;
}
for (int i=0;i<count;i++) {
step(dir);
delayMicroseconds(resetStepMicrosec);
}
}
void SwitecX12::zero()
{
currentStep = steps - 1;
stepTo(0);
targetStep = 0;
vel = 0;
dir = 0;
}
void SwitecX12::advance()
{
// detect stopped state
if (currentStep==targetStep && vel==0) {
stopped = true;
dir = 0;
time0 = micros();
return;
}
// if stopped, determine direction
if (vel==0) {
dir = currentStep<targetStep ? 1 : -1;
// do not set to 0 or it could go negative in case 2 below
vel = 1;
}
step(dir);
// determine delta, number of steps in current direction to target.
// may be negative if we are headed away from target
int delta = dir>0 ? targetStep-currentStep : currentStep-targetStep;
if (delta>0) {
// case 1 : moving towards target (maybe under accel or decel)
if (delta < vel) {
// time to declerate
vel = delta;
} else if (vel < maxVel) {
// accelerating
vel++;
} else {
// at full speed - stay there
}
} else {
// case 2 : at or moving away from target (slow down!)
vel--;
}
// vel now defines delay
unsigned char i = 0;
// this is why vel must not be greater than the last vel in the table.
while (accelTable[i][0]<vel) {
i++;
}
microDelay = accelTable[i][1];
time0 = micros();
}
void SwitecX12::setPosition(unsigned int pos)
{
// pos is unsigned so don't need to check for <0
if (pos >= steps) pos = steps-1;
targetStep = pos;
if (stopped) {
// reset the timer to avoid possible time overflow giving spurious deltas
stopped = false;
time0 = micros();
microDelay = 0;
}
}
void SwitecX12::update()
{
if (!stopped) {
unsigned long delta = micros() - time0;
if (delta >= microDelay) {
advance();
}
}
}