uStepper
uStepperServo.cpp
Go to the documentation of this file.
1 /********************************************************************************************
2 * File: uStepperServo.cpp *
3 * Version: 1.1.0 *
4 * date: December 10, 2016 *
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) 2016 *
74 * *
75 * ON Development IVS *
76 * www.on-development.com *
77 * administration@on-development.com *
78 * *
79 * The code contained in this file is based on the Arduino Software Servo Library found at *
80 * http://playground.arduino.cc/ComponentLib/Servo *
81 * *
82 * The code in this file is provided without warranty of any kind - use at own risk! *
83 * neither ON Development IVS nor the author, can be held responsible for any damage *
84 * caused by the use of the code contained in this file ! *
85 * *
86 ********************************************************************************************/
96 #include <uStepperServo.h>
97 
99 
100 
101 
102 uStepperServo::uStepperServo() : pin(0),angle(NO_ANGLE),pulse(0),min16(92),max16(150),next(0)
103 {
104 
105 }
106 
108 {
109  min16 = t/16;
110 }
111 
113 {
114  max16 = t/16;
115 }
116 
117 uint8_t uStepperServo::attach(int pinArg)
118 {
119  pin = pinArg;
120  angle = NO_ANGLE;
121  pulse = 0;
122  next = first;
123  first = this;
124  digitalWrite(pin,0);
125  pinMode(pin,OUTPUT);
126  return 1;
127 }
128 
130 {
131  for ( uStepperServo **p = &first; *p != 0; p = &((*p)->next) ) {
132  if ( *p == this) {
133  *p = this->next;
134  this->next = 0;
135  return;
136  }
137  }
138 }
139 
140 void uStepperServo::write(int angleArg)
141 {
142  if ( angleArg < 0) angleArg = 0;
143  if ( angleArg > 180) angleArg = 180;
144  angle = angleArg;
145  // bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
146  // That 64L on the end is the TCNT0 prescaler, it will need to change if the clock's prescaler changes,
147  // but then there will likely be an overflow problem, so it will have to be handled by a human.
148  pulse = (min16*16L*clockCyclesPerMicrosecond() + (max16-min16)*(16L*clockCyclesPerMicrosecond())*angle/180L)/64L;
149 }
150 
152 {
153  uint8_t count = 0, i = 0;
154  uint16_t base = 0;
155  uStepperServo *p;
156  static unsigned long lastRefresh = 0;
157  unsigned long m = millis();
158 
159  // if we haven't wrapped millis, and 20ms have not passed, then don't do anything
160  if ( m >= lastRefresh && m < lastRefresh + 20) return;
161  lastRefresh = m;
162 
163  for ( p = first; p != 0; p = p->next ) if ( p->pulse) count++;
164  if ( count == 0) return;
165 
166  // gather all the uStepperServos in an array
167  uStepperServo *s[count];
168  for ( p = first; p != 0; p = p->next ) if ( p->pulse) s[i++] = p;
169 
170  // bubblesort the uStepperServos by pulse time, ascending order
171  for(;;) {
172  uint8_t moved = 0;
173  for ( i = 1; i < count; i++) {
174  if ( s[i]->pulse < s[i-1]->pulse) {
175  uStepperServo *t = s[i];
176  s[i] = s[i-1];
177  s[i-1] = t;
178  moved = 1;
179  }
180  }
181  if ( !moved) break;
182  }
183 
184  // turn on all the pins
185  // Note the timing error here... when you have many uStepperServos going, the
186  // ones at the front will get a pulse that is a few microseconds too long.
187  // Figure about 4uS/uStepperServo after them. This could be compensated, but I feel
188  // it is within the margin of error of software uStepperServos that could catch
189  // an extra interrupt handler at any time.
190  TCCR1B &= ~(1 << CS10);
191  //cli();
192  for ( i = 0; i < count; i++) digitalWrite( s[i]->pin, 1);
193 
194  uint8_t start = TCNT0;
195  uint8_t now = start;
196  uint8_t last = now;
197 
198  // Now wait for each pin's time in turn..
199  for ( i = 0; i < count; i++) {
200  uint16_t go = start + s[i]->pulse;// current time + pulse length for specific servo
201 
202  // loop until we reach or pass 'go' time
203 
204  for (;;) {
205  now = TCNT0;
206  if ( now < last) base += 256;//Timer 0 tops at 255, so add 256 on overflow
207  last = now;//update overflow check variable
208 
209  if(base + now >= go - 16)
210  {
211  cli();
212  }
213 
214  if ( base+now > go) {
215  digitalWrite( s[i]->pin,0);
216  sei();
217  break;
218  }
219  }
220  }
221  TCCR1B |= (1 << CS10);
222 }
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:59
Prototype of class for ustepper servo.
Definition: uStepperServo.h:43
static void refresh()
Updates servo output pins.
uStepperServo()
Constructor for servo class.
uint16_t pulse
Definition: uStepperServo.h:51
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:62