uStepper
uStepperServo.cpp
Go to the documentation of this file.
1 /********************************************************************************************
2 * File: uStepper.cpp *
3 * Version: 1.3.0 *
4 * date: January 10th, 2018 *
5 * Author: Thomas Hørring Olsen *
6 * *
7 *********************************************************************************************
8 * uStepperServo class *
9 * *
10 * This file contains the implementation of the class methods, incorporated in the *
11 * uStepperServo arduino library. The library is used by instantiating an uStepperServo *
12 * object by calling either of the two overloaded constructors: *
13 * *
14 * example: *
15 * *
16 * uStepperServo servo; *
17 * *
18 * *
19 * after instantiation of the object, the object attach function, should be called within *
20 * arduino's setup function: *
21 * *
22 * example: *
23 * *
24 * uStepperServo servo; *
25 * *
26 * void setup() *
27 * { *
28 * servo.attach(10); *
29 * } *
30 * *
31 * This will attach a servo to pin 10, which is the argument of the attach function. *
32 * *
33 * The servo pulse widths are normally around 500 us for 0 deg and 2500 us for 180 deg. *
34 * The default values in this library are 1472 and 2400 us - giving a work area of *
35 * ~90-180deg. These values can be redefined to fit your servos specifications by calling *
36 * the setMaximumPulse and SetMinimumPulse functions. However, because of running the *
37 * stepper algorithm simultaniously with the servo, there is a risk of twitching if *
38 * using lower values than the 1500 us. * *
39 * *
40 * example: *
41 * *
42 * uStepperServo servo; *
43 * *
44 * void setup() *
45 * { *
46 * servo.attach(10); *
47 * servo.SetMaximumPulse(2400); *
48 * servo.SetMinimumPulse(1500);//Should be kept above 1500!! *
49 * } *
50 * *
51 * To apply the pulses to the attached servos, the refresh function should be called *
52 * periodically at a rate of 20-50 Hz, i.e. every 50-20 ms. Calling the function more *
53 * often than every 20 ms is not a problem for the servo library. *
54 * *
55 * example *
56 * *
57 * uStepperServo servo; *
58 * *
59 * void setup() *
60 * { *
61 * servo.attach(10); *
62 * servo.SetMaximumPulse(2400); *
63 * servo.SetMinimumPulse(1500); //Should be kept above 1500!! *
64 * } *
65 * *
66 * void loop() *
67 * { *
68 * uStepperServo::refresh(); *
69 * } *
70 * After this, the library is ready to control the Servo! *
71 * *
72 *********************************************************************************************
73 * (C) 2018 *
74 * *
75 * uStepper ApS *
76 * www.ustepper.com *
77 * administration@ustepper.com *
78 * *
79 * The code contained in this file is released under the following open source license: *
80 * *
81 * Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International *
82 * *
83 * The code in this file is provided without warranty of any kind - use at own risk! *
84 * neither uStepper ApS nor the author, can be held responsible for any damage *
85 * caused by the use of the code contained in this file ! *
86 * *
87 ********************************************************************************************/
97 #include <uStepperServo.h>
98 
100 
101 
102 
103 uStepperServo::uStepperServo() : pin(0),angle(NO_ANGLE),pulse(0),min16(92),max16(150),next(0)
104 {
105 
106 }
107 
109 {
110  min16 = t/16;
111 }
112 
114 {
115  max16 = t/16;
116 }
117 
118 uint8_t uStepperServo::attach(int pinArg)
119 {
120  pin = pinArg;
121  angle = NO_ANGLE;
122  pulse = 0;
123  next = first;
124  first = this;
125  digitalWrite(pin,0);
126  pinMode(pin,OUTPUT);
127  return 1;
128 }
129 
131 {
132  for ( uStepperServo **p = &first; *p != 0; p = &((*p)->next) ) {
133  if ( *p == this) {
134  *p = this->next;
135  this->next = 0;
136  return;
137  }
138  }
139 }
140 
141 void uStepperServo::write(int angleArg)
142 {
143  if ( angleArg < 0) angleArg = 0;
144  if ( angleArg > 180) angleArg = 180;
145  angle = angleArg;
146  // bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
147  // That 64L on the end is the TCNT0 prescaler, it will need to change if the clock's prescaler changes,
148  // but then there will likely be an overflow problem, so it will have to be handled by a human.
149  pulse = (min16*16L*clockCyclesPerMicrosecond() + (max16-min16)*(16L*clockCyclesPerMicrosecond())*angle/180L)/64L;
150 }
151 
153 {
154  uint8_t count = 0, i = 0;
155  uint16_t base = 0;
156  uStepperServo *p;
157  static unsigned long lastRefresh = 0;
158  unsigned long m = millis();
159 
160  // if we haven't wrapped millis, and 20ms have not passed, then don't do anything
161  if ( m >= lastRefresh && m < lastRefresh + 20) return;
162  lastRefresh = m;
163 
164  for ( p = first; p != 0; p = p->next ) if ( p->pulse) count++;
165  if ( count == 0) return;
166 
167  // gather all the uStepperServos in an array
168  uStepperServo *s[count];
169  for ( p = first; p != 0; p = p->next ) if ( p->pulse) s[i++] = p;
170 
171  // bubblesort the uStepperServos by pulse time, ascending order
172  for(;;) {
173  uint8_t moved = 0;
174  for ( i = 1; i < count; i++) {
175  if ( s[i]->pulse < s[i-1]->pulse) {
176  uStepperServo *t = s[i];
177  s[i] = s[i-1];
178  s[i-1] = t;
179  moved = 1;
180  }
181  }
182  if ( !moved) break;
183  }
184 
185  // turn on all the pins
186  // Note the timing error here... when you have many uStepperServos going, the
187  // ones at the front will get a pulse that is a few microseconds too long.
188  // Figure about 4uS/uStepperServo after them. This could be compensated, but I feel
189  // it is within the margin of error of software uStepperServos that could catch
190  // an extra interrupt handler at any time.
191  TCCR1B &= ~(1 << CS10);
192  //cli();
193  for ( i = 0; i < count; i++) digitalWrite( s[i]->pin, 1);
194 
195  uint8_t start = TCNT0;
196  uint8_t now = start;
197  uint8_t last = now;
198 
199  // Now wait for each pin's time in turn..
200  for ( i = 0; i < count; i++) {
201  uint16_t go = start + s[i]->pulse;// current time + pulse length for specific servo
202 
203  // loop until we reach or pass 'go' time
204 
205  for (;;) {
206  now = TCNT0;
207  if ( now < last) base += 256;//Timer 0 tops at 255, so add 256 on overflow
208  last = now;//update overflow check variable
209 
210  if(base + now >= go - 16)
211  {
212  cli();
213  }
214 
215  if ( base+now > go) {
216  digitalWrite( s[i]->pin,0);
217  sei();
218  break;
219  }
220  }
221  }
222  TCCR1B |= (1 << CS10);
223 }
void detach()
Detaches the servo motor from the uStepper.
void setMaximumPulse(uint16_t t)
Sets the maximum pulse.
uint8_t attach(int pinArg)
Attaches the servo motor to a specific pin.
class uStepperServo * next
Definition: uStepperServo.h:60
Prototype of class for ustepper servo.
Definition: uStepperServo.h:44
static void refresh()
Updates servo output pins.
uStepperServo()
Constructor for servo class.
uint16_t pulse
Definition: uStepperServo.h:52
Function prototypes and definitions for the uStepper Servo library.
void write(int angleArg)
Specify angle of servo motor.
void setMinimumPulse(uint16_t t)
Sets the minimum pulse.
static uStepperServo * first
Definition: uStepperServo.h:63