uStepper S-lite
uStepperServo.cpp
Go to the documentation of this file.
1 /********************************************************************************************
2 * File: uStepperServo.cpp *
3 * Version: 1.1.0 *
4 * Date: June 14, 2020 *
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) 2020 *
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 ********************************************************************************************/
98 #include <uStepperServo.h>
99 
101 
102 
103 
104 uStepperServo::uStepperServo() : pin(0),angle(NO_ANGLE),pulse(0),min16(92),max16(150),next(0)
105 {
106 
107 }
108 
110 {
111  min16 = t/16;
112 }
113 
115 {
116  max16 = t/16;
117 }
118 
119 uint8_t uStepperServo::attach(int pinArg)
120 {
121  pin = pinArg;
122  angle = NO_ANGLE;
123  pulse = 0;
124  next = first;
125  first = this;
126  digitalWrite(pin,0);
127  pinMode(pin,OUTPUT);
128  return 1;
129 }
130 
132 {
133  for ( uStepperServo **p = &first; *p != 0; p = &((*p)->next) ) {
134  if ( *p == this) {
135  *p = this->next;
136  this->next = 0;
137  return;
138  }
139  }
140 }
141 
142 void uStepperServo::write(int angleArg)
143 {
144  if ( angleArg < 0) angleArg = 0;
145  if ( angleArg > 180) angleArg = 180;
146  angle = angleArg;
147  // bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
148  // That 64L on the end is the TCNT0 prescaler, it will need to change if the clock's prescaler changes,
149  // but then there will likely be an overflow problem, so it will have to be handled by a human.
150  pulse = (min16*16L*clockCyclesPerMicrosecond() + (max16-min16)*(16L*clockCyclesPerMicrosecond())*angle/180L)/64L;
151 }
152 
154 {
155  uint8_t count = 0, i = 0;
156  uint16_t base = 0;
157  uStepperServo *p;
158  static unsigned long lastRefresh = 0;
159  unsigned long m = millis();
160 
161  // if we haven't wrapped millis, and 20ms have not passed, then don't do anything
162  if ( m >= lastRefresh && m < lastRefresh + 20) return;
163  lastRefresh = m;
164 
165  for ( p = first; p != 0; p = p->next ) if ( p->pulse) count++;
166  if ( count == 0) return;
167 
168  // gather all the uStepperServos in an array
169  uStepperServo *s[count];
170  for ( p = first; p != 0; p = p->next ) if ( p->pulse) s[i++] = p;
171 
172  // bubblesort the uStepperServos by pulse time, ascending order
173  for(;;) {
174  uint8_t moved = 0;
175  for ( i = 1; i < count; i++) {
176  if ( s[i]->pulse < s[i-1]->pulse) {
177  uStepperServo *t = s[i];
178  s[i] = s[i-1];
179  s[i-1] = t;
180  moved = 1;
181  }
182  }
183  if ( !moved) break;
184  }
185 
186  // turn on all the pins
187  // Note the timing error here... when you have many uStepperServos going, the
188  // ones at the front will get a pulse that is a few microseconds too long.
189  // Figure about 4uS/uStepperServo after them. This could be compensated, but I feel
190  // it is within the margin of error of software uStepperServos that could catch
191  // an extra interrupt handler at any time.
192 
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  cli();
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 
213  }
214 
215  if ( base+now > go) {
216  digitalWrite( s[i]->pin,0);
217 
218  break;
219  }
220  }
221  sei();
222  }
223 }
uStepperServo::refresh
static void refresh()
Updates servo output pins.
Definition: uStepperServo.cpp:153
uStepperServo::attach
uint8_t attach(int pinArg)
Attaches the servo motor to a specific pin.
Definition: uStepperServo.cpp:119
uStepperServo::detach
void detach()
Detaches the servo motor from the uStepper.
Definition: uStepperServo.cpp:131
uStepperServo::write
void write(int angleArg)
Specify angle of servo motor.
Definition: uStepperServo.cpp:142
uStepperServo::setMaximumPulse
void setMaximumPulse(uint16_t t)
Sets the maximum pulse.
Definition: uStepperServo.cpp:114
uStepperServo::setMinimumPulse
void setMinimumPulse(uint16_t t)
Sets the minimum pulse.
Definition: uStepperServo.cpp:109
uStepperServo.h
Function prototypes and definitions for the uStepper Servo library.
uStepperServo::next
class uStepperServo * next
Definition: uStepperServo.h:60
uStepperServo::first
static uStepperServo * first
Definition: uStepperServo.h:63
uStepperServo
Prototype of class for ustepper servo.
Definition: uStepperServo.h:45
uStepperServo::uStepperServo
uStepperServo()
Constructor for servo class.
Definition: uStepperServo.cpp:104
uStepperServo::min16
uint8_t min16
Definition: uStepperServo.h:54
uStepperServo::pin
uint8_t pin
Definition: uStepperServo.h:48
uStepperServo::max16
uint8_t max16
Definition: uStepperServo.h:56
uStepperServo::angle
uint8_t angle
Definition: uStepperServo.h:50
uStepperServo::pulse
uint16_t pulse
Definition: uStepperServo.h:52