Menu

[6510e4]: / SoftwareServo.cpp  Maximize  Restore  History

Download this file

129 lines (108 with data), 3.3 kB

  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
#include "SoftwareServo.h"
SoftwareServo *SoftwareServo::first;
#define NO_ANGLE (0xff)
SoftwareServo::SoftwareServo() : pin(0),angle(NO_ANGLE),pulse0(0),min16(34),max16(150),next(0)
{}
void SoftwareServo::setMinimumPulse(uint16_t t)
{
min16 = t/16;
}
void SoftwareServo::setMaximumPulse(uint16_t t)
{
max16 = t/16;
}
uint8_t SoftwareServo::attach(int pinArg)
{
pin = pinArg;
angle = NO_ANGLE;
pulse0 = 0;
next = first;
first = this;
digitalWrite(pin,0);
pinMode(pin,OUTPUT);
return 1;
}
void SoftwareServo::detach()
{
for ( SoftwareServo **p = &first; *p != 0; p = &((*p)->next) ) {
if ( *p == this) {
*p = this->next;
this->next = 0;
return;
}
}
}
void SoftwareServo::write(int angleArg)
{
if ( angleArg < 0) angleArg = 0;
if ( angleArg > 180) angleArg = 180;
angle = angleArg;
// bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
// That 64L on the end is the TCNT0 prescaler, it will need to change if the clock's prescaler changes,
// but then there will likely be an overflow problem, so it will have to be handled by a human.
pulse0 = (min16*16L*clockCyclesPerMicrosecond() + (max16-min16)*(16L*clockCyclesPerMicrosecond())*angle/180L)/64L;
}
uint8_t SoftwareServo::read()
{
return angle;
}
uint8_t SoftwareServo::attached()
{
for ( SoftwareServo *p = first; p != 0; p = p->next ) {
if ( p == this) return 1;
}
return 0;
}
void SoftwareServo::refresh()
{
uint8_t count = 0, i = 0;
uint16_t base = 0;
SoftwareServo *p;
static unsigned long lastRefresh = 0;
unsigned long m = millis();
// if we haven't wrapped millis, and 20ms have not passed, then don't do anything
if ( m >= lastRefresh && m < lastRefresh + 20) return;
lastRefresh = m;
for ( p = first; p != 0; p = p->next ) if ( p->pulse0) count++;
if ( count == 0) return;
// gather all the SoftwareServos in an array
SoftwareServo *s[count];
for ( p = first; p != 0; p = p->next ) if ( p->pulse0) s[i++] = p;
// bubblesort the SoftwareServos by pulse time, ascending order
for(;;) {
uint8_t moved = 0;
for ( i = 1; i < count; i++) {
if ( s[i]->pulse0 < s[i-1]->pulse0) {
SoftwareServo *t = s[i];
s[i] = s[i-1];
s[i-1] = t;
moved = 1;
}
}
if ( !moved) break;
}
// turn on all the pins
// Note the timing error here... when you have many SoftwareServos going, the
// ones at the front will get a pulse that is a few microseconds too long.
// Figure about 4uS/SoftwareServo after them. This could be compensated, but I feel
// it is within the margin of error of software SoftwareServos that could catch
// an extra interrupt handler at any time.
for ( i = 0; i < count; i++) digitalWrite( s[i]->pin, 1);
uint8_t start = TCNT0;
uint8_t now = start;
uint8_t last = now;
// Now wait for each pin's time in turn..
for ( i = 0; i < count; i++) {
uint16_t go = start + s[i]->pulse0;
// loop until we reach or pass 'go' time
for (;;) {
now = TCNT0;
if ( now < last) base += 256;
last = now;
if ( base+now > go) {
digitalWrite( s[i]->pin,0);
break;
}
}
}
}
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.